#include "NativeCodeGenerator.h"
#include "CompilerTypes.h"
#include "NativeCodeOutliner.h"
#include "Declaration.h"

#define JUMP_TO_BRANCH	1
#define CHECK_NULLPTR	0
#define REYCLE_JUMPS	1
#define DISASSEMBLE_OPT	0

static bool CheckFunc;
static bool CheckCase;


static const int CPU_REG_A = 256;
static const int CPU_REG_X = 257;
static const int CPU_REG_Y = 258;
static const int CPU_REG_C = 259;
static const int CPU_REG_Z = 260;

static const int NUM_REGS = 261;

static const uint32 LIVE_CPU_REG_A = 0x00000001;
static const uint32 LIVE_CPU_REG_X = 0x00000002;
static const uint32 LIVE_CPU_REG_Y = 0x00000004;
static const uint32 LIVE_CPU_REG_C = 0x00000008;
static const uint32 LIVE_CPU_REG_Z = 0x00000010;
static const uint32 LIVE_CPU_REG   = 0x0000001f;

static const uint32 LIVE_MEM	   = 0x00000020;

static const uint32 LIVE_ALL	   = 0x000000ff;

static int GlobalValueNumber = 0;

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

static unsigned BinMask(unsigned n)
{
	n |= n >> 8;
	n |= n >> 4;
	n |= n >> 2;
	n |= n >> 1;
	return n;
}

static unsigned LowBinMask(unsigned n)
{
	n = ~n;
	n |= n << 16;
	n |= n << 8;
	n |= n << 4;
	n |= n << 2;
	n |= n << 1;
	n = ~n;
	return n;
}

NativeRegisterData::NativeRegisterData(void)
	: mMode(NRDM_UNKNOWN), mValue(GlobalValueNumber++), mMask(0), mMinVal(0), mMaxVal(255)
{
	mUnique = mValue;
}

void NativeRegisterData::Set(NativeRegisterDataMode mode, int value, LinkerObject* lo, int flags, int minv, int maxv)
{
	mMode = mode;
	mValue = value;
	mLinkerObject = lo;
	mFlags = flags;
	mUnique = GlobalValueNumber++;
	mMinVal = minv;
	mMaxVal = maxv;
}

void NativeRegisterData::Reset(void)
{
	mFlags = 0;
	mMode = NRDM_UNKNOWN;
	mValue = mUnique = GlobalValueNumber++;
	mMinVal = 0;
	mMaxVal = 255;
}

void NativeRegisterData::ResetMask(void)
{
	mMask = 0;
}

void NativeRegisterData::SetMask(int mask, int value)
{
	mMask = mask;
	mValue = value;
}

void NativeRegisterData::ResetAliasing(void)
{
	if (mFlags & NCIF_ALIASING)
		Reset();
}


bool NativeRegisterData::SameData(const NativeCodeInstruction& ins) const
{
	if (ins.mMode == ASMIM_ZERO_PAGE)
		return mMode == NRDM_ZERO_PAGE && mValue == ins.mAddress;
	else if (ins.mMode == ASMIM_ABSOLUTE)
		return mMode == NRDM_ABSOLUTE && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
	else if (ins.mMode == ASMIM_ABSOLUTE_X)
		return mMode == NRDM_ABSOLUTE_X && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
	else if (ins.mMode == ASMIM_ABSOLUTE_Y)
		return mMode == NRDM_ABSOLUTE_Y && mValue == ins.mAddress && mLinkerObject == ins.mLinkerObject && mFlags == ins.mFlags;
	else if (ins.mMode == ASMIM_INDIRECT_Y)
		return mMode == NRDM_INDIRECT_Y && mValue == ins.mAddress;
	else
		return false;
}

bool NativeRegisterData::SameData(const NativeRegisterData& d) const
{
	if (mMode != d.mMode)
		return false;

	switch (mMode)
	{
	case NRDM_UNKNOWN:
	case NRDM_IMMEDIATE:
	case NRDM_ZERO_PAGE:
		return mValue == d.mValue;
	case NRDM_IMMEDIATE_ADDRESS:
	case NRDM_ABSOLUTE:
		return mValue == d.mValue && mLinkerObject == d.mLinkerObject && (mFlags & NCIF_IMMADDR_FLAGS) == (d.mFlags & NCIF_IMMADDR_FLAGS);
	default:
		return false;
	}
}

const NativeRegisterData& NativeRegisterDataSet::operator[](int reg) const
{
	return mRegs[reg];
}

void NativeRegisterDataSet::Set(int reg, NativeRegisterDataMode mode, int value, LinkerObject* lo, int flags, int minv, int maxv)
{
	mRegs[reg].Set(mode, value, lo, flags, minv, maxv);
}

void NativeRegisterDataSet::Set(int reg, const NativeRegisterData& data)
{
	mRegs[reg] = data;
}

void NativeRegisterDataSet::Reset(int reg)
{
	mRegs[reg].Reset();
}

void NativeRegisterDataSet::ResetMask(int reg)
{
	mRegs[reg].ResetMask();
}

void NativeRegisterDataSet::SetMask(int reg, int mask, int value)
{
	mRegs[reg].SetMask(mask, value);
}

void NativeRegisterDataSet::SetMask(int reg, const NativeRegisterData& data)
{
	mRegs[reg].SetMask(data.mMask, data.mValue);
}

void NativeRegisterDataSet::ResetAliasing(int reg)
{
	mRegs[reg].ResetAliasing();
}

void NativeRegisterDataSet::Reset(void)
{
	for (int i = 0; i < NUM_REGS; i++)
		mRegs[i].Reset();
}

void NativeRegisterDataSet::ResetMask(void)
{
	for (int i = 0; i < NUM_REGS; i++)
		mRegs[i].ResetMask();
}

void NativeRegisterDataSet::ResetCall(const NativeCodeInstruction& ins, int fastCallBase)
{
	if (!(ins.mFlags & NCIF_PRESERVE_CPU_REG_A))
		mRegs[CPU_REG_A].Reset();
	if (!(ins.mFlags & NCIF_PRESERVE_CPU_REG_X))
		mRegs[CPU_REG_X].Reset();
	if (!(ins.mFlags & NCIF_PRESERVE_CPU_REG_Y))
		mRegs[CPU_REG_Y].Reset();

	mRegs[CPU_REG_C].Reset();
	mRegs[CPU_REG_Z].Reset();

	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_ABSOLUTE ||
			mRegs[i].mMode == NRDM_ABSOLUTE_X ||
			mRegs[i].mMode == NRDM_ABSOLUTE_Y)
		{
			if (mRegs[i].mLinkerObject && mRegs[i].mLinkerObject->mVariable)
			{
				InterVariable* var = mRegs[i].mLinkerObject->mVariable;

				if (ins.mLinkerObject && ins.mLinkerObject->mProc)
				{
					if (!(var->mLinkerObject->mFlags & LOBJF_LOCAL_VAR))
					{
						if (var->mIndex && var->mIndex < ins.mLinkerObject->mProc->mModule->mGlobalVars.Size() && var == ins.mLinkerObject->mProc->mModule->mGlobalVars[var->mIndex])
						{
							if (ins.mLinkerObject->mProc->ModifiesGlobal(var->mIndex))
								mRegs[i].Reset();
						}
						else
							mRegs[i].Reset();
					}
					else if (var->mAliased && ins.mLinkerObject->mProc->mStoresIndirect)
						mRegs[i].Reset();
				}
				else if (var->mAliased)
					mRegs[i].Reset();
			}
			else
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
		{
			mRegs[i].Reset();
		}
	}

	ResetWorkRegs();

	if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
	{
		ResetAliasing();

		if (ins.mLinkerObject && ins.mLinkerObject->mProc)
		{
#if 1
			ResetZeroPageRange(BC_REG_TMP, ins.mLinkerObject->mProc->mCallerSavedTemps);
#else
			for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
				ResetZeroPage(i);
#endif
		}
		else
		{
#if 1
			ResetZeroPageRange(BC_REG_TMP, BC_REG_TMP_SAVED - BC_REG_TMP);
#else
			for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
				ResetZeroPage(i);
#endif
		}

		if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
		{
			for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS + fastCallBase; i++)
				if (ins.mLinkerObject->mZeroPageSet[i])
					ResetZeroPage(i);
		}
		else
		{
#if 1
			ResetZeroPageRange(BC_REG_FPARAMS, fastCallBase);
#else
			for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS + fastCallBase; i++)
				ResetZeroPage(i);
#endif
		}
	}
}




void NativeRegisterDataSet::ResetWorkRegs(void)
{
	ResetZeroPage(BC_REG_WORK_Y);
	ResetZeroPageRange(BC_REG_ADDR, 2);
	ResetZeroPageRange(BC_REG_ACCU, 4);
	ResetZeroPageRange(BC_REG_WORK, 8);
}

void NativeRegisterDataSet::ResetAliasing(void)
{
	for (int i = 0; i < NUM_REGS; i++)
		mRegs[i].ResetAliasing();
}

void NativeRegisterDataSet::ResetWorkMasks(void)
{
	mRegs[BC_REG_WORK_Y].ResetMask();
	mRegs[BC_REG_ADDR + 0].ResetMask();
	mRegs[BC_REG_ADDR + 1].ResetMask();

	for (int i = 0; i < 4; i++)
		mRegs[BC_REG_ACCU + i].ResetMask();
	for (int i = 0; i < 8; i++)
		mRegs[BC_REG_WORK + i].ResetMask();
}


void NativeRegisterDataSet::ResetZeroPage(int addr)
{
	mRegs[addr].Reset();
	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_ZERO_PAGE && mRegs[i].mValue == addr)
			mRegs[i].Reset();
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y && (mRegs[i].mValue == addr || mRegs[i].mValue + 1 == addr))
		{
			mRegs[i].mValue = mRegs[i].mUnique;
			mRegs[i].mMode = NRDM_UNKNOWN;	// Is not the memory pointed to, but still the same value
		}
	}
}

void NativeRegisterDataSet::ResetZeroPageRange(int addr, int num)
{
	for(int i=0; i<num; i++)
		mRegs[addr + i].Reset();
	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_ZERO_PAGE && mRegs[i].mValue >= addr && mRegs[i].mValue < addr + num)
			mRegs[i].Reset();
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y && mRegs[i].mValue + 1 >= addr && mRegs[i].mValue < addr + num)
		{
			mRegs[i].mValue = mRegs[i].mUnique;
			mRegs[i].mMode = NRDM_UNKNOWN;	// Is not the memory pointed to, but still the same value
		}
	}
}


int NativeRegisterDataSet::FindAbsolute(LinkerObject* linkerObject, int addr)
{
	for (int i = 0; i < 256; i++)
	{
		if (mRegs[i].mMode == NRDM_ABSOLUTE	&& mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue == addr)
			return i;
	}

	return -1;
}

void NativeRegisterDataSet::ResetAbsolute(LinkerObject* linkerObject, int addr)
{
	for (int i = 0; i < NUM_REGS; i++)
	{
		if ((mRegs[i].mMode == NRDM_ABSOLUTE || mRegs[i].mMode == NRDM_ABSOLUTE_X || mRegs[i].mMode == NRDM_ABSOLUTE_Y)
			&& mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue == addr)
			mRegs[i].Reset();
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
			mRegs[i].Reset();
	}
}

void NativeRegisterDataSet::ResetAbsoluteXY(LinkerObject* linkerObject, int addr)
{
	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_ABSOLUTE)
		{
			if (mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue < addr + 256 && mRegs[i].mValue >= addr)
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_ABSOLUTE_X || mRegs[i].mMode == NRDM_ABSOLUTE_Y)
		{
			if (mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue < addr + 256 && mRegs[i].mValue + 256 > addr)
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
			mRegs[i].Reset();
	}
}

void NativeRegisterDataSet::ResetX(void)
{
	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_ABSOLUTE_X)
		{
			mRegs[i].mValue = mRegs[i].mUnique;
			mRegs[i].mMode = NRDM_UNKNOWN;	// Is not the memory pointed to, but still the same value
		}
	}
}

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].mValue = mRegs[i].mUnique;
			mRegs[i].mMode = NRDM_UNKNOWN;	// Is not the memory pointed to, but still the same value
		}
	}
}

void NativeRegisterDataSet::ResetGlobal(void)
{
	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].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)
				;
			else if (mRegs[i].mLinkerObject)
			{
				if (mRegs[i].mLinkerObject->mVariable && !mRegs[i].mLinkerObject->mVariable->mAliased && mRegs[i].mLinkerObject->mSize <= 2)
					;
				else
					mRegs[i].Reset();
			}
			else
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_INDIRECT_Y )
		{
			mRegs[i].Reset();
		}
	}
}


void NativeRegisterDataSet::IntersectMask(const NativeRegisterDataSet& set)
{
	for (int i = 0; i < NUM_REGS; i++)
	{
		mRegs[i].mMask &= set.mRegs[i].mMask & ~(mRegs[i].mValue ^ set.mRegs[i].mValue);
	}
}


void NativeRegisterDataSet::Intersect(const NativeRegisterDataSet& set)
{

	for (int i = 0; i < NUM_REGS; i++)
	{
		if (mRegs[i].mMode == NRDM_UNKNOWN)
		{
			if (set.mRegs[i].mMode != NRDM_UNKNOWN || mRegs[i].mValue != set.mRegs[i].mValue)
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_IMMEDIATE)
		{
			if (set.mRegs[i].mMode != NRDM_IMMEDIATE || mRegs[i].mValue != set.mRegs[i].mValue)
				mRegs[i].Reset();
		}
		else if (mRegs[i].mMode == NRDM_IMMEDIATE_ADDRESS)
		{
			if (set.mRegs[i].mMode != NRDM_IMMEDIATE_ADDRESS || mRegs[i].mValue != set.mRegs[i].mValue || mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject || mRegs[i].mFlags != set.mRegs[i].mFlags)
				mRegs[i].Reset();
		}
	}

	bool	changed;
	do
	{
		changed = false;

		for (int i = 0; i < NUM_REGS; i++)
		{
			if (mRegs[i].mMode == NRDM_ZERO_PAGE)
			{
				if (set.mRegs[i].mMode != NRDM_ZERO_PAGE || mRegs[i].mValue != set.mRegs[i].mValue)
				{
					mRegs[i].Reset();
					changed = true;
				}
#if 0
				else if (mRegs[mRegs[i].mValue].mValue != set.mRegs[set.mRegs[i].mValue].mValue)
				{
					mRegs[i].Reset();
					changed = true;
				}
#endif
			}
			else if (mRegs[i].mMode == NRDM_ABSOLUTE)
			{
				if (set.mRegs[i].mMode != NRDM_ABSOLUTE || mRegs[i].mValue != set.mRegs[i].mValue || mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject)
				{
					mRegs[i].Reset();
					changed = true;
				}
			}
			else if (mRegs[i].mMode == NRDM_INDIRECT_Y)
			{
				if (set.mRegs[i].mMode != NRDM_INDIRECT_Y || mRegs[i].mValue != set.mRegs[i].mValue || !mRegs[CPU_REG_Y].SameData(set.mRegs[CPU_REG_Y]))
				{
					mRegs[i].Reset();
					changed = true;
				}
				else
				{
					int reg = mRegs[i].mValue;
					if (!mRegs[reg].SameData(set.mRegs[reg]) || !mRegs[reg + 1].SameData(set.mRegs[reg + 1]))
					{
						mRegs[i].Reset();
						changed = true;
					}
				}
			}
			else if (mRegs[i].mMode == NRDM_ABSOLUTE_X)
			{
				if (set.mRegs[i].mMode != NRDM_ABSOLUTE_X || 
					mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject ||
					mRegs[i].mValue != set.mRegs[i].mValue ||
					!mRegs[CPU_REG_X].SameData(set.mRegs[CPU_REG_X]))
				{
					mRegs[i].Reset();
					changed = true;
				}
			}
			else if (mRegs[i].mMode == NRDM_ABSOLUTE_Y)
			{
				if (set.mRegs[i].mMode != NRDM_ABSOLUTE_Y ||
					mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject ||
					mRegs[i].mValue != set.mRegs[i].mValue ||
					!mRegs[CPU_REG_Y].SameData(set.mRegs[CPU_REG_Y]))
				{
					mRegs[i].Reset();
					changed = true;
				}
			}
		}

	} while (changed);
}

ValueNumberingData::ValueNumberingData(void)
{
	mIndex = GlobalValueNumber++;
	mOffset = 0;
}

void ValueNumberingData::Reset(void)
{
	mIndex = GlobalValueNumber++;
	mOffset = 0;
}

bool ValueNumberingData::SameBase(const  ValueNumberingData& d) const
{
	return mIndex == d.mIndex;
}

int ValueNumberingDataSet::Find(const ValueNumberingData& data) const
{
	for (int i = 0; i < 256; i++)
	{
		if (mRegs[i].mIndex == data.mIndex && mRegs[i].mOffset == data.mOffset)
			return i;
	}
	return -1;
}

void ValueNumberingDataSet::Reset(void)
{
	for (int i = 0; i < 261; i++)
		mRegs[i].Reset();
}

void ValueNumberingDataSet::ResetWorkRegs(void)
{
	mRegs[BC_REG_WORK_Y].Reset();
	mRegs[BC_REG_ADDR].Reset();
	mRegs[BC_REG_ADDR + 1].Reset();

	for (int i = 0; i < 4; i++)
		mRegs[BC_REG_ACCU + i].Reset();
	for (int i = 0; i < 8; i++)
		mRegs[BC_REG_WORK + i].Reset();
}

void ValueNumberingDataSet::ResetCall(const NativeCodeInstruction& ins)
{
	mRegs[CPU_REG_C].Reset();
	mRegs[CPU_REG_Z].Reset();
	mRegs[CPU_REG_A].Reset();
	mRegs[CPU_REG_X].Reset();
	mRegs[CPU_REG_Y].Reset();

	ResetWorkRegs();

	if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
	{
		if (ins.mLinkerObject && ins.mLinkerObject->mProc)
		{
			if (!(ins.mFlags & NCIF_FEXEC) && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
			{
				for (int i = 0; i < 256; i++)
					if (ins.mLinkerObject->mZeroPageSet[i])
						mRegs[i].Reset();
				return;
			}

			for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
				mRegs[i].Reset();
		}
		else
		{
			for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
				mRegs[i].Reset();
		}

		for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
			mRegs[i].Reset();
	}

}

void ValueNumberingDataSet::Intersect(const ValueNumberingDataSet& set)
{
	for (int i = 0; i < 261; i++)
	{
		if (mRegs[i].mIndex != set.mRegs[i].mIndex || mRegs[i].mOffset != set.mRegs[i].mOffset)
			mRegs[i].Reset();
	}
}

ValueReuseData::ValueReuseData(void)
	: mBlock(nullptr)
{

}

void ValueReuseData::Reset(void)
{
	mBlock = nullptr;
}


void ValueReuseDataSet::Reset(void)
{
	for (int i = 0; i < 256; i++)
		mRegs[i].Reset();
}

void ValueReuseDataSet::ResetWorkRegs(void) 
{
	mRegs[BC_REG_WORK_Y].Reset();
	mRegs[BC_REG_ADDR].Reset();
	mRegs[BC_REG_ADDR + 1].Reset();

	for (int i = 0; i < 4; i++)
		mRegs[BC_REG_ACCU + i].Reset();
	for (int i = 0; i < 8; i++)
		mRegs[BC_REG_WORK + i].Reset();
}

void ValueReuseDataSet::ResetCall(const NativeCodeInstruction& ins)
{
	ResetWorkRegs();

	if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
	{
		if (ins.mLinkerObject && ins.mLinkerObject->mProc)
		{
			if (!(ins.mFlags & NCIF_FEXEC) && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
			{
				for (int i = 0; i < 256; i++)
					if (ins.mLinkerObject->mZeroPageSet[i])
						mRegs[i].Reset();
				return;
			}

			for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
				mRegs[i].Reset();
		}
		else
		{
			for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
				mRegs[i].Reset();
		}

		for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
			mRegs[i].Reset();
	}
}

void ValueReuseDataSet::Intersect(const ValueReuseDataSet& set)
{
	for (int i = 0; i < 261; i++)
	{
		if (!set.mRegs[i].mBlock || set.mRegs[i].mBlock != mRegs[i].mBlock || set.mRegs[i].mIndex != mRegs[i].mIndex)
			mRegs[i].mBlock = nullptr;
	}
}


NativeCodeInstruction::NativeCodeInstruction(void)
	: mIns(nullptr), mType(ASMIT_INV), mMode(ASMIM_IMPLIED), mAddress(0), mLinkerObject(nullptr), mFlags(NCIF_LOWER | NCIF_UPPER), mParam(0), mLive(LIVE_ALL), mMinVal(0), mMaxVal(255)
{}

NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmInsType type, AsmInsMode mode, int64 address, LinkerObject* linkerObject, uint32 flags, int param, int minv, int maxv)
	: mIns(ins), mType(type), mMode(mode), mAddress(int(address)), mLinkerObject(linkerObject), mFlags(flags), mParam(param), mLive(LIVE_ALL), mMinVal(minv), mMaxVal(maxv)
{
	if (mIns)
	{
		assert(mIns->mLocation.mFileName);
	}

	if (mode == ASMIM_IMMEDIATE_ADDRESS)
	{
#if 0
		assert(address >= 0);
#endif
		assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
		assert(HasAsmInstructionMode(mType, ASMIM_IMMEDIATE));
	}
	if (mode == ASMIM_IMMEDIATE)
	{
		assert(linkerObject || (address >= 0 && address < 256));
	}
	if (mode == ASMIM_ZERO_PAGE)
	{
		assert(linkerObject || (address >= 1 && address < 256));
	}
}

NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmInsType type, const NativeCodeInstruction& addr)
	: mIns(ins), mType(type), mMode(addr.mMode), mAddress(addr.mAddress), mLinkerObject(addr.mLinkerObject), mFlags(addr.mFlags), mParam(addr.mParam), mLive(LIVE_ALL), mMinVal(0), mMaxVal(255)
{
	if (mIns)
	{
		assert(mIns->mLocation.mFileName);
	}
}

const char* NativeCodeInstruction::AddrName(char* buffer) const
{
	if (mLinkerObject)
	{
		if (mLinkerObject->mIdent)
			sprintf_s(buffer, 160, "%s + %d", mLinkerObject->mIdent->mString, mAddress);
		else
			sprintf_s(buffer, 160, "_lobj%d + %d", mLinkerObject->mID, mAddress);
	}
	else if (mAddress < 256)
		sprintf_s(buffer, 160, "%02x", mAddress);
	else
		sprintf_s(buffer, 160, "%04x", mAddress);

	return buffer;
}

void NativeCodeInstruction::Disassemble(FILE* file) const
{
	char	buffer[160];
	char	flags[4];
	char	i = 0;
	if (mFlags & NCIF_VOLATILE)
		flags[i++] = 'V';
	if (mFlags & NCIF_MEMMAP)
		flags[i++] = 'M';
	flags[i++] = 0;

	switch (mMode)
	{
	case ASMIM_IMPLIED:
		fprintf(file, "%s", AsmInstructionNames[mType]);
		break;
	case ASMIM_IMMEDIATE:
		fprintf(file, "%s #$%02x\t[%02x-%02x]", AsmInstructionNames[mType], mAddress, mMinVal, mMaxVal);
		break;
	case ASMIM_IMMEDIATE_ADDRESS:
		if (mFlags & NCIF_LOWER)
			fprintf(file, "%s #<%s\t[%02x-%02x]", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal);
		else
			fprintf(file, "%s #>%s\t[%02x-%02x]", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal);
		break;
	case ASMIM_ZERO_PAGE:
		fprintf(file, "%s %s\t[%02x-%02x]", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal);
		break;
	case ASMIM_ZERO_PAGE_X:
		fprintf(file, "%s %s, x\t[%02x-%02x]", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal);
		break;
	case ASMIM_ZERO_PAGE_Y:
		fprintf(file, "%s %s, y\t[%02x-%02x]", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal);
		break;
	case ASMIM_ABSOLUTE:
		fprintf(file, "%s %s\t[%02x-%02x] {%s}", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal, flags);
		break;
	case ASMIM_ABSOLUTE_X:
		fprintf(file, "%s %s, x\t[%02x-%02x] {%s}", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal, flags);
		break;
	case ASMIM_ABSOLUTE_Y:
		fprintf(file, "%s %s, y\t[%02x-%02x] {%s}", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal, flags);
		break;
	case ASMIM_INDIRECT:
		fprintf(file, "%s (%s)", AsmInstructionNames[mType], AddrName(buffer));
		break;
	case ASMIM_INDIRECT_X:
		fprintf(file, "%s (%s, x)\t[%02x-%02x] {%s}", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal, flags);
		break;
	case ASMIM_INDIRECT_Y:
		fprintf(file, "%s (%s), y\t[%02x-%02x] {%s}", AsmInstructionNames[mType], AddrName(buffer), mMinVal, mMaxVal, flags);
		break;
	case ASMIM_RELATIVE:
		fprintf(file, "%s %d", AsmInstructionNames[mType], mAddress);
		break;
	}
}

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;
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_A))
			requiredTemps -= CPU_REG_A;
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_X))
			requiredTemps -= CPU_REG_X;
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_Y))
			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_USE_CPU_REG_C)
			requiredTemps += CPU_REG_C;

		if (mFlags & NCIF_RUNTIME)
		{
			for (int i = 0; i < 4; i++)
			{
				requiredTemps += BC_REG_ACCU + i;
				requiredTemps += BC_REG_WORK + i;
			}

			if (mFlags & NCIF_USE_ZP_32_X)
			{
				for (int i = 0; i < 4; i++)
					requiredTemps += mParam + i;
			}

			if (mFlags & NCIF_FEXEC)
			{
				requiredTemps += BC_REG_LOCALS;
				requiredTemps += BC_REG_LOCALS + 1;
				for(int i= BC_REG_FPARAMS; i< BC_REG_FPARAMS_END; i++)
					requiredTemps += i;
			}
		}
		else
		{
			if (mLinkerObject)
			{
				for (int i = 0; i < 4; i++)
				{
					if (mLinkerObject->mZeroPageSet[BC_REG_ACCU + i])
						requiredTemps -= BC_REG_ACCU + i;
					if (mLinkerObject->mZeroPageSet[BC_REG_WORK + i])
						requiredTemps -= BC_REG_WORK + i;
				}
			}

			if (mFlags & NICF_USE_WORKREGS)
			{
				for (int i = 0; i < 10; i++)
					requiredTemps += BC_REG_WORK + i;
			}

			requiredTemps += BC_REG_LOCALS;
			requiredTemps += BC_REG_LOCALS + 1;
			if (mLinkerObject)
			{
				for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
				{
					for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++)
						requiredTemps += mLinkerObject->mTemporaries[i] + j;
				}
			}
		}

		return true;
	}

	if (mType == ASMIT_RTS)
	{
#if 1
		if (mFlags & NCIF_USE_CPU_REG_A)
			requiredTemps += CPU_REG_A;
		else if (mFlags & NCIF_LOWER)
		{
			requiredTemps += BC_REG_ACCU;
			if (mFlags & NCIF_UPPER)
			{
				requiredTemps += BC_REG_ACCU + 1;

				if (mFlags & NCIF_LONG)
				{
					requiredTemps += BC_REG_ACCU + 2;
					requiredTemps += BC_REG_ACCU + 3;
				}
			}
		}
#endif
#if 0
		for (int i = 0; i < 4; i++)
		{
			requiredTemps += BC_REG_ACCU + i;
		}
#endif

		requiredTemps += BC_REG_STACK;
		requiredTemps += BC_REG_STACK + 1;
		requiredTemps += BC_REG_LOCALS;
		requiredTemps += BC_REG_LOCALS + 1;

		return true;
	}

	if (mType == ASMIT_BYTE)
		return true;

	// check side effects

	if (mFlags & NCIF_VOLATILE)
	{
		if (mMode != ASMIM_IMPLIED && mMode != ASMIM_ZERO_PAGE && !(mMode == ASMIM_ABSOLUTE && mLinkerObject))
			used = true;
	}

	switch (mType)
	{
	case ASMIT_STA:
	case ASMIT_STX:
	case ASMIT_STY:
	case ASMIT_INC:
	case ASMIT_DEC:
	case ASMIT_ASL:
	case ASMIT_LSR:
	case ASMIT_ROL:
	case ASMIT_ROR:
		if (mMode != ASMIM_IMPLIED && mMode != ASMIM_ZERO_PAGE)
			used = true;
		break;
	case ASMIT_JSR:
	case ASMIT_JMP:
	case ASMIT_BEQ:
	case ASMIT_BNE:
	case ASMIT_BPL:
	case ASMIT_BMI:
	case ASMIT_BCC:
	case ASMIT_BCS:
		used = true;
		break;
	}

	if (requiredTemps[CPU_REG_C])
	{
		switch (mType)
		{
		case ASMIT_CLC:
		case ASMIT_SEC:
		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_CMP:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_CPX:
		case ASMIT_CPY:
			used = true;
			break;
		}
	}

	if (requiredTemps[CPU_REG_Z])
	{
		switch (mType)
		{
		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_INC:
		case ASMIT_DEC:
		case ASMIT_CMP:
		case ASMIT_CPX:
		case ASMIT_CPY:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_ORA:
		case ASMIT_EOR:
		case ASMIT_AND:
		case ASMIT_LDA:
		case ASMIT_LDX:
		case ASMIT_LDY:
		case ASMIT_BIT:
		case ASMIT_INX:
		case ASMIT_DEX:
		case ASMIT_INY:
		case ASMIT_DEY:
		case ASMIT_TYA:
		case ASMIT_TXA:
		case ASMIT_TAY:
		case ASMIT_TAX:
			used = true;
			break;
		}
	}

	if (requiredTemps[CPU_REG_A])
	{
		switch (mType)
		{
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_ASL:
		case ASMIT_LSR:
			if (mMode == ASMIM_IMPLIED)
				used = true;
			break;
		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ORA:
		case ASMIT_EOR:
		case ASMIT_AND:
		case ASMIT_LDA:
		case ASMIT_TXA:
		case ASMIT_TYA:
			used = true;
			break;
		}
	}

	if (requiredTemps[CPU_REG_X])
	{
		switch (mType)
		{
		case ASMIT_LDX:
		case ASMIT_INX:
		case ASMIT_DEX:
		case ASMIT_TAX:
			used = true;
			break;
		}
	}

	if (requiredTemps[CPU_REG_Y])
	{
		switch (mType)
		{
		case ASMIT_LDY:
		case ASMIT_INY:
		case ASMIT_DEY:
		case ASMIT_TAY:
			used = true;
			break;
		}
	}

	if (mMode == ASMIM_ZERO_PAGE)
	{
		switch (mType)
		{
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_INC:
		case ASMIT_DEC:
		case ASMIT_STA:
		case ASMIT_STX:
		case ASMIT_STY:
			if (requiredTemps[mAddress])
				used = true;
			break;
		}
	}

	if (used)
	{
		switch (mMode)
		{
		case ASMIM_ZERO_PAGE_X:
		case ASMIM_INDIRECT_X:
		case ASMIM_ABSOLUTE_X:
			requiredTemps += CPU_REG_X;
			break;

		case ASMIM_ZERO_PAGE_Y:
		case ASMIM_ABSOLUTE_Y:
			requiredTemps += CPU_REG_Y;
			break;

		case ASMIM_INDIRECT_Y:
			requiredTemps += CPU_REG_Y;
			requiredTemps += mAddress;
			requiredTemps += mAddress + 1;
			break;

		case ASMIM_IMMEDIATE:
			if (mFlags & NICF_TMPREF)
			{
				if (mFlags & NCIF_LOWER)
					requiredTemps += mAddress;
				if (mFlags & NCIF_UPPER)
					requiredTemps += mAddress + 1;
			}
			break;
		}

		// check carry flags

		switch (mType)
		{
		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ROL:
		case ASMIT_ROR:
			requiredTemps += CPU_REG_C;
			break;
		case ASMIT_CMP:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_CPX:
		case ASMIT_CPY:
		case ASMIT_CLC:
		case ASMIT_SEC:
			requiredTemps -= CPU_REG_C;
			break;
		case ASMIT_BCC:
		case ASMIT_BCS:
			requiredTemps += CPU_REG_C;
			break;
		case ASMIT_BEQ:
		case ASMIT_BNE:
		case ASMIT_BPL:
		case ASMIT_BMI:
			requiredTemps += CPU_REG_Z;
			break;
		}

		// check zero flags

		switch (mType)
		{
		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_CMP:
		case ASMIT_CPX:
		case ASMIT_CPY:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_INC:
		case ASMIT_DEC:
		case ASMIT_ORA:
		case ASMIT_EOR:
		case ASMIT_AND:
		case ASMIT_LDA:
		case ASMIT_LDX:
		case ASMIT_LDY:
		case ASMIT_BIT:
		case ASMIT_TAY:
		case ASMIT_TYA:
		case ASMIT_TAX:
		case ASMIT_TXA:
		case ASMIT_INX:
		case ASMIT_DEX:
		case ASMIT_INY:
		case ASMIT_DEY:
			requiredTemps -= CPU_REG_Z;
			break;
		}

		// check CPU register

		switch (mType)
		{
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_ASL:
		case ASMIT_LSR:
			if (mMode == ASMIM_IMPLIED)
				requiredTemps += CPU_REG_A;
			break;

		case ASMIT_LDA:
			requiredTemps -= CPU_REG_A;
			break;

		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_ORA:
		case ASMIT_EOR:
		case ASMIT_AND:
			requiredTemps += CPU_REG_A;
			break;
		case ASMIT_LDX:
			requiredTemps -= CPU_REG_X;
			break;
		case ASMIT_INX:
		case ASMIT_DEX:
			requiredTemps += CPU_REG_X;
			break;
		case ASMIT_LDY:
			requiredTemps -= CPU_REG_Y;
			break;
		case ASMIT_INY:
		case ASMIT_DEY:
			requiredTemps += CPU_REG_Y;
			break;

		case ASMIT_CMP:
		case ASMIT_STA:
			requiredTemps += CPU_REG_A;
			break;
		case ASMIT_CPX:
		case ASMIT_STX:
			requiredTemps += CPU_REG_X;
			break;
		case ASMIT_CPY:
		case ASMIT_STY:
			requiredTemps += CPU_REG_Y;
			break;

		case ASMIT_TXA:
			requiredTemps += CPU_REG_X;
			requiredTemps -= CPU_REG_A;
			break;
		case ASMIT_TYA:
			requiredTemps += CPU_REG_Y;
			requiredTemps -= CPU_REG_A;
			break;
		case ASMIT_TAX:
			requiredTemps += CPU_REG_A;
			requiredTemps -= CPU_REG_X;
			break;
		case ASMIT_TAY:
			requiredTemps += CPU_REG_A;
			requiredTemps -= CPU_REG_Y;
			break;
		}

		if (mMode == ASMIM_ZERO_PAGE)
		{
			switch (mType)
			{
			case ASMIT_STA:
			case ASMIT_STX:
			case ASMIT_STY:
				requiredTemps -= mAddress;
				break;
			default:
				requiredTemps += mAddress;
			}
		}

		return true;
	}

	return false;
}

bool NativeCodeInstruction::LoadsAccu(void) const
{
	return mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_JSR;
}

bool NativeCodeInstruction::ChangesAccuAndFlag(void) const
{
	if (mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA ||
		mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
		mType == ASMIT_SBC || mType == ASMIT_ADC)
		return true;
	else if (mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROR || mType == ASMIT_ROL)
		return mMode == ASMIM_IMPLIED;
	else
		return false;
}

bool NativeCodeInstruction::ChangesFlagToAccu(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 ||
		mType == ASMIT_TAX || mType == ASMIT_TAY)
		return true;
	else if (mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROR || mType == ASMIT_ROL)
		return mMode == ASMIM_IMPLIED;
	else
		return false;
}

uint32 NativeCodeInstruction::NeedsLive(void) const
{
	uint32 live = mLive;
	if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y)
		live |= LIVE_CPU_REG_Y;
	if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X)
		live |= LIVE_CPU_REG_X;

	if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY)
		live |= LIVE_CPU_REG_Y;
	if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX)
		live |= LIVE_CPU_REG_X;

	if (mMode == ASMIM_IMPLIED && (mType == ASMIT_TAX || mType == ASMIT_TAY ||
		mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR))
		live |= LIVE_CPU_REG_A;

	if (mType == ASMIT_STA ||
		mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
		mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP)
		live |= LIVE_CPU_REG_A;

	if (mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_ROL || mType == ASMIT_ROR)
		live |= LIVE_CPU_REG_C;

	return live;
}

bool NativeCodeInstruction::RequiresYReg(void) const
{
	if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y)
		return true;
	if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY)
		return true;

	return false;
}

bool NativeCodeInstruction::RequiresXReg(void) const
{
	if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_ZERO_PAGE_X)
		return true;
	if (mType == ASMIT_TXA || mType == ASMIT_STX || mType == ASMIT_CPX || mType == ASMIT_INX || mType == ASMIT_DEX)
		return true;

	return false;
}


bool NativeCodeInstruction::ReplaceYRegWithXReg(void)
{
	bool	changed = false;

	switch (mType)
	{
	case ASMIT_LDY:
		mType = ASMIT_LDX;
		changed = true;
		break;
	case ASMIT_STY:
		mType = ASMIT_STX;
		changed = true;
		break;
	case ASMIT_CPY:
		mType = ASMIT_CPX;
		changed = true;
		break;
	case ASMIT_TYA:
		mType = ASMIT_TXA;
		changed = true;
		break;
	case ASMIT_TAY:
		mType = ASMIT_TAX;
		changed = true;
		break;
	case ASMIT_INY:
		mType = ASMIT_INX;
		changed = true;
		break;
	case ASMIT_DEY:
		mType = ASMIT_DEX;
		changed = true;
		break;
	}

	if (mMode == ASMIM_ABSOLUTE_Y)
	{
		assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X));
		mMode = ASMIM_ABSOLUTE_X;
		changed = true;
	}

	if (mLive & LIVE_CPU_REG_Y)
		mLive |= LIVE_CPU_REG_X;

	return changed;
}

bool NativeCodeInstruction::CanSwapXYReg(void)
{
	if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y)
		return false;
	else if (mMode == ASMIM_ABSOLUTE_X)
		return mType == ASMIT_LDY || HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y);
	else if (mMode == ASMIM_ABSOLUTE_Y)
		return mType == ASMIT_LDX || HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X);
	else if (mType == ASMIT_JSR && (mFlags & (NCIF_USE_CPU_REG_X | NCIF_USE_CPU_REG_Y | NCIF_PROVIDE_CPU_REG_X | NCIF_PROVIDE_CPU_REG_Y)))
		return false;
	else
		return true;
}

bool NativeCodeInstruction::SwapXYReg(void)
{
	bool	changed = false;

	switch (mType)
	{
	case ASMIT_LDX:
		mType = ASMIT_LDY;
		changed = true;
		break;
	case ASMIT_STX:
		mType = ASMIT_STY;
		changed = true;
		break;
	case ASMIT_CPX:
		mType = ASMIT_CPY;
		changed = true;
		break;
	case ASMIT_TXA:
		mType = ASMIT_TYA;
		changed = true;
		break;
	case ASMIT_TAX:
		mType = ASMIT_TAY;
		changed = true;
		break;
	case ASMIT_INX:
		mType = ASMIT_INY;
		changed = true;
		break;
	case ASMIT_DEX:
		mType = ASMIT_DEY;
		changed = true;
		break;
	case ASMIT_LDY:
		mType = ASMIT_LDX;
		changed = true;
		break;
	case ASMIT_STY:
		mType = ASMIT_STX;
		changed = true;
		break;
	case ASMIT_CPY:
		mType = ASMIT_CPX;
		changed = true;
		break;
	case ASMIT_TYA:
		mType = ASMIT_TXA;
		changed = true;
		break;
	case ASMIT_TAY:
		mType = ASMIT_TAX;
		changed = true;
		break;
	case ASMIT_INY:
		mType = ASMIT_INX;
		changed = true;
		break;
	case ASMIT_DEY:
		mType = ASMIT_DEX;
		changed = true;
		break;
	}

	if (mMode == ASMIM_ABSOLUTE_X)
	{
		assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y));
		mMode = ASMIM_ABSOLUTE_Y;
		changed = true;
	}
	else if (mMode == ASMIM_ABSOLUTE_Y)
	{
		assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X));
		mMode = ASMIM_ABSOLUTE_X;
		changed = true;
	}
	
	uint32	live = mLive;
	mLive &= ~(LIVE_CPU_REG_X | LIVE_CPU_REG_Y);
	if (live & LIVE_CPU_REG_X)
		mLive |= LIVE_CPU_REG_Y;
	if (live & LIVE_CPU_REG_Y)
		mLive |= LIVE_CPU_REG_X;

	return changed;

}

static void UpdateCollisionSet(NumberSet& liveTemps, NumberSet* collisionSets, int temp)
{
	int i;

	if (temp >= 0 && !liveTemps[temp])
	{
		for (i = 0; i < liveTemps.Size(); i++)
		{
			if (liveTemps[i])
			{
				collisionSets[i] += temp;
				collisionSets[temp] += i;
			}
		}

		liveTemps += temp;
	}
}

void NativeCodeInstruction::BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets)
{
	if (mMode == ASMIM_ZERO_PAGE)
	{
		if (ChangesAddress())
			liveTemps -= mAddress;
		if (UsesAddress())
			UpdateCollisionSet(liveTemps, collisionSets, mAddress);		
	}
	if (mMode == ASMIM_INDIRECT_Y)
	{
		UpdateCollisionSet(liveTemps, collisionSets, mAddress);
		UpdateCollisionSet(liveTemps, collisionSets, mAddress + 1);
	}
	if (mType == ASMIT_JSR)
	{
		for(int i= BC_REG_ACCU; i< BC_REG_ACCU + 4; i++)
			UpdateCollisionSet(liveTemps, collisionSets, i);
		for (int i = BC_REG_WORK; i < BC_REG_WORK + 4; i++)
			UpdateCollisionSet(liveTemps, collisionSets, i);

		if (mFlags & NCIF_RUNTIME)
		{

			if (mFlags & NCIF_USE_ZP_32_X)
			{
				for (int i = mParam; i < mParam + 4; i++)
					UpdateCollisionSet(liveTemps, collisionSets, i);
			}

			if (mFlags & NCIF_FEXEC)
			{
				for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
					UpdateCollisionSet(liveTemps, collisionSets, i);
			}
		}
		else
		{
			for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
				UpdateCollisionSet(liveTemps, collisionSets, i);

			if (mLinkerObject && mLinkerObject->mProc)
			{
				for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++)
					UpdateCollisionSet(liveTemps, collisionSets, i);
			}
			else if (mLinkerObject && mLinkerObject->mNumTemporaries)
			{
				for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
				{
					for (int j = 0; j < mLinkerObject->mTempSizes[i]; j++)
						UpdateCollisionSet(liveTemps, collisionSets, mLinkerObject->mTemporaries[i] + j);
				}
			}
			else
			{
				for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
					UpdateCollisionSet(liveTemps, collisionSets, i);
			}
		}
	}
	else if (mType == ASMIT_RTS)
	{
		if (mFlags & NCIF_LOWER)
		{
			UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 0);

			if (mFlags & NCIF_UPPER)
			{
				UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 1);

				if (mFlags & NCIF_LONG)
				{
					UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 2);
					UpdateCollisionSet(liveTemps, collisionSets, BC_REG_ACCU + 3);
				}
			}
		}
	}
}


bool NativeCodeInstruction::ReplaceXRegWithYReg(void)
{
	bool	changed = false;

	switch (mType)
	{
	case ASMIT_LDX:
		mType = ASMIT_LDY;
		changed = true;
		break;
	case ASMIT_STX:
		mType = ASMIT_STY;
		changed = true;
		break;
	case ASMIT_CPX:
		mType = ASMIT_CPY;
		changed = true;
		break;
	case ASMIT_TXA:
		mType = ASMIT_TYA;
		changed = true;
		break;
	case ASMIT_TAX:
		mType = ASMIT_TAY;
		changed = true;
		break;
	case ASMIT_INX:
		mType = ASMIT_INY;
		changed = true;
		break;
	case ASMIT_DEX:
		mType = ASMIT_DEY;
		changed = true;
		break;
	}

	if (mMode == ASMIM_ABSOLUTE_X)
	{
		assert(HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y));
		mMode = ASMIM_ABSOLUTE_Y;
		changed = true;
	}

	if (mLive & LIVE_CPU_REG_X)
		mLive |= LIVE_CPU_REG_Y;

	return changed;
}

bool NativeCodeInstruction::ChangesYReg(void) const
{
	if (mType == ASMIT_JSR)
		return !(mFlags & NCIF_PRESERVE_CPU_REG_Y);
	else
		return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY;
}

bool NativeCodeInstruction::ChangesXReg(void) const
{
	if (mType == ASMIT_JSR)
		return !(mFlags & NCIF_PRESERVE_CPU_REG_X);
	else
		return mType == ASMIT_TAX || mType == ASMIT_LDX || mType == ASMIT_INX || mType == ASMIT_DEX;
}

bool NativeCodeInstruction::ReferencesCarry(void) const
{
	return ChangesCarry() || RequiresCarry();
}

bool NativeCodeInstruction::ReferencesAccu(void) const
{
	return ChangesAccu() || RequiresAccu();
}

bool NativeCodeInstruction::ReferencesYReg(void) const	
{
	return ChangesYReg() || RequiresYReg();
}

bool NativeCodeInstruction::ReferencesXReg(void) const
{
	return ChangesXReg() || RequiresXReg();
}

bool NativeCodeInstruction::ReferencesZeroPage(int address) const
{
	return UsesZeroPage(address) || ChangesZeroPage(address);
}

bool NativeCodeInstruction::ChangesZeroPage(int address) const
{
	if (mMode == ASMIM_ZERO_PAGE && mAddress == address)
		return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY;
	else if (mType == ASMIT_JSR)
	{
		if (address == BC_REG_WORK_Y)
			return true;
		if (address >= BC_REG_ACCU && address < BC_REG_ACCU + 4)
			return true;
		if (address >= BC_REG_WORK && address < BC_REG_WORK + 8)
			return true;
		if (address >= BC_REG_ADDR && address < BC_REG_ADDR + 4)
			return true;

		if (!(mFlags & NCIF_RUNTIME) || (mFlags & NCIF_FEXEC))
		{
			if (mLinkerObject && mLinkerObject->mProc)
			{
				if (!(mFlags & NCIF_FEXEC) && (mLinkerObject->mFlags & LOBJF_ZEROPAGESET))
					return mLinkerObject->mZeroPageSet[address];
				if (address >= BC_REG_TMP && address < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps)
					return true;
			}
			else if (!mLinkerObject)
			{
				return false;
			}
			else
			{
				if (address >= BC_REG_TMP && address < BC_REG_TMP_SAVED)
					return true;
			}

			if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
				return true;
		}

		return false;
	}
	else
		return false;
}

bool NativeCodeInstruction::UsesZeroPage(int address) const
{
	if (mMode == ASMIM_ZERO_PAGE && mAddress == address)
		return true;
	else if (mMode == ASMIM_INDIRECT_Y && (mAddress == address || mAddress + 1 == address))
		return true;
	else if (mType == ASMIT_JSR)
	{
		if (mFlags & NCIF_RUNTIME)
		{
			if (address >= BC_REG_ACCU && address < BC_REG_ACCU + 4)
				return true;

			if (address >= BC_REG_WORK && address < BC_REG_WORK + 8)
				return true;

			if (mFlags & NCIF_USE_ZP_32_X)
			{
				if (address >= mParam && address < mParam + 4)
					return true;
			}

			if (mFlags & NCIF_FEXEC)
			{
				if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
					return true;
			}
		}
		else
		{
			if (mFlags & NICF_USE_WORKREGS)
			{
				if (address >= BC_REG_WORK && address < BC_REG_WORK + 10)
					return true;
			}

			if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END)
				return true;

			if (mLinkerObject)
			{
				for (int i = 0; i < mLinkerObject->mNumTemporaries; i++)
				{
					if (address >= mLinkerObject->mTemporaries[i] && address < mLinkerObject->mTemporaries[i] + mLinkerObject->mTempSizes[i])
						return true;
				}
			}
		}

		return false;
	}
	else if (mType == ASMIT_RTS)
	{
		if (mFlags & NCIF_LOWER)
		{
			if (address == BC_REG_ACCU + 0)
				return true;

			if (mFlags & NCIF_UPPER)
			{
				if (address == BC_REG_ACCU + 1)
					return true;

				if (mFlags & NCIF_LONG)
				{
					if (address == BC_REG_ACCU + 2 || address == BC_REG_ACCU + 3)
						return true;
				}
			}
		}

		return false;
	}
	else
		return false;
}

bool NativeCodeInstruction::LoadsZeroPage(int address) const
{
	if (mMode == ASMIM_ZERO_PAGE && mAddress == 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::IsPure(void) const
{
	return (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS || mMode == ASMIM_IMPLIED);
}

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::ReferencesGlobalMemory(void) const
{
	return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y;
}

bool NativeCodeInstruction::RequiresCarry(void) const
{
	if (mType == ASMIT_ADC || mType == ASMIT_SBC ||
		mType == ASMIT_ROL || mType == ASMIT_ROR)
	{
		return true;
	}
	else if (mType == ASMIT_JSR)
	{
		return mFlags & NCIF_USE_CPU_REG_C;
	}
	else
		return false;
}

bool NativeCodeInstruction::ChangesZFlag(void) const
{
	return 
		mType == ASMIT_ADC || mType == ASMIT_SBC ||
		mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROL || mType == ASMIT_ROR ||
		mType == ASMIT_INC || mType == ASMIT_DEC ||
		mType == ASMIT_INY || mType == ASMIT_DEY ||
		mType == ASMIT_INX || mType == ASMIT_DEX ||
		mType == ASMIT_TAX || mType == ASMIT_TAY || mType == ASMIT_TXA || mType == ASMIT_TYA ||
		mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
		mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY ||
		mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR ||
		mType == ASMIT_BIT ||
		mType == ASMIT_JSR;
}

bool NativeCodeInstruction::ChangesCarry(void) const
{
	return
		mType == ASMIT_CLC || mType == ASMIT_SEC ||
		mType == ASMIT_ADC || mType == ASMIT_SBC ||
		mType == ASMIT_LSR || mType == ASMIT_ASL || mType == ASMIT_ROL || mType == ASMIT_ROR ||
		mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
		mType == ASMIT_JSR;
}

bool NativeCodeInstruction::RequiresAccu(void) const
{
	if (mMode == ASMIM_IMPLIED)
	{
		return
			mType == ASMIT_TAX || mType == ASMIT_TAY ||
			mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
	}
	else if (mType == ASMIT_JSR)
	{
		return (mFlags & NCIF_USE_CPU_REG_A);
	}
	else
	{
		return
			mType == ASMIT_STA ||
			mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
			mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_CMP;
	}
}

bool NativeCodeInstruction::UsesAccu(void) const
{
	if (ChangesAccu())
		return true;

	return mType == ASMIT_STA || mType == ASMIT_CMP || mType == ASMIT_TAX || mType == ASMIT_TAY;
}

bool NativeCodeInstruction::ChangesAccu(void) const
{
	if (mMode == ASMIM_IMPLIED)
	{
		return
			mType == ASMIT_TXA || mType == ASMIT_TYA ||
			mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
	}
	else if (mType == ASMIT_JSR)
		return !(mFlags & NCIF_PRESERVE_CPU_REG_A);
	else
	{
		return
			mType == ASMIT_LDA || 
			mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR ||
			mType == ASMIT_SBC || mType == ASMIT_ADC;
	}
}



bool NativeCodeInstruction::UsesAddress(void) const
{
	if (mMode != ASMIM_IMPLIED)
	{
		return
			mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR ||
			mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY ||
			mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY ||
			mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR || mType == ASMIT_BIT;
	}
	else
		return false;
}

bool NativeCodeInstruction::ChangesAddress(void) const
{
	if (mMode != ASMIM_IMPLIED)
		return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY;
	else
		return false;
}

bool NativeCodeInstruction::IsSimpleJSR(void) const
{
	return mType == ASMIT_JSR && mMode == ASMIM_ABSOLUTE && !(mLinkerObject && (mLinkerObject->mFlags & LOBJF_INLINE)) && !(mFlags & NCIF_BREAKPOINT);
}

bool NativeCodeInstruction::IsShift(void) const
{
	return mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
}

bool NativeCodeInstruction::IsShiftOrInc(void) const
{
	return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR;
}

bool NativeCodeInstruction::IsShiftRotOrInc(void) const
{
	return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR;
}

bool NativeCodeInstruction::IsArithmetic(void) const
{
	return mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR;
}

bool NativeCodeInstruction::IsAddSub(void) const
{
	return mType == ASMIT_ADC || mType == ASMIT_SBC;
}

bool NativeCodeInstruction::IsCommutative(void) const
{
	return mType == ASMIT_ADC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR;
}

bool NativeCodeInstruction::IsStore(void) const
{
	return mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY;
}

bool NativeCodeInstruction::IsLoad(void) const
{
	return mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY;
}

bool NativeCodeInstruction::IsLogic(void) const
{
	return mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR;
}



bool NativeCodeInstruction::IsSame(const NativeCodeInstruction& ins) const
{
	if (mType == ins.mType && mMode == ins.mMode && mParam == ins.mParam)
	{
		switch (mMode)
		{
		case ASMIM_IMPLIED:
			return true;
		case ASMIM_IMMEDIATE:
		case ASMIM_ZERO_PAGE:
		case ASMIM_ZERO_PAGE_X:
		case ASMIM_ZERO_PAGE_Y:
		case ASMIM_INDIRECT_X:
		case ASMIM_INDIRECT_Y:
			return ins.mAddress == mAddress;
		case ASMIM_IMMEDIATE_ADDRESS:
			return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags);
		case ASMIM_ABSOLUTE:
		case ASMIM_ABSOLUTE_X:
		case ASMIM_ABSOLUTE_Y:
			return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress);
		default:
			return false;
		}
	}
	else
		return false;
}

bool NativeCodeInstruction::IsSameLS(const NativeCodeInstruction& ins) const
{
	if ((mType == ins.mType || mType == ASMIT_STA && ins.mType == ASMIT_LDA) && mMode == ins.mMode && mParam == ins.mParam)
	{
		switch (mMode)
		{
		case ASMIM_IMPLIED:
			return true;
		case ASMIM_IMMEDIATE:
		case ASMIM_ZERO_PAGE:
		case ASMIM_ZERO_PAGE_X:
		case ASMIM_ZERO_PAGE_Y:
		case ASMIM_INDIRECT_X:
		case ASMIM_INDIRECT_Y:
			return ins.mAddress == mAddress;
		case ASMIM_IMMEDIATE_ADDRESS:
			return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags);
		case ASMIM_ABSOLUTE:
		case ASMIM_ABSOLUTE_X:
		case ASMIM_ABSOLUTE_Y:
			return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress);
		default:
			return false;
		}
	}
	else
		return false;
}

bool NativeCodeInstruction::MayBeMovedBefore(const NativeCodeInstruction& ins) const
{
	if (mType == ASMIT_RTS)
		return false;
	if (mType == ASMIT_JSR || ins.mType == ASMIT_JSR)
		return false;
	if ((mFlags & NCIF_VOLATILE) && (ins.mFlags & NCIF_VOLATILE))
		return false;
	if ((mFlags & NCIF_MEMMAP) && ins.ReferencesGlobalMemory())
		return false;
	if ((ins.mFlags & NCIF_MEMMAP) && ReferencesGlobalMemory())
		return false;

	if ((ChangesAddress() || ins.ChangesAddress()) && MayBeSameAddress(ins))
		return false;
	if (ChangesAddress() && mMode == ASMIM_ZERO_PAGE && ins.mMode == ASMIM_INDIRECT_Y && (mAddress == ins.mAddress || mAddress == ins.mAddress + 1))
		return false;
	if (ins.ChangesAddress() && ins.mMode == ASMIM_ZERO_PAGE && mMode == ASMIM_INDIRECT_Y && (mAddress == ins.mAddress || mAddress + 1 == ins.mAddress))
		return false;
	if (RequiresXReg() && ins.ChangesXReg() || ins.RequiresXReg() && ChangesXReg())
		return false;
	if (RequiresYReg() && ins.ChangesYReg() || ins.RequiresYReg() && ChangesYReg())
		return false;
	if (RequiresAccu() && ins.ChangesAccu() || ins.RequiresAccu() && ChangesAccu())
		return false;
	if (RequiresCarry() && ins.ChangesCarry() || ins.RequiresCarry() && ChangesCarry())
		return false;
	if ((mLive & LIVE_CPU_REG_A) && ins.ChangesAccu())
		return false;
	if ((mLive & LIVE_CPU_REG_X) && ins.ChangesXReg())
		return false;
	if ((mLive & LIVE_CPU_REG_Y) && ins.ChangesYReg())
		return false;
	if ((mLive & LIVE_CPU_REG_C) && ins.ChangesCarry())
		return false;
	if ((mLive & LIVE_CPU_REG_Z) && ins.ChangesZFlag())
		return false;

	return true;
}

bool NativeCodeInstruction::MayBeMovedBehind(const NativeCodeInstruction& ins) const
{
	return ins.MayBeMovedBefore(*this);
}

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 if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
		{
			if (ins.mLinkerObject && ins.mLinkerObject->mVariable && !ins.mLinkerObject->mVariable->mAliased)
				return false;
			return true;
		}
		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 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 if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
		{
			if (ins.mLinkerObject && ins.mLinkerObject->mVariable && !ins.mLinkerObject->mVariable->mAliased)
				return false;
			return true;
		}
		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)
		{
			if (mLinkerObject && mLinkerObject->mVariable && !mLinkerObject->mVariable->mAliased)
				return false;
			return true;
		}
		else
			return mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X;
	}
	else
		return false;
}

bool NativeCodeInstruction::MayReference(const NativeCodeInstruction& ins, bool sameXY) const
{
	if (!ins.ChangesAddress())
		return false;

	if (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS || mMode == ASMIM_IMPLIED)
		return false;

	if (mType == ASMIT_JSR)
	{
		if (ins.mFlags & NCIF_ALIASING)
			return true;

		if (ins.mMode == ASMIM_ZERO_PAGE)
			return ReferencesZeroPage(ins.mAddress);
		else
			return true;
	}

	if (ins.mMode == ASMIM_ZERO_PAGE)
		return ReferencesZeroPage(ins.mAddress);
	else if (mMode == ASMIM_ZERO_PAGE)
		return false;
	else if (mMode == ASMIM_ABSOLUTE)
	{
		if (ins.mMode == ASMIM_ABSOLUTE)
			return mLinkerObject == ins.mLinkerObject && mAddress == ins.mAddress;
		else if (ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
			return mLinkerObject == ins.mLinkerObject;
		else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
			return ins.mAddress != BC_REG_STACK;
		else
			return false;
	}
	else if (mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
	{
		if (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
		{
			if (mLinkerObject != ins.mLinkerObject)
				return false;
			else
				return mMode != ins.mMode || !sameXY || mAddress == ins.mAddress;
		}
		else if (ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X)
			return ins.mAddress != BC_REG_STACK;
		else
			return false;
	}
	else if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_INDIRECT_X)
	{
		if (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y)
			return mAddress != BC_REG_STACK;
		else
			return ins.mMode == ASMIM_INDIRECT_Y || ins.mMode == ASMIM_INDIRECT_X;
	}
	else
		return false;
}

bool NativeCodeInstruction::SameLinkerObjectVariableRange(const NativeCodeInstruction& ins, bool sameXY) const
{
	if (mLinkerObject == ins.mLinkerObject)
	{
		if (mMode == ASMIM_ABSOLUTE && ins.mMode == ASMIM_ABSOLUTE)
			return mAddress == ins.mAddress;
		else if (mMode == ins.mMode && sameXY)
			return mAddress == ins.mAddress;
		else if (mLinkerObject && mLinkerObject->mStripe > 1)
			return mAddress / mLinkerObject->mStripe == ins.mAddress / mLinkerObject->mStripe;
		else if (mMode == ASMIM_ABSOLUTE && mAddress < ins.mAddress)
			return false;
		else if (ins.mMode == ASMIM_ABSOLUTE && ins.mAddress < mAddress)
			return false;
		else
			return true;
	}
	else
		return false;
}

bool NativeCodeInstruction::MayBeChangedOnAddress(const NativeCodeInstruction& ins, bool sameXY) const
{
	if (mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS)
		return false;

	if (ins.mFlags & NCIF_MEMMAP)
	{
		if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y)
			return true;
	}

	if (ins.mType == ASMIT_JSR)
	{
		if (mFlags & NCIF_ALIASING)
			return true;
		if (mMode == ASMIM_ZERO_PAGE)
			return ins.ChangesZeroPage(mAddress);
		else if (mMode == ASMIM_IMPLIED || mMode == ASMIM_IMMEDIATE || mMode == ASMIM_IMMEDIATE_ADDRESS)
			return false;
		else
			return true;
	}

	if (!ins.ChangesAddress())
		return false;

	if (ins.mMode == ASMIM_ZERO_PAGE)
	{
		if (mMode == ASMIM_ZERO_PAGE)
			return mAddress == ins.mAddress;
		else if (mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y)
			return mAddress == ins.mAddress || mAddress + 1 == ins.mAddress;
		else
			return mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y;
	}
	else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y)
	{
		return mMode == ASMIM_ZERO_PAGE || mMode == ASMIM_INDIRECT_X || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_X || mMode == ASMIM_ZERO_PAGE_Y;
	}
	else if (ins.mMode == ASMIM_ABSOLUTE)
	{
		if (mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y)
			return SameLinkerObjectVariableRange(ins, sameXY);
		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)
			return SameLinkerObjectVariableRange(ins, sameXY);
		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 if (mType == ASMIT_JSR)
		return true;
	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);
	case ASMIM_IMMEDIATE_ADDRESS:
		return (ins.mLinkerObject == mLinkerObject && ins.mAddress == mAddress && ins.mFlags == mFlags);
	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[mAddress].mMode == NRDM_IMMEDIATE)
		{
			mMode = ASMIM_IMMEDIATE;
			mAddress = data[mAddress].mValue;
			return true;
		}
		else if (mMode == ASMIM_ZERO_PAGE && data[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS)
		{
			mMode = ASMIM_IMMEDIATE_ADDRESS;
			mLinkerObject = data[mAddress].mLinkerObject;
			mFlags = data[mAddress].mFlags;
			mAddress = data[mAddress].mValue;
			assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
			return true;
		}
		break;
	}

	if (mMode == ASMIM_INDIRECT_Y && data[mAddress].mMode == NRDM_IMMEDIATE && data[mAddress + 1].mMode == NRDM_IMMEDIATE)
	{
		mMode = ASMIM_ABSOLUTE_Y;
		mAddress = data[mAddress].mValue + 256 * data[mAddress + 1].mValue;
		mLinkerObject = nullptr;
	}
	else if (mMode == ASMIM_INDIRECT_Y && data[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data[mAddress].mLinkerObject == data[mAddress + 1].mLinkerObject)
	{
		mMode = ASMIM_ABSOLUTE_Y;
		mLinkerObject = data[mAddress].mLinkerObject;
		mAddress = data[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.Reset(CPU_REG_C);
		data.Reset(CPU_REG_Z);
		data.Reset(CPU_REG_A);
		data.Reset(CPU_REG_X);
		data.Reset(CPU_REG_Y);

		data.ResetWorkRegs();

		if (mFlags & NCIF_FEXEC)
		{
			for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
				data.Reset(i);
		}
		else if (!(mFlags & NCIF_RUNTIME))
		{
			if (mLinkerObject && mLinkerObject->mProc)
			{
				for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++)
					data.Reset(i);
			}
			else
			{
				for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
					data.Reset(i);
			}
		}
		break;

	case ASMIT_ROL:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue << 1) | data[CPU_REG_C].mValue;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(reg, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Reset(CPU_REG_Z);
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[reg].mValue >= 128);
				data.Reset(reg);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_ROR:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue >> 1) | (data[CPU_REG_C].mValue << 7);
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[reg].mValue & 1);
				data.Set(reg, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Reset(CPU_REG_Z);
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[reg].mValue & 1);
				data.Reset(reg);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_ASL:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue << 1);
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(reg, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_LSR:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue >> 1);
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[reg].mValue & 1);
				data.Set(reg, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_INC:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Set(reg, NRDM_IMMEDIATE, (data[reg].mValue + 1) & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[reg].mValue);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_Z);
			}
		}
		else
			data.Reset(CPU_REG_Z);
		break;

	case ASMIT_DEC:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Set(reg, NRDM_IMMEDIATE, (data[reg].mValue - 1) & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[reg].mValue);
			}
			else
			{
				data.Reset(reg);
				data.Reset(CPU_REG_Z);
			}
		}
		else
			data.Reset(CPU_REG_Z);
		break;

	case ASMIT_ADC:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			{
				int	t = data[reg].mValue + data[CPU_REG_A].mValue + data[CPU_REG_C].mValue;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_SBC:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue ^ 0xff) + data[CPU_REG_A].mValue + data[CPU_REG_C].mValue;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_AND:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = data[reg].mValue & data[CPU_REG_A].mValue;
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else if ((data[reg].mMode == NRDM_IMMEDIATE && data[reg].mValue == 0) || (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == 0))
			{
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_ORA:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = data[reg].mValue | data[CPU_REG_A].mValue;
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else if ((data[reg].mMode == NRDM_IMMEDIATE && data[reg].mValue == 0xff) || (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == 0xff))
			{
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, 0xff);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0xff);
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_EOR:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = data[reg].mValue ^ data[CPU_REG_A].mValue;
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, t & 255);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_INX:
		if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_X, NRDM_IMMEDIATE, (data[CPU_REG_X].mValue + 1) & 255);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
		}
		else
		{
			data.Reset(CPU_REG_X);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_DEX:
		if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_X, NRDM_IMMEDIATE, (data[CPU_REG_X].mValue - 1) & 255);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
		}
		else
		{
			data.Reset(CPU_REG_X);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_INY:
		if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Y, NRDM_IMMEDIATE, (data[CPU_REG_Y].mValue + 1) & 255);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
		}
		else
		{
			data.Reset(CPU_REG_Y);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_DEY:
		if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Y, NRDM_IMMEDIATE, (data[CPU_REG_Y].mValue - 1) & 255);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
		}
		else
		{
			data.Reset(CPU_REG_Y);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_TXA:
		if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_A, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
		}
		else
		{
			data.Set(CPU_REG_A, data[CPU_REG_X]);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_TYA:
		if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_A, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
		}
		else
		{
			data.Set(CPU_REG_A, data[CPU_REG_Y]);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_TAX:
		if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_X, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
		}
		else
		{
			data.Set(CPU_REG_X, data[CPU_REG_A]);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_TAY:
		if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Y, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
		}
		else
		{
			data.Set(CPU_REG_Y, data[CPU_REG_A]);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_CMP:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue ^ 0xff) + data[CPU_REG_A].mValue + 1;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
		{
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_CPX:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue ^ 0xff) + data[CPU_REG_X].mValue + 1;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
		{
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_CPY:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE && data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
			{
				int	t = (data[reg].mValue ^ 0xff) + data[CPU_REG_Y].mValue + 1;
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, t >= 256);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, t & 255);
			}
			else
			{
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
		{
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_BIT:
		data.Reset(CPU_REG_Z);
		break;

	case ASMIT_LDA:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_A, data[reg]);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
			}
			else
			{
				data.Set(CPU_REG_A, data[reg]);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE)
		{
			data.Set(CPU_REG_A, NRDM_IMMEDIATE, mAddress);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			data.Set(CPU_REG_A, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_LDX:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_X, data[reg]);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
			}
			else
			{
				data.Set(CPU_REG_X, data[reg]);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE)
		{
			data.Set(CPU_REG_X, NRDM_IMMEDIATE, mAddress);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			data.Set(CPU_REG_X, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_X);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_LDY:
		if (reg >= 0)
		{
			if (data[reg].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_Y, data[reg]);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
			}
			else
			{
				data.Set(CPU_REG_Y, data[reg]);
				data.Reset(CPU_REG_Z);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE)
		{
			data.Set(CPU_REG_Y, NRDM_IMMEDIATE, mAddress);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			data.Set(CPU_REG_Y, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_Y);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_STA:
		if (reg >= 0)
		{
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE || data[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS)
				data.Set(reg, data[CPU_REG_A]);
			else
				data.Reset(reg);
		}
		break;

	case ASMIT_STX:
		if (reg >= 0)
		{
			if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE || data[CPU_REG_X].mMode == NRDM_IMMEDIATE_ADDRESS)
				data.Set(reg, data[CPU_REG_X]);
			else
				data.Reset(reg);
		}
		break;

	case ASMIT_STY:
		if (reg >= 0)
		{
			if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE || data[CPU_REG_Y].mMode == NRDM_IMMEDIATE_ADDRESS)
				data.Set(reg, data[CPU_REG_Y]);
			else
				data.Reset(reg);
		}
		break;

	case ASMIT_CLC:
		data.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
		break;

	case ASMIT_SEC:
		data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
		break;
	}
}

bool NativeCodeInstruction::BitFieldForwarding(NativeRegisterDataSet& data, AsmInsType& carryop)
{
	bool	changed = false;

	int		iaddr = -1;
	
	if (mMode == ASMIM_IMPLIED)
		iaddr = CPU_REG_A;
	else if (mMode == ASMIM_ZERO_PAGE)
		iaddr = mAddress;

	int opmask = 0, opvalue = 0;
	if (mMode == ASMIM_IMMEDIATE)
	{
		opmask = 0xff;
		opvalue = mAddress;
	}
	else if (mMode == ASMIM_ZERO_PAGE)
	{
		opmask = data[mAddress].mMask;
		opvalue = data[mAddress].mValue;
	}
	else if (mMode == ASMIM_ABSOLUTE && mLinkerObject && (mLinkerObject->mFlags & LOBJF_CONST) && mLinkerObject->mReferences.Size() == 0 && mType != ASMIT_JSR)
	{
		opmask = 0xff;
		opvalue = mLinkerObject->mData[mAddress];
	}
#if 1
	else if ((mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) && mLinkerObject && (mLinkerObject->mFlags & LOBJF_CONST) && mLinkerObject->mReferences.Size() == 0)
	{
		int mor = 0;
		int mand = 0xff;
		int ior = 0;
		int iand = 0xff;

		if (mMode == ASMIM_ABSOLUTE_X)
		{
			ior = data[CPU_REG_X].mMask & data[CPU_REG_X].mValue;
			iand = (~data[CPU_REG_X].mMask | data[CPU_REG_X].mValue) & 0xff;
		}
		else if (mMode == ASMIM_ABSOLUTE_Y)
		{
			ior = data[CPU_REG_Y].mMask & data[CPU_REG_Y].mValue;
			iand = (~data[CPU_REG_Y].mMask | data[CPU_REG_Y].mValue) & 0xff;
		}

		int size = mLinkerObject->mSize - mAddress;
		if (mLinkerObject->mStripe > 1)
		{
			int ssize = mLinkerObject->mStripe - mAddress % mLinkerObject->mStripe;
			if (ssize == 1 && size > mLinkerObject->mStripe)
				size = mLinkerObject->mStripe + 1;
			else
				size = ssize;
		}
		if (size > 256)
			size = 256;

		for (int i = 0; i < size; i++)
		{
			if ((i & ~iand) == 0 && (i & ior) == ior)
			{
				mor |= mLinkerObject->mData[mAddress + i];
				mand &= mLinkerObject->mData[mAddress + i];
			}
		}
		opmask = (mand | ~mor) & 0xff;
		opvalue = mand;
	}
#endif
	else
	{
		opmask = ~BinMask(mMaxVal) & 0xff;
		opvalue = 0;
	}

	switch (mType)
	{
	case ASMIT_JSR:
		data.ResetMask(CPU_REG_C);
		data.ResetMask(CPU_REG_Z);
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_A))
			data.ResetMask(CPU_REG_A);
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_X))
			data.ResetMask(CPU_REG_X);
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_Y))
			data.ResetMask(CPU_REG_Y);

		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.ResetMask(i);
			}
			else
			{
				for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
					data.ResetMask(i);
			}

			for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
				data.ResetMask(i);
		}
		break;
	case ASMIT_CLC:
		data.SetMask(CPU_REG_C, 1, 0);
		break;
	case ASMIT_SEC:
		data.SetMask(CPU_REG_C, 1, 1);
		break;

	case ASMIT_CMP:
	case ASMIT_CPX:
	case ASMIT_CPY:
		data.ResetMask(CPU_REG_C);
		break;

	case ASMIT_ADC:
		if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_C].mMask == 1 && data[CPU_REG_C].mValue == 0)
		{
			if ((mAddress & ~data[CPU_REG_A].mMask) == 0 && (mAddress & data[CPU_REG_A].mValue) == 0)
			{
				mType = ASMIT_ORA;
				data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask, data[CPU_REG_A].mValue | mAddress);
				changed = true;
			}
			else if (mAddress == 1 && (data[CPU_REG_A].mMask & 3) == 3 && (data[CPU_REG_A].mValue & 3) == 1)
			{
				mType = ASMIT_EOR;
				mAddress = 3;
				data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask, data[CPU_REG_A].mValue ^ 3);
				changed = true;
			}
			else if (mMode == ASMIM_IMMEDIATE && !(mLive & LIVE_CPU_REG_C) && !(mAddress & BinMask(data[CPU_REG_A].mMask ^ 0xff)))
			{
				int mask = BinMask(data[CPU_REG_A].mMask ^ 0xff) ^ 0xff;
				mType = ASMIT_EOR;
				mAddress = ((mAddress + data[CPU_REG_A].mValue) ^ data[CPU_REG_A].mValue) & mask;
				changed = true;
				data.SetMask(CPU_REG_C, 1, 0);
				data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask, data[CPU_REG_A].mValue^ mAddress);
			}
			else if (mMode == ASMIM_IMMEDIATE && mAddress + ((data[CPU_REG_A].mValue & data[CPU_REG_A].mMask) | (~data[CPU_REG_A].mMask & 255)) < 256)
			{
				data.SetMask(CPU_REG_C, 1, 0);
				data.SetMask(CPU_REG_A, ~BinMask(mAddress + ((data[CPU_REG_A].mValue & data[CPU_REG_A].mMask) | (~data[CPU_REG_A].mMask & 255))) & 255, 0);
			}
			else
			{
				data.ResetMask(CPU_REG_C);
				data.ResetMask(CPU_REG_A);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
		{
			int zeros = data[CPU_REG_A].mMask & ~data[CPU_REG_A].mValue;

			int fzero = 0x01;
			while (fzero < 0x100 && (fzero & zeros) == 0)
				fzero <<= 1;

			fzero |= (fzero - 1);

			data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask & ~fzero, data[CPU_REG_A].mValue);

			if (fzero >= 0x100)
				data.ResetMask(CPU_REG_C);
			else
				data.SetMask(CPU_REG_C, 1, 0);
		}
		else if (data[CPU_REG_C].mMask == 1 && data[CPU_REG_C].mValue == 0)
		{
			if ((((~opmask | opvalue) & (~data[CPU_REG_A].mMask | data[CPU_REG_A].mValue)) & 0xff) == 0)
			{
				mType = ASMIT_ORA;
				data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask & opmask, data[CPU_REG_A].mValue | opvalue);
				changed = true;
			}
			else
			{
				data.ResetMask(CPU_REG_C);
				data.ResetMask(CPU_REG_A);
			}
		}
		else
		{
			data.ResetMask(CPU_REG_C);
			data.ResetMask(CPU_REG_A);
		}

		break;
	case ASMIT_SBC:
		data.ResetMask(CPU_REG_C);
		data.ResetMask(CPU_REG_A);
		break;

	case ASMIT_LDA:
		if (mMode == ASMIM_IMMEDIATE)
		{
			if (data[CPU_REG_A].mMask == 0xff && data[CPU_REG_A].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
				data.SetMask(CPU_REG_A, 0xff, mAddress & 0xff);
		}
		else
		{
			data.SetMask(CPU_REG_A, opmask, opvalue);
			if (opmask == 0xff)
			{
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = opvalue;
				changed = true;
			}
		}
		break;
	case ASMIT_STA:
		if (mMode == ASMIM_ZERO_PAGE)
			data.SetMask(mAddress, data[CPU_REG_A]);
		break;

	case ASMIT_LDX:
		if (mMode == ASMIM_IMMEDIATE)
			data.SetMask(CPU_REG_X, 0xff, mAddress & 0xff);
		else
		{
			data.SetMask(CPU_REG_X, opmask, opvalue);
			if (opmask == 0xff)
			{
				mType = ASMIT_LDX;
				mMode = ASMIM_IMMEDIATE;
				mAddress = opvalue;
				changed = true;
			}
		}
		break;
	case ASMIT_STX:
		if (mMode == ASMIM_ZERO_PAGE)
			data.Set(mAddress, data[CPU_REG_X]);
		break;

	case ASMIT_LDY:
		if (mMode == ASMIM_IMMEDIATE)
			data.SetMask(CPU_REG_Y, 0xff, mAddress & 0xff);
		else
		{
			data.SetMask(CPU_REG_Y, opmask, opvalue);
			if (opmask == 0xff)
			{
				mType = ASMIT_LDY;
				mMode = ASMIM_IMMEDIATE;
				mAddress = opvalue;
				changed = true;
			}
		}
		break;
	case ASMIT_STY:
		if (mMode == ASMIM_ZERO_PAGE)
			data.SetMask(mAddress, data[CPU_REG_Y]);
		break;

	case ASMIT_AND:
	{
		int	zeros =
			(opmask & ~opvalue) |
			(data[CPU_REG_A].mMask & ~data[CPU_REG_A].mValue);

		int	ones =
			(opmask & opvalue) &
			(data[CPU_REG_A].mMask & data[CPU_REG_A].mValue);

		int cbits = (~data[CPU_REG_A].mMask | data[CPU_REG_A].mValue) & (~opmask | ~opvalue) & 0xff;

		if (cbits == 0)
		{
			if (mMode != ASMIM_IMMEDIATE || mAddress != 0xff)
			{
				mMode = ASMIM_IMMEDIATE;
				mAddress = 0xff;
				changed = true;
			}
		}
		else
		{
			data.SetMask(CPU_REG_A, (ones | zeros) & 0xff, ones & 0xff);

			if (data[CPU_REG_A].mMask == 0xff)
			{
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = data[CPU_REG_A].mValue;
				changed = true;
			}
		}
		
	}	break;

	case ASMIT_ORA:
	{
		int	ones =
			(opmask & opvalue) |
			(data[CPU_REG_A].mMask & data[CPU_REG_A].mValue);

		int	zeros =
			(opmask & ~opvalue) &
			(data[CPU_REG_A].mMask & ~data[CPU_REG_A].mValue);

		data.SetMask(CPU_REG_A, (ones | zeros) & 0xff, ones & 0xff);

		if (data[CPU_REG_A].mMask == 0xff)
		{
			mType = ASMIT_LDA;
			mMode = ASMIM_IMMEDIATE;
			mAddress = data[CPU_REG_A].mValue;
			changed = true;
		}
	}	break;

	case ASMIT_EOR:
		if (mMode == ASMIM_IMMEDIATE)
			data.SetMask(CPU_REG_A, data[CPU_REG_A].mMask, (data[CPU_REG_A].mValue ^ mAddress) & data[CPU_REG_A].mMask);
		else
			data.ResetMask(CPU_REG_A);
		break;

	case ASMIT_TAX:
		data.SetMask(CPU_REG_X, data[CPU_REG_A]);
		break;
	case ASMIT_TAY:
		data.SetMask(CPU_REG_Y, data[CPU_REG_A]);
		break;

	case ASMIT_TXA:
		data.SetMask(CPU_REG_A, data[CPU_REG_X]);
		break;

	case ASMIT_TYA:
		data.SetMask(CPU_REG_A, data[CPU_REG_Y]);
		break;

	case ASMIT_INX:
	case ASMIT_DEX:
		data.ResetMask(CPU_REG_X);
		break;

	case ASMIT_INY:
	case ASMIT_DEY:
		data.ResetMask(CPU_REG_Y);
		break;

	case ASMIT_INC:
	case ASMIT_DEC:
		if (mMode == ASMIM_ZERO_PAGE)
			data.ResetMask(mAddress);
		break;

	case ASMIT_ASL:
		if (iaddr >= 0)
		{
			int	mask = data[iaddr].mMask, value = data[iaddr].mValue;

			data.SetMask(iaddr, ((mask << 1) & 0xff) | 0x01, (value << 1) & 0xff);
			
			if (mask & 0x80)
				data.SetMask(CPU_REG_C, 1, value >> 7);
			else
				data.ResetMask(CPU_REG_C);

			if (mMode == ASMIM_IMPLIED && data[CPU_REG_A].mMask == 0xff && data[CPU_REG_C].mMask)
			{
				carryop = data[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = data[CPU_REG_A].mValue;
				changed = true;
			}
		}
		else
			data.ResetMask(CPU_REG_C);
		break;

	case ASMIT_LSR:
		if (iaddr >= 0)
		{
			int	mask = data[iaddr].mMask, value = data[iaddr].mValue;

			if (mask == 0xff && value == 0x00)
			{
				mType = ASMIT_CLC;
				mMode = ASMIM_IMPLIED;
				data.SetMask(CPU_REG_C, 1, 0);
				changed = true;
			}
			else
			{
				data.SetMask(iaddr, ((mask >> 1) & 0xff) | 0x80, (value >> 1) & 0x7f);

				if (mask & 0x01)
					data.SetMask(CPU_REG_C, 1, value & 1);
				else
					data.ResetMask(CPU_REG_C);

				if (mMode == ASMIM_IMPLIED && data[CPU_REG_A].mMask == 0xff && data[CPU_REG_C].mMask)
				{
					carryop = data[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
					mType = ASMIT_LDA;
					mMode = ASMIM_IMMEDIATE;
					mAddress = data[CPU_REG_A].mValue;
					changed = true;
				}
			}
		}
		else
			data.ResetMask(CPU_REG_C);
		break;

	case ASMIT_ROL:
		if (iaddr >= 0)
		{
			int	mask = data[iaddr].mMask, value = data[iaddr].mValue;

			int nmask = (mask << 1) & 0xff, nvalue = (value << 1) & 0xff;


			if (data[CPU_REG_C].mMask & 1)
			{
				nmask |= 1;
				nvalue |= data[CPU_REG_C].mValue & 1;
			}

			data.SetMask(iaddr, nmask, nvalue);

			if (mask & 0x80)
				data.SetMask(CPU_REG_C, 1, value >> 7);
			else
				data.ResetMask(CPU_REG_C);

			if (mMode == ASMIM_IMPLIED && data[CPU_REG_A].mMask == 0xff && data[CPU_REG_C].mMask)
			{
				carryop = data[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = data[CPU_REG_A].mValue;
				changed = true;
			}
		}
		else
			data.ResetMask(CPU_REG_C);
		break;

	case ASMIT_ROR:
		if (iaddr >= 0)
		{
			int	mask = data[iaddr].mMask, value = data[iaddr].mValue;

			int nmask = (mask >> 1) & 0x7f, nvalue = (value >> 1) & 0x7f;

			if (data[CPU_REG_C].mMask & 1)
			{
				nmask |= 0x80;
				nvalue |= (data[CPU_REG_C].mValue << 7) & 0x80;
			}

			data.SetMask(iaddr, nmask, nvalue);

			if (mask & 0x01)
				data.SetMask(CPU_REG_C, 1, value & 1);
			else
				data.ResetMask(CPU_REG_C);

			if (mMode == ASMIM_IMPLIED && data[CPU_REG_A].mMask == 0xff && data[CPU_REG_C].mMask)
			{
				carryop = data[CPU_REG_C].mValue ? ASMIT_SEC : ASMIT_CLC;
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = data[CPU_REG_A].mValue;
				changed = true;
			}
		}
		else
			data.ResetMask(CPU_REG_C);
		break;
	}

#if _DEBUG
	for (int i = 0; i < NUM_REGS; i++)
	{
		assert(!(data[i].mMask & 0xff00));
	}
#endif

	return changed;
}

bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsType& carryop, bool initial, bool final, int fastCallBase)
{
	bool	changed = false;

	carryop = ASMIT_NOP;

	mFlags &= ~NCIF_YZERO;

	if ((data[CPU_REG_Y].mMode & NRDM_IMMEDIATE) && (data[CPU_REG_Y].mValue == 0))
		mFlags |= NCIF_YZERO;

	if (mType == ASMIT_JSR)
	{
		data.ResetCall(*this, fastCallBase);

		return false;
	}

	if (data[CPU_REG_C].mMode == NRDM_IMMEDIATE && data[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.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
		break;
	case ASMIT_SEC:
		data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
		break;

	case ASMIT_ROL:
	case ASMIT_ROR:
		if (mMode == ASMIM_IMPLIED)
			data.Reset(CPU_REG_A);
		data.Reset(CPU_REG_C);
		data.Reset(CPU_REG_Z);
		break;

	case ASMIT_ASL:
	case ASMIT_LSR:
		if (mMode == ASMIM_IMPLIED)
		{
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == 0 && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_CLC;				
				data.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
				changed = true;
			}
			else
			{
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_C);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_INC:
	case ASMIT_DEC:
		data.Reset(CPU_REG_Z);
		break;

	case ASMIT_LDA:
		if (mMode == ASMIM_IMMEDIATE)
		{
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_A, NRDM_IMMEDIATE, mAddress);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS &&
				data[CPU_REG_A].mLinkerObject == mLinkerObject &&
				data[CPU_REG_A].mFlags == mFlags &&
				data[CPU_REG_A].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_A, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
				if (mLinkerObject)
					data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 1);
				else
					data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_INDIRECT_Y && mMode != ASMIM_ABSOLUTE_X && mMode != ASMIM_ABSOLUTE_Y)
				data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_STA:
		if (mMode == ASMIM_ZERO_PAGE && data[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mAddress == data[CPU_REG_A].mValue)
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		break;
	case ASMIT_STX:
		if (mMode == ASMIM_ZERO_PAGE && data[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mAddress == data[CPU_REG_X].mValue)
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		break;
	case ASMIT_STY:
		if (mMode == ASMIM_ZERO_PAGE && data[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mAddress == data[CPU_REG_Y].mValue)
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		break;

	case ASMIT_ADC:
		if (data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
		{
			if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data[CPU_REG_C].mValue == 0)
			{
				mType = ASMIT_ORA;
				changed = true;
			}
			else if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == 0 && data[CPU_REG_C].mValue == 0)
			{
				mType = ASMIT_LDA;
				changed = true;
			}
			else if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = mAddress + data[CPU_REG_A].mValue + data[CPU_REG_C].mValue;

				mType = ASMIT_LDA;
				mAddress = t & 0xff;

				int c = t >= 256;

				if (c && !data[CPU_REG_C].mValue)
					carryop = ASMIT_SEC;
				else if (!c && data[CPU_REG_C].mValue)
					carryop = ASMIT_CLC;

				changed = true;
			}
		}

		data.Reset(CPU_REG_A);
		data.Reset(CPU_REG_C);
		data.Reset(CPU_REG_Z);
		break;

	case ASMIT_SBC:
		if (data[CPU_REG_C].mMode == NRDM_IMMEDIATE)
		{
			if (mMode == ASMIM_IMMEDIATE && mAddress == 0 && data[CPU_REG_C].mValue == 1)
			{
				mType = ASMIT_ORA;
				changed = true;
			}
			else if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				int	t = (mAddress ^ 0xff) + data[CPU_REG_A].mValue + data[CPU_REG_C].mValue;

				mType = ASMIT_LDA;
				mAddress = t & 0xff;

				int c = t >= 256;

				if (c && !data[CPU_REG_C].mValue)
					carryop = ASMIT_SEC;
				else if (!c && data[CPU_REG_C].mValue)
					carryop = ASMIT_CLC;

				changed = true;
			}
			else if (mMode == ASMIM_IMMEDIATE_ADDRESS && data[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS && mLinkerObject == data[CPU_REG_A].mLinkerObject)
			{
				int	t;
				if (mFlags & NCIF_LOWER)
					t = ((mAddress ^ 0xffff) & 0xff) + (data[CPU_REG_A].mValue & 0xff) + data[CPU_REG_C].mValue;
				else
					t = ((mAddress ^ 0xffff) >> 8) + (data[CPU_REG_A].mValue >> 8) + data[CPU_REG_C].mValue;

				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = t & 0xff;

				int c = t >= 256;

				if (c && !data[CPU_REG_C].mValue)
					carryop = ASMIT_SEC;
				else if (!c && data[CPU_REG_C].mValue)
					carryop = ASMIT_CLC;

				changed = true;
			}
		}

		data.Reset(CPU_REG_A);
		data.Reset(CPU_REG_C);
		data.Reset(CPU_REG_Z);
		break;
	case ASMIT_CMP:
		if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_A].mValue - mAddress) & 0xff);
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[CPU_REG_A].mValue >= mAddress);
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS && data[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS)
		{
			if (mLinkerObject == data[CPU_REG_A].mLinkerObject)
			{
				if (mLinkerObject)
				{
					if (mLinkerObject->mFlags & LOBJF_NEVER_CROSS)
					{
						if (mFlags & NCIF_LOWER)
							data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_A].mValue - mAddress) & 0xff);
						else
							data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
					}
					else
					{
						if (mFlags & NCIF_LOWER)
						{
							data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_A].mValue & 0xff) == (mAddress & 0xff) ? 0 : 1);
						}
						else if (data[CPU_REG_A].mValue == mAddress)
						{
							data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
						}
						else
							data.Reset(CPU_REG_Z);
					}
				}
				else
				{
					if (mFlags & NCIF_LOWER)
					{
						data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_A].mValue - mAddress) & 0xff);
					}
					else
					{
						data.Set(CPU_REG_Z, NRDM_IMMEDIATE, ((data[CPU_REG_A].mValue - mAddress) >> 8) & 0xff);
					}
				}
			}
			else
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 1);
			data.Reset(CPU_REG_C);
		}
		else if (mMode == ASMIM_IMMEDIATE && mAddress == 0)
		{
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_CPX:
		if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_X].mValue - mAddress) & 0xff);
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[CPU_REG_X].mValue >= mAddress);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_CPY:
		if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
		{
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, (data[CPU_REG_Y].mValue - mAddress) & 0xff);
			data.Set(CPU_REG_C, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue >= mAddress);
		}
		else
		{
			data.Reset(CPU_REG_C);
			data.Reset(CPU_REG_Z);
		}
		break;

	case ASMIT_ORA:
	case ASMIT_EOR:
	case ASMIT_AND:
		if (mMode == ASMIM_IMMEDIATE && data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
		{
			if (mType == ASMIT_ORA)
				mAddress |= data[CPU_REG_A].mValue;
			else if (mType == ASMIT_AND)
				mAddress &= data[CPU_REG_A].mValue;
			else if (mType == ASMIT_EOR)
				mAddress ^= data[CPU_REG_A].mValue;
			mType = ASMIT_LDA;
			data.Set(CPU_REG_A, NRDM_IMMEDIATE, mAddress);
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
			changed = true;
		}
		else if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == 0)
		{
			if (mType == ASMIT_ORA || mType == ASMIT_EOR)
			{
				mType = ASMIT_LDA;
				data.Reset(CPU_REG_A);
				data.Reset(CPU_REG_Z);
			}
			else
			{
				mType = ASMIT_LDA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = 0;

				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
			}
			changed = true;
		}
		else if (mMode == ASMIM_IMMEDIATE && mType == ASMIT_ORA && mAddress != 0x00)
		{
			data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
			data.Reset(CPU_REG_A);
		}
		else if (mMode == ASMIM_IMMEDIATE && ((mAddress == 0 && (mType == ASMIT_ORA || mType == ASMIT_EOR)) || (mAddress == 0xff && mType == ASMIT_AND)))
		{
			data.Reset(CPU_REG_Z);
		}
		else
		{
			data.Reset(CPU_REG_A);
			data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_LDX:
		data.ResetX();
		if (mMode == ASMIM_IMMEDIATE)
		{
			if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE && data[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_X, NRDM_IMMEDIATE, mAddress);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE_ADDRESS &&
				data[CPU_REG_X].mLinkerObject == mLinkerObject &&
				data[CPU_REG_X].mFlags == mFlags &&
				data[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_X, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_ABSOLUTE_Y)
				data.Reset(CPU_REG_X);
			data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_BIT:
		data.Reset(CPU_REG_Z);
		break;
	case ASMIT_INX:
	case ASMIT_DEX:
		data.ResetX();
		data.Reset(CPU_REG_X);
		data.Reset(CPU_REG_Z);
		break;
	case ASMIT_LDY:
		data.ResetY();
		if (mMode == ASMIM_IMMEDIATE)
		{
			if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE && data[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_Y, NRDM_IMMEDIATE, mAddress);
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, mAddress);
			}
		}
		else if (mMode == ASMIM_IMMEDIATE_ADDRESS)
		{
			if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE_ADDRESS &&
				data[CPU_REG_Y].mLinkerObject == mLinkerObject &&
				data[CPU_REG_Y].mFlags == mFlags &&
				data[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else
			{
				data.Set(CPU_REG_Y, NRDM_IMMEDIATE_ADDRESS, mAddress, mLinkerObject, mFlags);
				data.Reset(CPU_REG_Z);
			}
		}
		else
		{
			if (mMode != ASMIM_ZERO_PAGE && mMode != ASMIM_ABSOLUTE && mMode != ASMIM_ABSOLUTE_X)
				data.Reset(CPU_REG_Y);
			data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_INY:
	case ASMIT_DEY:
		data.ResetY();
		data.Reset(CPU_REG_Y);
		data.Reset(CPU_REG_Z);
		break;

	case ASMIT_TXA:
		if (data[CPU_REG_A].SameData(data[CPU_REG_X]))
		{
			if (!(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
			}
			else
			{
				mType = ASMIT_ORA;
				mMode = ASMIM_IMMEDIATE;
				mAddress = 0x00;
			}

			changed = true;
		}
		else
		{
			data.Set(CPU_REG_A, data[CPU_REG_X]);
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				if (!final)
				{
					mType = ASMIT_LDA;
					mMode = ASMIM_IMMEDIATE;
					mAddress = data[CPU_REG_A].mValue;
				}

				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
			}
			else
				data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_TYA:
		if (data[CPU_REG_A].SameData(data[CPU_REG_Y]) && !(mLive & LIVE_CPU_REG_Z))
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		else
		{
			data.Set(CPU_REG_A, data[CPU_REG_Y]);
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE)
			{
				if (!final)
				{
					mType = ASMIT_LDA;
					mMode = ASMIM_IMMEDIATE;
					mAddress = data[CPU_REG_A].mValue;
				}

				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
			}
			else
				data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_TAX:
		if (data[CPU_REG_X].SameData(data[CPU_REG_A]) && !(mLive & LIVE_CPU_REG_Z))
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		else
		{
			data.ResetX();
			data.Set(CPU_REG_X, data[CPU_REG_A]);
			if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
			else
				data.Reset(CPU_REG_Z);
		}
		break;
	case ASMIT_TAY:
		if (data[CPU_REG_Y].SameData(data[CPU_REG_A]) && !(mLive & LIVE_CPU_REG_Z))
		{
			mType = ASMIT_NOP;
			mMode = ASMIM_IMPLIED;
			changed = true;
		}
		else
		{
			data.ResetY();
			data.Set(CPU_REG_Y, data[CPU_REG_A]);
			if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
				data.Set(CPU_REG_Z, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
			else
				data.Reset(CPU_REG_Z);
		}
		break;
	}

	if (mFlags & NCIF_MEMMAP)
		data.ResetGlobal();

#if 1
	if (mMode == ASMIM_ABSOLUTE_X && data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
	{
		mMode = ASMIM_ABSOLUTE;
		mAddress += data[CPU_REG_X].mValue;
		changed = true;
	}
	else if (mMode == ASMIM_ABSOLUTE_Y && data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
	{
		mMode = ASMIM_ABSOLUTE;
		mAddress += data[CPU_REG_Y].mValue;
		changed = true;
	}
#endif

#if 1
	if (mMode == ASMIM_ABSOLUTE_X && data[CPU_REG_X].SameData(data[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[CPU_REG_X].SameData(data[CPU_REG_Y]) && HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X) && !(mFlags & NICT_INDEXFLIPPED))
	{
		mFlags |= NICT_INDEXFLIPPED;
		mMode = ASMIM_ABSOLUTE_X;
		changed = true;
	}
#endif

#if 1
	if (mMode == ASMIM_ABSOLUTE && final && !(mFlags & NCIF_VOLATILE) && !ChangesAddress() && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
	{
		if (mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE))
		{
		}
		else
		{
			int i = data.FindAbsolute(mLinkerObject, mAddress);
			if (i >= 0)
			{
				mMode = ASMIM_ZERO_PAGE;
				mAddress = i;
				mLinkerObject = nullptr;
				changed = true;
			}
		}
	}
#endif
#if 1
	if (final && mType == ASMIT_STX && data[CPU_REG_A].SameData(data[CPU_REG_X]))
	{
		mType = ASMIT_STA;
		changed = true;
	}
	else if (final && mType == ASMIT_STY && data[CPU_REG_A].SameData(data[CPU_REG_Y]))
	{
		mType = ASMIT_STA;
		changed = true;
	}
#endif
	if (mMode == ASMIM_ZERO_PAGE)
	{
		switch (mType)
		{
		case ASMIT_LDA:
			if (data[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data[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[mAddress].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_A, data[mAddress]);
				mAddress = data[CPU_REG_A].mValue;
				mMode = ASMIM_IMMEDIATE;
				changed = true;
			}
			else if (data[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS)
			{
				data.Set(CPU_REG_A, data[mAddress]);
				mAddress = data[CPU_REG_A].mValue;
				mLinkerObject = data[CPU_REG_A].mLinkerObject;
				mFlags = (mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | (data[CPU_REG_A].mFlags & (NCIF_LOWER | NCIF_UPPER));
				mMode = ASMIM_IMMEDIATE_ADDRESS;
				changed = true;
			}
			else if (data[mAddress].SameData(data[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[mAddress].mMode == NRDM_ZERO_PAGE && ((mAddress < BC_REG_FPARAMS || mAddress >= BC_REG_FPARAMS_END)))// && (final || mAddress != BC_REG_ACCU)))
			else if (data[mAddress].mMode == NRDM_ZERO_PAGE && ((mAddress < BC_REG_FPARAMS || mAddress >= BC_REG_FPARAMS_END) && (final || mAddress != BC_REG_ACCU)))
			{
				data.Set(CPU_REG_A, data[mAddress]);
				mAddress = data[CPU_REG_A].mValue;
				changed = true;
			}
#if 1
			else if (data[CPU_REG_X].SameData(*this))
			{
				mType = ASMIT_TXA;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_A, data[CPU_REG_X]);
				changed = true;
			}
			else if (data[CPU_REG_Y].SameData(*this))
			{
				mType = ASMIT_TYA;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_A, data[CPU_REG_Y]);
				changed = true;
			}
#else
			else if (data.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_X].mValue == mAddress)
			{
				mType = ASMIT_TXA;
				mMode = ASMIM_IMPLIED;
				data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X];
				changed = true;
			}
			else if (data.mRegs[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data.mRegs[CPU_REG_Y].mValue == mAddress)
			{	
				mType = ASMIT_TYA;
				mMode = ASMIM_IMPLIED;
				data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y];
				changed = true;
			}
#endif
			else if (final && data[mAddress].mMode == NRDM_ABSOLUTE && data[mAddress].mLinkerObject && (data[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				data.Set(CPU_REG_A, data[mAddress]);
				mMode = ASMIM_ABSOLUTE;
				mFlags |= data[mAddress].mFlags;
				mLinkerObject = data[mAddress].mLinkerObject;
				mAddress = data[mAddress].mValue;
				changed = true;
			}
			else
			{
				data.Reset(CPU_REG_A);
				if (data[mAddress].mMode == NRDM_IMMEDIATE)
				{
					data.Set(CPU_REG_A, NRDM_IMMEDIATE, data[mAddress].mValue);
				}
				else if (initial && mAddress == BC_REG_WORK_Y)
				{
					data.Reset(CPU_REG_A);
				}
				else
				{
					data.Set(CPU_REG_A, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags, mMinVal, mMaxVal);
				}
			}
			break;

		case ASMIT_LDX:
			if (data[CPU_REG_X].mMode == NRDM_ZERO_PAGE && data[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (data[mAddress].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_X, data[mAddress]);
				mAddress = data[CPU_REG_X].mValue;
				mMode = ASMIM_IMMEDIATE;
				changed = true;
			}
			else if (data[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data[CPU_REG_A].mValue == mAddress)
			{
				mType = ASMIT_TAX;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_X, data[CPU_REG_A]);
				changed = true;
			}
			else if (data[mAddress].SameData(data[CPU_REG_A]))
			{
				mType = ASMIT_TAX;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_X, data[CPU_REG_A]);
				changed = true;
			}
#if 1
			else if (data[mAddress].mMode == NRDM_ZERO_PAGE)
			{
				data.Set(CPU_REG_X, data[mAddress]);
				mAddress = data[CPU_REG_X].mValue;
				changed = true;
			}
#endif
			else if (final && data[mAddress].mMode == NRDM_ABSOLUTE && data[mAddress].mLinkerObject && (data[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				data.Set(CPU_REG_X, data[mAddress]);
				mMode = ASMIM_ABSOLUTE;
				mFlags |= data[mAddress].mFlags;
				mLinkerObject = data[mAddress].mLinkerObject;
				mAddress = data[mAddress].mValue;
				changed = true;
			}
			else
			{
				data.Reset(CPU_REG_X);
				if (data[mAddress].mMode == NRDM_IMMEDIATE)
				{
					data.Set(CPU_REG_X, NRDM_IMMEDIATE, data[mAddress].mValue);
				}
				else
				{
					data.Set(CPU_REG_X, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags);
				}
			}
			break;

		case ASMIT_LDY:
			if (data[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && data[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (data[mAddress].mMode == NRDM_IMMEDIATE)
			{
				data.Set(CPU_REG_Y, data[mAddress]);
				mAddress = data[CPU_REG_Y].mValue;
				mMode = ASMIM_IMMEDIATE;
				changed = true;
			}
			else if (final && data[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data[CPU_REG_A].mValue == mAddress)
			{
				mType = ASMIT_TAY;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_Y, data[CPU_REG_A]);
				changed = true;
			}
			else if (final && data[mAddress].SameData(data[CPU_REG_A]))
			{
				mType = ASMIT_TAY;
				mMode = ASMIM_IMPLIED;
				data.Set(CPU_REG_Y, data[CPU_REG_A]);
				changed = true;
			}
#if 1
			else if (data[mAddress].mMode == NRDM_ZERO_PAGE)
			{
				data.Set(CPU_REG_Y, data[mAddress]);
				mAddress = data[CPU_REG_Y].mValue;
				changed = true;
			}
#endif
			else if (final && data[mAddress].mMode == NRDM_ABSOLUTE && data[mAddress].mLinkerObject && (data[mAddress].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				data.Set(CPU_REG_Y, data[mAddress]);
				mMode = ASMIM_ABSOLUTE;
				mFlags |= data[mAddress].mFlags;
				mLinkerObject = data[mAddress].mLinkerObject;
				mAddress = data[mAddress].mValue;
				changed = true;
			}
			else
			{
				data.Reset(CPU_REG_Y);
				if (data[mAddress].mMode == NRDM_IMMEDIATE)
				{
					data.Set(CPU_REG_Y, NRDM_IMMEDIATE, data[mAddress].mValue);
				}
				else
				{
					data.Set(CPU_REG_Y, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags);
				}
			}
			break;

		case ASMIT_ADC:
		case ASMIT_SBC:
		case ASMIT_AND:
		case ASMIT_ORA:
		case ASMIT_EOR:
		case ASMIT_CMP:
		case ASMIT_CPX:
		case ASMIT_CPY:
			if (data[mAddress].mMode == NRDM_IMMEDIATE)
			{
				mAddress = data[mAddress].mValue;
				mMode = ASMIM_IMMEDIATE;
				changed = true;
			}
			else if (data[mAddress].mMode == NRDM_ZERO_PAGE)
			{
				mMinVal = intmax(mMinVal, data[mAddress].mMinVal);
				mMaxVal = intmin(mMaxVal, data[mAddress].mMaxVal);
				mAddress = data[mAddress].mValue;
				changed = true;
			}
			else if (data[mAddress].mMode == NRDM_ABSOLUTE && !final)
			{
				mMode = ASMIM_ABSOLUTE;
				mLinkerObject = data[mAddress].mLinkerObject;
				mAddress = data[mAddress].mValue;
				changed = true;
			}
			break;

		case ASMIT_STA:
			if (data[mAddress].SameData(data[CPU_REG_A]) || data[CPU_REG_A].mMode == NRDM_ZERO_PAGE && data[CPU_REG_A].mValue == mAddress)
			{
				mType = ASMIT_NOP;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (final && data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[mAddress].mMode == NRDM_IMMEDIATE &&
				data[mAddress].mValue == ((data[CPU_REG_A].mValue - 1) & 255))
			{
				mType = ASMIT_INC;
				data.Set(mAddress, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
				changed = true;
			}
			else if (final && data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[mAddress].mMode == NRDM_IMMEDIATE &&
				data[mAddress].mValue == ((data[CPU_REG_A].mValue + 1) & 255))
			{
				mType = ASMIT_DEC;
				data.Set(mAddress, NRDM_IMMEDIATE, data[CPU_REG_A].mValue);
				changed = true;
			}
			else
			{
				data.ResetZeroPage(mAddress);
				if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE || data[CPU_REG_A].mMode == NRDM_IMMEDIATE_ADDRESS)
				{
					data.Set(mAddress, data[CPU_REG_A]);
				}
				else if (data[CPU_REG_A].mMode == NRDM_ZERO_PAGE)
				{
#if 1
					if (data[data[CPU_REG_A].mValue].mMode == NRDM_UNKNOWN &&
						(mAddress >= BC_REG_FPARAMS && mAddress < BC_REG_FPARAMS_END) &&
						!(data[CPU_REG_A].mValue >= BC_REG_FPARAMS && data[CPU_REG_A].mValue < BC_REG_FPARAMS_END))
					{
						data.Set(data[CPU_REG_A].mValue, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags);
						data.Reset(mAddress);
					}
					else
#endif	
					{
						data.Set(mAddress, data[CPU_REG_A]);
					}

				}
				else if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE)
				{
					data.Set(mAddress, data[CPU_REG_A]);
					if (!final)
						data.Set(CPU_REG_A, NRDM_ZERO_PAGE, mAddress);
				}
				else
				{
					data.Set(CPU_REG_A, NRDM_ZERO_PAGE, mAddress);
				}
			}
			break;
		case ASMIT_STX:
			data.ResetZeroPage(mAddress);
			if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE)
			{
				data.Set(mAddress, NRDM_IMMEDIATE, data[CPU_REG_X].mValue);
			}
			else if (data[CPU_REG_X].mMode == NRDM_ZERO_PAGE)
			{
				data.Set(mAddress, NRDM_ZERO_PAGE, data[CPU_REG_X].mValue, nullptr, data[CPU_REG_X].mFlags);
			}
			else if (data[CPU_REG_X].mMode == NRDM_ABSOLUTE)
			{
				data.Set(mAddress, data[CPU_REG_X]);
			}
			else
			{
				data.Set(CPU_REG_X, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags);
			}
			break;
		case ASMIT_STY:
			data.ResetZeroPage(mAddress);
			if (data[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
			{
				data.Set(mAddress, NRDM_IMMEDIATE, data[CPU_REG_Y].mValue);
			}
			else if (data[CPU_REG_Y].mMode == NRDM_ZERO_PAGE)
			{
				data.Set(mAddress, NRDM_ZERO_PAGE, data[CPU_REG_Y].mValue, nullptr, data[CPU_REG_Y].mFlags);
			}
			else if (data[CPU_REG_Y].mMode == NRDM_ABSOLUTE)
			{
				data.Set(mAddress, data[CPU_REG_Y]);
			}
			else
			{
				data.Set(CPU_REG_Y, NRDM_ZERO_PAGE, mAddress, nullptr, mFlags);
			}
			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[CPU_REG_Y].mMode == NRDM_IMMEDIATE && data[CPU_REG_Y].mValue == mAddress)
			{
				data.Set(CPU_REG_A, data[CPU_REG_Y]);
				mType = ASMIT_TYA;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (data[CPU_REG_X].mMode == NRDM_IMMEDIATE && data[CPU_REG_X].mValue == mAddress)
			{
				data.Set(CPU_REG_A, data[CPU_REG_X]);
				mType = ASMIT_TXA;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			break;
		case ASMIT_LDX:
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == mAddress)
			{
				data.Set(CPU_REG_X, data[CPU_REG_A]);
				mType = ASMIT_TAX;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			break;
		case ASMIT_LDY:
			if (data[CPU_REG_A].mMode == NRDM_IMMEDIATE && data[CPU_REG_A].mValue == mAddress)
			{
				data.Set(CPU_REG_Y, data[CPU_REG_A]);
				mType = ASMIT_TAY;
				mMode = ASMIM_IMPLIED;
				changed = true;
			}
			break;
		}
#endif
	}
	else if (mMode == ASMIM_INDIRECT_Y)
	{
		if (data[mAddress].mMode == NRDM_ZERO_PAGE && data[mAddress + 1].mMode == NRDM_ZERO_PAGE && data[mAddress].mValue + 1 == data[mAddress + 1].mValue)
		{
			mFlags |= NICT_ZPFLIPPED;
			mAddress = data[mAddress].mValue;
			if (mType == ASMIT_LDA)
				data.Reset(CPU_REG_A);
		}
		else if (data[mAddress + 0].mMode == NRDM_ZERO_PAGE && data[mAddress + 1].mMode == NRDM_ZERO_PAGE && 
				 data[data[mAddress + 1].mValue - 1].mMode == NRDM_ZERO_PAGE &&
				 data[mAddress + 0].mValue == data[data[mAddress + 1].mValue - 1].mValue)
		{
			mFlags |= NICT_ZPFLIPPED;
			mAddress = data[mAddress + 1].mValue - 1;
			if (mType == ASMIT_LDA)
				data.Reset(CPU_REG_A);
		}
		else if (data[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data[mAddress].mLinkerObject == data[mAddress + 1].mLinkerObject)
		{
			mMode = ASMIM_ABSOLUTE_Y;
			mLinkerObject = data[mAddress].mLinkerObject;
			mAddress = data[mAddress + 1].mValue;
			if (mType == ASMIT_LDA)
				data.Reset(CPU_REG_A);
		}
		else if (mType == ASMIT_LDA)
		{
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_A].mMode == NRDM_INDIRECT_Y && data[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[CPU_REG_X].SameData(*this))
				{
					mType = ASMIT_TXA;
					mMode = ASMIM_IMPLIED;
					data.Set(CPU_REG_A, data[CPU_REG_X]);
					changed = true;
				}
				else if (data[CPU_REG_Y].SameData(*this))
				{
					mType = ASMIT_TYA;
					mMode = ASMIM_IMPLIED;
					data.Set(CPU_REG_A, data[CPU_REG_Y]);
					changed = true;
				}
				else
				{
					data.Set(CPU_REG_A, NRDM_INDIRECT_Y, mAddress, nullptr, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_A);
		}

		if (ChangesAddress())
			data.ResetIndirect(mAddress);
	}
	else if (mMode == ASMIM_ABSOLUTE_X)
	{
		if (mType == ASMIT_LDA)
		{
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[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.Set(CPU_REG_A, NRDM_ABSOLUTE_X, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_A);
		}
		else if (mType == ASMIT_LDY)
		{
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_Y].mMode == NRDM_ABSOLUTE_X && data[CPU_REG_Y].mLinkerObject == mLinkerObject && data[CPU_REG_Y].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
				{
					mType = ASMIT_NOP;
					mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[CPU_REG_A].mValue == mAddress)
				{
					mType = ASMIT_TAY;
					mMode = ASMIM_IMPLIED;
					data.Set(CPU_REG_Y, data[CPU_REG_A]);
					changed = true;
				}
				else
				{
					data.Set(CPU_REG_Y, NRDM_ABSOLUTE_X, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_Y);
		}

		if (ChangesAddress())
			data.ResetAbsoluteXY(mLinkerObject, mAddress);
	}
	else if (mMode == ASMIM_ABSOLUTE_Y)
	{
		if (mType == ASMIT_LDA)
		{
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE_Y && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[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.Set(CPU_REG_A, NRDM_ABSOLUTE_Y, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_A);
		}
		else if (mType == ASMIT_LDX)
		{
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_X].mMode == NRDM_ABSOLUTE_Y && data[CPU_REG_X].mLinkerObject == mLinkerObject && data[CPU_REG_X].mValue == mAddress && !(mLive & LIVE_CPU_REG_Z))
				{
					mType = ASMIT_NOP;
					mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE_Y && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[CPU_REG_A].mValue == mAddress)
				{
					mType = ASMIT_TAX;
					mMode = ASMIM_IMPLIED;
					data.Set(CPU_REG_X, data[CPU_REG_A]);
					changed = true;
				}
				else
				{
					data.Set(CPU_REG_X, NRDM_ABSOLUTE_Y, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_X);
		}

		if (ChangesAddress())
			data.ResetAbsoluteXY(mLinkerObject, mAddress);
	}
	else if (mMode == ASMIM_ABSOLUTE)
	{
		switch (mType)
		{
		case ASMIT_LDA:
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[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.Set(CPU_REG_A, NRDM_ABSOLUTE, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_A);
			break;
#if 1
		case ASMIT_STA:
			if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
			{
				if (data[CPU_REG_A].mMode == NRDM_ABSOLUTE && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[CPU_REG_A].mValue == mAddress)
				{
					mType = ASMIT_NOP;
					mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (final || data[CPU_REG_A].mMode == NRDM_UNKNOWN)
				{
					data.ResetAbsolute(mLinkerObject, mAddress);
					data.Set(CPU_REG_A, NRDM_ABSOLUTE, mAddress, mLinkerObject, mFlags);
				}
				else
					data.ResetAbsolute(mLinkerObject, mAddress);
			}
			else
				data.ResetAbsolute(mLinkerObject, mAddress);
			break;
#endif
		case ASMIT_LDY:
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_Y].mMode == NRDM_ABSOLUTE && data[CPU_REG_Y].mLinkerObject == mLinkerObject && data[CPU_REG_Y].mValue == mAddress)
				{
					if (!(mLive & LIVE_CPU_REG_Z))
					{
						mType = ASMIT_NOP;
						mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				else if (final && data[CPU_REG_A].mMode == NRDM_ABSOLUTE && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[CPU_REG_A].mValue == mAddress)
				{
					mType = ASMIT_TAY;
					mMode = ASMIM_IMPLIED;

					data.Set(CPU_REG_Y, data[CPU_REG_A]);
					changed = true;
				}
				else
				{
					data.Set(CPU_REG_Y, NRDM_ABSOLUTE, mAddress, mLinkerObject,mFlags);
				}
			}
			else
				data.Reset(CPU_REG_Y);
			break;

		case ASMIT_STY:
			if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
			{
				if (data[CPU_REG_Y].mMode == NRDM_ABSOLUTE && data[CPU_REG_Y].mLinkerObject == mLinkerObject && data[CPU_REG_Y].mValue == mAddress)
				{
					mType = ASMIT_NOP;
					mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (data[CPU_REG_Y].mMode == NRDM_UNKNOWN)
				{
					data.ResetAbsolute(mLinkerObject, mAddress);
					data.Set(CPU_REG_Y, NRDM_ABSOLUTE, mAddress, mLinkerObject, mFlags);
				}
				else
					data.ResetAbsolute(mLinkerObject, mAddress);
			}
			else
				data.ResetAbsolute(mLinkerObject, mAddress);
			break;

		case ASMIT_LDX:
			if (!(mFlags & NCIF_VOLATILE))
			{
				if (data[CPU_REG_X].mMode == NRDM_ABSOLUTE && data[CPU_REG_X].mLinkerObject == mLinkerObject && data[CPU_REG_X].mValue == mAddress)
				{
					if (!(mLive & LIVE_CPU_REG_Z))
					{
						mType = ASMIT_NOP;
						mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				else if (final && data[CPU_REG_A].mMode == NRDM_ABSOLUTE && data[CPU_REG_A].mLinkerObject == mLinkerObject && data[CPU_REG_A].mValue == mAddress)
				{
					mType = ASMIT_TAX;
					mMode = ASMIM_IMPLIED;

					data.Set(CPU_REG_X, data[CPU_REG_A]);
					changed = true;
				}
				else
				{
					data.Set(CPU_REG_X, NRDM_ABSOLUTE, mAddress, mLinkerObject, mFlags);
				}
			}
			else
				data.Reset(CPU_REG_X);
			break;

		case ASMIT_STX:
			if (!(mFlags & NCIF_VOLATILE) && mLinkerObject)
			{
				if (data[CPU_REG_X].mMode == NRDM_ABSOLUTE && data[CPU_REG_X].mLinkerObject == mLinkerObject && data[CPU_REG_X].mValue == mAddress)
				{
					mType = ASMIT_NOP;
					mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (data[CPU_REG_X].mMode == NRDM_UNKNOWN)
				{
					data.ResetAbsolute(mLinkerObject, mAddress);
					data.Set(CPU_REG_X, NRDM_ABSOLUTE, mAddress, mLinkerObject, mFlags);
				}
				else
					data.ResetAbsolute(mLinkerObject, mAddress);
			}
			else
				data.ResetAbsolute(mLinkerObject, mAddress);
			break;

		default:
			if (ChangesAddress())
				data.ResetAbsolute(mLinkerObject, mAddress);
		}
	}

	return changed;
}

void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet& providedTemps)
{
	// check runtime calls

	if (mType == ASMIT_JSR)
	{
#if 1
		if (mFlags & NCIF_USE_CPU_REG_A)
		{
			if (!providedTemps[CPU_REG_A])
				requiredTemps += CPU_REG_A;
		}
		if (mFlags & NCIF_USE_CPU_REG_X)
		{
			if (!providedTemps[CPU_REG_X])
				requiredTemps += CPU_REG_X;
		}
		if (mFlags & NCIF_USE_CPU_REG_Y)
		{
			if (!providedTemps[CPU_REG_Y])
				requiredTemps += CPU_REG_Y;
		}
		if (mFlags & NCIF_USE_CPU_REG_C)
		{
			if (!providedTemps[CPU_REG_C])
				requiredTemps += CPU_REG_C;
		}

		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;

		if (!(mFlags & NCIF_PRESERVE_CPU_REG_A))
			providedTemps += CPU_REG_A;
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_X))
			providedTemps += CPU_REG_X;
		if (!(mFlags & NCIF_PRESERVE_CPU_REG_Y))
			providedTemps += CPU_REG_Y;
		providedTemps += CPU_REG_C;
		providedTemps += CPU_REG_Z;
		return;
	}

	if (mType == ASMIT_RTS)
	{
#if 1
		if (mFlags & NCIF_USE_CPU_REG_A)
		{
			if (!providedTemps[CPU_REG_A])
				requiredTemps += CPU_REG_A;
		}

		if (mFlags & NCIF_LOWER)
		{
			if (!providedTemps[BC_REG_ACCU + 0]) requiredTemps += BC_REG_ACCU + 0;

			if (mFlags & NCIF_UPPER)
			{
				if (!providedTemps[BC_REG_ACCU + 1]) requiredTemps += BC_REG_ACCU + 1;

				if (mFlags & NCIF_LONG)
				{
					if (!providedTemps[BC_REG_ACCU + 2]) requiredTemps += BC_REG_ACCU + 2;
					if (!providedTemps[BC_REG_ACCU + 3]) requiredTemps += BC_REG_ACCU + 3;
				}
			}
		}
#endif
#if 0
		for (int i = 0; i < 4; i++)
		{
			if (!providedTemps[BC_REG_ACCU + i])
				requiredTemps += BC_REG_ACCU + i;
		}
#endif
		if (!providedTemps[BC_REG_STACK])
			requiredTemps += BC_REG_STACK;
		if (!providedTemps[BC_REG_STACK + 1])
			requiredTemps += BC_REG_STACK + 1;
		if (!providedTemps[BC_REG_LOCALS])
			requiredTemps += BC_REG_LOCALS;
		if (!providedTemps[BC_REG_LOCALS + 1])
			requiredTemps += BC_REG_LOCALS + 1;

		return;
	}

	// check index

	switch (mMode)
	{
	case ASMIM_ZERO_PAGE_X:
	case ASMIM_INDIRECT_X:
	case ASMIM_ABSOLUTE_X:
		if (!providedTemps[CPU_REG_X])
			requiredTemps += CPU_REG_X;
		break;

	case ASMIM_ZERO_PAGE_Y:
	case ASMIM_ABSOLUTE_Y:
		if (!providedTemps[CPU_REG_Y])
			requiredTemps += CPU_REG_Y;
		break;

	case ASMIM_INDIRECT_Y:
		if (!providedTemps[CPU_REG_Y])
			requiredTemps += CPU_REG_Y;
		if (!providedTemps[mAddress])
			requiredTemps += mAddress;
		if (!providedTemps[mAddress + 1])
			requiredTemps += mAddress + 1;
		break;
	}

	// check carry flags

	switch (mType)
	{
	case ASMIT_ADC:
	case ASMIT_SBC:
	case ASMIT_ROL:
	case ASMIT_ROR:
		if (!providedTemps[CPU_REG_C])
			requiredTemps += CPU_REG_C;
		providedTemps += CPU_REG_C;
		break;
	case ASMIT_CMP:
	case ASMIT_ASL:
	case ASMIT_LSR:
	case ASMIT_CPX:
	case ASMIT_CPY:
	case ASMIT_CLC:
	case ASMIT_SEC:
		providedTemps += CPU_REG_C;
		break;
	case ASMIT_BCC:
	case ASMIT_BCS:
		if (!providedTemps[CPU_REG_C])
			requiredTemps += CPU_REG_C;
		break;
	case ASMIT_BEQ:
	case ASMIT_BNE:
	case ASMIT_BPL:
	case ASMIT_BMI:
		if (!providedTemps[CPU_REG_Z])
			requiredTemps += CPU_REG_Z;
		break;
	}

	// check zero flag

	switch (mType)
	{
	case ASMIT_ADC:
	case ASMIT_SBC:
	case ASMIT_ROL:
	case ASMIT_ROR:
	case ASMIT_INC:
	case ASMIT_DEC:
	case ASMIT_CMP:
	case ASMIT_CPX:
	case ASMIT_CPY:
	case ASMIT_ASL:
	case ASMIT_LSR:
	case ASMIT_ORA:
	case ASMIT_EOR:
	case ASMIT_AND:
	case ASMIT_LDA:
	case ASMIT_LDX:
	case ASMIT_LDY:
	case ASMIT_BIT:
	case ASMIT_TAX:
	case ASMIT_TXA:
	case ASMIT_TAY:
	case ASMIT_TYA:
	case ASMIT_DEY:
	case ASMIT_INY:
	case ASMIT_DEX:
	case ASMIT_INX:
		providedTemps += CPU_REG_Z;
		break;
	}

	// check CPU register

	switch (mType)
	{
	case ASMIT_ROL:
	case ASMIT_ROR:
	case ASMIT_ASL:
	case ASMIT_LSR:
		if (mMode == ASMIM_IMPLIED)
		{
			if (!providedTemps[CPU_REG_A])
				requiredTemps += CPU_REG_A;
			providedTemps += CPU_REG_A;
		}
		break;

	case ASMIT_LDA:
		providedTemps += CPU_REG_A;
		break;

	case ASMIT_CMP:
	case ASMIT_STA:
		if (!providedTemps[CPU_REG_A])
			requiredTemps += CPU_REG_A;
		break;
	case ASMIT_CPX:
	case ASMIT_STX:
		if (!providedTemps[CPU_REG_X])
			requiredTemps += CPU_REG_X;
		break;
	case ASMIT_CPY:
	case ASMIT_STY:
		if (!providedTemps[CPU_REG_Y])
			requiredTemps += CPU_REG_Y;
		break;

	case ASMIT_ADC:
	case ASMIT_SBC:
	case ASMIT_ORA:
	case ASMIT_EOR:
	case ASMIT_AND:
		if (!providedTemps[CPU_REG_A])
			requiredTemps += CPU_REG_A;
		providedTemps += CPU_REG_A;
		break;
	case ASMIT_LDX:
		providedTemps += CPU_REG_X;
		break;
	case ASMIT_INX:
	case ASMIT_DEX:
		if (!providedTemps[CPU_REG_X])
			requiredTemps += CPU_REG_X;
		providedTemps += CPU_REG_X;
		break;
	case ASMIT_LDY:
		providedTemps += CPU_REG_Y;
		break;
	case ASMIT_INY:
	case ASMIT_DEY:
		if (!providedTemps[CPU_REG_Y])
			requiredTemps += CPU_REG_Y;
		providedTemps += CPU_REG_Y;
		break;

	case ASMIT_TAX:
		if (!providedTemps[CPU_REG_A])
			requiredTemps += CPU_REG_A;
		providedTemps += CPU_REG_X;
		break;
	case ASMIT_TAY:
		if (!providedTemps[CPU_REG_A])
			requiredTemps += CPU_REG_A;
		providedTemps += CPU_REG_Y;
		break;
	case ASMIT_TXA:
		if (!providedTemps[CPU_REG_X])
			requiredTemps += CPU_REG_X;
		providedTemps += CPU_REG_A;
		break;
	case ASMIT_TYA:
		if (!providedTemps[CPU_REG_Y])
			requiredTemps += CPU_REG_Y;
		providedTemps += CPU_REG_A;
		break;
	}

	if (mMode == ASMIM_ZERO_PAGE)
	{
		switch (mType)
		{
		case ASMIT_STA:
		case ASMIT_STX:
		case ASMIT_STY:
			providedTemps += mAddress;
			break;
		case ASMIT_ROL:
		case ASMIT_ROR:
		case ASMIT_ASL:
		case ASMIT_LSR:
		case ASMIT_INC:
		case ASMIT_DEC:
			if (!providedTemps[mAddress])
				requiredTemps += mAddress;
			providedTemps += mAddress;
			break;
		default:
			if (!providedTemps[mAddress])
				requiredTemps += mAddress;
		}
	}
}

uint32 NativeCodeInstruction::CodeHash(void) const
{
	uint32	hash = mType + 137 * mMode + 4111 * mAddress;
	if (mLinkerObject)
		hash += mLinkerObject->mID * 135123;
	hash ^= hash >> 13;
	hash ^= hash << 11;
	hash ^= hash >> 23;
	return hash;
}

bool NativeCodeInstruction::CodeSame(const NativeCodeInstruction& ins)
{
	if (mType != ins.mType || mMode != ins.mMode)
		return false;
	if (mMode != ASMIM_IMPLIED && (mAddress != ins.mAddress || mLinkerObject != ins.mLinkerObject))
		return false;
	if (mMode == ASMIM_IMMEDIATE_ADDRESS && (mFlags & (NCIF_LOWER | NCIF_UPPER)) != (ins.mFlags & (NCIF_LOWER | NCIF_UPPER)))
		return false;
	if ((mFlags & NCIF_USE_ZP_32_X) && mParam != ins.mParam)
		return false;

	return true;
}

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::CopyModeAndRange(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));
	mMinVal = ins.mMinVal;
	mMaxVal = ins.mMaxVal;
}

void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block)
{
	bool	weak = true;

	if (mIns)
	{
		if (ChangesAddress() && (mMode != ASMIM_ZERO_PAGE || mLinkerObject))
			weak = false;
		else if (mType == ASMIT_JSR && !(mFlags & NCIF_RUNTIME))
			weak = false;
		block->PutLocation(mIns->mLocation, weak);
	}

	if (mType == ASMIT_BYTE)
		block->PutByte(mAddress);
	else if (mType == ASMIT_JSR && (mFlags & NCIF_BREAKPOINT))
	{
		LinkerReference		rl;
		rl.mOffset = block->mCode.Size();

		rl.mRefObject = nullptr;
		rl.mRefOffset = 0;
		rl.mFlags = LREF_BREAKPOINT;

		block->mRelocations.Push(rl);
		block->PutByte(0xEA);
	}
	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 || mType == ASMIT_JMP) && (mFlags & NCIF_USE_ZP_32_X))
		{
			block->PutOpcode(AsmInsOpcodes[ASMIT_LDX][ASMIM_IMMEDIATE]);
			block->PutByte(mParam);
		}

		AsmInsMode	mode = mMode;

		if (mode == ASMIM_ABSOLUTE && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
			mode = ASMIM_ZERO_PAGE;
		else if (mode == ASMIM_ABSOLUTE_X && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_X))
			mode = ASMIM_ZERO_PAGE_X;
		else if (mode == ASMIM_ABSOLUTE_Y && !mLinkerObject && mAddress < 256 && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_Y))
			mode = ASMIM_ZERO_PAGE_Y;
		else if (mode == ASMIM_ABSOLUTE && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE))
			mode = ASMIM_ZERO_PAGE;
		else if (mode == ASMIM_ABSOLUTE_X && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_X))
			mode = ASMIM_ZERO_PAGE_X;
		else if (mode == ASMIM_ABSOLUTE_Y && mLinkerObject && (mLinkerObject->mFlags & LOBJF_ZEROPAGE) && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE_Y))
			mode = ASMIM_ZERO_PAGE_Y;

		if (mode == ASMIM_IMMEDIATE_ADDRESS)
		{
			assert((mFlags & (NCIF_LOWER | NCIF_UPPER)) != (NCIF_LOWER | NCIF_UPPER));
			assert(HasAsmInstructionMode(mType, ASMIM_IMMEDIATE));
			block->PutOpcode(AsmInsOpcodes[mType][ASMIM_IMMEDIATE]);
		}
		else
		{
			assert(HasAsmInstructionMode(mType, mode));
			block->PutOpcode(AsmInsOpcodes[mType][mode]);
		}
		
		switch (mode)
		{
		case ASMIM_IMPLIED:
			break;
		case ASMIM_ZERO_PAGE:
		case ASMIM_ZERO_PAGE_X:
		case ASMIM_ZERO_PAGE_Y:
		case ASMIM_INDIRECT_X:
		case ASMIM_INDIRECT_Y:
			if (mLinkerObject)
			{
				LinkerReference		rl;
				rl.mOffset = block->mCode.Size();

				rl.mRefObject = mLinkerObject;
				rl.mRefOffset = mAddress;
				rl.mFlags = LREF_LOWBYTE;

				block->mRelocations.Push(rl);
				block->PutByte(0);
			}
			else
			{
				if (mAddress == 0 && !(mFlags & NCIF_VOLATILE))
					block->mProc->mGenerator->mErrors->Error(mIns->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced");
				block->PutByte(uint8(mAddress));
			}
			break;
		case ASMIM_IMMEDIATE:
			block->PutByte(uint8(mAddress));
			break;
		case ASMIM_IMMEDIATE_ADDRESS:
			if (mLinkerObject)
			{
				LinkerReference		rl;
				rl.mOffset = block->mCode.Size();
				rl.mFlags = 0;
				if (mFlags & NCIF_LOWER)
					rl.mFlags |= LREF_LOWBYTE;
				if (mFlags & NCIF_UPPER)
					rl.mFlags |= LREF_HIGHBYTE;
				rl.mRefObject = mLinkerObject;

				rl.mRefObject = mLinkerObject;
				rl.mRefOffset = mAddress;

				if (mLinkerObject)
					mLinkerObject->mFlags |= LOBJF_NO_CROSS;

				block->mRelocations.Push(rl);
				block->PutByte(0);
			}
			else
			{
				block->PutByte(uint8(mAddress));
			}
			break;
		case ASMIM_ABSOLUTE:
		case ASMIM_INDIRECT:
		case ASMIM_ABSOLUTE_X:
		case ASMIM_ABSOLUTE_Y:
			if (mLinkerObject)
			{
				if (mFlags & NCIF_SELFMOD)
				{
					block->PutSelfModSource(mAddress);
					block->PutWord(0);
				}
				else
				{
					int	w = 0;

					LinkerReference		rl;
					rl.mOffset = block->mCode.Size();

					rl.mRefObject = mLinkerObject;
					if (mType != ASMIT_JSR && mType != ASMIT_JSR && mMode == ASMIM_ABSOLUTE && mLinkerObject == block->mProc->mLinkerObject)
					{
						rl.mFlags = LREF_SELFMOD | LREF_LOWBYTE | LREF_HIGHBYTE;
						rl.mRefOffset = mAddress;
					}
					else
					{
						if (mFlags & NCIF_LOWER)
						{
							rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
							rl.mRefOffset = mAddress;
						}
						else
						{
							rl.mFlags = LREF_HIGHBYTE;
							rl.mOffset++;
							rl.mRefOffset = mAddress & 0xff00;

							w = mAddress & 0xff;
						}
					}

					if (mode != ASMIM_ABSOLUTE)
						mLinkerObject->mFlags |= LOBJF_NO_CROSS;

					block->mRelocations.Push(rl);
					block->PutWord(w);
				}
			}
			else
			{
				if (mAddress == 0 && !(mFlags & NCIF_VOLATILE))
					block->mProc->mGenerator->mErrors->Error(mIns->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced");
				block->PutWord(uint16(mAddress));
			}
			break;
		case ASMIM_RELATIVE:
			block->PutByte(uint8(mAddress));
			break;
		}
	}

	if (mIns)
		block->PutLocation(mIns->mLocation, weak);
}

void NativeCodeBasicBlock::PutLocation(const Location& location, bool weak)
{
	int sz = mCodeLocations.Size();
	if (sz > 0 && 
		mCodeLocations[sz - 1].mLocation.mFileName == location.mFileName &&
		mCodeLocations[sz - 1].mLocation.mLine == location.mLine)
	{
		mCodeLocations[sz - 1].mEnd = this->mCode.Size();
		if (mCodeLocations[sz - 1].mWeak)
			mCodeLocations[sz - 1].mWeak = weak;
	}
	else if (sz > 0 && mCodeLocations[sz - 1].mWeak)
	{
		mCodeLocations[sz - 1].mLocation = location;
		mCodeLocations[sz - 1].mEnd = this->mCode.Size();
		mCodeLocations[sz - 1].mWeak = weak;
	}
	else
	{
		CodeLocation	loc;
		loc.mLocation = location;
		loc.mStart = loc.mEnd = this->mCode.Size();
		loc.mWeak = weak;
		mCodeLocations.Push(loc);
	}

	sz = mCodeOrigins.Size();
	if (sz > 0 &&
		mCodeOrigins[sz - 1].mLocation.mFileName == location.mFileName &&
		mCodeOrigins[sz - 1].mLocation.mLine == location.mLine)
	{
		mCodeOrigins[sz - 1].mEnd = this->mCode.Size();
	}
	else
	{
		CodeLocation	loc;
		loc.mLocation = location;
		loc.mStart = loc.mEnd = this->mCode.Size();
		mCodeOrigins.Push(loc);
	}
}

void NativeCodeBasicBlock::PutSelfModSource(int id)
{
	mProc->mSelfModSources[id] = SelfModReference{ this, this->mCode.Size() };
}

void NativeCodeBasicBlock::PutOpcode(short opcode)
{
	assert(opcode >= 0 && opcode < 256);
	this->mCode.Push(uint8(opcode));
}

void NativeCodeBasicBlock::PutByte(uint8 code)
{
	this->mCode.Push(code);
}

void NativeCodeBasicBlock::PutWord(uint16 code)
{
	this->mCode.Push((uint8)(code & 0xff));
	this->mCode.Push((uint8)(code >> 8));
}

static AsmInsType InvertBranchCondition(AsmInsType code)
{
	switch (code)
	{
	case ASMIT_BEQ: return ASMIT_BNE;
	case ASMIT_BNE: return ASMIT_BEQ;
	case ASMIT_BPL: return ASMIT_BMI;
	case ASMIT_BMI: return ASMIT_BPL;
	case ASMIT_BCS: return ASMIT_BCC;
	case ASMIT_BCC: return ASMIT_BCS;
	default:
		return code;
	}
}

static AsmInsType TransposeBranchCondition(AsmInsType code)
{
	switch (code)
	{
	case ASMIT_BEQ: return ASMIT_BEQ;
	case ASMIT_BNE: return ASMIT_BNE;
	case ASMIT_BPL: return ASMIT_BMI;
	case ASMIT_BMI: return ASMIT_BPL;
	case ASMIT_BCS: return ASMIT_BCC;
	case ASMIT_BCC: return ASMIT_BCS;
	default:
		return code;
	}
}


int NativeCodeBasicBlock::PutJump(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, int from, int to, AsmInsType code)
{
	if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
	{
		if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
		{
			this->mCode[this->mCode.Size() - 3] = 0x4c;
			return 0;
		}
		else
		{
			PutByte(0x60);
			return 1;
		}
	}
	else if (target->mIns.Size() == 2 && target->mIns[0].IsSimpleJSR() && target->mIns[1].mType == ASMIT_RTS)
	{
		PutByte(0x4c);

		LinkerReference		rl;
		rl.mObject = nullptr;
		rl.mOffset = mCode.Size();
		rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
		rl.mRefObject = target->mIns[0].mLinkerObject;
		rl.mRefOffset = target->mIns[0].mAddress;
		mRelocations.Push(rl);

		PutWord(0);
		return 3;
	}
	else if (to - from >= -126 && to - from <= 129)
	{
		if (code != ASMIT_INV)
		{
			PutOpcode(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]);
			PutByte(to - from - 2);
			return 2;
		}
#if JUMP_TO_BRANCH
		else if (mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
		{
			if (mNDataSet[CPU_REG_C].mValue)
				PutOpcode(AsmInsOpcodes[ASMIT_BCS][ASMIM_RELATIVE]);
			else
				PutOpcode(AsmInsOpcodes[ASMIT_BCC][ASMIM_RELATIVE]);

			PutByte(to - from - 2);
			return 2;
		}
		else if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
		{
			if (mNDataSet[CPU_REG_Z].mValue)
				PutOpcode(AsmInsOpcodes[ASMIT_BNE][ASMIM_RELATIVE]);
			else
				PutOpcode(AsmInsOpcodes[ASMIT_BEQ][ASMIM_RELATIVE]);

			PutByte(to - from - 2);
			return 2;
		}
#endif
	}
	
	target->mAsmFromJump = from;

	if (target->mCode.Size() == 2 && target->mRelocations.Size() == 0 && !target->mFalseJump && target->mTrueJump && target->mTrueJump->mIns.Size() == 1 && target->mTrueJump->mIns[0].mType == ASMIT_RTS)
	{
		PutByte(target->mCode[0]);
		PutByte(target->mCode[1]);
		PutByte(0x60);
		return 3;
	}

	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::CheckFinalBranchByteSize(NativeCodeBasicBlock* target, int from, int to) const
{
	if (to - from >= -126 && to - from <= 129)
		return 2;
	else
	{
		if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
			return 3;
#if REYCLE_JUMPS
		if (target->mAsmFromJump >= 0 && target->mAsmFromJump - from >= -126)
			return 2;
#endif
		return 5;
	}
}

int NativeCodeBasicBlock::BranchByteSize(NativeCodeBasicBlock* target, int from, int to, bool final) const
{
	if (to - from >= -126 && to - from <= 129)
		return 2;
	else
	{
		if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
			return 3;
		if (final)
		{
#if REYCLE_JUMPS
			if (target->mAsmFromJump >= 0 && target->mAsmFromJump - from >= -126)
				return 2;
#endif
			target->mAsmFromJump = from + 2;
			return 5;
		}
		else
		{
			return 5;
		}
	}
}

int NativeCodeBasicBlock::JumpByteSize(NativeCodeBasicBlock* target, int from, int to, bool second, bool final)
{
	if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
	{
		if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
			return 0;
		else
			return 1;
	}
	else if (target->mIns.Size() == 2 && target->mIns[0].IsSimpleJSR() && target->mIns[1].mType == ASMIT_RTS)
	{
		return 3;
	}
	else if (to - from >= -126 && to - from <= 129)
	{
		if (second)
			return 2;
#if JUMP_TO_BRANCH
		else if (mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			return 2;
		else if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
			return 2;
#endif
		else
		{
			if (final)
				target->mAsmFromJump = from;
			return 3;
		}
	}
	else
	{
		if (final)
			target->mAsmFromJump = from;

		return 3;
	}
}


int NativeCodeBasicBlock::PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int from, int to)
{
	if (to - from >= -126 && to - from <= 129)
	{
		PutOpcode(AsmInsOpcodes[code][ASMIM_RELATIVE]);
		PutByte(to - from - 2);
		return 2;
	}
#if REYCLE_JUMPS
	else if (target->mAsmFromJump >= 0 && target->mAsmFromJump - from >= -126)
	{
		PutOpcode(AsmInsOpcodes[code][ASMIM_RELATIVE]);
		PutByte(target->mAsmFromJump - from - 2);
		return 2;
	}
#endif
	else
	{
		PutOpcode(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]);

		if (target->mIns.Size() == 1 && target->mIns[0].mType == ASMIT_RTS)
		{
			PutByte(1);
			PutByte(0x60);
			return 3;
		}
		else
		{
			PutByte(3);

			target->mAsmFromJump = from + 2;

			PutByte(0x4c);

			LinkerReference		rl;
			rl.mObject = nullptr;
			rl.mOffset = mCode.Size();
			rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
			rl.mRefObject = nullptr;
			rl.mRefOffset = to;
			mRelocations.Push(rl);

			PutWord(0);
			return 5;
		}
	}
}

void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure* proc, const InterInstruction* ins, const InterOperand& op, InterType type, int reg, bool checkRange)
{

	if (type == IT_FLOAT)
	{
		union { float f; unsigned int v; } cc;
		cc.f = float(op.mFloatConst);

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
	}
	else if (type == IT_POINTER)
	{
		if (op.mMemory == IM_GLOBAL)
		{
			if (checkRange && (op.mIntConst < 0 || op.mIntConst > op.mLinkerObject->mSize))
				proc->mModule->mErrors->Error(ins->mLocation, EWARN_UNDEFINED_POINTER_ARITHMETIC, "Undefined constant pointer arithmetic");

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_LOWER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_UPPER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
		else if (op.mMemory == IM_ABSOLUTE)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
		else if (op.mMemory == IM_FPARAM || op.mMemory == IM_FFRAME)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + op.mVarIndex + op.mIntConst));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
		else if (op.mMemory == IM_FRAME)
		{
			int	index = op.mVarIndex + int(op.mIntConst) + 2;

			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
		else if (op.mMemory == IM_LOCAL || op.mMemory == IM_PARAM)
		{
			int	index = int(op.mIntConst);
			int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
			if (op.mMemory == IM_LOCAL)
				index += proc->mLocalVars[op.mVarIndex]->mOffset;
			else
				index += op.mVarIndex + proc->mLocalSize + 2;
			index += mFrameOffset;
			CheckFrameIndex(ins, areg, index, 2);

			if (index != 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
			if (index != 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
			if (index != 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
		else if (op.mMemory == IM_PROCEDURE)
		{
			NativeCodeInstruction	lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_LOWER);
			NativeCodeInstruction	hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, op.mIntConst, op.mLinkerObject, NCIF_UPPER);

			mIns.Push(lins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
			mIns.Push(hins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
	}
	else if (type == IT_INT32)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 16) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 24) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, op.mIntConst & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		if (InterTypeSize[type] > 1)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (op.mIntConst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		}
	}
}

void NativeCodeBasicBlock::LoadConstantToReg(InterCodeProcedure * proc, const InterInstruction * ins, InterType type, int reg)
{
	LoadConstantToReg(proc, ins, ins->mConst, type, reg);
}

void NativeCodeBasicBlock::LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins)
{
	LoadConstantToReg(proc, ins, ins->mDst.mType, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]);
}

void NativeCodeBasicBlock::CheckFrameIndex(const InterInstruction* ins, int& reg, int& index, int size, int treg)
{
	if (index < 0 || index + size > 256)
	{
		if (treg == 0)
			treg = BC_REG_ADDR;
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
		index = 0;
		reg = treg;
	}
}

void NativeCodeBasicBlock::StoreValue(InterCodeProcedure* proc, const InterInstruction * ins)
{
	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (ins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (ins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (ins->mAliasing)
		flags |= NCIF_ALIASING;

	if (ins->mSrc[0].mType == IT_FLOAT)
	{
		int stride = ins->mSrc[1].mStride;

		if (ins->mSrc[1].mTemp < 0)
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				union { float f; unsigned int v; } cc;
				cc.f = float(ins->mSrc[0].mFloatConst);

				if (ins->mSrc[1].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3));
				}
				else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[1].mIntConst);
					int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[1].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
					else
						index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, reg, index, 4);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
				}
				else if (ins->mSrc[1].mMemory == IM_FRAME)
				{
					int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y,BC_REG_STACK));
				}
			}
			else
			{
				int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];

				if (ins->mSrc[0].mFinal && CheckPredAccuStore(sreg))
				{
					// cull previous store from accu to temp using direcrt forwarding from accu
					mIns.SetSize(mIns.Size() - 8);
					sreg = BC_REG_ACCU;
				}

				if (ins->mSrc[1].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3));
				}
				else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[1].mIntConst);
					int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[1].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
					else
						index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, reg, index, 4);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
				}
				else if (ins->mSrc[1].mMemory == IM_FRAME)
				{
					int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				}
			}
		}
		else
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					union { float f; unsigned int v; } cc;
					cc.f = float(ins->mSrc[0].mFloatConst);

					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;

					if (stride * 4 <= 256)
					{
						CheckFrameIndex(ins, reg, index, stride * 4);

						for (int i = 0; i < 4; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						}
					}
					else
					{
						for (int i = 0; i < 4; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));

							index += stride;
						}
					}
				}
			}
			else
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;

					if (stride * 4 <= 256)
					{
						CheckFrameIndex(ins, reg, index, stride * 4);

						for (int i = 0; i < 4; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						}
					}
					else
					{
						for (int i = 0; i < 4; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));

							index += stride;
						}
					}
				}
			}
		}
	}
	else if (ins->mSrc[0].mType == IT_POINTER)
	{
		int stride = ins->mSrc[1].mStride;

		if (ins->mSrc[1].mTemp < 0)
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[1].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
				}
				else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[1].mIntConst);
					int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[1].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
					else
						index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, reg, index, 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
				}
				else if (ins->mSrc[1].mMemory == IM_FRAME)
				{
					int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				}
			}
			else
			{
				if (ins->mSrc[1].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
				}
				else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1));
				}
				else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[1].mIntConst);
					int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[1].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
					else
						index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, reg, index, 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
				}
				else if (ins->mSrc[1].mMemory == IM_FRAME)
				{
					int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				}
			}
		}
		else
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;

					if (2 * stride <= 256)
					{
						CheckFrameIndex(ins, reg, index, 2 * stride);

						for (int i = 0; i < 2; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						}
					}
					else
					{
						for (int i = 0; i < 2; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));

							index += stride;
						}
					}
				}
			}
			else
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;

					if (2 * stride <= 256)
					{
						CheckFrameIndex(ins, reg, index, 2 * stride);

						for (int i = 0; i < 2; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						}
					}
					else
					{
						for (int i = 0; i < 2; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));

							index += stride;
						}
					}
				}
			}
		}
	}
	else
	{
		if (ins->mSrc[1].mTemp < 0)
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (InterTypeSize[ins->mSrc[0].mType] == 1)
				{
					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 1);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
				else if (InterTypeSize[ins->mSrc[0].mType] == 2)
				{
					int stride = ins->mSrc[1].mStride;

					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + stride));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
				else if (InterTypeSize[ins->mSrc[0].mType] == 4)
				{
					int stride = ins->mSrc[1].mStride;

					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3 * stride));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 4);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
			}
			else
			{
				if (InterTypeSize[ins->mSrc[0].mType] == 1)
				{
					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 1);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
				else if (InterTypeSize[ins->mSrc[0].mType] == 2)
				{
					int stride = ins->mSrc[1].mStride;

					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						if (ins->mSrc[0].IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
						if (ins->mSrc[0].IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + stride, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
						if (ins->mSrc[0].IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + stride));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;

						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
						if (ins->mSrc[0].IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
						if (ins->mSrc[0].IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
				else if (InterTypeSize[ins->mSrc[0].mType] == 4)
				{
					int stride = ins->mSrc[1].mStride;

					if (ins->mSrc[1].mMemory == IM_GLOBAL)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, ins->mSrc[1].mLinkerObject, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, ins->mSrc[1].mLinkerObject, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 1 * stride, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 2 * stride, nullptr, flags));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + 3 * stride, nullptr, flags));
					}
					else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 3 * stride));
					}
					else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
					{
						int	index = int(ins->mSrc[1].mIntConst);
						int	reg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;

						if (ins->mSrc[1].mMemory == IM_LOCAL)
							index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
						else
							index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
						index += mFrameOffset;
						CheckFrameIndex(ins, reg, index, 4);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg));
					}
					else if (ins->mSrc[1].mMemory == IM_FRAME)
					{
						int	index = int(ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + 2);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
				}
			}
		}
		else
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;
					int size = InterTypeSize[ins->mSrc[0].mType];

					if (stride * size <= 256)
					{
						CheckFrameIndex(ins, reg, index, stride * size);

						for (int i = 0; i < size; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg, nullptr, flags));
						}
					}
					else
					{
						for (int i = 0; i < size; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg, nullptr, flags));

							index += stride;
						}
					}
				}
			}
			else
			{
				if (ins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	reg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
					int index = int(ins->mSrc[1].mIntConst);
					int stride = ins->mSrc[1].mStride;
					int size = InterTypeSize[ins->mSrc[0].mType];

					if (stride * size <= 256)
					{
						CheckFrameIndex(ins, reg, index, stride * size);

						for (int i = 0; i < size; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg, nullptr, flags));
						}
					}
					else
					{
						for (int i = 0; i < size; i++)
						{
							CheckFrameIndex(ins, reg, index, 1);

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, reg, nullptr, flags));

							index += stride;
						}
					}
				}
			}
		}
	}

}

void NativeCodeBasicBlock::LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins)
{
	mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));

	int stride = rins->mSrc[0].mStride;

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		flags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
	{
		if (i != 0)
		{
			if (stride == 1)
				mIns.Push(NativeCodeInstruction(rins, ASMIT_INY, ASMIM_IMPLIED));
			else
			{
				mIns.Push(NativeCodeInstruction(rins, ASMIT_TYA, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_CLC, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_ADC, ASMIM_IMMEDIATE, stride));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_TAY, ASMIM_IMPLIED));
			}
		}
		mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
		if (rins->mDst.mTemp == iins->mSrc[1].mTemp)
			mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
		else
			mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
	}

	if (rins->mDst.mTemp == iins->mSrc[1].mTemp)
	{
		for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
		{
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
			mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
		}
	}
}

void NativeCodeBasicBlock::StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
	mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));

	int stride = wins->mSrc[1].mStride;

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		flags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
	{
		if (i != 0)
		{
			if (stride == 1)
				mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED));
			else
			{
				mIns.Push(NativeCodeInstruction(wins, ASMIT_TYA, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(wins, ASMIT_CLC, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(wins, ASMIT_ADC, ASMIM_IMMEDIATE, stride));
				mIns.Push(NativeCodeInstruction(wins, ASMIT_TAY, ASMIM_IMPLIED));
			}
		}
		if (wins->mSrc[0].mTemp < 0)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
		mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
	}
}

void NativeCodeBasicBlock::CopyByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* riins, const InterInstruction* wiins, const InterInstruction* rins, const InterInstruction* wins)
{
	mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[riins->mSrc[0].mTemp]));

	int stride = rins->mSrc[1].mStride;

	uint32	rflags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		rflags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		rflags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		rflags |= NCIF_ALIASING;
	uint32	wflags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		wflags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		wflags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		wflags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
	{
		if (i != 0)
		{
			if (stride == 1)
				mIns.Push(NativeCodeInstruction(rins, ASMIT_INY, ASMIM_IMPLIED));
			else
			{
				mIns.Push(NativeCodeInstruction(rins, ASMIT_TYA, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_CLC, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_ADC, ASMIM_IMMEDIATE, stride));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_TAY, ASMIM_IMPLIED));
			}
		}
		mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[riins->mSrc[1].mTemp], nullptr, rflags));
		mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wiins->mSrc[1].mTemp], nullptr, wflags));
	}
}

void NativeCodeBasicBlock::LoadAbsoluteByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins)
{
	mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
	int address = int(iins->mSrc[1].mIntConst + rins->mSrc[0].mIntConst);

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		flags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++)
	{
		mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE_X, address + i * rins->mSrc[0].mStride, iins->mSrc[1].mLinkerObject, flags));
		mIns.Push(NativeCodeInstruction(rins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i));
	}
}

void NativeCodeBasicBlock::StoreAbsoluteByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
	mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
	int address = int(iins->mSrc[1].mIntConst + wins->mSrc[1].mIntConst);

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		flags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
	{
		if (wins->mSrc[0].mTemp < 0)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));

		mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE_X, address + i * wins->mSrc[1].mStride, iins->mSrc[1].mLinkerObject, flags));
	}
}

void NativeCodeBasicBlock::StoreByteOffsetIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins)
{
	mIns.Push(NativeCodeInstruction(iins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp]));
	mIns.Push(NativeCodeInstruction(iins, ASMIT_CLC));
	mIns.Push(NativeCodeInstruction(iins, ASMIT_ADC, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst));
	mIns.Push(NativeCodeInstruction(iins, ASMIT_TAY));

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		flags |= NCIF_ALIASING;

	for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++)
	{
		if (i != 0)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED));
		if (wins->mSrc[0].mTemp < 0)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
		mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags));
	}
}

void NativeCodeBasicBlock::LoadStoreIndirectPair(InterCodeProcedure* proc, const InterInstruction* wins0, const InterInstruction* wins1)
{
	int sreg = BC_REG_TMP + proc->mTempOffset[wins0->mSrc[0].mTemp];

	int	ireg0 = BC_REG_TMP + proc->mTempOffset[wins0->mSrc[1].mTemp];
	int index0 = int(wins0->mSrc[1].mIntConst);
	uint32	wflags0 = NCIF_LOWER | NCIF_UPPER;
	if (wins0->mVolatile)
		wflags0 |= NCIF_VOLATILE;
	if (wins0->mMemmap)
		wflags0 |= NCIF_MEMMAP;
	if (wins0->mAliasing)
		wflags0 |= NCIF_ALIASING;

	int	ireg1 = BC_REG_TMP + proc->mTempOffset[wins1->mSrc[1].mTemp];
	int index1 = int(wins1->mSrc[1].mIntConst);
	uint32	wflags1 = NCIF_LOWER | NCIF_UPPER;
	if (wins1->mVolatile)
		wflags1 |= NCIF_VOLATILE;
	if (wins1->mMemmap)
		wflags1 |= NCIF_MEMMAP;
	if (wins1->mAliasing)
		wflags1 |= NCIF_ALIASING;

	CheckFrameIndex(wins0, ireg0, index0, 1, BC_REG_ADDR);
	CheckFrameIndex(wins1, ireg1, index1, 1, BC_REG_ACCU);

	mIns.Push(NativeCodeInstruction(wins0, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));

	mIns.Push(NativeCodeInstruction(wins0, ASMIT_LDY, ASMIM_IMMEDIATE, index0));
	mIns.Push(NativeCodeInstruction(wins0, ASMIT_STA, ASMIM_INDIRECT_Y, ireg0, nullptr, wflags0));

	mIns.Push(NativeCodeInstruction(wins1, ASMIT_LDY, ASMIM_IMMEDIATE, index1));
	mIns.Push(NativeCodeInstruction(wins1, ASMIT_STA, ASMIM_INDIRECT_Y, ireg1, nullptr, wflags1));
}

void NativeCodeBasicBlock::LoadStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* wins)
{
	int size = InterTypeSize[wins->mSrc[0].mType];

	AsmInsMode	rmode = ASMIM_INDIRECT_Y;
	int	rindex = int(rins->mSrc[0].mIntConst);
	int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
	LinkerObject* rlobject = nullptr;
	int rstride = rins->mSrc[0].mStride;

	uint32	rflags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		rflags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		rflags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		rflags |= NCIF_ALIASING;

	switch (rins->mSrc[0].mMemory)
	{
	case IM_PARAM:
		rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_LOCAL:
		rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PROCEDURE:
	case IM_GLOBAL:
		rmode = ASMIM_ABSOLUTE;
		rlobject = rins->mSrc[0].mLinkerObject;
		rindex = int(rins->mSrc[0].mIntConst);
		break;
	case IM_FRAME:
		rindex = int(rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst + 2);
		rareg = BC_REG_STACK;
		break;
	case IM_INDIRECT:
		rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
		break;
	case IM_ABSOLUTE:
		rmode = ASMIM_ABSOLUTE;
		rindex = int(rins->mSrc[0].mIntConst);
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		rmode = ASMIM_ZERO_PAGE;
		rareg = int(BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst);
		break;
	}

	AsmInsMode	wmode = ASMIM_INDIRECT_Y;
	int	windex = int(wins->mSrc[1].mIntConst);
	int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
	LinkerObject* wlobject = nullptr;
	int wstride = wins->mSrc[1].mStride;

	uint32	wflags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		wflags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		wflags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		wflags |= NCIF_ALIASING;

	switch (wins->mSrc[1].mMemory)
	{
	case IM_PARAM:
		windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_LOCAL:
		windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PROCEDURE:
	case IM_GLOBAL:
		wmode = ASMIM_ABSOLUTE;
		wlobject = wins->mSrc[1].mLinkerObject;
		windex = int(wins->mSrc[1].mIntConst);
		break;
	case IM_FRAME:
		windex = int(wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst + 2);
		wareg = BC_REG_STACK;
		break;
	case IM_INDIRECT:
		wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
		break;
	case IM_ABSOLUTE:
		wmode = ASMIM_ABSOLUTE;
		windex = int(wins->mSrc[1].mIntConst);
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		wmode = ASMIM_ZERO_PAGE;
		wareg = BC_REG_FPARAMS + wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
		break;
	}

	for (int i = 0; i < size; i++)
	{
		if (rmode == ASMIM_INDIRECT_Y)
			CheckFrameIndex(rins, rareg, rindex, 1, BC_REG_ADDR);
		if (wmode == ASMIM_INDIRECT_Y)
			CheckFrameIndex(wins, wareg, windex, 1, BC_REG_ACCU);

		if (rmode == ASMIM_INDIRECT_Y)
		{
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex));
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, rareg, nullptr, rflags));
		}
		else if (rmode == ASMIM_ZERO_PAGE)
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, rareg + i));
		else
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rindex, rlobject, rflags));

		if (wmode == ASMIM_INDIRECT_Y)
		{
			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex));
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, wareg, nullptr, wflags));
		}
		else if (wmode == ASMIM_ZERO_PAGE)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, wareg + i));
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, windex, wlobject, wflags));

		rindex += rstride;
		windex += wstride;
	}
}

void NativeCodeBasicBlock::LoadStoreValue(InterCodeProcedure* proc, const InterInstruction * rins, const InterInstruction * wins)
{
	uint32	rflags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		rflags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		rflags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		rflags |= NCIF_ALIASING;

	uint32	wflags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		wflags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		wflags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		wflags |= NCIF_ALIASING;


	if (rins->mDst.mType == IT_FLOAT)
	{

	}
	else if (rins->mDst.mType == IT_POINTER)
	{

	}
	else
	{

		if (InterTypeSize[wins->mSrc[0].mType] == 1)
		{
			if (rins->mSrc[0].mTemp < 0)
			{
				if (rins->mSrc[0].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, rins->mSrc[0].mLinkerObject, rflags));
				}
				else if (rins->mSrc[0].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ABSOLUTE, rins->mSrc[0].mIntConst, nullptr, rflags));
				}
				else if (rins->mSrc[0].mMemory == IM_FPARAM)
				{
					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + rins->mSrc[0].mIntConst));
				}
				else if (rins->mSrc[0].mMemory == IM_LOCAL || rins->mSrc[0].mMemory == IM_PARAM)
				{
					int	index = int(rins->mSrc[0].mIntConst);
					int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (rins->mSrc[0].mMemory == IM_LOCAL)
						index += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset;
					else
						index += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(rins, areg, index, 1);

					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				}
			}
			else
			{
				if (rins->mSrc[0].mMemory == IM_INDIRECT)
				{
					int	areg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
					int index = int(rins->mSrc[0].mIntConst);

					CheckFrameIndex(rins, areg, index, 1);

					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				}
			}

			if (wins->mSrc[1].mTemp < 0)
			{
				if (wins->mSrc[1].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, wins->mSrc[1].mIntConst, wins->mSrc[1].mLinkerObject, wflags));
				}
				else if (wins->mSrc[1].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ABSOLUTE, wins->mSrc[1].mIntConst, nullptr, wflags));
				}
				else if (wins->mSrc[1].mMemory == IM_FPARAM || wins->mSrc[1].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + wins->mSrc[1].mVarIndex + wins->mSrc[1].mIntConst));
				}
				else if (wins->mSrc[1].mMemory == IM_LOCAL || wins->mSrc[1].mMemory == IM_PARAM)
				{
					int	index = int(wins->mSrc[1].mIntConst);
					int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (wins->mSrc[1].mMemory == IM_LOCAL)
						index += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset;
					else
						index += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(wins, areg, index, 1);

					mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, areg));
				}
				else if (wins->mSrc[1].mMemory == IM_FRAME)
				{
					int	index = wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst) + 2;

					mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				}
			}
			else
			{
				if (wins->mSrc[1].mMemory == IM_INDIRECT)
				{
					int	areg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
					int index = int(wins->mSrc[1].mIntConst);

					CheckFrameIndex(wins, areg, index, 1);

					mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, areg));
				}
			}
		}
	}
}

bool NativeCodeBasicBlock::LoadLoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins1, const InterInstruction* rins0, const InterInstruction* oins, const InterInstruction* wins)
{
	if (rins1->mSrc[0].mMemory == IM_INDIRECT && rins0->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT)
	{
		if (rins1->mSrc[0].mStride != 1 || rins0->mSrc[0].mStride != 1 || wins->mSrc[1].mStride != 1)
			return false;

		int size = InterTypeSize[oins->mDst.mType];

		if (!wins->mSrc[0].mFinal) 
		{
			if (wins->mSrc[0].mTemp == rins1->mSrc[0].mTemp || wins->mSrc[0].mTemp == rins0->mSrc[0].mTemp)
				return false;
		}

		switch (oins->mOperator)
		{
		case IA_ADD:
			mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
			break;
		default:
			return false;
		}

		for (int i = 0; i < size; i++)
		{
			if (rins1->mSrc[0].mIntConst == wins->mSrc[1].mIntConst && rins0->mSrc[0].mIntConst != wins->mSrc[1].mIntConst)
			{
				mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i));
				mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp]));

				mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i));
				mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp]));
			}
			else
			{
				mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, rins1->mSrc[0].mIntConst + i));
				mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins1->mSrc[0].mTemp]));

				mIns.Push(NativeCodeInstruction(rins0, ASMIT_LDY, ASMIM_IMMEDIATE, rins0->mSrc[0].mIntConst + i));
				mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[rins0->mSrc[0].mTemp]));
			}

			mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst + i));
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));

			if (!wins->mSrc[0].mFinal)
				mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));
		}

		return true;
	}
#if 1
	else if (rins1->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT && rins0->mSrc[0].mMemory == IM_FPARAM)
	{
		if (rins1->mSrc[0].mTemp == wins->mSrc[1].mTemp && rins1->mSrc[0].mIntConst == wins->mSrc[1].mIntConst && rins1->mSrc[0].mStride == wins->mSrc[1].mStride && 
			wins->mSrc[0].mFinal && wins->mSrc[1].mFinal)
		{
			int size = InterTypeSize[oins->mDst.mType];

			AsmInsType	aop;

			switch (oins->mOperator)
			{
			case IA_ADD:
				mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
				aop = ASMIT_ADC;
				break;
			case IA_OR:
				aop = ASMIT_ORA;
				break;
			case IA_XOR:
				aop = ASMIT_EOR;
				break;
			case IA_AND:
				aop = ASMIT_AND;
				break;
			default:
				return false;
			}

			int	offset = int(wins->mSrc[1].mIntConst);
			for (int i = 0; i < size; i++)
			{
				while (offset >= 256)
				{
					mIns.Push(NativeCodeInstruction(rins1, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp] + 1));
					offset -= 256;
				}

				mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDY, ASMIM_IMMEDIATE, offset));
				mIns.Push(NativeCodeInstruction(rins1, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));

				mIns.Push(NativeCodeInstruction(oins, ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + rins0->mSrc[0].mVarIndex + int(rins0->mSrc[0].mIntConst) + i));

				mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp]));

				offset += wins->mSrc[1].mStride;
			}

			return true;
		}


		return false;
	}
	else if (rins0->mSrc[0].mMemory == IM_INDIRECT && wins->mSrc[1].mMemory == IM_INDIRECT && rins1->mSrc[0].mMemory == IM_FPARAM)
	{
		return false;
	}
#endif
	else
		return false;
}

bool NativeCodeBasicBlock::LoadUnopStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, const InterInstruction* wins)
{
	int size = InterTypeSize[wins->mSrc[0].mType];
	int rstride = rins->mSrc[0].mStride;
	int wstride = wins->mSrc[1].mStride;

	if (size > 1 && rstride != wstride)
		return false;

	AsmInsMode  ram = ASMIM_INDIRECT_Y, wam = ASMIM_INDIRECT_Y;
	bool		sfinal = wins->mSrc[0].mFinal;
	int			imm;
	AsmInsType	at;

	switch (oins->mOperator)
	{
	case IA_NEG:
		mIns.Push(NativeCodeInstruction(oins, ASMIT_SEC));
		imm = 0x00;
		at = ASMIT_SBC;
		break;
	case IA_NOT:
		imm = 0xff;
		at = ASMIT_EOR;
		break;
	default:
		return false;
	}

	int	rindex = int(rins->mSrc[0].mIntConst);
	int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;

	switch (rins->mSrc[0].mMemory)
	{
	case IM_INDIRECT:
		rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
		break;
	case IM_LOCAL:
		rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PARAM:
		rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		ram = ASMIM_ZERO_PAGE;
		rareg = BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + int(rins->mSrc[0].mIntConst);
		break;
	default:
		return false;
	}

	int	windex = int(wins->mSrc[1].mIntConst);
	int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;

	switch (wins->mSrc[1].mMemory)
	{
	case IM_INDIRECT:
		wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
		break;
	case IM_LOCAL:
		windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PARAM:
		windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		wam = ASMIM_ZERO_PAGE;
		wareg = BC_REG_FPARAMS + +wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
		break;
	default:
		return false;
	}

	uint32	rflags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		rflags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		rflags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		rflags |= NCIF_ALIASING;

	uint32	wflags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		wflags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		wflags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		wflags |= NCIF_ALIASING;



	for (int i = 0; i < size; i++)
	{
		if (ram == ASMIM_INDIRECT_Y)
			CheckFrameIndex(rins, rareg, rindex, 1, BC_REG_ADDR);
		if (wam == ASMIM_INDIRECT_Y)
			CheckFrameIndex(wins, wareg, windex, 1, BC_REG_ACCU);


		mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMMEDIATE, imm));

		if (ram == ASMIM_INDIRECT_Y)
		{
			mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex));
			mIns.Push(NativeCodeInstruction(oins, at, ram, rareg));
		}
		else
			mIns.Push(NativeCodeInstruction(oins, at, ram, rareg + i));

		if (!sfinal)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));

		if (wam == ASMIM_INDIRECT_Y)
		{
			if (ram != ASMIM_INDIRECT_Y || rindex != windex)
				mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex));
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg));
		}
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg + i));

		rindex += rstride;
		windex += wstride;
	}

	return true;

}

bool NativeCodeBasicBlock::LoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, int oindex, const InterInstruction* wins)
{
	int size = InterTypeSize[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 = int(rins->mSrc[0].mIntConst);
	int rareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
	int rstride = rins->mSrc[0].mStride;

	switch (rins->mSrc[0].mMemory)
	{
	case IM_INDIRECT:
		rareg = BC_REG_TMP + proc->mTempOffset[rins->mSrc[0].mTemp];
		break;
	case IM_LOCAL:
		rindex += proc->mLocalVars[rins->mSrc[0].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PARAM:
		rindex += rins->mSrc[0].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		ram = ASMIM_ZERO_PAGE;
		rareg = BC_REG_FPARAMS + rins->mSrc[0].mVarIndex + int(rins->mSrc[0].mIntConst);
		break;
	default:
		return false;
	}

	int	windex = int(wins->mSrc[1].mIntConst);
	int wareg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
	int wstride = wins->mSrc[1].mStride;

	switch (wins->mSrc[1].mMemory)
	{
	case IM_INDIRECT:
		wareg = BC_REG_TMP + proc->mTempOffset[wins->mSrc[1].mTemp];
		break;
	case IM_LOCAL:
		windex += proc->mLocalVars[wins->mSrc[1].mVarIndex]->mOffset + mFrameOffset;
		break;
	case IM_PARAM:
		windex += wins->mSrc[1].mVarIndex + proc->mLocalSize + 2 + mFrameOffset;
		break;
	case IM_FPARAM:
	case IM_FFRAME:
		wam = ASMIM_ZERO_PAGE;
		wareg = BC_REG_FPARAMS + +wins->mSrc[1].mVarIndex + int(wins->mSrc[1].mIntConst);
		break;
	default:
		return false;
	}

	if (rstride * (size - 1) >= 256 || wstride * (size - 1) >= 256)
		return false;

	uint32	rflags = NCIF_LOWER | NCIF_UPPER;
	if (rins->mVolatile)
		rflags |= NCIF_VOLATILE;
	if (rins->mMemmap)
		rflags |= NCIF_MEMMAP;
	if (rins->mAliasing)
		rflags |= NCIF_ALIASING;

	uint32	wflags = NCIF_LOWER | NCIF_UPPER;
	if (wins->mVolatile)
		wflags |= NCIF_VOLATILE;
	if (wins->mMemmap)
		wflags |= NCIF_MEMMAP;
	if (wins->mAliasing)
		wflags |= NCIF_ALIASING;

	if (ram == ASMIM_INDIRECT_Y && wam == ASMIM_INDIRECT_Y && rareg == wareg && rindex == windex)
	{
		CheckFrameIndex(rins, rareg, rindex, (size - 1) * rstride + 1, BC_REG_ADDR);
		windex = rindex;
		wareg = rareg;
	}
	else
	{
		if (ram == ASMIM_INDIRECT_Y)
			CheckFrameIndex(rins, rareg, rindex, (size - 1) * rstride + 1, BC_REG_ADDR);
		if (wam == ASMIM_INDIRECT_Y)
			CheckFrameIndex(wins, wareg, windex, (size - 1) * wstride + 1, BC_REG_ACCU);
	}

	switch (oins->mOperator)
	{
	case IA_ADD:
		mIns.Push(NativeCodeInstruction(oins, ASMIT_CLC));
		break;
	case IA_SUB:
		mIns.Push(NativeCodeInstruction(oins, ASMIT_SEC));
		break;
	}

	for (int i = 0; i < size; i++)
	{
		if (reverse)
		{
			if (am == ASMIM_IMPLIED)
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMPLIED));
			else if (am == ASMIM_IMMEDIATE)
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff));
			else
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i));

			if (ram == ASMIM_INDIRECT_Y)
			{
				mIns.Push(NativeCodeInstruction(oins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride));
				mIns.Push(NativeCodeInstruction(oins, at, ram, rareg));
			}
			else
				mIns.Push(NativeCodeInstruction(oins, at, ram, rareg + i));
		}
		else
		{
			if (ram == ASMIM_INDIRECT_Y)
			{
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDY, ASMIM_IMMEDIATE, rindex + i * rstride));
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ram, rareg));
			}
			else
				mIns.Push(NativeCodeInstruction(rins, ASMIT_LDA, ram, rareg + i));

			if (am == ASMIM_IMPLIED)
				mIns.Push(NativeCodeInstruction(oins, at, ASMIM_IMPLIED));
			else if (am == ASMIM_IMMEDIATE)
				mIns.Push(NativeCodeInstruction(oins, at, ASMIM_IMMEDIATE, (oins->mSrc[oindex].mIntConst >> (8 * i)) & 0xff));
			else
				mIns.Push(NativeCodeInstruction(oins, at, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[oins->mSrc[oindex].mTemp] + i));
		}

		if (!sfinal)
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i));

		at = an;
		if (wam == ASMIM_INDIRECT_Y)
		{
			if (ram != ASMIM_INDIRECT_Y || rindex != windex)
				mIns.Push(NativeCodeInstruction(wins, ASMIT_LDY, ASMIM_IMMEDIATE, windex + i * wstride));
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg));
		}
		else
			mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, wam, wareg + i));
	}

	return true;
}

void NativeCodeBasicBlock::LoadValueToReg(InterCodeProcedure* proc, const InterInstruction * ins, int reg, const NativeCodeInstruction* ainsl, const NativeCodeInstruction* ainsh)
{
	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (ins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (ins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (ins->mAliasing)
		flags |= NCIF_ALIASING;

	if (ins->mDst.mType == IT_FLOAT)
	{
		int stride = ins->mSrc[0].mStride;

		if (ins->mSrc[0].mTemp < 0)
		{
			if (ins->mSrc[0].mMemory == IM_GLOBAL)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
			}
			else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
			}
			else if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_FFRAME)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3, nullptr, flags));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
			}
			else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
			{
				int	index = int(ins->mSrc[0].mIntConst);
				int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
				if (ins->mSrc[0].mMemory == IM_LOCAL)
					index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
				else
					index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
				index += mFrameOffset;
				CheckFrameIndex(ins, areg, index, 4);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
			}
		}
		else
		{
			if (ins->mSrc[0].mMemory == IM_INDIRECT)
			{
				int		areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
				int		index = int(ins->mSrc[0].mIntConst);
				int		stride = ins->mSrc[0].mStride;
				bool	accu = reg == areg;

				if (stride * 4 <= 256)
				{
					CheckFrameIndex(ins, areg, index, stride * 4);

					for (int i = 0; i < 4; i++)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
						if (accu)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
					}
				}
				else
				{
					for (int i = 0; i < 4; i++)
					{
						CheckFrameIndex(ins, areg, index, 1);

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
						if (accu)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));

						index += stride;
					}
				}

				if (accu)
				{
					for (int i = 0; i < 4; i++)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
					}
				}
			}
		}
	}
	else if (ins->mDst.mType == IT_POINTER)
	{
		int stride = ins->mSrc[0].mStride;

		if (ins->mSrc[0].mTemp < 0)
		{
			if (ins->mSrc[0].mMemory == IM_GLOBAL)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, ins->mSrc[0].mLinkerObject, flags));
				if (ainsh) mIns.Push(*ainsh);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
			}
			else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + stride, nullptr, flags));
				if (ainsh) mIns.Push(*ainsh);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
			}
			else if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_FFRAME)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags));
				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + stride, nullptr, flags));
				if (ainsh) mIns.Push(*ainsh);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
			}
			else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
			{
				int	index = int(ins->mSrc[0].mIntConst);
				int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
				if (ins->mSrc[0].mMemory == IM_LOCAL)
					index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
				else
					index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
				index += mFrameOffset;
				CheckFrameIndex(ins, areg, index, 2);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				if (ainsh) mIns.Push(*ainsh);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
			}
		}
		else
		{
			if (ins->mSrc[0].mMemory == IM_INDIRECT)
			{
				int	areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
				int index = int(ins->mSrc[0].mIntConst);

				CheckFrameIndex(ins, areg, index, 2);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				if (reg == areg)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + stride));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				if (ainsh) mIns.Push(*ainsh);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				if (reg == areg)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
				}
			}
		}
	}
	else
	{
		if (ins->mSrc[0].mTemp < 0)
		{
			if (InterTypeSize[ins->mDst.mType] == 1)
			{
				if (ins->mSrc[0].mMemory == IM_GLOBAL)
				{
					if (ins->mDst.IsUByte())
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags, 0, uint8(ins->mDst.mRange.mMinValue), uint8(ins->mDst.mRange.mMaxValue)));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
				}
				else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
				}
				else if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_FFRAME)
				{
					if (ins->mDst.IsUByte())
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags, 0, uint8(ins->mDst.mRange.mMinValue), uint8(ins->mDst.mRange.mMaxValue)));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags));
				}
				else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[0].mIntConst);
					int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[0].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
					else
						index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, areg, index, 1);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
				}

				if (ainsl)
				{
					if (ainsl->mType == ASMIT_ADC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					else if (ainsl->mType == ASMIT_SBC)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(*ainsl);
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));

				if (InterTypeSize[ins->mDst.mType] > 1)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					if (ainsh) mIns.Push(*ainsh);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				}
			}
			else if (InterTypeSize[ins->mDst.mType] == 2)
			{
				int stride = ins->mSrc[0].mStride;

				if (ins->mSrc[0].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
					if (ainsl)
					{
						if (ainsl->mType == ASMIT_ADC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						else if (ainsl->mType == ASMIT_SBC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(*ainsl);
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
					if (ainsh) mIns.Push(*ainsh);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				}
				else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
					if (ainsl)
					{
						if (ainsl->mType == ASMIT_ADC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						else if (ainsl->mType == ASMIT_SBC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(*ainsl);
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
					if (ainsh) mIns.Push(*ainsh);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				}
				else if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags));
					if (ainsl)
					{
						if (ainsl->mType == ASMIT_ADC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						else if (ainsl->mType == ASMIT_SBC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(*ainsl);
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
					if (ainsh) mIns.Push(*ainsh);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				}
				else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[0].mIntConst);
					int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[0].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
					else
						index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, areg, index, 2);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					if (ainsl)
					{
						if (ainsl->mType == ASMIT_ADC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						else if (ainsl->mType == ASMIT_SBC)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(*ainsl);
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					if (ainsh) mIns.Push(*ainsh);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
				}
			}
			else if (InterTypeSize[ins->mDst.mType] == 4)
			{
				int stride = ins->mSrc[0].mStride;

				if (ins->mSrc[0].mMemory == IM_GLOBAL)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
				}
				else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
				}
				else if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_FFRAME)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 1 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 2 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + 3 * stride, nullptr, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
				}
				else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
				{
					int	index = int(ins->mSrc[0].mIntConst);
					int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
					if (ins->mSrc[0].mMemory == IM_LOCAL)
						index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
					else
						index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
					index += mFrameOffset;
					CheckFrameIndex(ins, areg, index, 4);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 1 * stride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 2 * stride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + 3 * stride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 3));
				}
			}
		}
		else
		{
			if (ins->mSrc[0].mMemory == IM_INDIRECT)
			{
				int		areg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
				int		index = int(ins->mSrc[0].mIntConst);
				int		stride = ins->mSrc[0].mStride;
				int		size = InterTypeSize[ins->mDst.mType];
				bool	accu = false;

				if (size * stride <= 256)
				{
					CheckFrameIndex(ins, areg, index, size * stride);

					accu = reg == areg;

					for (int i = 0; i < size; i++)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * stride));
						if (ins->mDst.IsUByte())
						{
							if (i == 0)
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags, 0, int(ins->mDst.mRange.mMinValue), int(ins->mDst.mRange.mMaxValue)));
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						}
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags));

						if (i == 0)
						{
							if (ainsl)
							{
								if (ainsl->mType == ASMIT_ADC)
									mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
								else if (ainsl->mType == ASMIT_SBC)
									mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
								mIns.Push(*ainsl);
							}
						}
						else if (ainsh)
							mIns.Push(*ainsh);

						if (accu)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
					}
				}
				else
				{
					assert(ainsl == nullptr && ainsh == nullptr);

					for (int i = 0; i < size; i++)
					{
						CheckFrameIndex(ins, areg, index, 1);
						if (reg == areg)
							accu = true;

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
						if (ins->mDst.IsUByte())
						{
							if (i == 0)
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags, 0, int(ins->mDst.mRange.mMinValue), int(ins->mDst.mRange.mMaxValue)));
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						}
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, areg, nullptr, flags));

						if (accu)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));

						index += stride;
					}
				}

				if (accu)
				{
					for (int i = 0; i < size; i++)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + i));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + i));
					}
				}
			}
		}
	}
}

void NativeCodeBasicBlock::LoadValue(InterCodeProcedure* proc, const InterInstruction * ins)
{
	LoadValueToReg(proc, ins, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], nullptr, nullptr);
}

NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc)
{
	int	size = ins->mConst.mOperandSize;
	int	msize = 4, dstride = ins->mSrc[1].mStride, sstride = ins->mSrc[0].mStride;

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (ins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (ins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (ins->mAliasing)
		flags |= NCIF_ALIASING;

	if (sstride > 1 || dstride > 1)
		msize = 32;
	else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
		msize = 8;
	else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
		msize = 2;
#if 1
	if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp < 0)
	{
		if (ins->mSrc[0].mMemory == IM_GLOBAL && (ins->mSrc[1].mMemory == IM_FRAME || ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM) && size < 256 && dstride == 1 && sstride == 1)
		{
			int areg = BC_REG_STACK;

			int	index = int(ins->mSrc[1].mIntConst);
			if (ins->mSrc[1].mMemory == IM_FRAME)
				index += ins->mSrc[1].mVarIndex + 2;
			else
			{
				if (!mNoFrame)
					areg = BC_REG_LOCALS;

				if (ins->mSrc[1].mMemory == IM_LOCAL)
					index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
				else
					index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
				index += mFrameOffset;
			}
			CheckFrameIndex(ins, areg, index, size, BC_REG_ADDR);

			if (size <= msize)
			{
				for (int i = 0; i < size; i++)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
				}

				return this;
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
				this->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - index, ins->mSrc[0].mLinkerObject, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CPY, ASMIM_IMMEDIATE, (index + size) & 255));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				return eblock;
			}
		}
		else if ((ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) && (ins->mSrc[1].mMemory == IM_GLOBAL || ins->mSrc[1].mMemory == IM_ABSOLUTE))
		{	
			NativeCodeBasicBlock* block = this;

			int	offset = 0;
			if (size >= 256)
			{
				block = nproc->AllocateBlock();

				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();

				
				if (size > 256)
				{
					if (size < 512 && !(size & 1))
					{
						int	step = size >> 1;

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
						lblock->Close(ins, lblock, block, ASMIT_BNE);

						return block;
					}
					else if (size < 1024 && !(size & 3))
					{
						int	step = size >> 2;

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + step - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 2 * step - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 2 * step - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + 3 * step - 1, ins->mSrc[0].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 3 * step - 1, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
						lblock->Close(ins, lblock, block, ASMIT_BNE);

						return block;
					}
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
				this->Close(ins, lblock, nullptr, ASMIT_JMP);
				while (offset + 255 < size)
				{
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset, ins->mSrc[0].mLinkerObject, flags));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
					offset += 256;
				}
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, block, ASMIT_BNE);

				size &= 255;
			}

			if (size <= msize)
			{
				LinkerObject* slo = ins->mSrc[0].mLinkerObject;
				if (slo && (slo->mFlags & LOBJF_CONST))
				{
				
					for (int i = 0; i < size; i++)
					{
						int64 si = ins->mSrc[0].mIntConst + offset + i * sstride;

						LinkerReference* lr = slo->FindReference(si);
						if (lr)
						{
							if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si)
								block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER));
							else
								block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER));
						}
						else
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si]));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
					}
				}
				else
				{
					for (int i = 0; i < size; i++)
					{
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
					}
				}
			}
			else if (size <= 128)
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
				block->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset, ins->mSrc[0].mLinkerObject, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BPL);

				block = eblock;
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
				block->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, ins->mSrc[0].mIntConst + offset - 1, ins->mSrc[0].mLinkerObject, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset - 1, ins->mSrc[1].mLinkerObject, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				block = eblock;
			}

			return block;
		}
		else if ((ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) && (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME))
		{
			LinkerObject* slo = ins->mSrc[0].mLinkerObject;
			if (slo && (slo->mFlags & LOBJF_CONST))
			{

				for (int i = 0; i < size; i++)
				{
					int64 si = ins->mSrc[0].mIntConst + i * sstride;

					LinkerReference* lr = slo->FindReference(si);
					if (lr)
					{
						if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER));
						else
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER));
					}
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));
				}
			}
			else
			{
				for (int i = 0; i < size; i++)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));
				}
			}

			return this;
		}
	}
#endif

	int	sreg, dreg;
	int si = 0, di = 0;

	if (ins->mSrc[0].mTemp < 0)
	{
		if (ins->mSrc[0].mMemory == IM_GLOBAL)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			sreg = BC_REG_ACCU;
		}
		else if (ins->mSrc[0].mMemory == IM_ABSOLUTE)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			sreg = BC_REG_ACCU;
		}
		else if (ins->mSrc[0].mMemory == IM_FPARAM)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			sreg = BC_REG_ACCU;
		}
		else if (ins->mSrc[0].mMemory == IM_LOCAL || ins->mSrc[0].mMemory == IM_PARAM)
		{
			int	index = int(ins->mSrc[0].mIntConst);
			sreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
			if (ins->mSrc[0].mMemory == IM_LOCAL)
				index += proc->mLocalVars[ins->mSrc[0].mVarIndex]->mOffset;
			else
				index += ins->mSrc[0].mVarIndex + proc->mLocalSize + 2;
			index += mFrameOffset;
			CheckFrameIndex(ins, sreg, index, 256, BC_REG_ACCU);
		}
	}
	else if (ins->mSrc[0].mIntConst != 0)
	{
		int	index = int(ins->mSrc[0].mIntConst);
		if (size <= msize && (size - 1) * sstride + 1 + index <= 256)
		{
			si = index;
			sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			sreg = BC_REG_ACCU;
		}
	}
	else if (size * sstride > 256 && !ins->mSrc[0].mFinal)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		sreg = BC_REG_ACCU;
	}
	else
	{
		sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
	}
	
	if (ins->mSrc[1].mTemp < 0)
	{
		if (ins->mSrc[1].mMemory == IM_GLOBAL)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
		{
			int	index = int(ins->mSrc[1].mIntConst);
			dreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
			if (ins->mSrc[1].mMemory == IM_LOCAL)
				index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
			else
				index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
			index += mFrameOffset;
			CheckFrameIndex(ins, dreg, index, 256, BC_REG_ADDR);
		}
		else if (ins->mSrc[1].mMemory == IM_FRAME)
		{
			int	index = ins->mSrc[1].mVarIndex + int(ins->mSrc[1].mIntConst) + 2;

			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
	}
	else if (ins->mSrc[1].mIntConst != 0)
	{
		int	index = int(ins->mSrc[1].mIntConst);
		if (size <= msize && (size - 1) * dstride + 1 + index <= 256)
		{
			di = index;
			dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
	}
	else if (size * dstride > 256 && !ins->mSrc[1].mFinal)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
		dreg = BC_REG_ADDR;
	}
	else
	{
		dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
	}

	if (size <= msize)
	{
		for (int i = 0; i < size; i++)
		{
			if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_FPARAM)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[0].mVarIndex + ins->mSrc[0].mIntConst + i));
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, si));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
			}
			if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_FFRAME)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i));
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, di));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
			}

			si += sstride;
			di += dstride;
			if (si >= 256)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, sreg + 1));
				si &= 0xff;
			}
			if (di >= 256)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
				di &= 0xff;
			}
		}

		return this;
	}
	else
	{
		NativeCodeBasicBlock* block = this;

		if (size >= 256)
		{
			block = nproc->AllocateBlock();

			if (sreg != BC_REG_ACCU && !ins->mSrc[0].mFinal)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				sreg = BC_REG_ACCU;
			}
			if (dreg != BC_REG_ADDR && !ins->mSrc[1].mFinal)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
				dreg = BC_REG_ADDR;
			}

			NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* lblock2 = nproc->AllocateBlock();

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
			if (size >= 512)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, size >> 8));
			this->Close(ins, lblock, nullptr, ASMIT_JMP);
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
			lblock->Close(ins, lblock, lblock2, ASMIT_BNE);
			lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, sreg + 1));
			lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
			if (size >= 512)
			{
				lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock2->Close(ins, lblock, block, ASMIT_BNE);
			}
			else
				lblock2->Close(ins, block, nullptr, ASMIT_JMP);

			size &= 0xff;
		}

		if (size > 0)
		{
			NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

			if (size < 128)
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
				block->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BPL);
			}
			else if (size <= 256)
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size - 1));
				block->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg, nullptr, flags));
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
			}

			block = eblock;
		}

		return block;
	}
}

NativeCodeBasicBlock* NativeCodeBasicBlock::FillValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
	int	size = ins->mConst.mOperandSize;
	int	msize = 4, dstride = ins->mSrc[1].mStride;

	uint32	flags = NCIF_LOWER | NCIF_UPPER;
	if (ins->mVolatile)
		flags |= NCIF_VOLATILE;
	if (ins->mMemmap)
		flags |= NCIF_MEMMAP;
	if (ins->mAliasing)
		flags |= NCIF_ALIASING;

	if (dstride > 1)
		msize = 32;
	else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
		msize = 8;
	else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
		msize = 2;
#if 1
	if (ins->mSrc[1].mTemp < 0)
	{
		if ((ins->mSrc[1].mMemory == IM_FRAME || ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM) && size < 256 && dstride == 1)
		{
			int areg = BC_REG_STACK;

			int	index = int(ins->mSrc[1].mIntConst);
			if (ins->mSrc[1].mMemory == IM_FRAME)
				index += ins->mSrc[1].mVarIndex + 2;
			else
			{
				if (!mNoFrame)
					areg = BC_REG_LOCALS;

				if (ins->mSrc[1].mMemory == IM_LOCAL)
					index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
				else
					index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
				index += mFrameOffset;
			}
			CheckFrameIndex(ins, areg, index, size, BC_REG_ADDR);

			if (ins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

			if (size <= msize)
			{
				for (int i = 0; i < size; i++)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
				}

				return this;
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, index));
				this->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CPY, ASMIM_IMMEDIATE, (index + size) & 255));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				return eblock;
			}
		}
		else if ((ins->mSrc[1].mMemory == IM_GLOBAL || ins->mSrc[1].mMemory == IM_ABSOLUTE) && size <= 256 * msize)
		{
			NativeCodeBasicBlock* block = this;

			if (ins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

			int	offset = 0;
			if (size >= 256)
			{
				block = nproc->AllocateBlock();

				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();

				if (size > 256)
				{
					if (size < 512 && !(size & 1))
					{
						int	step = size >> 1;

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step, ins->mSrc[1].mLinkerObject, flags));
						lblock->Close(ins, lblock, block, ASMIT_BNE);

						return block;
					}
					else if (size < 1024 && !(size & 3))
					{
						int	step = size >> 2;

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, step));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + step, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 2 * step, ins->mSrc[1].mLinkerObject, flags));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + 3 * step, ins->mSrc[1].mLinkerObject, flags));
						lblock->Close(ins, lblock, block, ASMIT_BNE);

						return block;
					}
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
				this->Close(ins, lblock, nullptr, ASMIT_JMP);
				while (offset + 255 < size)
				{
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
					offset += 256;
				}
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, block, ASMIT_BNE);

				size &= 255;
			}

			if (size <= msize)
			{
				for (int i = 0; i < size; i++)
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
				block->Close(ins, lblock, nullptr, ASMIT_JMP);
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE_Y, ins->mSrc[1].mIntConst + offset, ins->mSrc[1].mLinkerObject, flags));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				block = eblock;
			}

			return block;
		}
		else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
		{
			if (ins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

			for (int i = 0; i < size; i++)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride));

			return this;
		}
	}
#endif

	int	dreg;
	int di = 0, ioffset = 0;

	if (ins->mSrc[1].mTemp < 0)
	{
		if (ins->mSrc[1].mMemory == IM_GLOBAL)
		{
			if ((size > 256) && (size & 255) != 0)
				ioffset = 256 - (size & 255);

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst - ioffset, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst - ioffset, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
		{
			if ((size > 256) && (size & 255) != 0)
				ioffset = 256 - (size & 255);

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst - ioffset) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[1].mIntConst - ioffset) >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
		else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
		{
			int	index = int(ins->mSrc[1].mIntConst);
			dreg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
			if (ins->mSrc[1].mMemory == IM_LOCAL)
				index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
			else
				index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
			index += mFrameOffset;
			CheckFrameIndex(ins, dreg, index, 256, BC_REG_ADDR);
		}
		else if (ins->mSrc[1].mMemory == IM_FRAME)
		{
			int	index = ins->mSrc[1].mVarIndex + int(ins->mSrc[1].mIntConst) + 2;

			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
	}
	else if (ins->mSrc[1].mIntConst != 0)
	{
		int	index = int(ins->mSrc[1].mIntConst);
		if (size <= msize && (size - 1) * dstride + 1 + index <= 256)
		{
			di = index;
			dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
			dreg = BC_REG_ADDR;
		}
	}
	else if (size * dstride > 256 && !ins->mSrc[1].mFinal)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
		dreg = BC_REG_ADDR;
	}
	else
	{
		dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
	}

	size += ioffset;

	if (size <= msize)
	{
		if (ins->mSrc[0].mTemp < 0)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

		for (int i = 0; i < size; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, di));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));

			di += dstride;
			if (di >= 256)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
				di &= 0xff;
			}
		}

		return this;
	}
	else
	{
		NativeCodeBasicBlock* block = this;

		if (size >= 256)
		{
			block = nproc->AllocateBlock();

			if (dreg != BC_REG_ADDR && !ins->mSrc[1].mFinal)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
				dreg = BC_REG_ADDR;
			}

			if (ins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

			NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* lblock2 = nproc->AllocateBlock();

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, ioffset));
			if (size >= 512)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, size >> 8));
			this->Close(ins, lblock, nullptr, ASMIT_JMP);
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
			lblock->Close(ins, lblock, lblock2, ASMIT_BNE);
			lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, dreg + 1));
			if (size >= 512)
			{
				lblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock2->Close(ins, lblock, block, ASMIT_BNE);
			}
			else
				lblock2->Close(ins, block, nullptr, ASMIT_JMP);

			size &= 0xff;
		}
		else
		{
			if (ins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
		}

		if (size > 0)
		{
			NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, size));
			block->Close(ins, lblock, nullptr, ASMIT_JMP);
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEY, ASMIM_IMPLIED));
			lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg, nullptr, flags));
			lblock->Close(ins, lblock, eblock, ASMIT_BNE);

			block = eblock;
		}

		return block;
	}
}

void NativeCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
	if (ins->mSrc[0].mTemp < 0)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	}

	NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("malloc")));
	mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

	if (ins->mDst.mTemp >= 0)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
	}
}

void NativeCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
	if (ins->mSrc[0].mTemp < 0)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	}

	NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("free")));
	mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
}


NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc)
{
	int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

	NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
	NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

	mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0xff));
	this->Close(ins, lblock, nullptr, ASMIT_JMP);
	lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY, ASMIM_IMPLIED));
	lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
	lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
	lblock->Close(ins, lblock, eblock, ASMIT_BNE);

	return eblock;
}

bool NativeCodeBasicBlock::CheckPredAccuStore(int reg)
{
	if (mIns.Size() < 8)
		return false;

	int	p = mIns.Size() - 8;

	for (int i = 0; i < 4; i++)
	{
		if (mIns[p + 0].mType != ASMIT_LDA || mIns[p + 0].mMode != ASMIM_ZERO_PAGE || mIns[p + 0].mAddress != BC_REG_ACCU + i)
			return false;
		if (mIns[p + 1].mType != ASMIT_STA || mIns[p + 1].mMode != ASMIM_ZERO_PAGE || mIns[p + 1].mAddress != reg + i)
			return false;

		p += 2;
	}

	return true;
}

bool NativeCodeBasicBlock::CheckIsInAccu(int reg)
{
	int i = mIns.Size() - 1;
	while (i > 0)
	{
		if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == reg &&
			mIns[i - 1].mType == ASMIT_LDA && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == BC_REG_ACCU)
			return true;
		if (mIns[i].ReferencesZeroPage(reg) || mIns[i].ReferencesZeroPage(BC_REG_ACCU))
			return false;

		i--;
	}
	return false;
}

void NativeCodeBasicBlock::ShiftRegisterRight(const InterInstruction* ins, int reg, int shift)
{
	if (shift == 0)
	{
	}
	else if (shift == 1)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, reg));
	}
	else if (shift == 15)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0));
	}
	else if (shift == 14)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift >= 8)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		for (int i = 8; i < shift; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift >= 5)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, reg));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		for (int i = shift; i < 8; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		for (int i = 1; i < shift; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
}

void NativeCodeBasicBlock::ShiftRegisterLeft(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift)
{
	if (shift == 0)
	{

	}
	else if (shift == 1)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift >= 13)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		for (int i = shift; i < 16; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << (shift - 8)) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else if (shift >= 8)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		for (int i = 8; i < shift; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else if (shift >= 5)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		for (int i = shift; i < 8; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, reg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
		for (int i = 0; i < shift; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
}

void NativeCodeBasicBlock::ShiftRegisterLeftFromByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift, int max)
{
	if (shift == 0)
	{

	}
	else if (shift >= 8)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		for (int i = 8; i < shift; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else if (shift == 1)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		if (max >= 128)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift >= 5 && (max << shift) >= 512)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		for (int i = shift; i < 7; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff >> (8 - shift)) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift >= 5 && (max << shift) < 256)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		for (int i = shift; i < 8; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
	else if (shift == 4 && max >= 128)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xf0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		while (shift > 0 && max < 256)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			shift--;
			max *= 2;
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		if (max > 255)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		while (shift > 0)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			shift--;
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1));
	}
}

void NativeCodeBasicBlock::ShiftRegisterLeftByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift)
{
	if (shift == 0)
	{

	}
	else if (shift == 1)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, reg));
	}
	else if (shift >= 6)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
		for (int i = shift; i < 8; i++)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
		for (int i = 0; i < shift; i++)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
	}
}

int NativeCodeBasicBlock::ShortSignedDivide(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction* ins, const InterInstruction* sins, int mul)
{
	int	dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
	int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

	if (sins)
	{
		LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
		sreg = dreg;
	}

	if (mul == 2)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
	}
	else if (mul == 4)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x03));


		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, sreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));

		// Two signed shifts
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
	}
	else if (mul == 8)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x07));


		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, sreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));

		// Three signed shifts
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, dreg + 0));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x10));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x10));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
	}

	return dreg;
}

int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins, const InterInstruction* sins, int index, int mul)
{
	mul &= 0xffff;

	if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue == 1 && mul > 4 && mul < 256)
	{	
		int	dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
		int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];

		if (sins)
		{
			LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
			sreg = dreg;
		}

		if (mul == 128)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, mul));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
		}
	
		return dreg;
	}

#if 1
	if (mul >= 0xfffc)
	{
		int	dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
		int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];

		if (sins)
		{
			LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
			sreg = dreg;
		}

		int	wreg = BC_REG_ACCU;
		if (sreg != dreg)
			wreg = dreg;

		switch (mul)
		{
		case 0xffff: // -1
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			break;
		case 0xfffe: // -2
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			break;
		case 0xfffd: // -3
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));

			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, wreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			break;
		case 0xfffc: // -4
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, sreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			break;
		}

		return dreg;
	}
#endif

	int	lshift = 0, lmul = mul;
	while (!(lmul & 1))
	{
		lmul >>= 1;
		lshift++;
	}

	if (mul > 1 && ((lshift & 7) > 3 || lmul != 1) && ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 16)
	{
		int	dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];

		if (sins)
		{
			LoadValueToReg(proc, sins, dreg, nullptr, nullptr);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, dreg));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp]));
		}

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, int(ins->mSrc[index].mRange.mMaxValue) + 1, false)));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
		if (ins->mDst.IsUByte())
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_MUL, mul, int(ins->mSrc[index].mRange.mMaxValue) + 1, true)));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}

		return dreg;
	}
	
	if (lmul == 1 && !sins && ins->mSrc[index].mTemp == ins->mDst.mTemp)
	{
		// shift in place

		int	dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];

		if (ins->mDst.IsUByte())
		{
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else if (ins->mDst.IsSByte())
		{
			// Upper byte will retain sign
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
		}
		else if (ins->mSrc[index].IsUByte())
			ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue));
		else
			ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
	}

	int	dreg = BC_REG_ACCU;

	if (sins)
		LoadValueToReg(proc, sins, BC_REG_ACCU, nullptr, nullptr);
	else if (ins->mSrc[index].mTemp == ins->mDst.mTemp)
		dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
	else
	{
		int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[index].mTemp];
		dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
	}

	int	wreg = BC_REG_ACCU;
	if (dreg == BC_REG_ACCU)
		wreg = BC_REG_WORK + 4;

	switch (lmul)
	{
#if 1
	case 1:
		if (ins->mDst.IsUByte())
		{
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else if (ins->mDst.IsSByte())
		{
			// Upper byte will retain sign
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
		}
		else if (ins->mSrc[index].IsUByte())
			ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue));
		else
			ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
	case 3:
		if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 85)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		}
		else if (ins->mSrc[index].IsSByte() && ins->mSrc[index].mRange.mMinValue >= -42 && ins->mSrc[index].mRange.mMaxValue <= 42)
		{
			// Will retain sign
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		if (ins->mDst.IsUByte())
		{
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else if (ins->mDst.IsSByte())
		{
			// Upper byte will retain sign
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
		}
		else
			ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
	case 5:
		if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue <= 51)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));

			if (ins->mDst.IsUByte())
			{
				ShiftRegisterLeftByte(proc, ins, dreg, lshift);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			}
			else
				ShiftRegisterLeftFromByte(proc, ins, dreg, lshift, int(ins->mSrc[index].mRange.mMaxValue) * 5);
		}
		else if (ins->mSrc[index].IsSByte() && ins->mSrc[index].mRange.mMinValue >= -25 && ins->mSrc[index].mRange.mMaxValue <= 25)
		{
			// Will retain sign
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));

			if (ins->mDst.IsSByte())
			{
				// Upper byte will retain sign
				ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			}
			else
				ShiftRegisterLeft(proc, ins, dreg, lshift);
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));

			if (ins->mDst.IsUByte())
			{
				ShiftRegisterLeftByte(proc, ins, dreg, lshift);
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			}
			else
				ShiftRegisterLeft(proc, ins, dreg, lshift);
		}
		return dreg;
	case 7:
		if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 64)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		}
		else if (ins->mSrc[index].IsUByte() && ins->mSrc[index].mRange.mMaxValue < 128)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		}

		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		if (ins->mDst.IsUByte())
		{
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else
			ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
	case 9:
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		if (ins->mDst.IsUByte())
		{
			ShiftRegisterLeftByte(proc, ins, dreg, lshift);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		}
		else
			ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
#if 1
	case 25:
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TAY, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TYA, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, wreg + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, dreg + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
		ShiftRegisterLeft(proc, ins, dreg, lshift);
		return dreg;
#endif
#endif
	default:
		if (mul & 0xff00)
		{
			if (ins->mSrc[index].IsUByte())
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, mul & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, mul >> 8));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

				NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));

				return BC_REG_ACCU;
			}
			else
			{
				if (dreg != BC_REG_ACCU)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul >> 8));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
		}
		else
		{
			if (dreg != BC_REG_ACCU)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			}

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, mul));
//			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));

			NativeCodeGenerator::Runtime& rt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, rt.mOffset, rt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));

			return BC_REG_ACCU;
		}

		return BC_REG_WORK + 2;
	}
}


void NativeCodeBasicBlock::AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins)
{
	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mSrc[1].mTemp]));

	for (int i = 0; i < sins->mSrc[0].mIntConst; i++)
	{
		mIns.Push(NativeCodeInstruction(sins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
		mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR));
	}
	mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, 0x00));
	mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mDst.mTemp]));

	mIns.Push(NativeCodeInstruction(sins, ASMIT_ASL, ASMIM_IMPLIED));
	mIns.Push(NativeCodeInstruction(sins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
	mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
	mIns.Push(NativeCodeInstruction(sins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
	mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mDst.mTemp] + 1));

}

void NativeCodeBasicBlock::BinaryShlAddConstPair(InterCodeProcedure* proc, const InterInstruction* sins, const InterInstruction* ains)
{
	int64	aconst = ains->mSrc[0].mIntConst;
	if (ains->mOperator == IA_SUB)
		aconst = -aconst;

	int di = BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp];
	int shift = sins->mSrc[0].mIntConst & 15;

	if (shift >= 8)
	{
		mIns.Push(NativeCodeInstruction(sins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mSrc[1].mTemp]));
		switch (shift)
		{
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
			for(int i=8; i<shift; i++)
				mIns.Push(NativeCodeInstruction(sins, ASMIT_ASL, ASMIM_IMPLIED));
			break;
		case 14:
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, 0x03));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			break;
		case 15:
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, 0x01));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			break;
		}
		mIns.Push(NativeCodeInstruction(sins, ASMIT_CLC, ASMIM_IMPLIED));
		mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, (aconst >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di + 1));
		mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_IMMEDIATE, aconst & 0xff));
		mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di));
	}
	else
	{
		char mask = (1 << shift) - 1;

		mIns.Push(NativeCodeInstruction(sins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[sins->mSrc[1].mTemp]));
		switch (shift)
		{
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
			mIns.Push(NativeCodeInstruction(sins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, (aconst >> shift) & 0xff));
			for(int i=0; i<shift; i++)
				mIns.Push(NativeCodeInstruction(sins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TAX, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, mask ^ 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ORA, ASMIM_IMMEDIATE, aconst & mask));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TXA, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, mask));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, (aconst >> (shift + 8) << shift) & 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di + 1));
			break;
		case 6:
			mIns.Push(NativeCodeInstruction(sins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TAX, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, 0x80));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, aconst & 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TXA, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_AND, ASMIM_IMMEDIATE, 0x3f));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, (aconst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di + 1));
			break;
		case 7:
			mIns.Push(NativeCodeInstruction(sins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TAX, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ROR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_CLC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, aconst & 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_TXA, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_ADC, ASMIM_IMMEDIATE, (aconst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(sins, ASMIT_STA, ASMIM_ZERO_PAGE, di + 1));
			break;
		}
	}
}

void NativeCodeBasicBlock::BinaryAddCarry(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* cins)
{
	if (cins->mSrc[0].mTemp == ains->mDst.mTemp)
		mIns.Push(NativeCodeInstruction(cins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mSrc[1].mTemp]));
	else if (cins->mSrc[0].mTemp >= 0)
		mIns.Push(NativeCodeInstruction(cins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mSrc[0].mTemp]));
	else
		mIns.Push(NativeCodeInstruction(cins, ASMIT_LDA, ASMIM_IMMEDIATE, cins->mSrc[0].mIntConst));
	mIns.Push(NativeCodeInstruction(cins, ASMIT_LSR));

	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mSrc[0].mTemp]));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mSrc[1].mTemp]));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mDst.mTemp]));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_ROL));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mDst.mTemp] + 1));
}

void NativeCodeBasicBlock::BinaryAndMulConst(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* mins)
{
	unsigned	mask = ains->mSrc[0].mIntConst & 0xff;
	unsigned	mul = unsigned(mins->mSrc[0].mIntConst);
	unsigned	vmax = unsigned(mins->mSrc[1].mRange.mMaxValue);
	unsigned	shift = 0;

	int			src = BC_REG_TMP + proc->mTempOffset[ains->mSrc[1].mTemp];
	int			dst = BC_REG_TMP + proc->mTempOffset[mins->mDst.mTemp];
	int			tmp = BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp];

	while (!(mul & 1))
	{
		shift++;
		mul >>= 1;
	}

	switch (mul)
	{
	case 1:
		mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, src));
		mIns.Push(NativeCodeInstruction(ains, ASMIT_AND, ASMIM_IMMEDIATE, mask));
		mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
		ShiftRegisterLeftFromByte(proc, mins, dst, shift, vmax);
		return;
	case 3:
		if ((mask & 1) == 0)
		{
			mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, src));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_AND, ASMIM_IMMEDIATE, mask));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			if (vmax <= 170)
				ShiftRegisterLeftFromByte(proc, mins, dst, shift + 1, vmax + (vmax >> 1));
			else
			{
				mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(mins, ASMIT_ROL, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst + 1));
				ShiftRegisterLeft(proc, mins, dst, shift + 1);
			}
			return;
		}
		break;
	case 5:
		if ((mask & 3) == 0)
		{
			mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, src));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_AND, ASMIM_IMMEDIATE, mask));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			if (vmax <= 204)
				ShiftRegisterLeftFromByte(proc, mins, dst, shift + 2, vmax + (vmax >> 2));
			else
			{
				mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(mins, ASMIT_ROL, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst + 1));
				ShiftRegisterLeft(proc, mins, dst, shift + 2);
			}
			return;
		}
		break;
	case 7:
		if ((mask & 7) == 0 && vmax <= 144)
		{
			mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, src));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_AND, ASMIM_IMMEDIATE, mask));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LSR, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_ZERO_PAGE, dst));
			mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst));
			ShiftRegisterLeftFromByte(proc, mins, dst, shift + 2, vmax + (vmax >> 1) + (vmax >> 2));
			return;
		}
		break;
	}

	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, src));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_AND, ASMIM_IMMEDIATE, mask));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, tmp));
	mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, tmp + 1));

	int reg = ShortMultiply(proc, mProc, mins, nullptr, 1, int(mins->mSrc[0].mIntConst));

	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst + 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, dst + 1));
}

void NativeCodeBasicBlock::BinaryDivModPair(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction* ins1, const InterInstruction* ins2, bool sign)
{
	if (ins1->mSrc[1].mTemp < 0)
	{
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, ins1->mSrc[1].mIntConst & 0xff));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 8) & 0xff));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		if (ins1->mDst.mType == IT_INT32)
		{
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 16) & 0xff));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[1].mIntConst >> 24) & 0xff));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		}
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp]));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		if (ins1->mDst.mType == IT_INT32)
		{
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[1].mTemp] + 3));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		}
	}

	if (!sign && ins1->mSrc[0].IsUByte() && ins1->mDst.mType == IT_INT16)
	{
		if (ins1->mSrc[0].mTemp < 0)
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, ins1->mSrc[0].mIntConst & 0xff));
		else
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp]));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16by8")));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
	}
	else
	{
		if (ins1->mSrc[0].mTemp < 0)
		{
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, ins1->mSrc[0].mIntConst & 0xff));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
			if (ins1->mDst.mType == IT_INT32)
			{
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 16) & 0xff));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_IMMEDIATE, (ins1->mSrc[0].mIntConst >> 24) & 0xff));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
			}
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
			if (ins1->mDst.mType == IT_INT32)
			{
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mSrc[0].mTemp] + 3));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
			}
		}

		if (sign)
		{
			if (ins1->mDst.mType == IT_INT32)
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divmods32")));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
			else
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divmods16")));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
		}
		else
		{
			if (ins1->mDst.mType == IT_INT32)
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu32")));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
			else
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16")));
				mIns.Push(NativeCodeInstruction(ins1, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
		}
	}

	mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
	mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp]));
	mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 1));
	if (ins1->mDst.mType == IT_INT32)
	{
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins1, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins1->mDst.mTemp] + 3));
	}

	if (ins2->mDst.mType == IT_INT32)
	{
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 4));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp]));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 5));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 6));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 7));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 3));
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp]));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
		mIns.Push(NativeCodeInstruction(ins2, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins2->mDst.mTemp] + 1));
	}
}

NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins, const InterInstruction * sins1, const InterInstruction * sins0)
{
	int	treg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];

	if (ins->mDst.mType == IT_FLOAT)
	{
		int		sop0 = 0, sop1 = 1;
		bool	flipop = false;
		bool	changedSign = false;

		if (ins->mOperator == IA_ADD || ins->mOperator == IA_MUL || ins->mOperator == IA_SUB)
		{
			if (!sins0 && ins->mSrc[sop0].mTemp >= 0 && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop0].mTemp]))
			{
				flipop = true;
				sop0 = 1; sop1 = 0;
				const InterInstruction* sins = sins0; sins0 = sins1; sins1 = sins;
			}
			else if (!sins1 && !sins0 && ins->mSrc[sop0].mTemp < 0 && ins->mSrc[sop1].mTemp >= 0 && !CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]))
			{
				flipop = true;
				sop0 = 1; sop1 = 0;
				const InterInstruction* sins = sins0; sins0 = sins1; sins1 = sins;
			}			
			else if (!sins1 && !sins0 && ins->mSrc[sop1].mTemp >= 0 && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]) && ins->mSrc[sop1].mFinal)
			{
				// no flip in this case
			}
			else if (ins->mLockOrder)
			{
				printf("LockedOrder %d, %d\n", ins->mSrc[sop0].mTemp, ins->mSrc[sop1].mTemp);
				// maintain order due to loop
			}
			else if (!sins0 && !sins1 && ins->mSrc[sop0].mTemp >= 0 && ins->mSrc[sop1].mTemp >= 0 && ins->mDst.mTemp == ins->mSrc[sop0].mTemp)
			{
				flipop = true;
				sop0 = 1; sop1 = 0;
			}
		}

		int	sreg0 = ins->mSrc[sop0].mTemp < 0 ? -1 : BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop0].mTemp];

		if (ins->mSrc[sop1].mTemp >= 0 && ins->mSrc[sop0].mTemp >= 0 && sins1 && sins1 == sins0)
		{
			LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
			NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitx")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, BC_REG_ACCU));
		}
		else
		{
			if (ins->mSrc[sop1].mTemp < 0)
			{
				union { float f; unsigned int v; } cc;

				if (ins->mOperator == IA_SUB && flipop)
				{
					changedSign = true;
					cc.f = float(-ins->mSrc[sop1].mFloatConst);
				}
				else
					cc.f = float(ins->mSrc[sop1].mFloatConst);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
			}
			else if (sins1)
			{
				LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
			}
			else if (CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp]))
			{
				if (ins->mSrc[sop1].mFinal)
				{
					// cull previous store from accu to temp using direcrt forwarding
					mIns.SetSize(mIns.Size() - 8);
				}
				if (sreg0 == BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp])
					sreg0 = BC_REG_ACCU;
			}
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[sop1].mTemp] + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
			}

			if (ins->mSrc[sop0].mTemp < 0)
			{
				union { float f; unsigned int v; } cc;

				if (ins->mOperator == IA_SUB && !flipop)
				{
					changedSign = true;
					cc.f = float(-ins->mSrc[sop0].mFloatConst);
				}
				else
					cc.f = float(ins->mSrc[sop0].mFloatConst);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitt")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
			else if (sins0)
			{
				LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitt")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
			else
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplitx")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, sreg0));
			}
		}


		switch (ins->mOperator)
		{
		case IA_ADD:
		{
			NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("fadd")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
		}	break;
		case IA_SUB:
		{
			bool	add = false;
			if (changedSign)
				add = true;
			else if (flipop)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				add = true;
			}

			NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique(add ? "fadd" : "fsub")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
		}	break;
		case IA_MUL:
		{
			NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("fmul")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
		}	break;
		case IA_DIVS:
		case IA_DIVU:
		{
			NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("fdiv")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
		}	break;
		}

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
	}
	else if (ins->mDst.mType == IT_INT32)
	{
		switch (ins->mOperator)
		{
		case IA_ADD:
		case IA_SUB:
		case IA_OR:
		case IA_AND:
		case IA_XOR:
		{
			if (sins1 && sins0 && sins1->mDst.mTemp == sins0->mSrc[0].mTemp)
			{
				LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
				LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			}
			else
			{
				if (sins1)	LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
				if (sins0)	LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);
			}

			AsmInsType	atype;
			switch (ins->mOperator)
			{
			case IA_ADD:
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
				atype = ASMIT_ADC;
				break;
			case IA_SUB:
				mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
				atype = ASMIT_SBC;
				break;
			case IA_OR:
				atype = ASMIT_ORA;
				break;
			case IA_AND:
				atype = ASMIT_AND;
				break;
			case IA_XOR:
				atype = ASMIT_EOR;
				break;
			}

			for (int i = 0; i < 4; i++)
			{
				if (ins->mSrc[1].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> (8 * i)) & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + i));
				if (ins->mSrc[0].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + i));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + i));
			}
		} break;

		case IA_MUL:
		case IA_DIVS:
		case IA_MODS:
		case IA_DIVU:
		case IA_MODU:
		{
			int	reg = BC_REG_ACCU;

			if (ins->mOperator == IA_MUL && ins->mSrc[0].IsUByte())
			{
				if (sins1)
					LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}

				if (sins0)
				{
					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				}
				else if (ins->mSrc[0].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul32by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_WORK + 4;
			}
			else if (ins->mOperator == IA_MUL && ins->mSrc[1].IsUByte())
			{
				if (sins0)
					LoadValueToReg(proc, sins0, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[0].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}

				if (sins1)
				{
					LoadValueToReg(proc, sins1, BC_REG_WORK, nullptr, nullptr);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				}
				else if (ins->mSrc[1].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul32by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_WORK + 4;
			}
			else
			{
				if (sins1)
					LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				}

				if (sins0)
					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
				else if (ins->mSrc[0].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
				}

				switch (ins->mOperator)
				{
				case IA_MUL:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul32")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 4;
				}	break;
				case IA_DIVS:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divs32")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
				}	break;
				case IA_MODS:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mods32")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 4;
				}	break;
				case IA_DIVU:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu32")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
				}	break;
				case IA_MODU:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("modu32")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 4;
				}	break;
				}

			}

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
		} break;
		case IA_SHL:
		{
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int	shift = ins->mSrc[0].mIntConst & 31;

				int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

				if (shift >= 24)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					sreg = treg;
					shift -= 24;
				}
				else if (shift >= 16)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					sreg = treg;
					shift -= 16;
				}
				else if (shift >= 8)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					sreg = treg;
					shift -= 8;
				}

				if (shift == 0)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}
				}
				else if (shift == 1)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
					}
				}
				else if (shift == 2)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 3));
				}
				else if (shift == 7)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
				}
				else
				{
					NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					}
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
					this->Close(ins, lblock, nullptr, ASMIT_JMP);

					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
					lblock->Close(ins, lblock, eblock, ASMIT_BNE);

					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					return eblock;
				}
			}
			else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 1)
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* hblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x10));
				this->Close(ins, lblock, hblock, ASMIT_BEQ);

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 8, frt.mLinkerObject));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset, frt.mLinkerObject));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				lblock->Close(ins, eblock, nullptr, ASMIT_JMP);

				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset - 8, frt.mLinkerObject));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset - 16, frt.mLinkerObject));
				hblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
				hblock->Close(ins, eblock, nullptr, ASMIT_JMP);

				return eblock;
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
				}
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
				this->Close(ins, lblock, eblock, ASMIT_BNE);

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 0));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 2));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
				return eblock;
			}
		} break;

		case IA_SHR:
		{
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int	shift = ins->mSrc[0].mIntConst & 31;

				int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
				int nvbits = 32;
				if (ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND)
				{
					int64	mv = ins->mSrc[1].mRange.mMaxValue;
					while (nvbits > 0 && mv < (1LL << (nvbits - 1)))
						nvbits--;
				}

				if (shift >= nvbits)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					return this;
				}

				if (shift >= 24)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 24;
					nvbits -= 24;
				}
				else if (shift >= 16)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 16;
					nvbits -= 16;
				}
				else if (shift >= 8)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 8;
					nvbits -= 8;
				}

				if (shift == 0)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}
				}
				else if (shift == 1)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
					}
				}
				else if (shift == 2)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
					}
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
				}
				else
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}

					int nregs = (nvbits + 7) >> 3;

					if ((nvbits & 7) == 1)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + nregs - 1));
						for (int i = nregs - 1; i > 0; i--)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1));
						nvbits--;
						nregs--;
						shift--;
					}

					if (nregs <= 2)
					{
						ShiftRegisterRight(ins, treg, shift);
					}
					else
					{
						NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
						NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1));

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);

						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						for (int i = nregs - 1; i > 0; i--)
							lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1));

						//					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
						//					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
						lblock->Close(ins, lblock, eblock, ASMIT_BNE);

						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1));
						return eblock;
					}
				}
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
				}
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
				this->Close(ins, lblock, eblock, ASMIT_BNE);

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
				return eblock;
			}
		} break;

		case IA_SAR:
		{
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int	shift = ins->mSrc[0].mIntConst & 31;

				int	sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
				int	nbytes = 4;

				if (shift >= 24)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 24;
					nbytes = 1;
				}
				else if (shift >= 16)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 16;
					nbytes = 2;
				}
				else if (shift >= 8)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					sreg = treg;
					shift -= 8;
					nbytes = 3;
				}

				if (shift == 0)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
					}
				}
				else if (shift == 1)
				{
					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + nbytes - 1));

						for(int i=nbytes - 2; i >=0; i--)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
					}
				}
				else
				{
					NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

					if (sreg != treg)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3));
					}
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nbytes - 1));


					int lcost = 8 + 2 * (nbytes - 1);
					int	ucost = shift * (1 + 2 * nbytes);

					if ((nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)   && lcost < ucost ||
						!(nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
						this->Close(ins, lblock, nullptr, ASMIT_JMP);

						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						for (int i = nbytes - 2; i >= 0; i--)
							lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
						lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
						lblock->Close(ins, lblock, eblock, ASMIT_BNE);

						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
						return eblock;
					}
					else
					{
						for (int si = 0; si < shift; si++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
							for (int i = nbytes - 2; i >= 0; i--)
								mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nbytes - 1));
						}
					}
				}
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x1f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 16) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 24) & 0xff));
				}
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 3));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
				this->Close(ins, lblock, eblock, ASMIT_BNE);

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
				return eblock;
			}
		} break;
		}
	}
	else
	{
		switch (ins->mOperator)
		{
		case IA_ADD:
		case IA_OR:
		case IA_AND:
		case IA_XOR:
		{
			if (ins->mOperator == IA_ADD && InterTypeSize[ins->mDst.mType] == 1 && (
				ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp ||
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 1 && !sins0 && ins->mSrc[0].mTemp == ins->mDst.mTemp))
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, treg));
				if (InterTypeSize[ins->mDst.mType] > 1)
				{
					if (ins->mDst.IsUByte())
					{
						if (ins->mSrc[0].mTemp >= 0 && !ins->mSrc[0].IsUByte() || ins->mSrc[1].mTemp >= 0 && !ins->mSrc[1].IsUByte())
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else
					{
						NativeCodeBasicBlock* iblock = nproc->AllocateBlock();
						NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

						this->Close(ins, eblock, iblock, ASMIT_BNE);

						iblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INC, ASMIM_ZERO_PAGE, treg + 1));

						iblock->Close(ins, eblock, nullptr, ASMIT_JMP);
						return eblock;
					}
				}
			}
			else if (ins->mOperator == IA_ADD && InterTypeSize[ins->mDst.mType] == 1 && (
				ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == -1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp ||
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == -1 && !sins0 && ins->mSrc[0].mTemp == ins->mDst.mTemp))
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_DEC, ASMIM_ZERO_PAGE, treg));
			}
			else
			{
				NativeCodeInstruction	insl, insh;

				AsmInsType	atype;
				switch (ins->mOperator)
				{
				case IA_ADD:
					atype = ASMIT_ADC;
					break;
				case IA_OR:
					atype = ASMIT_ORA;
					break;
				case IA_AND:
					atype = ASMIT_AND;
					break;
				case IA_XOR:
					atype = ASMIT_EOR;
					break;
				}

				if (ins->mSrc[1].mTemp < 0)
				{
					int64	ci = ins->mSrc[1].mIntConst;
					if (ins->mOperator == IA_AND && ins->mSrc[0].IsUnsigned())
					{
						unsigned uci = unsigned(ci >> 8);
						if (uci == BinMask(uci) && (ins->mSrc[0].mRange.mMaxValue >> 8) <= uci)
							ci |= 0xff00;
					}

					insl = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, ci & 0xff);
					insh = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ci >> 8) & 0xff);
					if (sins0)
					{
						if (ins->mDst.IsUByte())
							insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);

						LoadValueToReg(proc, sins0, treg, &insl, &insh);
					}
					else
					{
						if (ins->mOperator == IA_ADD)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						if (treg == BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] &&
							((ins->mOperator == IA_AND && (ins->mSrc[1].mIntConst & 0xff) == 0xff) ||
								(ins->mOperator == IA_OR && (ins->mSrc[1].mIntConst & 0xff) == 0x00)))
						{

						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
							mIns.Push(insl);
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
							if (ins->mDst.IsUByte())
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
							else
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
								mIns.Push(insh);
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
						}
					}
				}
				else if (ins->mSrc[0].mTemp < 0)
				{
					int64	ci = ins->mSrc[0].mIntConst;
					if (ins->mOperator == IA_AND && ins->mSrc[1].IsUnsigned())
					{
						unsigned uci = unsigned(ci >> 8);
						if (uci == BinMask(uci) && (ins->mSrc[1].mRange.mMaxValue >> 8) <= uci)
							ci |= 0xff00;
					}

					insl = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, ci & 0xff);
					insh = NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, (ci >> 8) & 0xff);

					if (sins1)
					{
						if (ins->mDst.IsUByte())
							insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);

						LoadValueToReg(proc, sins1, treg, &insl, &insh);
					}
					else
					{
						if (ins->mOperator == IA_ADD)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						if (treg == BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] &&
							((ins->mOperator == IA_AND && (ins->mSrc[0].mIntConst & 0xff) == 0xff) ||
								(ins->mOperator == IA_OR && (ins->mSrc[0].mIntConst & 0xff) == 0x00)))
						{

						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(insl);
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
							if (ins->mDst.IsUByte())
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
							else
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
								mIns.Push(insh);
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
						}
					}
				}
				else
				{
					if (sins1 && sins0)
					{
						if (sins0->mSrc[0].mMemory == IM_INDIRECT && sins1->mSrc[0].mMemory == IM_INDIRECT && 
							sins0->mSrc[0].mIntConst + (InterTypeSize[ins->mDst.mType] - 1) * sins0->mSrc[0].mStride < 255 && 
							sins1->mSrc[0].mIntConst + (InterTypeSize[ins->mDst.mType] - 1) * sins1->mSrc[0].mStride < 255)
						{
							if (ins->mOperator == IA_ADD)
								mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + 0));
							mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins1->mSrc[0].mTemp]));
							if (InterTypeSize[ins->mDst.mType] > 1)
							{
								if (ins->mDst.mTemp == sins0->mSrc[0].mTemp || ins->mDst.mTemp == sins1->mSrc[0].mTemp)
									mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
								else
									mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins0->mSrc[0].mIntConst + sins0->mSrc[0].mStride));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins0->mSrc[0].mTemp]));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, sins1->mSrc[0].mIntConst + sins1->mSrc[0].mStride));
								mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[sins1->mSrc[0].mTemp]));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
								if (ins->mDst.mTemp == sins0->mSrc[0].mTemp || ins->mDst.mTemp == sins1->mSrc[0].mTemp)
								{
									mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK_Y));
									mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
								}
							}
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						else
						{
							insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, treg);
							insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, treg + 1);

							if (sins1->mDst.mTemp == ins->mDst.mTemp)
							{
								LoadValueToReg(proc, sins1, treg, nullptr, nullptr);
								LoadValueToReg(proc, sins0, treg, &insl, &insh);
							}
							else
							{
								LoadValueToReg(proc, sins0, treg, nullptr, nullptr);
								LoadValueToReg(proc, sins1, treg, &insl, &insh);
							}
						}
					}
					else if (sins1)
					{
						insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]);
						insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1);

						LoadValueToReg(proc, sins1, treg, &insl, &insh);
					}
					else if (sins0)
					{
						insl = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]);
						insh = NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1);

						LoadValueToReg(proc, sins0, treg, &insl, &insh);
					}
					else
					{
						if (ins->mOperator == IA_ADD)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
#if 1
							if (ins->mDst.IsUByte())
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
#if 1
							else if (ins->mOperator == IA_ADD && ins->mSrc[0].IsUByte() && ins->mSrc[1].IsSByte() && ins->mDst.mTemp != ins->mSrc[1].mTemp && ins->mSrc[1].mFinal)
							{
//								printf("ADD0 %s:%d, %d+%d->%d\n", mProc->mIdent->mString, mIndex, ins->mSrc[0].mTemp, ins->mSrc[1].mTemp, treg);
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x01));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x00));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
							else if (ins->mOperator == IA_ADD && ins->mSrc[1].IsUByte() && ins->mSrc[0].IsSByte() && ins->mDst.mTemp != ins->mSrc[0].mTemp && ins->mSrc[0].mFinal)
							{
//								printf("ADD1 %s:%d, %d+%d->%d\n", mProc->mIdent->mString, mIndex, ins->mSrc[0].mTemp, ins->mSrc[1].mTemp, treg);
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x01));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x00));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
#endif
							else
#endif
							{
								if (ins->mSrc[1].IsUByte())
									mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								else
									mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
								if (ins->mSrc[0].IsUByte())
									mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_IMMEDIATE, 0));
								else
									mIns.Push(NativeCodeInstruction(ins, atype, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
						}

					}
				}
			}
		} break;
		case IA_SUB:
		{
			NativeCodeInstruction	insl, insh;

			if (InterTypeSize[ins->mDst.mType] == 1 &&
				ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 1 && !sins1 && ins->mSrc[1].mTemp == ins->mDst.mTemp)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_DEC, ASMIM_ZERO_PAGE, treg));
			}
			else if (ins->mSrc[0].mTemp < 0)
			{
				insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
				if (ins->mDst.IsUByte())
					insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
				else
					insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);

				if (sins1)
					LoadValueToReg(proc, sins1, treg, &insl, &insh);
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(insl);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (InterTypeSize[ins->mDst.mType] > 1)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(insh);
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
			}
			else if (ins->mSrc[1].mTemp < 0)
			{
				if ((ins->mSrc[1].mIntConst & (ins->mSrc[1].mIntConst + 1)) == 0 && ins->mSrc[0].IsUnsigned() && ins->mSrc[0].mRange.mMaxValue <= ins->mSrc[1].mIntConst)
				{
					NativeCodeInstruction	insl = NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff);
					NativeCodeInstruction	insh = NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff);
					if (sins0)
					{
						if (ins->mDst.IsUByte())
							insh = NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0);

						LoadValueToReg(proc, sins0, treg, &insl, &insh);
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
						mIns.Push(insl);
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
							if (ins->mDst.IsUByte())
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
							else
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
								mIns.Push(insh);
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
						}
					}
				}
				else if (sins0)
				{
					LoadValueToReg(proc, sins0, treg, nullptr, nullptr);

					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (InterTypeSize[ins->mDst.mType] > 1)
					{
						if (ins->mDst.IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg + 1));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (InterTypeSize[ins->mDst.mType] > 1)
					{
						if (ins->mDst.IsUByte())
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
			}
			else
			{
				if (sins0)
				{
					insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 0);
					if (ins->mDst.IsUByte())
						insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
					else
						insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_WORK + 1);

					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
				}
				else
				{
					insl = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]);
					if (ins->mDst.IsUByte())
						insh = NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0);
					else
						insh = NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1);
				}

				if (sins1)
				{
					LoadValueToReg(proc, sins1, treg, &insl, &insh);
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(insl);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (InterTypeSize[ins->mDst.mType] > 1)
					{
						if (ins->mDst.IsUByte())
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(insh);
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
				}
			}
		} break;
		case IA_MUL:
		case IA_DIVS:
		case IA_MODS:
		case IA_DIVU:
		case IA_MODU:
		{
			int	reg = BC_REG_ACCU;

			if (ins->mOperator == IA_MUL && ins->mSrc[1].mTemp < 0)
			{
				reg = ShortMultiply(proc, nproc, ins, sins0, 0, int(ins->mSrc[1].mIntConst));
			}
			else if (ins->mOperator == IA_MUL && ins->mSrc[0].mTemp < 0)
			{
				reg = ShortMultiply(proc, nproc, ins, sins1, 1, int(ins->mSrc[0].mIntConst));
			}
			else if (ins->mOperator == IA_MUL && ins->mSrc[0].IsUByte())
			{
				if (!sins0 && !sins1 && ins->mSrc[1].IsUByte() && CheckIsInAccu(BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]))
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
				}
				else
				{
					if (sins1)
						LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					}

					if (sins0)
					{
						LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
					}
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				}

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_ACCU;
			}
			else if (ins->mOperator == IA_MUL && ins->mSrc[1].IsUByte())
			{
				if (sins0)
					LoadValueToReg(proc, sins0, BC_REG_ACCU, nullptr, nullptr);
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}

				if (sins1)
				{
					LoadValueToReg(proc, sins1, BC_REG_WORK, nullptr, nullptr);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				}
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_ACCU;
			}
			else if (ins->mOperator == IA_DIVU && ins->mSrc[0].IsUByte())
			{
				if (sins1)
					LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}

				if (sins0)
				{
					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				}
				else if (ins->mSrc[0].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_ACCU;
			}
			else if (ins->mOperator == IA_MODU && ins->mSrc[0].IsUByte())
			{
				if (sins1)
					LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}

				if (sins0)
				{
					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
				}
				else if (ins->mSrc[0].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16by8")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_CPU_REG_A));
				reg = BC_REG_WORK + 2;
			}
#if 1
			else if (ins->mOperator == IA_DIVS && ins->mSrc[0].mTemp < 0 && (ins->mSrc[0].mIntConst == 2 || ins->mSrc[0].mIntConst == 4 || ins->mSrc[0].mIntConst == 8))
			{
				reg = ShortSignedDivide(proc, nproc, ins, sins1, int(ins->mSrc[0].mIntConst));
			}
#endif
			else
			{
				if (sins1)
					LoadValueToReg(proc, sins1, BC_REG_ACCU, nullptr, nullptr);
				else if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				}

				if (sins0)
					LoadValueToReg(proc, sins0, BC_REG_WORK, nullptr, nullptr);
				else if (ins->mSrc[0].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
				}

				switch (ins->mOperator)
				{
				case IA_MUL:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mul16")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 2;
				}	break;
				case IA_DIVS:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divs16")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
				}	break;
				case IA_MODS:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("mods16")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 2;
				}	break;
				case IA_DIVU:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("divu16")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
				}	break;
				case IA_MODU:
				{
					NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("modu16")));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
					reg = BC_REG_WORK + 2;
				}	break;
				}
			}

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		} break;
		case IA_SHL:
		{
			if (ins->mSrc[0].mTemp < 0 && (ins->mSrc[0].mIntConst & 15) == 1 && sins1)
			{
				NativeCodeInstruction	insl(ins, ASMIT_ASL, ASMIM_IMPLIED);
				NativeCodeInstruction	insh(ins, ASMIT_ROL, ASMIM_IMPLIED);
				LoadValueToReg(proc, sins1, treg, &insl, &insh);
				return this;
			}
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

				int	shift = ins->mSrc[0].mIntConst & 15;
				if (ins->mDst.IsUByte() || InterTypeSize[ins->mDst.mType] == 1)
				{
					if (shift == 0)
					{
						if (sreg != treg)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
					}
					else if (shift == 1)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
						}
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else if (shift > 5)
					{

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						for(int i=shift; i<8; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg ));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						for (int i = 0; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}

					if (InterTypeSize[ins->mDst.mType] > 1)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
				else if (ins->mDst.IsSByte() && shift < 8)
				{
					if (shift == 0)
					{
						if (sreg != treg)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
					}
					else if (shift == 1)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
						}
					}
					else if (shift > 5)
					{

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						for (int i = shift; i < 8; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						for (int i = 0; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					if (shift == 0)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift == 1)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							if (ins->mSrc[1].IsUByte())
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
#if 1
					else if (shift == 6)
					{
						int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xc0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
#endif
					else if (shift == 7)
					{
						int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else if (shift == 15)
					{
						int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];

						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (shift == 4 && ins->mSrc[1].IsUByte() && ins->mSrc[1].mRange.mMaxValue >= 128)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_TXA, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xf0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						for (int i = 8; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							if (ins->mSrc[1].IsUByte())
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						}
						else
						{
							if (ins->mSrc[1].IsUByte())
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
						}

						int	check = 0xffff;
						if (ins->mSrc[1].IsUByte())
							check = int(ins->mSrc[1].mRange.mMaxValue);

						check <<= 1;
						if (check >= 0x100)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						for (int i = 1; i < shift; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
							check <<= 1;
							if (check >= 0x100)
								mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						}

						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
			}
			else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
			{
				int	l = Binlog(ins->mSrc[1].mIntConst & 0xffff);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));

				if (l < 8)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 8 + l, frt.mLinkerObject));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				if (ins->mDst.IsUByte())
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + l, frt.mLinkerObject));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
			}
			else if (ins->mSrc[1].mTemp < 0)
			{
				int	size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
					size = 16;
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, int(ins->mSrc[1].mIntConst), size, false)));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				if (ins->mDst.IsUByte())
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHL, int(ins->mSrc[1].mIntConst), size, true)));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
				}
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
				this->Close(ins, lblock, eblock, ASMIT_BNE);

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				return eblock;
			}
		} break;
		case IA_SHR:
		{
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int	shift = ins->mSrc[0].mIntConst & 15;
#if 1
				if (ins->mSrc[1].IsUByte() || InterTypeSize[ins->mSrc[1].mType] == 1)
				{
					if (shift == 0)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							if (InterTypeSize[ins->mDst.mType] > 1)
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							}
						}
					}
					else if (shift == 7)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						if (InterTypeSize[ins->mDst.mType] > 1)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else if (shift == 6)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						if (InterTypeSize[ins->mDst.mType] > 1)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						for (int i = 0; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						if (InterTypeSize[ins->mDst.mType] > 1)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
				}
				else
#endif
				{
					if (shift == 0)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift == 1)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg));
						}
					}
					else if (shift == 15)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else if (shift == 14)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						for (int i = 8; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (shift >= 5)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						for (int i = shift; i < 8; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else
					{
						uint32	mask = 0xffff;
						if (ins->mSrc[1].IsPositive() && ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND)
							mask = uint32(ins->mSrc[1].mRange.mMaxValue);

						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						for (int i = 1; i < shift; i++)
						{
							mask >>= 1;
							if (mask > 0xff)
							{
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + 1));
								mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
							}
							else
								mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						}
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}
				}
			}
#if 1
			else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
			{
				int	l = Binlog(ins->mSrc[1].mIntConst & 0xffff);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				if (l >= 8)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
			}
#endif
			else if (ins->mSrc[1].mTemp < 0)
			{
				int	size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
					size = 16;
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, int(ins->mSrc[1].mIntConst), size, false)));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				if (ins->mDst.IsUByte())
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SHR, int(ins->mSrc[1].mIntConst), size, true)));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
			}
			else if (ins->mSrc[1].IsUByte())
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));

				if (ins->mSrc[0].IsInRange(1, 15))
					this->Close(ins, lblock, nullptr, ASMIT_JMP);
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
					this->Close(ins, lblock, eblock, ASMIT_BNE);
				}

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				return eblock;
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].mTemp < 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
				}
				else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
				}

				if (ins->mSrc[0].IsInRange(1, 15))
					this->Close(ins, lblock, nullptr, ASMIT_JMP);
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
					this->Close(ins, lblock, eblock, ASMIT_BNE);
				}

				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
				lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
				lblock->Close(ins, lblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				return eblock;
			}



		} break;
		case IA_SAR:
		{
			if (sins1) LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp], nullptr, nullptr);
			if (sins0) LoadValueToReg(proc, sins0, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], nullptr, nullptr);

			if (ins->mSrc[0].mTemp < 0)
			{
				int	shift = ins->mSrc[0].mIntConst & 15;

				if (ins->mSrc[1].IsUByte())
				{
					if (shift == 0)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift == 7)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					}
					else if (shift == 6)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						for (int i = 0; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
				else if (InterTypeSize[ins->mDst.mType] == 1)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));

					if (shift > 5)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						for (int i = shift; i < 8; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift));

						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
					}
					else if (shift > 0)
					{
						for (int i = 0; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));

						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
					}

					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
				}
				else if (ins->mSrc[1].IsSByte() && shift != 0 && shift < 5)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));

					for (int i = 0; i < shift; i++)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));

					mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					if (shift == 0)
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift == 1)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					}
					else if (shift == 7)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (shift == 6)
					{
						int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
						if (sreg != treg)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));

							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));

							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, treg + 1));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						}
					}
					else if (shift >= 8)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						for (int i = 8; i < shift; i++)
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> (shift - 8)));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> (shift - 8)));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else
					{
						if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						}
						else
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
						}

						for (int i = 0; i < shift; i++)
						{
							mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
							mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg));
						}

						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
			}
#if 1
			else if (ins->mSrc[1].mTemp < 0 && IsPowerOf2(ins->mSrc[1].mIntConst & 0xffff))
			{
				int	l = Binlog(ins->mSrc[1].mIntConst & 0xffff);

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bitshift")));

				if (l == 15)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					if (l >= 8)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 39 - l, frt.mLinkerObject));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (l >= 8)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, frt.mOffset + 47 - l, frt.mLinkerObject));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
			}
#endif
			else if (ins->mSrc[1].mTemp < 0)
			{
				int	size = int(ins->mSrc[0].mRange.mMaxValue) + 1;
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
					size = 16;
				}
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, int(ins->mSrc[1].mIntConst), size, false)));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
				if (ins->mDst.IsUByte())
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, nproc->mGenerator->AllocateShortMulTable(IA_SAR, int(ins->mSrc[1].mIntConst), size, true)));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
			}
			else
			{
				NativeCodeBasicBlock* lblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				if (!ins->mSrc[0].IsUByte() || ins->mSrc[0].mRange.mMaxValue > 15)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x0f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX, ASMIM_IMPLIED));

				if (ins->mSrc[1].IsUByte())
				{
					if (ins->mSrc[1].mTemp < 0)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					}
					else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
					}

					if (ins->mSrc[0].IsInRange(1, 15))
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
						this->Close(ins, lblock, eblock, ASMIT_BNE);
					}

					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
					lblock->Close(ins, lblock, eblock, ASMIT_BNE);

					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				else if (ins->mSrc[1].IsSByte())
				{
					if (ins->mSrc[1].mTemp < 0)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
					}
					else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg));
					}

					if (ins->mSrc[0].IsInRange(1, 15))
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
						this->Close(ins, lblock, eblock, ASMIT_BNE);
					}

					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
					lblock->Close(ins, lblock, eblock, ASMIT_BNE);

					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
					if (ins->mSrc[1].mTemp < 0)
					{
						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
					else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
					{
						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
						eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
					}
				}
				else
				{
					if (ins->mSrc[1].mTemp < 0)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
					}
					else if (ins->mSrc[1].mTemp != ins->mDst.mTemp)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
					}
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 1));
					}

					if (ins->mSrc[0].IsInRange(1, 15))
						this->Close(ins, lblock, nullptr, ASMIT_JMP);
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CPX, ASMIM_IMMEDIATE, 0x00));
						this->Close(ins, lblock, eblock, ASMIT_BNE);
					}

					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, 0x80));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED));
					lblock->Close(ins, lblock, eblock, ASMIT_BNE);

					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
				}
				return eblock;
			}
		} break;

		}
	}

	return this;
}

void NativeCodeBasicBlock::SignExtendAddImmediate(InterCodeProcedure* proc, const InterInstruction* xins, const InterInstruction* ains)
{
	int val = ains->mSrc[0].mTemp == xins->mDst.mTemp ? int(ains->mSrc[1].mIntConst) : int(ains->mSrc[0].mIntConst);
	val -= 128;

	mIns.Push(NativeCodeInstruction(xins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[xins->mSrc[0].mTemp] + 0));
	mIns.Push(NativeCodeInstruction(xins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_CLC));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_ADC, ASMIM_IMMEDIATE, val & 0xff));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_ADC, ASMIM_IMMEDIATE, (val >> 8) & 0xff));
	mIns.Push(NativeCodeInstruction(ains, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ains->mDst.mTemp] + 1));
}

void NativeCodeBasicBlock::BinaryFloatOperatorLookup(InterCodeProcedure* proc, const InterInstruction* cins, const InterInstruction* ins)
{
	mIns.Push(NativeCodeInstruction(cins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[cins->mSrc[0].mTemp] + 0));
	mIns.Push(NativeCodeInstruction(cins, ASMIT_SEC));
	mIns.Push(NativeCodeInstruction(cins, ASMIT_SBC, ASMIM_IMMEDIATE, cins->mSrc[0].mRange.mMinValue));
	mIns.Push(NativeCodeInstruction(cins, ASMIT_TAX));

	bool	reverse = false;
	double	fconst;

	if (ins->mSrc[0].mTemp < 0)
	{
		fconst = ins->mSrc[0].mFloatConst;
	}
	else
	{
		fconst = ins->mSrc[1].mFloatConst;
		if (ins->mOperator == IA_SUB || ins->mOperator == IA_DIVS)
			reverse = true;
	}

	for (int i = 0; i < 4; i++)
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, mProc->mGenerator->AllocateFloatTable(ins->mOperator, reverse,
			int(cins->mSrc[0].mRange.mMinValue), int(cins->mSrc[0].mRange.mMaxValue), float(fconst), i)));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + i));
	}
}

void NativeCodeBasicBlock::UnaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins)
{
	int	treg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];

	if (ins->mDst.mType == IT_FLOAT)
	{
		switch (ins->mOperator)
		{
		case IA_NEG:
		case IA_ABS:
			if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
			}
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

			if (ins->mOperator == IA_NEG)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x7f));

			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
			break;
		case IA_FLOOR:
		case IA_CEIL:
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

			NativeCodeGenerator::Runtime& frx(nproc->mGenerator->ResolveRuntime(Ident::Unique("fsplita")));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frx.mOffset, frx.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

			if (ins->mOperator == IA_FLOOR)
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffloor")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}
			else
			{
				NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fceil")));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));
			}

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
			break;
		}
	}
	else
	{
		switch (ins->mOperator)
		{
		case IA_NEG:
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
			if (ins->mDst.mType == IT_INT32)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
			}
			break;

		case IA_NOT:
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
			if (ins->mDst.mType == IT_INT32)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3));
			}
			break;
		}
	}
}

void NativeCodeBasicBlock::NumericConversion(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins)
{
	switch (ins->mOperator)
	{
	case IA_FLOAT2INT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftoi")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));

	}	break;
	case IA_INT2FLOAT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromi")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	} break;
	case IA_FLOAT2UINT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftou")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));

	}	break;
	case IA_UINT2FLOAT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromu")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	} break;
	case IA_FLOAT2LINT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftoli")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	}	break;
	case IA_LINT2FLOAT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromli")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	} break;
	case IA_FLOAT2LUINT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ftolu")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	}	break;
	case IA_LUINT2FLOAT:
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("ffromlu")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));

	} break;
	case IA_EXT8TO16S:
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
		if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
		if (ins->mSrc[0].IsInRange(-128, -1))
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		break;
	case IA_EXT8TO16U:
		if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		break;
	case IA_EXT16TO32S:
		if (ins->mSrc[0].IsUnsigned())
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		}
		else
		{
			if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			}
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		break;
	case IA_EXT16TO32U:
		if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		break;
	case IA_EXT8TO32S:
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
		if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
		if (ins->mSrc[0].IsInRange(-128, -1))
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0xff));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		break;
	case IA_EXT8TO32U:
		if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
		}
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		break;
	}
}

static const bool NearMemCompare(const InterInstruction* ins)
{
	if (ins->mSrc[0].mMemoryBase == ins->mSrc[1].mMemoryBase && ins->mSrc[0].mType == IT_POINTER)
	{
		if (ins->mSrc[0].mMemoryBase == IM_LOCAL || ins->mSrc[0].mMemoryBase == IM_GLOBAL)
		{
			if (ins->mSrc[0].mLinkerObject && ins->mSrc[0].mLinkerObject == ins->mSrc[1].mLinkerObject)
			{
				if (ins->mSrc[0].mLinkerObject->mSize < 256)
					return true;
				else if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mRange.IsBound())
				{
					if (ins->mSrc[1].mRange.mMaxValue - ins->mSrc[1].mRange.mMinValue < 256 &&
						ins->mSrc[0].mIntConst >= ins->mSrc[1].mRange.mMinValue &&
						ins->mSrc[0].mIntConst <= ins->mSrc[1].mRange.mMaxValue)
						return true;
				}
				else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[0].mRange.IsBound())
				{
					if (ins->mSrc[0].mRange.mMaxValue - ins->mSrc[0].mRange.mMinValue < 256 &&
						ins->mSrc[1].mIntConst >= ins->mSrc[0].mRange.mMinValue &&
						ins->mSrc[1].mIntConst <= ins->mSrc[0].mRange.mMaxValue)
						return true;
				}
			}
		}
	}

	return false;

}

void NativeCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump)
{
	InterOperator	op = ins->mOperator;

	bool	scmp = (op == IA_CMPGES) || (op == IA_CMPLES) || (op == IA_CMPGS) || (op == IA_CMPLS) || (op == IA_CMPEQ) || (op == IA_CMPNE);
	bool	ucmp = (op == IA_CMPGEU) || (op == IA_CMPLEU) || (op == IA_CMPGU) || (op == IA_CMPLU) || (op == IA_CMPEQ) || (op == IA_CMPNE);

	if (ins->mSrc[0].mType == IT_FLOAT)
	{
		if (ins->mSrc[0].mTemp < 0 || ins->mSrc[1].mTemp < 0)
		{
			InterOperator	op = ins->mOperator;

			int ci = 0, vi = 1;
			if (ins->mSrc[1].mTemp < 0)
			{
				ci = 1;
				vi = 0;
				op = MirrorRelational(op);
			}

			union { float f; unsigned int v; } cc;
			cc.f = float(ins->mSrc[ci].mFloatConst);

			int	ti = BC_REG_TMP + proc->mTempOffset[ins->mSrc[vi].mTemp];

			if (cc.f == 0)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0x7f));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, ti + 0));

				if (op == IA_CMPEQ)
				{
					Close(ins, trueJump, falseJump, ASMIT_BEQ);
				}
				else if (op == IA_CMPNE)
				{
					Close(ins, trueJump, falseJump, ASMIT_BNE);
				}
				else
				{
					NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

					if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPLES || op == IA_CMPLEU)
						Close(ins, trueJump, nblock, ASMIT_BEQ);
					else
						Close(ins, falseJump, nblock, ASMIT_BEQ);

					nblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
					if (op == IA_CMPGES || op == IA_CMPGEU || op == IA_CMPGS || op == IA_CMPGU)
						nblock->Close(ins, trueJump, falseJump, ASMIT_BPL);
					else
						nblock->Close(ins, trueJump, falseJump, ASMIT_BMI);
				}
				return;
			}
			else
			{
				NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
				NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();


				if (op == IA_CMPEQ)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					Close(ins, eblock1, falseJump, ASMIT_BEQ);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					eblock1->Close(ins, eblock2, falseJump, ASMIT_BEQ);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					eblock2->Close(ins, eblock3, falseJump, ASMIT_BEQ);
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
					eblock3->Close(ins, trueJump, falseJump, ASMIT_BEQ);
					return;
				}
				else if (op == IA_CMPNE)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					Close(ins, eblock1, trueJump, ASMIT_BEQ);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					eblock1->Close(ins, eblock2, trueJump, ASMIT_BEQ);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					eblock2->Close(ins, eblock3, trueJump, ASMIT_BEQ);
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
					eblock3->Close(ins, falseJump, trueJump, ASMIT_BEQ);
					return;
				}
				else if (op == IA_CMPGS || op == IA_CMPGES || op == IA_CMPGU || op == IA_CMPGEU)
				{
					NativeCodeBasicBlock* eblock0 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
					NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
					if (cc.f < 0)
						Close(ins, trueJump, eblock0, ASMIT_BPL);
					else
						Close(ins, falseJump, eblock0, ASMIT_BMI);
					eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					eblock0->Close(ins, nblock, eblock1, ASMIT_BNE);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					eblock1->Close(ins, nblock, eblock2, ASMIT_BNE);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					eblock2->Close(ins, nblock, eblock3, ASMIT_BNE);
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
					if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU)
						eblock3->Close(ins, nblock, trueJump, ASMIT_BNE);
					else
						eblock3->Close(ins, nblock, falseJump, ASMIT_BNE);

					if (cc.f < 0)
						nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
					else
						nblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
					return;
				}
				else
				{
					NativeCodeBasicBlock* eblock0 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
					NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 3));
					if (cc.f < 0)
						Close(ins, falseJump, eblock0, ASMIT_BPL);
					else
						Close(ins, trueJump, eblock0, ASMIT_BMI);
					eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					eblock0->Close(ins, nblock, eblock1, ASMIT_BNE);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 2));
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					eblock1->Close(ins, nblock, eblock2, ASMIT_BNE);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 1));
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					eblock2->Close(ins, nblock, eblock3, ASMIT_BNE);
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ti + 0));
					eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, cc.v & 0xff));
					if (op == IA_CMPGES || op == IA_CMPLES || op == IA_CMPGEU || op == IA_CMPLEU)
						eblock3->Close(ins, nblock, trueJump, ASMIT_BNE);
					else
						eblock3->Close(ins, nblock, falseJump, ASMIT_BNE);

					if (cc.f < 0)
						nblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
					else
						nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
					return;
				}
			}
		}

		int	li = 0, ri = 1;
		if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
		{
			li = 1; ri = 0;
		}

		if (ins->mSrc[li].mTemp < 0)
		{
			union { float f; unsigned int v; } cc;
			cc.f = float(ins->mSrc[li].mFloatConst);

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		}
		else if (ins->mSrc[li].mFinal && CheckPredAccuStore(BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]))
		{
			// cull previous store from accu to temp using direcrt forwarding
			mIns.SetSize(mIns.Size() - 8);
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
		}

		if (ins->mSrc[ri].mTemp < 0)
		{
			union { float f; unsigned int v; } cc;
			cc.f = float(ins->mSrc[ri].mFloatConst);

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
		}

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("fcmp")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_JSRFLAGS));

		switch (op)
		{
		case IA_CMPEQ:
			Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		case IA_CMPNE:
			Close(ins, falseJump, trueJump, ASMIT_BEQ);
			break;
		case IA_CMPLU:
		case IA_CMPLS:
		case IA_CMPGU:
		case IA_CMPGS:
			Close(ins, trueJump, falseJump, ASMIT_BMI);
			break;
		case IA_CMPLEU:
		case IA_CMPLES:
		case IA_CMPGEU:
		case IA_CMPGES:
			Close(ins, falseJump, trueJump, ASMIT_BMI);
			break;
		}
	}
	else if (ins->mSrc[0].mType == IT_POINTER)
	{
		int	li = 1, ri = 0;
		if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
		{
			li = 0; ri = 1;
		}

		int	lreg = ins->mSrc[li].mTemp, rreg = ins->mSrc[ri].mTemp;
		if (lreg < 0)
		{
			lreg = BC_REG_ACCU;
			LoadConstantToReg(proc, ins, ins->mSrc[li], IT_POINTER, lreg, false);
		}
		else
			lreg = BC_REG_TMP + proc->mTempOffset[lreg];

		if (rreg < 0)
		{
			rreg = BC_REG_ACCU;
			LoadConstantToReg(proc, ins, ins->mSrc[ri], IT_POINTER, rreg, false);
		}
		else
			rreg = BC_REG_TMP + proc->mTempOffset[rreg];

		if ((op == IA_CMPEQ || op == IA_CMPNE) && NearMemCompare(ins))
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg));

			Close(ins, trueJump, falseJump, op == IA_CMPEQ ? ASMIT_BEQ : ASMIT_BNE);
		}
		else
		{
			NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

			if (op == IA_CMPEQ || op == IA_CMPNE)
			{
				// Lower byte compare more likely to miss on not equal with first
				// compare

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg));

				Close(ins, nblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg + 1));
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg + 1));
			}
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg + 1));

				Close(ins, nblock, eblock, ASMIT_BNE);

				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, lreg));
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, rreg));
			}

			switch (op)
			{
			case IA_CMPEQ:
				nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
				eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
				break;
			case IA_CMPNE:
				nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
				eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
				break;
			case IA_CMPLU:
			case IA_CMPLS:
			case IA_CMPGU:
			case IA_CMPGS:
				eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
				nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
				break;
			case IA_CMPLEU:
			case IA_CMPLES:
			case IA_CMPGEU:
			case IA_CMPGES:
				eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
				nblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
				break;

			}
		}
	}
	else if (ins->mSrc[0].mType == IT_INT32)
	{
		if ((op >= IA_CMPGES && op <= IA_CMPLS) && 
			(ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst >= 0 && ins->mSrc[0].mIntConst < 256 ||
			 ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst >= 0 && ins->mSrc[1].mIntConst < 256))
		{
			NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock0 = nproc->AllocateBlock();

			int li = 1, ri = 0;
			if (ins->mSrc[1].mTemp < 0)
			{
				li = 0;
				ri = 1;
				op = MirrorRelational(op);
			}

			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
			if (op == IA_CMPGS || op == IA_CMPGES)
			{
				if (op == IA_CMPGES && ins->mSrc[ri].mIntConst == 0)
					this->Close(ins, falseJump, trueJump, ASMIT_BMI);
				else
				{
					this->Close(ins, falseJump, eblock3, ASMIT_BMI);
					eblock3->Close(ins, trueJump, eblock2, ASMIT_BNE);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
					eblock2->Close(ins, trueJump, eblock1, ASMIT_BNE);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
					if (op == IA_CMPGS && ins->mSrc[ri].mIntConst == 255)
						eblock1->Close(ins, trueJump, falseJump, ASMIT_BNE);
					else
					{
						eblock1->Close(ins, trueJump, eblock0, ASMIT_BNE);
						eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
						eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[ri].mIntConst + (op == IA_CMPGS)));
						eblock0->Close(ins, trueJump, falseJump, ASMIT_BCS);
					}
				}
			}
			else
			{
				if (op == IA_CMPLS && ins->mSrc[ri].mIntConst == 0)
					this->Close(ins, trueJump, falseJump, ASMIT_BMI);
				else
				{
					this->Close(ins, trueJump, eblock3, ASMIT_BMI);
					eblock3->Close(ins, falseJump, eblock2, ASMIT_BNE);
					eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
					eblock2->Close(ins, falseJump, eblock1, ASMIT_BNE);
					eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
					eblock1->Close(ins, falseJump, eblock0, ASMIT_BNE);
					if (op == IA_CMPLES && ins->mSrc[ri].mIntConst == 255)
						eblock1->Close(ins, falseJump, trueJump, ASMIT_BNE);
					else
					{
						eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
						eblock0->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[ri].mIntConst + (op == IA_CMPLES)));
						eblock0->Close(ins, falseJump, trueJump, ASMIT_BCS);
					}
				}
			}
		}
		else
		{
			int	li = 1, ri = 0;
			if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
			{
				li = 0; ri = 1;
				op = MirrorRelational(op);
			}

			NativeCodeBasicBlock* eblock3 = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock2 = nproc->AllocateBlock();
			NativeCodeBasicBlock* eblock1 = nproc->AllocateBlock();
			NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
			NativeCodeBasicBlock* rblock = nproc->AllocateBlock();


			if (op >= IA_CMPGES && op <= IA_CMPLS)
			{
				if (ins->mSrc[ri].mTemp >= 0)
				{
					NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

					if (ins->mSrc[li].mTemp < 0)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 24) & 0xff));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));

					this->Close(ins, eblock3, eblock, ASMIT_BEQ);
					eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
					eblock->Close(ins, nblock, rblock, ASMIT_BPL);
				}
				else
				{
					if (ins->mSrc[ri].mTemp >= 0)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK));
					}

					if (ins->mSrc[li].mTemp < 0)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 24) & 0xff) ^ 0x80));
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
					}

					if (ins->mSrc[ri].mTemp < 0)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ((ins->mSrc[ri].mIntConst >> 24) & 0xff) ^ 0x80));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK));
					this->Close(ins, nblock, eblock3, ASMIT_BNE);
				}
			}
			else
			{
				if (ins->mSrc[li].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 24) & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 3));
				if (ins->mSrc[ri].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 24) & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 3));
				this->Close(ins, nblock, eblock3, ASMIT_BNE);
			}


			if (ins->mSrc[li].mTemp < 0)
				eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 16) & 0xff));
			else
				eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 2));
			if (ins->mSrc[ri].mTemp < 0)
				eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 16) & 0xff));
			else
				eblock3->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 2));

			eblock3->Close(ins, nblock, eblock2, ASMIT_BNE);

			if (ins->mSrc[li].mTemp < 0)
				eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff));
			else
				eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
			if (ins->mSrc[ri].mTemp < 0)
				eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (ins->mSrc[ri].mIntConst >> 8) & 0xff));
			else
				eblock2->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));

			eblock2->Close(ins, nblock, eblock1, ASMIT_BNE);

			if (ins->mSrc[li].mTemp < 0)
				eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
			else
				eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
			if (ins->mSrc[ri].mTemp < 0)
				eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[ri].mIntConst & 0xff));
			else
				eblock1->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));

			switch (op)
			{
			case IA_CMPEQ:
				nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
				rblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
				eblock1->Close(ins, trueJump, falseJump, ASMIT_BEQ);
				break;
			case IA_CMPNE:
				nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
				rblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
				eblock1->Close(ins, falseJump, trueJump, ASMIT_BEQ);
				break;
			case IA_CMPLU:
			case IA_CMPLS:
			case IA_CMPGU:
			case IA_CMPGS:
				eblock1->Close(ins, nblock, nullptr, ASMIT_JMP);
				nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
				rblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
				break;
			case IA_CMPLEU:
			case IA_CMPLES:
			case IA_CMPGEU:
			case IA_CMPGES:
				eblock1->Close(ins, nblock, nullptr, ASMIT_JMP);
				nblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
				rblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
				break;

			}
		}
	}
	else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0)
	{
		int	rt = ins->mSrc[1].mTemp;
		int ri = 1;
		if (rt < 0)
		{
			rt = ins->mSrc[0].mTemp;
			ri = 0;
			switch (op)
			{
			case IA_CMPLEU:
				op = IA_CMPGEU;
				break;
			case IA_CMPGEU:
				op = IA_CMPLEU;
				break;
			case IA_CMPLU:
				op = IA_CMPGU;
				break;
			case IA_CMPGU:
				op = IA_CMPLU;
				break;
			case IA_CMPLES:
				op = IA_CMPGES;
				break;
			case IA_CMPGES:
				op = IA_CMPLES;
				break;
			case IA_CMPLS:
				op = IA_CMPGS;
				break;
			case IA_CMPGS:
				op = IA_CMPLS;
				break;
			}
		}

		switch (op)
		{
		case IA_CMPEQ:
		case IA_CMPLEU:
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			if (InterTypeSize[ins->mSrc[0].mType] > 1 && !ins->mSrc[ri].IsUByte() && !ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		case IA_CMPNE:
		case IA_CMPGU:
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			if (InterTypeSize[ins->mSrc[0].mType] > 1 && !ins->mSrc[ri].IsUByte() && !ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, trueJump, falseJump, ASMIT_BNE);
			break;
		case IA_CMPGEU:
			this->Close(ins, trueJump, nullptr, ASMIT_JMP);
			break;
		case IA_CMPLU:
			this->Close(ins, falseJump, nullptr, ASMIT_JMP);
			break;
		case IA_CMPGES:
			if (InterTypeSize[ins->mSrc[0].mType] == 1 || ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, trueJump, falseJump, ASMIT_BPL);
			break;
		case IA_CMPLS:
			if (InterTypeSize[ins->mSrc[0].mType] == 1 || ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, trueJump, falseJump, ASMIT_BMI);
			break;
		case IA_CMPGS:
		{
			NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
			if (InterTypeSize[ins->mSrc[0].mType] == 1 || ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, eblock, falseJump, ASMIT_BPL);
			if (InterTypeSize[ins->mSrc[0].mType] != 1 && !ins->mSrc[ri].IsSByte())
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BNE);
			break;
		}
		case IA_CMPLES:
		{
			NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
			if (InterTypeSize[ins->mSrc[0].mType] == 1 || ins->mSrc[ri].IsSByte())
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt]));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));
			this->Close(ins, eblock, trueJump, ASMIT_BPL);
			if (InterTypeSize[ins->mSrc[0].mType] != 1 && !ins->mSrc[ri].IsSByte())
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		}

		}
	}
	else if (InterTypeSize[ins->mSrc[0].mType] == 1 || 
			scmp && ins->mSrc[0].IsSByte() && ins->mSrc[1].IsSByte() || 
			ucmp && ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte() ||
			op == IA_CMPLU && ins->mSrc[1].IsSByte() && ins->mSrc[0].IsSByte() && ins->mSrc[0].IsPositive())
	{
		int	li = 1, ri = 0;
		if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
		{
			li = 0; ri = 1;
			op = MirrorRelational(op);
		}

		int		iconst = 0;
		bool	rconst = false;

		if (ins->mSrc[li].mTemp < 0 && op == IA_CMPGES && int16(ins->mSrc[li].mIntConst) < 127)
		{
			iconst = int(ins->mSrc[li].mIntConst) + 1;
			rconst = true;
			li = ri; ri = 1 - li;
			op = IA_CMPLS;
		}
		else if (ins->mSrc[li].mTemp < 0 && op == IA_CMPLS && int16(ins->mSrc[li].mIntConst) < 127)
		{
			iconst = int(ins->mSrc[li].mIntConst) + 1;
			rconst = true;
			li = ri; ri = 1 - li;
			op = IA_CMPGES;
		}
		else if (ins->mSrc[ri].mTemp < 0)
		{
			iconst = int(ins->mSrc[ri].mIntConst);
			rconst = true;
		}

		if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS)
		{
			if (!rconst)
			{
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
				NativeCodeBasicBlock* pblock = nproc->AllocateBlock();

				NativeCodeBasicBlock* eqjmp, * gtjmp, * ltjmp;

				if (op == IA_CMPGES || op == IA_CMPLES)
					eqjmp = trueJump;
				else
					eqjmp = falseJump;

				if (op == IA_CMPGS || op == IA_CMPGES)
				{
					gtjmp = trueJump;
					ltjmp = falseJump;
				}
				else
				{
					gtjmp = falseJump;
					ltjmp = trueJump;
				}

				if (ins->mSrc[li].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
				else
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));

				this->Close(ins, eqjmp, eblock, ASMIT_BEQ);
				eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
				eblock->Close(ins, pblock, nblock, ASMIT_BCS);

				pblock->Close(ins, gtjmp, ltjmp, ASMIT_BPL);
				nblock->Close(ins, ltjmp, gtjmp, ASMIT_BPL);
				return;
			}
			else
			{
				if (ins->mSrc[li].mTemp < 0)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst & 0xff) ^ 0x80));
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
				}

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (iconst & 0xff) ^ 0x80));
			}
		}
		else
		{
			if (ins->mSrc[li].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
			if (rconst)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));
		}

		switch (op)
		{
		case IA_CMPEQ:
			this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		case IA_CMPNE:
			this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
			break;
		case IA_CMPLU:
		case IA_CMPLS:
		case IA_CMPGU:
		case IA_CMPGS:
			this->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		case IA_CMPLEU:
		case IA_CMPLES:
		case IA_CMPGEU:
		case IA_CMPGES:
			this->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;

		}
	}
#if 1
	else if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst < 256 && ins->mSrc[1].mIntConst > 0 || ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst < 256 && ins->mSrc[0].mIntConst > 0)
	{
		int	rt = ins->mSrc[1].mTemp;
		int ival = int(ins->mSrc[0].mIntConst);
		bool	u8 = ins->mSrc[1].IsUByte();
		if (rt < 0)
		{
			rt = ins->mSrc[0].mTemp;
			u8 = ins->mSrc[0].IsUByte();;
			ival = int(ins->mSrc[1].mIntConst);
			switch (op)
			{
			case IA_CMPLEU:
				op = IA_CMPGEU;
				break;
			case IA_CMPGEU:
				op = IA_CMPLEU;
				break;
			case IA_CMPLU:
				op = IA_CMPGU;
				break;
			case IA_CMPGU:
				op = IA_CMPLU;
				break;
			case IA_CMPLES:
				op = IA_CMPGES;
				break;
			case IA_CMPGES:
				op = IA_CMPLES;
				break;
			case IA_CMPLS:
				op = IA_CMPGS;
				break;
			case IA_CMPGS:
				op = IA_CMPLS;
				break;
			}
		}

		NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
		if (u8)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 1));

		switch (op)
		{
		case IA_CMPEQ:
		{
			this->Close(ins, eblock, falseJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		}
		case IA_CMPNE:
		{
			this->Close(ins, eblock, trueJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
			break;
		}

		case IA_CMPLEU:
		{
			this->Close(ins, eblock, falseJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;
		}

		case IA_CMPGEU:
		{
			this->Close(ins, eblock, trueJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;
		}

		case IA_CMPLU:
		{
			this->Close(ins, eblock, falseJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		}

		case IA_CMPGU:
		{
			this->Close(ins, eblock, trueJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		}

		case IA_CMPLES:
		{
			NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
			this->Close(ins, sblock, trueJump, ASMIT_BPL);
			sblock->Close(ins, eblock, falseJump, ASMIT_BEQ);

			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;
		}

		case IA_CMPGES:
		{
			NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
			this->Close(ins, sblock, falseJump, ASMIT_BPL);
			sblock->Close(ins, eblock, trueJump, ASMIT_BEQ);

			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;
		}

		case IA_CMPLS:
		{
			NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
			this->Close(ins, sblock, trueJump, ASMIT_BPL);
			sblock->Close(ins, eblock, falseJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ival));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		}

		case IA_CMPGS:
		{
			NativeCodeBasicBlock* sblock = nproc->AllocateBlock();
			this->Close(ins, sblock, falseJump, ASMIT_BPL);
			sblock->Close(ins, eblock, trueJump, ASMIT_BEQ);
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ival));
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rt] + 0));
			eblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		}

		}
	}
#endif
#if 1
	// Special case counting to 256
	else if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 256 && op == IA_CMPLU &&
			ins->mSrc[1].mRange.mMinState == IntegerValueRange::S_BOUND && ins->mSrc[1].mRange.mMinValue > 0 && 
			ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND && ins->mSrc[1].mRange.mMaxValue == 256)
	{
		if (ins->mSrc[1].mTemp < 0)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));
		this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
	}
#endif
#if 1
	// Special case >= or < with multiple of 256, no need to check low byte then
	else if (ins->mSrc[0].mTemp < 0 && !(ins->mSrc[0].mIntConst & 255) && op == IA_CMPGEU)
	{
		if (ins->mSrc[1].mTemp < 0)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst >> 8));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst >> 8));
		this->Close(ins, trueJump, falseJump, ASMIT_BCS);
	}
#endif
	else if (ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte())
	{
		NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
		NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

		int	li = 1, ri = 0;
		if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
		{
			li = 0; ri = 1;
		}

		int		iconst = 0;
		bool	rconst = false;

		if (ins->mSrc[ri].mTemp < 0)
		{
			iconst = int(ins->mSrc[ri].mIntConst);
			rconst = true;
		}

		if (ins->mSrc[li].mTemp < 0)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
		if (rconst)
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));

		switch (op)
		{
		case IA_CMPEQ:
			this->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		case IA_CMPNE:
			this->Close(ins, falseJump, trueJump, ASMIT_BEQ);
			break;
		case IA_CMPLU:
		case IA_CMPLS:
		case IA_CMPGU:
		case IA_CMPGS:
			this->Close(ins, trueJump, falseJump, ASMIT_BCC);
			break;
		case IA_CMPLEU:
		case IA_CMPLES:
		case IA_CMPGEU:
		case IA_CMPGES:
			this->Close(ins, falseJump, trueJump, ASMIT_BCC);
			break;

		}

	}
	else
	{
		NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
		NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
		NativeCodeBasicBlock* rblock = nproc->AllocateBlock();
		NativeCodeBasicBlock* cblock = this;

		if (op == IA_CMPLU && ins->mSrc[0].mTemp == -1 && ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxValue == ins->mSrc[0].mIntConst)
			op = IA_CMPNE;

		int	li = 1, ri = 0;
		if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
		{
			li = 0; ri = 1;
		}

		int		iconst = 0;
		bool	rconst = false;

		if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPGES || op == IA_CMPLS) && int16(ins->mSrc[li].mIntConst) > - 32768)
		{
			iconst = int(ins->mSrc[li].mIntConst) - 1;
			rconst = true;
			li = ri; ri = 1 - li;

			NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
		}
		else if (ins->mSrc[li].mTemp < 0 && (op == IA_CMPLES || op == IA_CMPGS) && int16(ins->mSrc[li].mIntConst) < 32767)
		{
			iconst = int(ins->mSrc[li].mIntConst) + 1;
			rconst = true;
			li = ri; ri = 1 - li;

			NativeCodeBasicBlock* t = trueJump; trueJump = falseJump; falseJump = t;
		}
		else if (ins->mSrc[ri].mTemp < 0)
		{
			iconst = int(ins->mSrc[ri].mIntConst);
			rconst = true;
		}

		if (op >= IA_CMPGES && ins->mOperator <= IA_CMPLS)
		{
			if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[li].IsPositive() && (op == IA_CMPGS || op == IA_CMPLS))
			{
				cblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));

				this->Close(ins, falseJump, cblock, ASMIT_BMI);

				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
				cblock->Close(ins, nblock, eblock, ASMIT_BNE);
			}
			else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES))
			{
				cblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));

				this->Close(ins, falseJump, cblock, ASMIT_BMI);

				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
				cblock->Close(ins, nblock, eblock, ASMIT_BNE);
			}
			else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[ri].IsPositive() && (op == IA_CMPGS || op == IA_CMPLS))
			{
				cblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));

				this->Close(ins, trueJump, cblock, ASMIT_BMI);

				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
				cblock->Close(ins, nblock, eblock, ASMIT_BNE);
			}
			else if (ins->mSrc[li].mTemp >= 0 && ins->mSrc[ri].mTemp >= 0 && ins->mSrc[li].IsPositive() && (op == IA_CMPGES || op == IA_CMPLES))
			{
				cblock = nproc->AllocateBlock();

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));

				this->Close(ins, trueJump, cblock, ASMIT_BMI);

				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
				cblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
				cblock->Close(ins, nblock, eblock, ASMIT_BNE);
			}
			else
			{
				if (!rconst)
				{
					NativeCodeBasicBlock* sblock = nproc->AllocateBlock();

					if (ins->mSrc[li].mTemp < 0)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));

					this->Close(ins, eblock, sblock, ASMIT_BEQ);
					sblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
					sblock->Close(ins, nblock, rblock, ASMIT_BPL);
				}
				else
				{
					if (!rconst)
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK));
					}

					if (ins->mSrc[li].mTemp < 0)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ((ins->mSrc[li].mIntConst >> 8) & 0xff) ^ 0x80));
					else
					{
						mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
						mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
					}

					if (rconst)
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, ((iconst >> 8) & 0xff) ^ 0x80));
					else
						mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_WORK));
					cblock->Close(ins, nblock, eblock, ASMIT_BNE);
				}
			}
		}
		else
		{
			if (ins->mSrc[li].mTemp < 0)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[li].mIntConst >> 8) & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp] + 1));
			if (rconst)
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, (iconst >> 8) & 0xff));
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp] + 1));
			cblock->Close(ins, nblock, eblock, ASMIT_BNE);
		}


		if (ins->mSrc[li].mTemp < 0)
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[li].mIntConst & 0xff));
		else
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[li].mTemp]));
		if (rconst)
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_IMMEDIATE, iconst & 0xff));
		else
			eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[ri].mTemp]));

		switch (op)
		{
		case IA_CMPEQ:
			nblock->Close(ins, falseJump, nullptr, ASMIT_JMP);
			eblock->Close(ins, trueJump, falseJump, ASMIT_BEQ);
			break;
		case IA_CMPNE:
			nblock->Close(ins, trueJump, nullptr, ASMIT_JMP);
			eblock->Close(ins, falseJump, trueJump, ASMIT_BEQ);
			break;
		case IA_CMPLU:
		case IA_CMPLS:
		case IA_CMPGU:
		case IA_CMPGS:
			eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
			nblock->Close(ins, trueJump, falseJump, ASMIT_BCC);
			rblock->Close(ins, trueJump, falseJump, ASMIT_BCS);
			break;
		case IA_CMPLEU:
		case IA_CMPLES:
		case IA_CMPGEU:
		case IA_CMPGES:
			eblock->Close(ins, nblock, nullptr, ASMIT_JMP);
			nblock->Close(ins, falseJump, trueJump, ASMIT_BCC);
			rblock->Close(ins, falseJump, trueJump, ASMIT_BCS);
			break;

		}
	}
}

void NativeCodeBasicBlock::LoadStoreOpAbsolute2D(InterCodeProcedure* proc, const InterInstruction* lins1, const InterInstruction* lins2, const InterInstruction* mins)
{	
	mIns.Push(NativeCodeInstruction(lins1, ASMIT_CLC));

	if (lins1->mSrc[0].mTemp < 0)
		mIns.Push(NativeCodeInstruction(lins1, ASMIT_LDA, ASMIM_IMMEDIATE, lins1->mSrc[0].mIntConst));
	else
		mIns.Push(NativeCodeInstruction(lins1, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins1->mSrc[0].mTemp]));

	if (lins2->mSrc[0].mTemp < 0)
		mIns.Push(NativeCodeInstruction(lins2, ASMIT_ADC, ASMIM_IMMEDIATE, lins2->mSrc[0].mIntConst));
	else
		mIns.Push(NativeCodeInstruction(lins2, ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[lins2->mSrc[0].mTemp]));

	int64 offset = lins1->mSrc[1].mIntConst;

	if (mins->mCode == IC_STORE)
		offset += mins->mSrc[1].mIntConst;
	else
		offset += mins->mSrc[0].mIntConst;

	if (offset < 0)
	{
		if (lins1->mSrc[1].mLinkerObject->mSize - offset > 256)
		{
			mIns.Push(NativeCodeInstruction(mins, ASMIT_CLC));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_IMMEDIATE, (offset & 255)));
			offset = 0;
		}
		else
			offset = (offset & 255) - 256;
	}
	else if (offset > 0)
	{
		if (!lins1->mSrc[0].IsUnsigned() || !lins2->mSrc[0].IsUnsigned())
		{
			mIns.Push(NativeCodeInstruction(mins, ASMIT_CLC));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_ADC, ASMIM_IMMEDIATE, (offset & 255)));
			offset = 0;
		}
		else
			offset &= 255;
	}

	mIns.Push(NativeCodeInstruction(mins, ASMIT_TAY));

	if (mins->mCode == IC_STORE)
	{
		for (int i = 0; i < InterTypeSize[mins->mSrc[0].mType]; i++)
		{
			if (mins->mSrc[0].mTemp < 0)
				mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_IMMEDIATE, (mins->mSrc[0].mIntConst >> (8 * i)) & 0xff));
			else
				mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[mins->mSrc[0].mTemp] + i));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_STA, ASMIM_ABSOLUTE_Y, offset + i, lins1->mSrc[1].mLinkerObject));
		}
	}
	else
	{
		for (int i = 0; i < InterTypeSize[mins->mDst.mType]; i++)
		{
			mIns.Push(NativeCodeInstruction(mins, ASMIT_LDA, ASMIM_ABSOLUTE_Y, offset + i, lins1->mSrc[1].mLinkerObject));
			mIns.Push(NativeCodeInstruction(mins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[mins->mDst.mTemp] + i));
		}
	}
}


void NativeCodeBasicBlock::LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction * ins, const InterInstruction* sins1, const InterInstruction* sins0, bool addrvalid, bool addrused)
{
	bool		isub = false;
	int			ireg = ins->mSrc[0].mTemp;
	AsmInsType	iop = ASMIT_ADC;

	if (sins0)
	{
		isub = true;
		ireg = sins0->mSrc[0].mTemp;
		iop = ASMIT_SBC;
	}

	if (sins1)
	{
		if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0)
			LoadValueToReg(proc, sins1, ins->mDst.mTemp, nullptr, nullptr);
		else
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				NativeCodeInstruction	ainsl(ins, ASMIT_ADC, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
				NativeCodeInstruction	ainsh(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);

				LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
			}
			else
			{
				NativeCodeInstruction	ainsl(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]);
				if (ins->mSrc[0].IsUByte())
				{
					NativeCodeInstruction	ainsh(ins, iop, ASMIM_IMMEDIATE, 0);

					LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
				}
				else
				{
					NativeCodeInstruction	ainsh(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1);

					LoadValueToReg(proc, sins1, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp], &ainsl, &ainsh);
				}
			}
		}
	}
	else if (ins->mSrc[1].mTemp < 0)
	{

		mIns.Push(NativeCodeInstruction(ins, isub ? ASMIT_SEC : ASMIT_CLC, ASMIM_IMPLIED));
		if (ins->mSrc[1].mMemory == IM_GLOBAL)
		{
			if (!ins->mSrc[0].IsUnsigned() && ins->mSrc[1].mIntConst != 0 && ins->mSrc[1].mLinkerObject->mSize < 256)
			{
				// Negative index, small global

				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst) & 0xff));
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));

				mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, 0, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			}
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst & 0xffff, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
				// if the global variable is smaller than 256 bytes, we can safely ignore the upper byte?
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst & 0xffff, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
#if 1
				if (ins->mSrc[0].IsUByte())
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
				else if ((ins->mSrc[1].mIntConst == 0 || ins->mSrc[0].IsUnsigned()) &&
					(ins->mSrc[1].mLinkerObject->mSize - ins->mSrc[1].mIntConst < 256 || (addrvalid && ins->mSrc[1].mLinkerObject->mSize - ins->mSrc[1].mIntConst <= 256)))
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
				else
#endif
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			}
		}
		else if (ins->mSrc[1].mMemory == IM_ABSOLUTE)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[1].mIntConst & 0xff));
			mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[1].mIntConst >> 8) & 0xff));
#if 1
			if (ins->mSrc[0].IsUByte())
			{
				if (iop == ASMIT_ADC && ins->mSrc[0].mRange.mMaxState == IntegerValueRange::S_BOUND && ins->mSrc[0].mRange.mMaxValue + (ins->mSrc[1].mIntConst & 0xff) < 0x100 && addrused)
					;
				else
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
			}
			else
#endif
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		}
		else if (ins->mSrc[1].mMemory == IM_PROCEDURE)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_LOWER));
			mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER));
#if 1
			if (ins->mSrc[0].IsUByte())
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
			else
#endif
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		}
		else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
			mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			if (ins->mSrc[0].IsUByte())
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
			else
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
		}
		else if (ins->mSrc[1].mMemory == IM_LOCAL || ins->mSrc[1].mMemory == IM_PARAM)
		{
			int dreg = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
			int	index = int(ins->mSrc[1].mIntConst);
			int areg = mNoFrame ? BC_REG_STACK : BC_REG_LOCALS;
			if (ins->mSrc[1].mMemory == IM_LOCAL)
				index += proc->mLocalVars[ins->mSrc[1].mVarIndex]->mOffset;
			else
				index += ins->mSrc[1].mVarIndex + proc->mLocalSize + 2;
			index += mFrameOffset;

			if (ins->mSrc[0].IsUByte() && ins->mSrc[0].mRange.mMaxValue + index < 256 && !isub && index >= 0)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_ZERO_PAGE, areg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
			}
			else
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, areg + 1));
				if (ins->mSrc[0].IsUByte())
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
				else
					mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));

				if (index != 0)
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, dreg + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, dreg + 1));
				}
			}
		}
	}
	else
	{
		bool	crossing = true;
		if (ins->mSrc[1].mMemoryBase == IM_GLOBAL && ins->mSrc[1].mLinkerObject && (ins->mSrc[1].mLinkerObject->mFlags & LOBJF_NEVER_CROSS))
			crossing = false;
		else if (ins->mSrc[1].mMemoryBase == IM_ABSOLUTE && ins->mSrc[1].mRange.IsBound() && ins->mDst.mRange.IsBound() && 
			((ins->mSrc[1].mRange.mMinValue ^ ins->mDst.mRange.mMaxValue) & ~0xff) == 0 &&
			((ins->mSrc[1].mRange.mMaxValue ^ ins->mDst.mRange.mMinValue) & ~0xff) == 0)
			crossing = false;

		if (ins->mSrc[0].mTemp >= 0 || ins->mSrc[0].mIntConst != 0)
			mIns.Push(NativeCodeInstruction(ins, isub ? ASMIT_SEC : ASMIT_CLC, ASMIM_IMPLIED));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]));

		if (ins->mSrc[0].mTemp < 0)
		{
			if (ins->mSrc[0].mIntConst)
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
		}
		else if (ins->mSrc[0].IsUByte())
			mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg], nullptr, NCIF_LOWER | NCIF_UPPER, 0, int(ins->mSrc[0].mRange.mMinValue), int(ins->mSrc[0].mRange.mMaxValue)));
		else
			mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg]));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]));

		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp] + 1));

		if (crossing)
		{
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[0].mIntConst)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
			}
			else if (ins->mSrc[0].IsUByte())
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_IMMEDIATE, 0));
			else
				mIns.Push(NativeCodeInstruction(ins, iop, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ireg] + 1));
		}

		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
	}
}

void NativeCodeBasicBlock::CallFunction(InterCodeProcedure* proc, NativeCodeProcedure * nproc, const InterInstruction * ins)
{
	if (ins->mSrc[0].mTemp < 0)
	{
		if (ins->mSrc[0].mLinkerObject)
		{
			NativeCodeInstruction	lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_LOWER);
			NativeCodeInstruction	hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, NCIF_UPPER);

			mIns.Push(lins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
			mIns.Push(hins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		}
		else
		{
			NativeCodeInstruction	lins(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff);
			NativeCodeInstruction	hins(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff);

			mIns.Push(lins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
			mIns.Push(hins);
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
		}
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
	}

	NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec")));
	mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_FEXEC));

	if (ins->mDst.mTemp >= 0)
	{
		if (ins->mDst.mType == IT_FLOAT)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		}
		else
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
			if (InterTypeSize[ins->mDst.mType] > 1)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			}
			if (InterTypeSize[ins->mDst.mType] > 2)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
			}
		}
	}
}


void NativeCodeBasicBlock::DisassembleBody(FILE* file)
{
	fprintf(file, "L%d: (", mIndex);
	bool	first = true;
	if (mEntryRequiredRegs.Size() > 0)
	{
		for (int i = 0; i < 256; i++)
		{
			if (mEntryRequiredRegs[i])
			{
				fprintf(file, "%02x", i);
				if (!first)
					fprintf(file, ", ");
				first = false;
			}
		}
	}

	fprintf(file, ")");

	if (mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
	{
		fprintf(file, ",C=%d", mNDataSet[CPU_REG_C].mValue);
	}
	if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
	{
		fprintf(file, ",Z=%d", mNDataSet[CPU_REG_Z].mValue);
	}
	fprintf(file, "\n");

	for (int i = 0; i < mIns.Size(); i++)
	{
		fprintf(file, "%03d (%4d) ", i, mIns[i].mIns ? mIns[i].mIns->mLocation.mLine : 0);
		mIns[i].Disassemble(file);
		fprintf(file, "\n");
	}
	fprintf(file, "%03d (%4d) %s", mIns.Size(), mBranchIns ? mBranchIns->mLocation.mLine : 0, AsmInstructionNames[mBranch]);
	if (mTrueJump)
	{
		fprintf(file, " L%d", mTrueJump->mIndex);
		if (mFalseJump)
			fprintf(file, ", L%d", mFalseJump->mIndex);
	}
	fprintf(file, "\n");
}

void NativeCodeBasicBlock::Disassemble(FILE* file)
{
	if (!mVisited)
	{
		mVisited = true;

		DisassembleBody(file);

		if (mTrueJump) mTrueJump->Disassemble(file);
		if (mFalseJump) mFalseJump->Disassemble(file);
	}
}


NativeCodeInstruction NativeCodeBasicBlock::DecodeNative(const InterInstruction* ins, LinkerObject* lobj, int& offset) const
{
	uint8	op = lobj->mData[offset++];

	AsmInsData			d = DecInsData[op];
	int					address = 0;
	LinkerObject	*	linkerObject = nullptr;
	uint32				flags = NCIF_LOWER | NCIF_UPPER;
	LinkerReference	*	lref;

	switch (d.mMode)
	{
	case ASMIM_ABSOLUTE:
	case ASMIM_ABSOLUTE_X:
	case ASMIM_ABSOLUTE_Y:
	case ASMIM_INDIRECT:
		lref = lobj->FindReference(offset);
		address = lobj->mData[offset++];
		address += lobj->mData[offset++] << 8;
		if (lref)
		{
			linkerObject = lref->mRefObject;
			address = lref->mRefOffset;
		}
		else if (d.mType != ASMIT_JSR)
			flags |= NCIF_VOLATILE;
		break;
	case ASMIM_ZERO_PAGE:
	case ASMIM_ZERO_PAGE_X:
	case ASMIM_ZERO_PAGE_Y:
	case ASMIM_INDIRECT_X:
	case ASMIM_INDIRECT_Y:
		lref = lobj->FindReference(offset);
		address = lobj->mData[offset++];
		if (lref && (lref->mFlags & LREF_TEMPORARY))
			address += lobj->mTemporaries[lref->mRefOffset];
		else if (lref)
		{
			linkerObject = lref->mRefObject;
			address = lref->mRefOffset;
		}
		else if (address >= BC_REG_TMP || d.mMode == ASMIM_ZERO_PAGE && address <= 0x01)
			flags |= NCIF_VOLATILE;
		break;
	case ASMIM_RELATIVE:
		address = lobj->mData[offset++];
		address += offset;
		break;
	case ASMIM_IMMEDIATE:
		lref = lobj->FindReference(offset);
		address = lobj->mData[offset++];
		if (lref)
		{
			if (lref->mFlags & LREF_TEMPORARY)
			{
				address = lobj->mTemporaries[lref->mRefOffset];
				flags |= NICF_TMPREF | NCIF_LOWER;
				if (lobj->mTempSizes[lref->mRefOffset] > 1)
					flags |= NCIF_UPPER;
			}
			else
			{
				d.mMode = ASMIM_IMMEDIATE_ADDRESS;
				linkerObject = lref->mRefObject;
				address = lref->mRefOffset;
				if (lref->mFlags & LREF_LOWBYTE)
					flags = NCIF_LOWER;
				else
					flags = NCIF_UPPER;
			}
		}
		break;
	}

	return NativeCodeInstruction(ins, d.mType, d.mMode, address, linkerObject, flags);
}


void NativeCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, NativeCodeProcedure * nproc, const InterInstruction* ins)
{
	if (ins->mCode == IC_ASSEMBLER)
	{
		if (ins->mNumOperands > 1 && ins->mSrc[0].mLinkerObject->mNumTemporaries)
		{
			ins->mSrc[0].mLinkerObject = ins->mSrc[0].mLinkerObject->CloneAssembler(proc->mModule->mLinker);
		}

		for (int i = 1; i < ins->mNumOperands; i++)
		{
			if (ins->mSrc[i].mTemp < 0)
			{
				if (ins->mSrc[i].mMemory == IM_FPARAM || ins->mSrc[i].mMemory == IM_FFRAME)
					ins->mSrc[0].mLinkerObject->mTemporaries[i - 1] = BC_REG_FPARAMS + ins->mSrc[i].mVarIndex + int(ins->mSrc[i].mIntConst);
			}
			else
				ins->mSrc[0].mLinkerObject->mTemporaries[i - 1] = BC_REG_TMP + proc->mTempOffset[ins->mSrc[i].mTemp];
			ins->mSrc[0].mLinkerObject->mTempSizes[i - 1] = InterTypeSize[ins->mSrc[i].mType];
		}
		ins->mSrc[0].mLinkerObject->mNumTemporaries = ins->mNumOperands - 1;
	}

	uint32	lf = 0;

	if (ins->mSrc[0].mTemp < 0)
	{
		uint32	flags = NCIF_LOWER | NCIF_UPPER;
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_A)
		{
			flags |= NCIF_USE_CPU_REG_A;
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS));
		}
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_X)
		{
			flags |= NCIF_USE_CPU_REG_X;
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + 1));
		}
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_ARG_REG_Y)
			flags |= NCIF_USE_CPU_REG_Y;

		uint32	pflags = 0;
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_PRESERVE_REG_A)
			pflags |= NCIF_PRESERVE_CPU_REG_A;
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_PRESERVE_REG_X)
			pflags |= NCIF_PRESERVE_CPU_REG_X;
		if (ins->mSrc[0].mLinkerObject->mFlags & LOBJF_PRESERVE_REG_Y)
			pflags |= NCIF_PRESERVE_CPU_REG_Y;

		assert(ins->mSrc[0].mLinkerObject);

		if (ins->mCode == IC_ASSEMBLER && (proc->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER) && ins->mSrc[0].mLinkerObject->mSection == proc->mLinkerObject->mSection && !ins->mVolatile)
		{
			ExpandingArray<NativeCodeInstruction>	tains;

			uint32	uflags = 0;

			bool	simple = true, jsrs = false;
			int i = 0;
			while (i < ins->mSrc[0].mLinkerObject->mSize)
			{
				NativeCodeInstruction	dins = DecodeNative(ins, ins->mSrc[0].mLinkerObject, i);
				if (dins.mMode == ASMIM_RELATIVE)
					simple = false;
				if (dins.mType == ASMIT_JMP)
					simple = false;
				if (dins.mType == ASMIT_RTS && i != ins->mSrc[0].mLinkerObject->mSize)
					simple = false;
				if (dins.mType == ASMIT_JSR)
				{
					dins.mFlags |= uflags | NCIF_JSRFLAGS;
					jsrs = true;
				}

				if (dins.mType == ASMIT_BRK || dins.mMode == ASMIM_INDIRECT_X || dins.mMode == ASMIM_INDIRECT || 
					dins.mType == ASMIT_SEI || dins.mType == ASMIT_CLI || dins.mType == ASMIT_SED || dins.mType == ASMIT_CLD ||
					dins.mType == ASMIT_RTI || dins.mType == ASMIT_TXS || dins.mType == ASMIT_TSX ||
					dins.mType == ASMIT_PHP || dins.mType == ASMIT_PLP || dins.mType == ASMIT_PHA || dins.mType == ASMIT_PLA)
					simple = false;
				if (dins.mFlags & NCIF_VOLATILE)
					simple = false;

				if (dins.mMode == ASMIM_ZERO_PAGE)
				{
					if (dins.mAddress >= BC_REG_WORK && dins.mAddress < BC_REG_WORK + 8)
						uflags |= NICF_USE_WORKREGS;
					else if (dins.mLinkerObject)
						dins.mMode = ASMIM_ABSOLUTE;				// Make sure we are not aliasing zeropage globals
				}

				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;
				if (dins.ChangesCarry())
					uflags |= NCIF_USE_CPU_REG_C;
				tains.Push(dins);
			}
			
			if (simple)
			{
				if (jsrs && (uflags & (NCIF_USE_CPU_REG_A | NCIF_USE_CPU_REG_X | NCIF_USE_CPU_REG_Y)))
				{
					int	live = 0;
					for (int i = tains.Size() - 1; i >= 0; i--)
					{
						if (tains[i].mType == ASMIT_JSR)
						{
							if (live & LIVE_CPU_REG_A)
								tains[i].mFlags |= NCIF_PROVIDE_CPU_REG_A;
							if (live & LIVE_CPU_REG_X)
								tains[i].mFlags |= NCIF_PROVIDE_CPU_REG_X;
							if (live & LIVE_CPU_REG_Y)
								tains[i].mFlags |= NCIF_PROVIDE_CPU_REG_Y;
							tains[i].mFlags |= pflags;
							live = 0;
						}
						else
						{
							if (tains[i].ChangesAccu())
								live &= ~LIVE_CPU_REG_A;
							if (tains[i].ChangesXReg())
								live &= ~LIVE_CPU_REG_X;
							if (tains[i].ChangesYReg())
								live &= ~LIVE_CPU_REG_Y;
							if (tains[i].RequiresAccu())
								live |= LIVE_CPU_REG_A;
							if (tains[i].RequiresXReg())
								live |= LIVE_CPU_REG_X;
							if (tains[i].RequiresYReg())
								live |= LIVE_CPU_REG_Y;
						}
					}
				}

				for (int i = 0; i + 1 < tains.Size(); i++)
					mIns.Push(tains[i]);
			}
			else
				mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));
		}
		else
			mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst, ins->mSrc[0].mLinkerObject, flags));

		lf = ins->mSrc[0].mLinkerObject->mFlags;
	}
	else
	{
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

		NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("bcexec")));
		mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_FEXEC));
	}

	if (ins->mDst.mTemp >= 0)
	{
		if (ins->mDst.mType == IT_FLOAT)
		{
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
		}
		else
		{
			if (!(lf & LOBJF_RET_REG_A))
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
			mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0));
			if (InterTypeSize[ins->mDst.mType] > 1)
			{
				if (lf & LOBJF_RET_REG_X)
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
				else
				{
					mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1));
				}
			}
			if (InterTypeSize[ins->mDst.mType] > 2)
			{
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 2));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));
				mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 3));
			}
		}
	}
}

void NativeCodeBasicBlock::BuildLocalRegSets(void)
{
	int i;

	if (!mVisited)
	{
		mVisited = true;

		mLocalRequiredRegs.Reset(NUM_REGS);
		mLocalProvidedRegs.Reset(NUM_REGS);

		mEntryRequiredRegs.Reset(NUM_REGS);
		mEntryProvidedRegs.Reset(NUM_REGS);
		mExitRequiredRegs.Reset(NUM_REGS);
		mExitProvidedRegs.Reset(NUM_REGS);

		if (mEntryRegA)
			mLocalProvidedRegs += CPU_REG_A;
		if (mEntryRegX)
			mLocalProvidedRegs += CPU_REG_X;
		if (mEntryRegY)
			mLocalProvidedRegs += CPU_REG_Y;

		for (i = 0; i < mIns.Size(); i++)
		{
			mIns[i].FilterRegUsage(mLocalRequiredRegs, mLocalProvidedRegs);
		}

		switch (mBranch)
		{
		case ASMIT_BCC:
		case ASMIT_BCS:
			if (!mLocalProvidedRegs[CPU_REG_C])
				mLocalRequiredRegs += CPU_REG_C;
			break;
		case ASMIT_BEQ:
		case ASMIT_BNE:
		case ASMIT_BMI:
		case ASMIT_BPL:
			if (!mLocalProvidedRegs[CPU_REG_Z])
				mLocalRequiredRegs += CPU_REG_Z;
			break;
		}

		if (mExitRegA)
		{
			if (!mLocalProvidedRegs[CPU_REG_A])
				mLocalRequiredRegs += CPU_REG_A;
		}
		if (mExitRegX)
		{
			if (!mLocalProvidedRegs[CPU_REG_X])
				mLocalRequiredRegs += CPU_REG_X;
		}

		mEntryRequiredRegs = mLocalRequiredRegs;
		mExitProvidedRegs = mLocalProvidedRegs;

		if (mTrueJump) mTrueJump->BuildLocalRegSets();
		if (mFalseJump) mFalseJump->BuildLocalRegSets();
	}

}

void NativeCodeBasicBlock::BuildGlobalProvidedRegSet(NumberSet fromProvidedRegs)
{
	if (!mVisited || !(fromProvidedRegs <= mEntryProvidedRegs))
	{
		mEntryProvidedRegs |= fromProvidedRegs;
		fromProvidedRegs |= mExitProvidedRegs;

		mVisited = true;

		if (mTrueJump) mTrueJump->BuildGlobalProvidedRegSet(fromProvidedRegs);
		if (mFalseJump) mFalseJump->BuildGlobalProvidedRegSet(fromProvidedRegs);
	}

}

bool NativeCodeBasicBlock::BuildGlobalRequiredRegSet(NumberSet& fromRequiredRegs)
{
	bool revisit = false;

	if (!mVisited)
	{
		mVisited = true;

		mNewRequiredRegs = mExitRequiredRegs;

		if (mTrueJump && mTrueJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true;
		if (mFalseJump && mFalseJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true;

		if (!(mNewRequiredRegs <= mExitRequiredRegs))
		{
			revisit = true;

			mExitRequiredRegs = mNewRequiredRegs;
			mNewRequiredRegs -= mLocalProvidedRegs;
			mEntryRequiredRegs |= mNewRequiredRegs;
		}

	}

	fromRequiredRegs |= mEntryRequiredRegs;

	return revisit;

}

bool NativeCodeBasicBlock::RemoveUnusedResultInstructions(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		NumberSet		requiredRegs(mExitRequiredRegs);
		int i;

		switch (mBranch)
		{
		case ASMIT_BCC:
		case ASMIT_BCS:
			requiredRegs += CPU_REG_C;
			break;
		case ASMIT_BEQ:
		case ASMIT_BNE:
		case ASMIT_BMI:
		case ASMIT_BPL:
			requiredRegs += CPU_REG_Z;
			break;
		}

		for (i = mIns.Size() - 1; i >= 0; i--)
		{
			if (mIns[i].mType != ASMIT_NOP && !mIns[i].IsUsedResultInstructions(requiredRegs))
			{
				if (i > 0 && mIns[i - 1].mMode == ASMIM_RELATIVE && mIns[i - 1].mAddress > 0)
				{
					mIns[i - 1].mType = ASMIT_NOP;
					mIns[i - 1].mMode = ASMIM_IMPLIED;
				}
				mIns[i].mType = ASMIT_NOP;
				mIns[i].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (mTrueJump)
		{
			if (mTrueJump->RemoveUnusedResultInstructions())
				changed = true;
		}
		if (mFalseJump)
		{
			if (mFalseJump->RemoveUnusedResultInstructions())
				changed = true;
		}
	}

	return changed;
}

bool NativeCodeBasicBlock::RemoveUnusedBitOps(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool			usesC = false;
		int				usesZ = 0x00;
		int				usesA = mExitRequiredRegs[CPU_REG_A] ? 0xff : 0x0;
		int				usesX = mExitRequiredRegs[CPU_REG_X] ? 0xff : 0x0;
		int				usesY = mExitRequiredRegs[CPU_REG_Y] ? 0xff : 0x0;

		if (mExitRequiredRegs[CPU_REG_C])
			usesC = true;
		if (mExitRequiredRegs[CPU_REG_Z])
			usesZ = true;

		switch (mBranch)
		{
		case ASMIT_BCC:
		case ASMIT_BCS:
			usesC = true;
			break;
		case ASMIT_BEQ:
		case ASMIT_BNE:
			usesZ = 0xff;
			break;
		case ASMIT_BMI:
		case ASMIT_BPL:
			usesZ = 0x80;
			break;
		}

		for (int i = mIns.Size() - 1; i >= 0; i--)
		{
			NativeCodeInstruction& ins(mIns[i]);

			switch (ins.mType)
			{
			case ASMIT_TAX:
				usesA |= usesX | usesZ;
				usesX = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_TXA:
				usesX |= usesA | usesZ;
				usesA = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_TAY:
				usesA |= usesY | usesZ;
				usesY = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_TYA:
				usesY |= usesA | usesZ;
				usesA = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_LDA:
				usesA = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_LDX:
				usesX = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_LDY:
				usesY = 0x00;
				usesZ = 0x00;
				break;
			case ASMIT_JSR:
				usesA = usesX = usesY = 0xff;
				usesZ = 0x00;
				usesC = false;
				break;
			case ASMIT_AND:
				if (ins.mMode == ASMIM_IMMEDIATE)
				{
					if (!usesZ && ins.mAddress == usesA)
					{
						ins.mType = ASMIT_NOP;
						ins.mMode = ASMIM_IMPLIED;
					}
					else
						usesA = ins.mAddress;
				}
				else
					usesA = 0xff;
				usesZ = 0x00;
				break;
			case ASMIT_ORA:
				if (ins.mMode == ASMIM_IMMEDIATE)
					usesA = ins.mAddress ^ 255;
				else
					usesA = 0xff;
				break;
				usesZ = 0x00;
			case ASMIT_ASL:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (usesZ) usesA = 0xff;
					usesA = (usesA >> 1);
					if (usesC)
						usesA |= 0x80;
				}
				usesC = false;
				usesZ = 0x00;
				break;
			case ASMIT_LSR:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (usesZ) usesA = 0xff;
					usesA = (usesA << 1) & 0xff;
					if (usesC)
						usesA |= 0x01;
				}
				usesC = false;
				usesZ = 0x00;
				break;
			case ASMIT_ROL:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (usesZ) usesA = 0xff;
					if (usesA || usesC)
					{
						bool	nc = usesA & 0x01;
						usesA = (usesA >> 1);
						if (usesC)
							usesA |= 0x80;
						usesC = nc;
					}
					else
					{
						ins.mType = ASMIT_NOP;
						changed = true;
					}
				}
				else
					usesC = true;
				usesZ = 0x00;
				break;
			case ASMIT_ROR:
			{
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (usesZ) usesA = 0xff;
					if (usesA || usesC)
					{
						bool	nc = usesA & 0x80;
						usesA = (usesA << 1) & 0xff;
						if (usesC)
							usesA |= 0x01;
						usesC = nc;
					}
					else
					{
						ins.mType = ASMIT_NOP;
						changed = true;
					}
				}
				else
					usesC = true;
				usesZ = 0x00;
			}	break;
			case ASMIT_ADC:
				if (ins.mMode == ASMIM_IMMEDIATE && ins.mAddress == 0)
				{
					if (usesC || usesZ)
						usesA = 0xff;
					else
						usesA = BinMask(usesA);
				}
				else
					usesA = 0xff;
				usesC = true;
				usesZ = 0x00;
				break;
			case ASMIT_CLC:
			case ASMIT_SEC:
				usesC = false;
				break;
			default:
				if (ins.ReferencesAccu())
					usesA = 0xff;
				if (ins.ReferencesXReg())
					usesX = 0xff;
				if (ins.ReferencesYReg())
					usesY = 0xff;
				if (ins.ReferencesCarry())
					usesC = true;
				if (ins.ChangesZFlag())
					usesZ = 0x00;
				break;
			}

			switch (ins.mMode)
			{
			case ASMIM_ABSOLUTE_X:
			case ASMIM_ZERO_PAGE_X:
			case ASMIM_INDIRECT_X:
				usesX = 0xff;
				break;
			case ASMIM_ABSOLUTE_Y:
			case ASMIM_ZERO_PAGE_Y:
			case ASMIM_INDIRECT_Y:
				usesY = 0xff;
				break;
			}
		}

		if (mTrueJump && mTrueJump->RemoveUnusedBitOps())
			changed = true;
		if (mFalseJump && mFalseJump->RemoveUnusedBitOps())
			changed = true;
	}

	return changed;
}


void NativeCodeBasicBlock::BuildCollisionTable(NumberSet* collisionSets)
{
	if (!mVisited)
	{
		mVisited = true;

		NumberSet		requiredTemps(mExitRequiredRegs);
		int i, j;

		for (i = 0; i < mExitRequiredRegs.Size(); i++)
		{
			if (mExitRequiredRegs[i])
			{
				for (j = 0; j < mExitRequiredRegs.Size(); j++)
				{
					if (mExitRequiredRegs[j])
					{
						collisionSets[i] += j;
					}
				}
			}
		}

		for (i = mIns.Size() - 1; i >= 0; i--)
		{
			mIns[i].BuildCollisionTable(requiredTemps, collisionSets);
		}

		if (mTrueJump) mTrueJump->BuildCollisionTable(collisionSets);
		if (mFalseJump) mFalseJump->BuildCollisionTable(collisionSets);
	}
}

void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from, DominatorStacks& stacks)
{
	if (from == this)
		return;
	else if (!mDominator)
		mDominator = from;
	else if (from == mDominator)
		return;
	else
	{
		stacks.d1.SetSize(0);
		stacks.d2.SetSize(0);

		NativeCodeBasicBlock* b = mDominator;
		while (b)
		{
			stacks.d1.Push(b);
			b = b->mDominator;
		}
		b = from;
		while (b)
		{
			stacks.d2.Push(b);
			b = b->mDominator;
		}

		b = nullptr;
		while (stacks.d1.Size() > 0 && stacks.d2.Size() > 0 && stacks.d1.Last() == stacks.d2.Last())
		{
			b = stacks.d1.Pop(); stacks.d2.Pop();
		}

		if (mDominator == b)
			return;

		mDominator = b;
	}

	if (mTrueJump)
		mTrueJump->BuildDominatorTree(this, stacks);
	if (mFalseJump)
		mFalseJump->BuildDominatorTree(this, stacks);
}


void NativeCodeBasicBlock::CountEntries(NativeCodeBasicBlock * fromJump)
{
	if (mVisiting)
		mLoopHead = true;

	if (mNumEntries == 0)
		mFromJump = fromJump;
	else
		mFromJump = nullptr;
	mNumEntries++;

	if (!mVisited)
	{
		mVisited = true;
		mVisiting = true;

		if (mTrueJump)
			mTrueJump->CountEntries(this);
		if (mFalseJump)
			mFalseJump->CountEntries(this);

		mVisiting = false;
	}
}

bool NativeCodeBasicBlock::IsSame(const NativeCodeBasicBlock* block) const
{
	if (block->mIns.Size() != mIns.Size())
		return false;

	if (block->mBranch != mBranch)
		return false;

	if (mTrueJump)
	{
		if (!block->mTrueJump)
			return false;

		if (mTrueJump == this)
		{
			if (block->mTrueJump != block)
				return false;
		}
		else if (mTrueJump != block->mTrueJump)
			return false;
	}
	else if (block->mTrueJump)
		return false;

	if (mFalseJump)
	{
		if (!block->mFalseJump)
			return false;

		if (mFalseJump == this)
		{
			if (block->mFalseJump != block)
				return false;
		}
		else if (mFalseJump != block->mFalseJump)
			return false;
	}
	else if (block->mFalseJump)
		return false;

	for (int i = 0; i < mIns.Size(); i++)
		if (!mIns[i].IsSame(block->mIns[i]))
			return false;

	return true;
}

bool NativeCodeBasicBlock::FindSameBlocks(NativeCodeProcedure* nproc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (!mSameBlock && this != mProc->mEntryBlock)
		{
			for (int i = 0; i < nproc->mBlocks.Size(); i++)
			{
				if (nproc->mBlocks[i] != this && nproc->mBlocks[i]->IsSame(this))
				{
					nproc->mBlocks[i]->mSameBlock = this;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->FindSameBlocks(nproc))
			changed = true;
		if (mFalseJump && mFalseJump->FindSameBlocks(nproc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MergeSameBlocks(NativeCodeProcedure* nproc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (this == mProc->mEntryBlock && mSameBlock && mIns.Size() > 1)
		{
			mTrueJump = mSameBlock;
			mFalseJump = nullptr;
			mBranch = ASMIT_JMP;
			mIns.SetSize(0);
			changed = true;
			mSameBlock = nullptr;
		}

		if (mTrueJump && mTrueJump->mSameBlock)
		{
			mTrueJump = mTrueJump->mSameBlock;
			changed = true;
		}

		if (mFalseJump && mFalseJump->mSameBlock)
		{
			mFalseJump = mFalseJump->mSameBlock;
			changed = true;
		}

		if (mTrueJump && mTrueJump->MergeSameBlocks(nproc))
			changed = true;
		if (mFalseJump && mFalseJump->MergeSameBlocks(nproc))
			changed = true;
	}

	return changed;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::ForwardAccuBranch(bool eq, bool ne, bool pl, bool mi, int limit)
{
	if (limit == 4)
		return this;
	limit++;

	if (mIns.Size() == 0 && mNumEntries == 1 || mIns.Size() == 1 && mIns[0].mType == ASMIT_ORA && mIns[0].mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == 0)
	{
		if (mBranch == ASMIT_BEQ)
		{
			if (eq)
				return mTrueJump->ForwardAccuBranch(true, false, true, false, limit);
			if (ne || mi)
				return mFalseJump->ForwardAccuBranch(false, true, pl, mi, limit);
		}
		else if (mBranch == ASMIT_BNE)
		{
			if (eq)
				return mFalseJump->ForwardAccuBranch(true, false, true, false, limit);
			if (ne || mi)
				return mTrueJump->ForwardAccuBranch(false, true, pl, mi, limit);
		}
		else if (mBranch == ASMIT_BPL)
		{
			if (eq || pl)
				return mTrueJump->ForwardAccuBranch(eq, ne, true, false, limit);
			if (mi)
				return mFalseJump->ForwardAccuBranch(false, true, false, true, limit);
		}
		else if (mBranch == ASMIT_BMI)
		{
			if (eq || pl)
				return mFalseJump->ForwardAccuBranch(eq, ne, true, false, limit);
			if (mi)
				return mTrueJump->ForwardAccuBranch(false, true, false, true, limit);
		}
	}

	return this;
}


NativeCodeBasicBlock* NativeCodeBasicBlock::UniqueEntryBlock(NativeCodeBasicBlock* prefix)
{
	if (mNumEntries > 1)
		return PrefixLoopBlock(prefix);
	else
		return this;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::PrefixLoopBlock(NativeCodeBasicBlock* prefix)
{
	NativeCodeBasicBlock* block = mProc->AllocateBlock();
	
	block->mTrueJump = this;
	block->mBranch = ASMIT_JMP;
	if (this == prefix->mTrueJump)
		prefix->mTrueJump = block;
	else
		prefix->mFalseJump = block;
	block->mEntryBlocks.Push(prefix);
	block->mNumEntries = 1;
	mEntryBlocks.RemoveAll(prefix);
	mEntryBlocks.Push(block);

	block->mEntryRequiredRegs = block->mExitRequiredRegs = mEntryRequiredRegs;

	return block;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::CloneBlock(void)
{
	NativeCodeBasicBlock* block = mProc->AllocateBlock();

	block->mTrueJump = mTrueJump;
	block->mFalseJump = mFalseJump;
	block->mBranch = mBranch;
	block->mBranchIns = mBranchIns;

	if (mTrueJump)
	{
		mTrueJump->mEntryBlocks.RemoveAll(this);
		mTrueJump->mEntryBlocks.Push(block);
	}
	if (mFalseJump)
	{
		mFalseJump->mEntryBlocks.RemoveAll(this);
		mFalseJump->mEntryBlocks.Push(block);
	}

	block->mNumEntries = 1;
	block->mEntryBlocks.Push(this);

	for (int i = 0; i < mIns.Size(); i++)
		block->mIns.Push(mIns[i]);

	block->mEntryRequiredRegs = mEntryRequiredRegs;
	block->mExitRequiredRegs = mExitRequiredRegs;
	block->mEntryProvidedRegs = mEntryProvidedRegs;
	block->mExitProvidedRegs = mExitProvidedRegs;

	return block;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::SplitBlock(int at)
{
	NativeCodeBasicBlock* block = mProc->AllocateBlock();
	block->mTrueJump = mTrueJump;
	block->mFalseJump = mFalseJump;
	block->mBranch = mBranch;
	block->mBranchIns = mBranchIns;

	if (mTrueJump)
	{
		mTrueJump->mEntryBlocks.RemoveAll(this);
		mTrueJump->mEntryBlocks.Push(block);
	}
	if (mFalseJump)
	{
		mFalseJump->mEntryBlocks.RemoveAll(this);
		mFalseJump->mEntryBlocks.Push(block);
	}

	block->mNumEntries = 1;
	block->mEntryBlocks.Push(this);
	mTrueJump = block;
	mFalseJump = nullptr;
	mBranch = ASMIT_JMP;

	for (int i = at; i < mIns.Size(); i++)
		block->mIns.Push(mIns[i]);
	mIns.SetSize(at);

	return block;
}

bool NativeCodeBasicBlock::RemoveJumpToBranch(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mTrueJump->RemoveJumpToBranch()) changed = true;
		if (mFalseJump && mFalseJump->RemoveJumpToBranch()) changed = true;

		if (mTrueJump && !mFalseJump && mTrueJump != this && mTrueJump->mIns.Size() == 0 && (mTrueJump->mFalseJump || mTrueJump->mTrueJump != mTrueJump))
		{
			mTrueJump->mEntryBlocks.RemoveAll(this);
			mTrueJump->mNumEntries--;
			mBranch = mTrueJump->mBranch;
			mFalseJump = mTrueJump->mFalseJump;
			mTrueJump = mTrueJump->mTrueJump;
			if (mTrueJump)
			{
				mTrueJump->mNumEntries++;
				mTrueJump->mEntryBlocks.Push(this);
			}
			if (mFalseJump)
			{
				mFalseJump->mNumEntries++;
				mFalseJump->mEntryBlocks.Push(this);
			}
			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;
			}

			int steps = 100;
			while (mTrueJump && mTrueJump->mIns.Size() == 0 && !mTrueJump->mFalseJump && !mTrueJump->mLocked && mTrueJump != this && mTrueJump->mTrueJump != mTrueJump && steps > 0)
			{
				mTrueJump->mNumEntries--;
				mTrueJump = mTrueJump->mTrueJump;
				mTrueJump->mNumEntries++;
				changed = true;
				steps--;
			}

			steps = 100;
			while (mFalseJump && mFalseJump->mTrueJump && mFalseJump->mIns.Size() == 0 && !mFalseJump->mFalseJump && !mFalseJump->mLocked && mFalseJump != this && mFalseJump->mTrueJump != mFalseJump && steps > 0)
			{
				mFalseJump->mNumEntries--;
				mFalseJump = mFalseJump->mTrueJump;
				mFalseJump->mNumEntries++;
				changed = true;
				steps--;
			}

			if (mTrueJump && mTrueJump == mFalseJump)
			{
				mBranch = ASMIT_JMP;
				mFalseJump = nullptr;
				changed = true;
			}
#if 1
			if (mIns.Size() > 0 && mIns.Last().ChangesAccuAndFlag() && mTrueJump && mFalseJump)
			{
				NativeCodeBasicBlock* ntb = mTrueJump, * nfb = mFalseJump;

				if (mBranch == ASMIT_BEQ)
				{
					ntb = ntb->ForwardAccuBranch(true, false, true, false, 0);
					nfb = nfb->ForwardAccuBranch(false, true, false, false, 0);
				}
				else if (mBranch == ASMIT_BNE)
				{
					nfb = nfb->ForwardAccuBranch(true, false, true, false, 0);
					ntb = ntb->ForwardAccuBranch(false, true, false, false, 0);
				}
				else if (mBranch == ASMIT_BPL)
				{
					ntb = ntb->ForwardAccuBranch(false, false, true, false, 0);
					nfb = nfb->ForwardAccuBranch(false, true, false, true, 0);
				}
				else if (mBranch == ASMIT_BMI)
				{
					nfb = nfb->ForwardAccuBranch(false, false, true, false, 0);
					ntb = ntb->ForwardAccuBranch(false, true, false, true, 0);
				}

				if (ntb != mTrueJump)
				{
					mTrueJump->mNumEntries--;
					mTrueJump = ntb;
					mTrueJump->mNumEntries++;
					changed = true;
				}

				if (nfb != mFalseJump)
				{
					mFalseJump->mNumEntries--;
					mFalseJump = nfb;
					mFalseJump->mNumEntries++;
					changed = true;
				}
			}
#endif
		}

		if (mTrueJump && mTrueJump->MergeBasicBlocks())
			changed = true;
		if (mFalseJump && mFalseJump->MergeBasicBlocks())
			changed = true;

		assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
	}
	return changed;
}

bool NativeCodeBasicBlock::ShortcutBranchSequence(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump && mIns.Size() && mIns.Last().ChangesFlagToAccu())
		{
			NativeCodeBasicBlock* eblock = nullptr, * nblock = nullptr;

			if (mBranch == ASMIT_BEQ)
			{
				eblock = mTrueJump;
				nblock = mFalseJump;
			}
			else if (mBranch == ASMIT_BNE)
			{
				eblock = mFalseJump;
				nblock = mTrueJump;
			}

			if (eblock && nblock)
			{
				int reg = -1;
				if (mIns.Last().mType == ASMIT_LDA && mIns.Last().mMode == ASMIM_ZERO_PAGE)
					reg = mIns.Last().mAddress;

				if (nblock && nblock->mIns.Size() == 1 && nblock->mIns[0].mType == ASMIT_ORA && nblock->mIns[0].mMode == ASMIM_IMMEDIATE && nblock->mIns[0].mAddress == 0)
				{
					NativeCodeBasicBlock* block = mProc->AllocateBlock();
					block->mBranch = nblock->mBranch;
					block->mTrueJump = nblock->mTrueJump;
					block->mFalseJump = nblock->mFalseJump;

					nblock->mEntryBlocks.RemoveAll(this);
					nblock->mNumEntries--;
					
					block->mTrueJump->mEntryBlocks.Push(this);
					block->mTrueJump->mNumEntries++;
					block->mFalseJump->mEntryBlocks.Push(this);
					block->mFalseJump->mNumEntries++;

					block->mNumEntries++;
					block->mEntryBlocks.Push(this);
					if (mTrueJump == nblock)
						mTrueJump = block;
					else
						mFalseJump = block;
					changed = true;
				}
				else if (nblock && nblock->mIns.Size() == 0 && nblock->mNumEntries == 1)
				{
					if (nblock->mBranch == ASMIT_BPL || nblock->mBranch == ASMIT_BMI)
					{
						NativeCodeBasicBlock* tblock = nblock->mTrueJump;
						if (tblock->mFalseJump)
						{
							if (tblock->mIns.Size() == 0 ||
								tblock->mIns.Size() == 1 && tblock->mIns[0].mType == ASMIT_LDA && tblock->mIns[0].mMode == ASMIM_ZERO_PAGE && tblock->mIns[0].mAddress == reg)
							{
								if (tblock->mBranch == ASMIT_BEQ)
								{
									tblock->mNumEntries--;
									tblock->mEntryBlocks.RemoveAll(nblock);
									nblock->mTrueJump = tblock->mFalseJump;
									nblock->mTrueJump->mNumEntries++;
									nblock->mTrueJump->mEntryBlocks.Push(nblock);
									changed = true;
								}
								else if (tblock->mBranch == ASMIT_BNE)
								{
									tblock->mNumEntries--;
									tblock->mEntryBlocks.RemoveAll(nblock);
									nblock->mTrueJump = tblock->mTrueJump;
									nblock->mTrueJump->mNumEntries++;
									nblock->mTrueJump->mEntryBlocks.Push(nblock);
									changed = true;
								}
							}
						}

						NativeCodeBasicBlock* fblock = nblock->mFalseJump;
						if (fblock->mFalseJump)
						{
							if (fblock->mIns.Size() == 0 ||
								fblock->mIns.Size() == 1 && fblock->mIns[0].mType == ASMIT_LDA && fblock->mIns[0].mMode == ASMIM_ZERO_PAGE && fblock->mIns[0].mAddress == reg)
							{
								if (fblock->mBranch == ASMIT_BEQ)
								{
									fblock->mNumEntries--;
									fblock->mEntryBlocks.RemoveAll(nblock);
									nblock->mFalseJump = fblock->mFalseJump;
									nblock->mFalseJump->mNumEntries++;
									nblock->mFalseJump->mEntryBlocks.Push(nblock);
									changed = true;
								}
								else if (fblock->mBranch == ASMIT_BNE)
								{
									fblock->mNumEntries--;
									fblock->mEntryBlocks.RemoveAll(nblock);
									nblock->mFalseJump = fblock->mTrueJump;
									nblock->mFalseJump->mNumEntries++;
									nblock->mFalseJump->mEntryBlocks.Push(nblock);
									changed = true;
								}
							}
						}
					}
				}

				if (!changed && mIns.Last().mType == ASMIT_LDA && mIns.Last().mMode == ASMIM_ZERO_PAGE)
				{
					int reg = mIns.Last().mAddress;

					if (nblock && nblock->mIns.Size() == 0 && nblock->mNumEntries == 1)
					{
						if (nblock->mBranch == ASMIT_BPL || nblock->mBranch == ASMIT_BMI)
						{

						}
					}

				}
			}
		}

		if (mTrueJump && mTrueJump->ShortcutBranchSequence())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutBranchSequence())
			changed = true;
	}

	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++)
		{
			// TODO CHECK for uniqueID
			if (set[i].mMode == NRDM_IMMEDIATE)
			{
				if (mEntryRegisterDataSet[i].mMode == NRDM_IMMEDIATE && set[i].mValue == mEntryRegisterDataSet[i].mValue)
				{
				}
				else if (mEntryRegisterDataSet[i].mMode != NRDM_UNKNOWN)
				{
					mEntryRegisterDataSet.Reset(i);
					mVisited = false;
				}
			}
			else if (set[i].mMode == NRDM_IMMEDIATE_ADDRESS)
			{
				if (mEntryRegisterDataSet[i].mMode == NRDM_IMMEDIATE_ADDRESS &&
					set[i].mValue == mEntryRegisterDataSet[i].mValue &&
					set[i].mLinkerObject == mEntryRegisterDataSet[i].mLinkerObject &&
					set[i].mFlags == mEntryRegisterDataSet[i].mFlags)
				{
				}
				else if (mEntryRegisterDataSet[i].mMode != NRDM_UNKNOWN)
				{
					mEntryRegisterDataSet.Reset(i);
					mVisited = false;
				}
			}
			else if (mEntryRegisterDataSet[i].mMode != NRDM_UNKNOWN)
			{
				mEntryRegisterDataSet.Reset(i);
				mVisited = false;
			}
		}
	}

	if (!mVisited)
	{
		mVisited = true;

		mNDataSet = mEntryRegisterDataSet;

		for (int i = 0; i < mIns.Size(); i++)
			mIns[i].Simulate(mNDataSet);

		mFDataSet = mNDataSet;
		if (mBranch == ASMIT_BCC)
		{
			mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
			mFDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
		}
		else if (mBranch == ASMIT_BCS)
		{
			mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
			mFDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
		}

		if (mTrueJump)
			mTrueJump->BuildEntryDataSet(mNDataSet);
		if (mFalseJump)
			mFalseJump->BuildEntryDataSet(mFDataSet);
	}
}

bool NativeCodeBasicBlock::ApplyEntryDataSet(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		mNDataSet = mEntryRegisterDataSet;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].ApplySimulation(mNDataSet))
				changed = true;
			mIns[i].Simulate(mNDataSet);
		}

		if (mTrueJump && mTrueJump->ApplyEntryDataSet())
			changed = true;
		if (mFalseJump && mFalseJump->ApplyEntryDataSet())
			changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu)
{
	if (!mVisited)
	{
		mVisited = true;

		if (mNumEntries > 1)
			accu = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[i].mType == ASMIT_LDA)
					accu = mIns[i].mAddress;
				else if (mIns[i].mType == ASMIT_STA)
				{
					if (accu < 0 || !statics[accu])
						invalid += mIns[i].mAddress;
					else if (alias[mIns[i].mAddress])
					{
						if (alias[mIns[i].mAddress] != accu)
							invalid += mIns[i].mAddress;
					}
					else
					{
						alias[mIns[i].mAddress] = accu;
					}
				}
				else if (mIns[i].ChangesAccu())
					accu = -1;
				else if (mIns[i].ChangesAddress())
					invalid += mIns[i].mAddress;

				if (mIns[i].mFlags & NCIF_ALIASING)
					invalid += mIns[i].mAddress;
			}
			else if (mIns[i].mType == ASMIT_JSR && (mIns[i].mFlags & NCIF_USE_ZP_32_X))
			{
				int j = mIns[i].mParam;
				invalid += j;
				invalid += j + 1;
				invalid += j + 2;
				invalid += j + 3;
				accu = -1;
			}
			else if (mIns[i].ChangesAccu())
				accu = -1;
		}

		if (mTrueJump)
			mTrueJump->FindZeroPageAlias(statics, invalid, alias, accu);
		if (mFalseJump)
			mFalseJump->FindZeroPageAlias(statics, invalid, alias, accu);
	}
}

void NativeCodeBasicBlock::CheckGlobalAliasing(bool& globalStores, bool& globalLoads)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			const NativeCodeInstruction& ins(mIns[i]);
			if (ins.mType == ASMIT_JSR)
			{
				if (ins.mLinkerObject)
				{
					if (!(ins.mLinkerObject->mFlags & LOBJF_NO_GLOBAL_STORES))
						globalStores = true;
					if (!(ins.mLinkerObject->mFlags & LOBJF_NO_GLOBAL_LOADS))
						globalLoads = true;
				}
				else
				{
					globalLoads = true;
					globalStores = true;
				}
			}
			else if (ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y || ins.mMode == ASMIM_INDIRECT)
			{
				if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC || ins.mType == ASMIT_ASL || ins.mType == ASMIT_LSR || ins.mType == ASMIT_ROL || ins.mType == ASMIT_ROR)
				{
					globalLoads = true;
					globalStores = true;
				}
				else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY)
					globalStores = true;
				else
					globalLoads = true;
			}
		}

		if (mTrueJump) mTrueJump->CheckGlobalAliasing(globalStores, globalLoads);
		if (mFalseJump) mFalseJump->CheckGlobalAliasing(globalStores, globalLoads);
	}
}

bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global, bool ignorefcall)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			switch (mIns[i].mMode)
			{
			case ASMIM_ZERO_PAGE:
				if (mIns[i].ChangesAddress())
					locals += mIns[i].mAddress;
				break;
			case ASMIM_ABSOLUTE:
				if (mIns[i].mType == ASMIT_JSR)
				{
					if (mIns[i].mFlags & NCIF_RUNTIME)
					{
						if (mIns[i].mFlags & NCIF_FEXEC)
						{
							if (!ignorefcall)
								return false;
						}
						else
						{
							for (int j = 0; j < 4; j++)
							{
								locals += BC_REG_ACCU + j;
								locals += BC_REG_WORK + j;
							}
						}
					}

					if (mIns[i].mLinkerObject)
					{
						LinkerObject* lo = mIns[i].mLinkerObject;

						if (lo->mFlags & LOBJF_ZEROPAGESET)
						{
							global |= lo->mZeroPageSet;
						}
						else if (!lo->mProc)
						{
							for (int i = 0; i < lo->mNumTemporaries; i++)
							{
								for (int j = 0; j < lo->mTempSizes[i]; j++)
									global += lo->mTemporaries[i] + j;
							}
						}
						else
							return false;
					}
				}
				break;
			case ASMIM_ZERO_PAGE_X:
				if (mIns[i].ChangesAddress())
				{
					if (i > 1 && i + 2 < mIns.Size())
					{
						if (mIns[i - 2].mType == ASMIT_LDX && mIns[i - 2].mMode == ASMIM_IMMEDIATE &&
							mIns[i - 1].mType == ASMIT_LDA &&
							mIns[i + 0].mType == ASMIT_STA &&
							mIns[i + 1].mType == ASMIT_DEX &&
							mIns[i + 2].mType == ASMIT_BPL)
						{
							for (int j = 0; j < mIns[i - 2].mAddress; j++)
								locals += mIns[i].mAddress + j;
						}
					}
				}
				break;
			}
		}

		if (mTrueJump && !mTrueJump->CollectZeroPageSet(locals, global, ignorefcall))
			return false;
		if (mFalseJump && !mFalseJump->CollectZeroPageSet(locals, global, ignorefcall))
			return false;
	}

	return true;
}

void NativeCodeBasicBlock::CollectZeroPageUsage(NumberSet& used, NumberSet &modified, NumberSet& pairs)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			switch (mIns[i].mMode)
			{
			case ASMIM_ZERO_PAGE:
				used += mIns[i].mAddress;
				if (mIns[i].ChangesAddress() || (mIns[i].mFlags & NCIF_ALIASING))
					modified += mIns[i].mAddress;
				break;
			case ASMIM_INDIRECT_Y:
				used += mIns[i].mAddress + 0;
				used += mIns[i].mAddress + 1;
				pairs += mIns[i].mAddress;
				break;
			case ASMIM_ABSOLUTE:
				if (mIns[i].mType == ASMIT_JSR)
				{
					if (mIns[i].mFlags & NCIF_RUNTIME)
					{
						for (int j = 0; j < 4; j++)
						{
							used += BC_REG_ACCU + j;
							used += BC_REG_WORK + j;
							modified += BC_REG_ACCU + j;
							modified += BC_REG_WORK + j;
						}

						if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
						{
							for (int j = 0; j < 4; j++)
								used += mIns[i].mParam + j;
							for (int j = 0; j < 3; j++)
								pairs += mIns[i].mParam + j;
						}
					}

					if (mIns[i].mLinkerObject)
					{
						LinkerObject* lo = mIns[i].mLinkerObject;

						for (int i = 0; i < lo->mNumTemporaries; i++)
						{
							for (int j = 0; j < lo->mTempSizes[i]; j++)
								used += lo->mTemporaries[i] + j;
						}

						if (lo->mProc)
						{
							if (!(mIns[i].mFlags & NCIF_FEXEC) && (lo->mFlags & LOBJF_ZEROPAGESET))
							{
								for (int i = 0; i < 256; i++)
									if (lo->mZeroPageSet[i])
										modified += i;
							}
						}
					}
				}
				break;
			}
		}

		if (mTrueJump)
			mTrueJump->CollectZeroPageUsage(used, modified, pairs);
		if (mFalseJump)
			mFalseJump->CollectZeroPageUsage(used, modified, pairs);
	}
}

void NativeCodeBasicBlock::GlobalRegisterXMap(int reg)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				switch (ins.mType)
				{
				case ASMIT_STA:
					ins.mType = ASMIT_TAX;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_LDA:
					ins.mType = ASMIT_TXA;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_INC:
					ins.mType = ASMIT_INX;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_DEC:
					ins.mType = ASMIT_DEX;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_LDX:
					assert(ins.mAddress == reg);
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					break;
				}
			}
		}

		if (mTrueJump)
			mTrueJump->GlobalRegisterXMap(reg);
		if (mFalseJump)
			mFalseJump->GlobalRegisterXMap(reg);
	}
}

void NativeCodeBasicBlock::GlobalRegisterYMap(int reg)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				switch (ins.mType)
				{
				case ASMIT_STA:
					ins.mType = ASMIT_TAY;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_LDA:
					ins.mType = ASMIT_TYA;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_INC:
					ins.mType = ASMIT_INY;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_DEC:
					ins.mType = ASMIT_DEY;
					ins.mMode = ASMIM_IMPLIED;
					break;
				case ASMIT_LDY:
					assert(ins.mAddress == reg);
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					break;
				}
			}
		}

		if (mTrueJump)
			mTrueJump->GlobalRegisterYMap(reg);
		if (mFalseJump)
			mFalseJump->GlobalRegisterYMap(reg);
	}
}

bool NativeCodeBasicBlock::ReplaceYRegWithXReg(int start, int end)
{
	bool	changed = false;

//	CheckLive();

	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.ReplaceYRegWithXReg())
			changed = true;
	}

//	CheckLive();

	return changed;
}

bool NativeCodeBasicBlock::ReduceLocalYPressure(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

#if 1
		if (mLoopHead && mFalseJump && mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_X] && !mExitRequiredRegs[CPU_REG_X] && mEntryBlocks.Size() == 2 && (mFalseJump == this || mTrueJump == this))
		{
			NativeCodeBasicBlock* pblock, * nblock;
			if (mTrueJump == this)
				nblock = mFalseJump;
			else
				nblock = mTrueJump;
			if (mEntryBlocks[0] == this)
				pblock = mEntryBlocks[1];
			else
				pblock = mEntryBlocks[0];

			if (!pblock->mFalseJump && !nblock->mEntryRequiredRegs[CPU_REG_Y])
			{
				int	pz = pblock->mIns.Size();
				while (pz > 0 && !pblock->mIns[pz - 1].ReferencesYReg() && !pblock->mIns[pz - 1].ReferencesXReg())
					pz--;

				if (mEntryRequiredRegs[CPU_REG_Y] && pz > 0 && pblock->mIns[pz - 1].mType == ASMIT_LDY && pblock->mIns[pz - 1].mMode == ASMIM_IMMEDIATE)
				{
					if (CanReplaceYRegWithXReg(0, mIns.Size()))
					{
						mEntryRequiredRegs += CPU_REG_X; 
						mExitRequiredRegs += CPU_REG_X; 
						pblock->mExitRequiredRegs += CPU_REG_X; pblock->mExitRequiredRegs -= CPU_REG_Y;

						ReplaceYRegWithXReg(0, mIns.Size());

						mEntryRequiredRegs -= CPU_REG_Y;
						mExitRequiredRegs -= CPU_REG_Y;

						pz--;
						pblock->mIns[pz].mType = ASMIT_LDX;
						while (pz < pblock->mIns.Size())
						{
							pblock->mIns[pz].mLive |= LIVE_CPU_REG_X;
							pz++;
						}

						changed = true;
					}
				}
			}
		}
#endif
		int start = 0;
		while (start < mIns.Size())
		{
			const NativeCodeInstruction& ins(mIns[start]);

			if ((ins.mType == ASMIT_LDY || ins.mType == ASMIT_TAY) && ins.mMode != ASMIM_ABSOLUTE_X && !(ins.mLive & LIVE_CPU_REG_X))
			{
				int end = start + 1;
				while (end < mIns.Size())
				{
					const NativeCodeInstruction& eins(mIns[end]);
					if (eins.mType == ASMIT_LDY || eins.mType == ASMIT_TAY)
					{
						ReplaceYRegWithXReg(start, end);
						changed = true;
						break;
					}
					else if (eins.mType == ASMIT_JSR && (eins.mFlags & LOBJF_ARG_REG_Y))
						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) && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				if (aload != -1 && mIns[i].SameEffectiveAddress(mIns[aload]))
				{
					if (aoffset == 0)
					{
						for (int j = apred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_A;

						if (mIns[i].mLive & LIVE_CPU_REG_Z)
						{
							mIns[i].mType = ASMIT_ORA; mIns[i].mMode = ASMIM_IMMEDIATE; mIns[i].mAddress = 0;
						}
						else
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						}
						changed = true;
					}
					else if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
					{
						for (int j = apred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_A;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mAddress = (mIns[i + 2].mAddress - aoffset) & 0xff;
						changed = true;
					}
					else if (carry == 1 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
					{
						for (int j = apred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_A;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mAddress = (mIns[i + 1].mAddress - aoffset) & 0xff;
						changed = true;
					}
					else
					{
						aload = i;
						aoffset = 0;
					}
				}
				else
				{
					aload = i;
					aoffset = 0;
				}

				apred = i;
			}
			else if (mIns[i + 0].mType == ASMIT_CLC)
				carry = 1;
			else if (mIns[i + 0].mType == ASMIT_SEC)
				carry = -1;
			else if (aload != -1 && carry == 1 &&
				mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE)
			{
				aoffset = (aoffset + mIns[i + 0].mAddress) & 0xff;
				apred = i;
				carry = 0;
			}
			else if (aload != -1 && carry == -1 &&
				mIns[i + 0].mType == ASMIT_SBC && mIns[i + 0].mMode == ASMIM_IMMEDIATE)
			{
				aoffset = (aoffset - mIns[i + 0].mAddress) & 0xff;
				apred = i;
			}
			else if (aload != -1 && mIns[i].mType == ASMIT_STA && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && mIns[i].SameEffectiveAddress(mIns[aload]))
			{
				aoffset = 0;
				apred = i;
			}
			else if (aload != -1 && mIns[i].mType == ASMIT_STA && mIns[aload].mMode != ASMIM_ZERO_PAGE&& mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				aload = i;
				aoffset = 0;
				apred = i;
			}
			else
			{
				if (mIns[i].ChangesCarry())
					carry = 0;

				if (aload != -1 && mIns[i].ChangesAccu())
					aload = -1;
			
				if (aload != -1 && mIns[aload].MayBeChangedOnAddress(mIns[i]))
					aload = -1;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->ForwardAccuAddSub())
			changed = true;

		if (mFalseJump && mFalseJump->ForwardAccuAddSub())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ForwardAXYReg(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool	xisa = false, yisa = false;
		int		xoffset = -1, yoffset = -1;
		int		zpx = -1, zpy = -1, zpa = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_TAX)
			{
				xisa = true;
				xoffset = i;
				zpx = zpa;
			}
			else if (mIns[i].mType == ASMIT_TXA)
			{
				xisa = true;
				yisa = false;
				xoffset = i;
				zpa = zpx;
			}
			else if (mIns[i].mType == ASMIT_TAY)
			{
				yisa = true;
				yoffset = i;
				zpy = zpa;
			}
			else if (mIns[i].mType == ASMIT_TYA)
			{
				yisa = true;
				xisa = false;
				yoffset = i;
				zpa = zpy;
			}
			else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (zpx == mIns[i].mAddress)
				{
					mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;
					xisa = true;
					yisa = false;
					int j = i;
					while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_X))
					{
						mIns[j - 1].mLive |= LIVE_CPU_REG_X;
						j--;
					}
				}
				else if (zpy == mIns[i].mAddress)
				{
					mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
					yisa = true;
					xisa = false;
					int j = i;
					while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_Y))
					{
						mIns[j - 1].mLive |= LIVE_CPU_REG_Y;
						j--;
					}
				}
				else
				{
					xisa = false;
					yisa = false;
				}
				zpa = mIns[i].mAddress;
			}
			else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				xisa = false;
				zpx = mIns[i].mAddress;
			}
			else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				yisa = false;
				zpy = mIns[i].mAddress;
			}
			else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				zpa = mIns[i].mAddress;
				if (yisa)
					zpy = mIns[i].mAddress;
				else if (zpy == mIns[i].mAddress)
					zpy = -1;
				if (xisa)
					zpx = mIns[i].mAddress;
				else if (zpx == mIns[i].mAddress)
					zpx = -1;
			}
			else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				zpx = mIns[i].mAddress;
				if (xisa)
					zpa = mIns[i].mAddress;
				else if (zpa == mIns[i].mAddress)
					zpa = -1;
				if (zpy == mIns[i].mAddress)
					zpy = -1;
			}
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				zpy = mIns[i].mAddress;
				if (yisa)
					zpa = mIns[i].mAddress;
				else if (zpa == mIns[i].mAddress)
					zpa = -1;
				if (zpx == mIns[i].mAddress)
					zpx = -1;
			}
			else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
			{
				if (xisa && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
				{
					if (mIns[i + 1].mAddress == 1)
					{
						mIns[i + 0].mType = ASMIT_INX;
						mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
						for (int j = xoffset; j < i + 1; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;
						xisa = false;
						changed = true;
					}
				}
				else if (yisa && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
				{
					if (mIns[i + 1].mAddress == 1)
					{
						mIns[i + 0].mType = ASMIT_INY;
						mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mMode = ASMIM_IMPLIED;
						for (int j = yoffset; j < i + 1; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;
						yisa = false;
						changed = true;
					}
				}
			}
			else
			{
				if (mIns[i].ChangesXReg())
				{
					xisa = false;
					zpx = -1;
				}
				if (mIns[i].ChangesYReg())
				{
					yisa = false;
					zpy = -1;
				}
				if (mIns[i].ChangesAccu())
				{
					xisa = false;
					yisa = false;
					zpa = -1;
				}

				if (zpa >= 0 && mIns[i].ChangesZeroPage(zpa))
					zpa = -1;
				if (zpx >= 0 && mIns[i].ChangesZeroPage(zpx))
					zpx = -1;
				if (zpy >= 0 && mIns[i].ChangesZeroPage(zpy))
					zpy = -1;
			}

		}

		if (mTrueJump && mTrueJump->ForwardAXYReg())
			changed = true;
		if (mFalseJump && mFalseJump->ForwardAXYReg())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ForwardZpYIndex(bool full)
{
	CheckLive();

	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int	yreg = -1, yoffset = 0, ypred = 0;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (yreg == mIns[i].mAddress)
				{
					bool	zfail = false;
					int live = LIVE_CPU_REG_Y;

					if (mIns[i].mLive & LIVE_CPU_REG_Z)
					{
						int k = i - 1;
						while (k > ypred && !mIns[k].ChangesZFlag())
							k--;
						if (k != ypred)
							zfail = true;
						live |= LIVE_CPU_REG_Z;
					}

					if (yoffset == 0 && !zfail)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= live;

						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;

						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;

						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;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (yoffset == 2 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_DEY;
						changed = true;
					}
					else if (yoffset == 3 && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY && mIns[i + 2].mType == ASMIT_INY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (yoffset == 3 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED;
						yoffset = 2;
						changed = true;
					}

					else if (yoffset == 0xff && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (yoffset == 0xff)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED;
						yoffset = 0;
						changed = true;
					}
					else if (yoffset == 0xfe && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY && mIns[i + 2].mType == ASMIT_DEY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (yoffset == 0xfe && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_INY;
						changed = true;
					}
					else if (yoffset == 0xfd && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY && mIns[i + 2].mType == ASMIT_DEY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (yoffset == 0xfd && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_DEY)
					{
						for (int j = ypred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;

						mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
						yoffset = 0xfe;
						changed = true;
					}
					else
						yoffset = 0;
					ypred = i;
				}
				else
				{
					if (full && yreg >= 0)
					{
						int j = i;
						while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(yreg))
							j++;
						if (j + 2 < mIns.Size() &&
							mIns[j - 1].mType == ASMIT_CLC &&
							mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
							mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
							mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == yreg &&
							!(mIns[j + 2].mLive & LIVE_CPU_REG_C))
						{
							if (mIns[j + 1].mAddress == ((yoffset + 1) & 0xff))
							{
								for (int k = ypred; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_Y;

								mIns.Remove(j + 2);
								mIns.Remove(j + 1);
								mIns.Remove(j - 1);
								mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
								mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
								i += 2;
								changed = true;
							}
							else if (mIns[j + 1].mAddress == ((yoffset - 1) & 0xff))
							{
								for (int k = ypred; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_Y;

									mIns.Remove(j + 2);
									mIns.Remove(j + 1);
									mIns.Remove(j - 1);
									mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
									mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
									i += 2;
									changed = true;
							}
						}
					}

					yreg = mIns[i].mAddress;
					yoffset = 0;
					ypred = i;
				}
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 3].mType == ASMIT_TAY)
			{
				if (mIns[i + 1].mAddress == yreg && mIns[i + 2].mAddress == ((yoffset + 1) & 0xff) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
				{
					for (int j = ypred; j < i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INY;
					changed = true;
				}
				else if (mIns[i + 1].mAddress == yreg && mIns[i + 2].mAddress == ((yoffset - 1) & 0xff) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
				{
					for (int j = ypred; j < i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_DEY;
					changed = true;
				}
				else
				{
					yreg = mIns[i + 1].mAddress;
					yoffset = mIns[i + 2].mAddress;
					ypred = i + 3;
					i += 3;
				}
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset + 1) & 0xff) &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
			{
				for (int j = ypred; j < i + 3; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
				mIns[i + 0].mType = ASMIT_INY;
				mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mAddress = mIns[i + 3].mAddress;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				
				ypred = i + 1;
				yoffset = (yoffset + 1) & 0xff;

				if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
				{
					mIns[i + 3].mType = ASMIT_TYA;
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}
				else
				{
					mIns[i + 3].mType = ASMIT_NOP; 
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset - 1) & 0xff) &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
			{
				for (int j = ypred; j < i + 3; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
				mIns[i + 0].mType = ASMIT_DEY;
				mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mAddress = mIns[i + 3].mAddress;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				
				ypred = i + 1;
				yoffset = (yoffset - 1) & 0xff;

				if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
				{
					mIns[i + 3].mType = ASMIT_TYA;
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}
				else
				{
					mIns[i + 3].mType = ASMIT_NOP; 
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == ((yoffset + 2) & 0xff) &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
			{
				for (int j = ypred; j < i + 3; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y | (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
				mIns[i + 0].mType = ASMIT_INY;
				mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].CopyMode(mIns[i + 3]);

				ypred = i + 1;
				yoffset = (yoffset + 2) & 0xff;

				if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
				{
					mIns[i + 3].mType = ASMIT_TYA;
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}
				else
				{
					mIns[i + 3].mType = ASMIT_NOP;
					mIns[i + 3].mMode = ASMIM_IMPLIED;
				}

				changed = true;
			}
			else if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == yreg &&
				mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg && yoffset == 0)
			{
				for (int j = ypred; j < i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 1].mType = ASMIT_STY;

				ypred = i + 1;
				yoffset = (yoffset + 1) & 0xff;

				changed = true;
			}
			else if (i + 2 < mIns.Size() && full &&
				mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == yreg &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == yreg && yoffset == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
			{
				for (int j = ypred; j < i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y;
				mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY, ASMIM_IMPLIED));
				mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
				yreg = -1;
				changed = true;
			}
			else if (mIns[i].mType == ASMIT_INY)
			{
				yoffset = (yoffset + 1) & 255;
			}
			else if (mIns[i].mType == ASMIT_DEY)
			{
				yoffset = (yoffset - 1) & 255;
			}
			else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
			{
				i++;
				yreg = mIns[i].mAddress;
				yoffset = 0;
				ypred = i;
			}
			else if (mIns[i].ChangesYReg())
			{
				if (full && yreg >= 0 && !mIns[i].RequiresYReg())
				{
					int j = i;
					while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(yreg))
						j++;
					if (j + 2 < mIns.Size() &&
						mIns[j - 1].mType == ASMIT_CLC &&
						mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
						mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
						mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == yreg &&
						!(mIns[j + 2].mLive & LIVE_CPU_REG_C))
					{
						if (mIns[j + 1].mAddress == yoffset + 1)
						{
							for (int k = ypred; k < i; k++)
								mIns[k].mLive |= LIVE_CPU_REG_Y;

							mIns.Remove(j + 2);
							mIns.Remove(j + 1);
							mIns.Remove(j - 1);
							mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
							mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
							i += 2;
							changed = true;
						}
					}
				}

				yreg = -1;
			}
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg)
			{
				yoffset = 0;
				ypred = i;
			}
			else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 1 && !(mIns[i].mLive & LIVE_CPU_REG_Z))
			{
				mIns[i].mType = ASMIT_STY;
				for (int j = ypred; j < i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y;
				yoffset = 0;
				ypred = i;
				changed = true;
			}
#if 1
			else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 0 && mIns[ypred].mType == ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
			{
				for (int j = ypred; j < i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y;
				mIns[i].mType = ASMIT_STY;
				mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
				ypred = i + 1;
			}
#endif
			else if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
			{
				yreg = -1;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->ForwardZpYIndex(full))
			changed = true;

		if (mFalseJump && mFalseJump->ForwardZpYIndex(full))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CanCombineSameYtoX(int start, int end)
{
	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if (ins.mMode == ASMIM_INDIRECT_Y)
			return false;

		if (ins.mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_X))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CanCombineSameXtoY(int start, int end)
{
	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if (ins.mMode == ASMIM_INDIRECT_X)
			return false;

		if (ins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y))
			return false;

	}

	return true;
}



bool NativeCodeBasicBlock::CombineSameXtoY(int xpos, int ypos, int end)
{
	if (xpos < ypos)
	{
		if (CanCombineSameXtoY(xpos, ypos) &&
			CanCombineSameXtoY(ypos + 1, end) &&
			!ReferencesYReg(xpos, ypos))
		{
			ReplaceXRegWithYReg(xpos, ypos);
			ReplaceXRegWithYReg(ypos + 1, end);

			for (int i = xpos; i < ypos; i++)
				mIns[i].mLive |= LIVE_CPU_REG_Y;

			if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z))
			{
				mIns[ypos].mType = ASMIT_NOP;
				mIns[ypos].mMode = ASMIM_IMPLIED;
			}
			return true;
		}
	}
	else
	{
		if (CanCombineSameXtoY(xpos, end))
		{
			ReplaceXRegWithYReg(xpos, end);
			for (int i = ypos; i < xpos; i++)
				mIns[i].mLive |= LIVE_CPU_REG_Y;

			if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z))
			{
				mIns[xpos].mType = ASMIT_NOP;
				mIns[xpos].mMode = ASMIM_IMPLIED;
			}
			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::CombineSameYtoX(int xpos, int ypos, int end)
{
	if (ypos < xpos)
	{
		if (CanCombineSameYtoX(ypos, xpos) &&
			CanCombineSameYtoX(xpos + 1, end) &&
			!ReferencesXReg(ypos, xpos))
		{
			ReplaceYRegWithXReg(ypos, xpos);
			ReplaceYRegWithXReg(xpos + 1, end);

			for (int i = ypos; i < xpos; i++)
				mIns[i].mLive |= LIVE_CPU_REG_X;

			if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z))
			{
				mIns[xpos].mType = ASMIT_NOP;
				mIns[xpos].mMode = ASMIM_IMPLIED;
			}
			return true;
		}
	}
	else
	{
		if (CanCombineSameYtoX(ypos, end))
		{
			ReplaceYRegWithXReg(ypos, end);
			for (int i = xpos; i < ypos; i++)
				mIns[i].mLive |= LIVE_CPU_REG_X;

			if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z))
			{
				mIns[ypos].mType = ASMIT_NOP;
				mIns[ypos].mMode = ASMIM_IMPLIED;
			}
			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::CombineSameXY(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int	xreg = -1, yreg = -1;
		int	xpos, ypos;
		bool	samexy = false;

		CheckLive();

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.ChangesXReg())
			{
				if (samexy)
				{
					if (!ins.RequiresXReg() && CombineSameXtoY(xpos, ypos, i))
						changed = true;
					else if (!ins.RequiresYReg() && !(ins.mLive & LIVE_CPU_REG_Y) && CombineSameYtoX(xpos, ypos, i))
					{
						changed = true;
						yreg = -1;
					}
					CheckLive();
				}

				xreg = -1;
				samexy = false;
			}
			if (ins.ChangesYReg())
			{
				if (samexy)
				{
					if (!ins.RequiresYReg() && CombineSameYtoX(xpos, ypos, i))
						changed = true;
					else if (!ins.RequiresXReg() && !(ins.mLive & LIVE_CPU_REG_X) && CombineSameXtoY(xpos, ypos, i))
					{
						changed = true;
						xreg = -1;
					}
					CheckLive();
				}

				yreg = -1;
				samexy = false;
			}

			if (ins.mType == ASMIT_TAX)
			{
				xreg = CPU_REG_A;
				xpos = i;
				samexy = yreg == xreg;
			}
			else if (ins.mType == ASMIT_TAY)
			{
				yreg = CPU_REG_A;
				ypos = i;
				samexy = xreg == yreg;
			}
			else if (ins.mType == ASMIT_LDX)
			{
				if (ins.mMode == ASMIM_ZERO_PAGE)
				{
					xreg = ins.mAddress;
					xpos = i;
					samexy = yreg == xreg;
				}
				else
					xreg = -1;
			}
			else if (ins.mType == ASMIT_LDY)
			{
				if (ins.mMode == ASMIM_ZERO_PAGE)
				{
					yreg = ins.mAddress;
					ypos = i;
					samexy = xreg == yreg;
				}
				else
					yreg = -1;
			}
			else if (ins.ChangesAccu())
			{
				if (xreg == CPU_REG_A)
					xreg = -1;
				if (yreg == CPU_REG_A)
					yreg = -1;
			}
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
			{
				if (xreg == ins.mAddress)
					xreg = -1;
				if (yreg == ins.mAddress)
					yreg = -1;
			}
		}


		if (samexy)
		{
			if (!mExitRequiredRegs[CPU_REG_X] && CombineSameXtoY(xpos, ypos, mIns.Size()))
				changed = true;
			else  if (!mExitRequiredRegs[CPU_REG_Y] && CombineSameYtoX(xpos, ypos, mIns.Size()))
				changed = true;
		}

		CheckLive();

		if (mTrueJump && mTrueJump->CombineSameXY())
			changed = true;
		if (mFalseJump && mFalseJump->CombineSameXY())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::JoinXYCrossBlock(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int xins = -1, yins = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDX)
			{
				xins = i;
				if (yins >= 0 && mIns[yins].SameEffectiveAddress(mIns[xins]))
				{
					if (CanCombineSameXtoYCrossBlock(xins + 1))
					{
						for (int j = yins; j <= xins; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;
						if (CombineSameXtoYCrossBlock(xins + 1))
							changed = true;
					}
					else if (CanCombineSameYtoX(yins + 1, xins) && CanCombineSameYtoXCrossBlock(xins + 1))
					{
						ReplaceXRegWithYReg(yins, xins);
						for (int j = yins; j <= xins; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;
						if (CombineSameYtoXCrossBlock(xins + 1))
							changed = true;
					}
				}
				yins = -1;
			}
			else if (mIns[i].mType == ASMIT_LDY)
			{
				yins = i;
				if (xins >= 0 && mIns[yins].SameEffectiveAddress(mIns[xins]))
				{
					if (CanCombineSameYtoXCrossBlock(yins + 1))
					{
						for (int j = xins; j <= yins; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;
						if (CombineSameYtoXCrossBlock(yins + 1))
							changed = true;
					}
					else if (CanCombineSameXtoY(xins + 1, yins) && CanCombineSameXtoYCrossBlock(yins + 1))
					{
						ReplaceYRegWithXReg(xins, yins);
						for (int j = xins; j <= yins; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;
						if (CombineSameXtoYCrossBlock(yins + 1))
							changed = true;
					}
				}
				xins = -1;
			}
			else
			{
				if (mIns[i].ChangesXReg())
					xins = -1;
				if (mIns[i].ChangesYReg())
					yins = -1;
				if (xins >= 0 && mIns[xins].MayBeChangedOnAddress(mIns[i]))
					xins = -1;
				if (yins >= 0 && mIns[yins].MayBeChangedOnAddress(mIns[i]))
					yins = -1;
			}
		}

		if (mTrueJump && mTrueJump->JoinXYCrossBlock())
			changed = true;
		if (mFalseJump && mFalseJump->JoinXYCrossBlock())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CanCombineSameXtoYCrossBlock(int from)
{
	if (!from)
	{
		if (!mEntryRequiredRegs[CPU_REG_X])
			return true;
		if (mEntryBlocks.Size() > 1)
			return false;
	}

	for (int i = from; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesXReg())
			return !mIns[i].ReferencesXReg();
		if (mIns[i].ChangesYReg())
			return false;
		if (mIns[i].mMode == ASMIM_INDIRECT_X)
			return false;
		if (mIns[i].mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
			return false;
	}

	if (mTrueJump && !mTrueJump->CanCombineSameXtoYCrossBlock(0))
		return false;
	if (mFalseJump && !mFalseJump->CanCombineSameXtoYCrossBlock(0))
		return false;

	return true;
}

bool NativeCodeBasicBlock::CanCombineSameYtoXCrossBlock(int from)
{
	if (!from)
	{
		if (!mEntryRequiredRegs[CPU_REG_Y])
			return true;
		if (mEntryBlocks.Size() > 1)
			return false;
	}

	for (int i = from; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesYReg())
			return !mIns[i].ReferencesYReg();
		if (mIns[i].ChangesXReg())
			return false;
		if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			return false;
		if (mIns[i].mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
			return false;
	}

	if (mTrueJump && !mTrueJump->CanCombineSameYtoXCrossBlock(0))
		return false;
	if (mFalseJump && !mFalseJump->CanCombineSameYtoXCrossBlock(0))
		return false;

	return true;
}

bool NativeCodeBasicBlock::CombineSameXtoYCrossBlock(int from)
{
	if (!from)
	{
		if (!mEntryRequiredRegs[CPU_REG_X])
			return false;
		mEntryRequiredRegs += CPU_REG_Y;
		assert(mEntryBlocks.Size() == 1);
	}

	bool	changed = false;

	for (int i = from; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesXReg())
			return changed;

		mIns[i].mLive |= LIVE_CPU_REG_Y;

		if (mIns[i].mMode == ASMIM_ABSOLUTE_X)
		{
			mIns[i].mMode = ASMIM_ABSOLUTE_Y;
			changed = true;
		}
		if (mIns[i].mType == ASMIT_TXA)
		{
			mIns[i].mType = ASMIT_TYA;
			changed = true;
		}
		else if (mIns[i].mType == ASMIT_STX)
		{
			mIns[i].mType = ASMIT_STY;
			changed = true;
		}
	}

	mExitRequiredRegs += CPU_REG_Y;

	if (mTrueJump && mTrueJump->CombineSameXtoYCrossBlock(0))
		changed = true;
	if (mFalseJump && !mFalseJump->CombineSameXtoYCrossBlock(0))
		changed = true;

	return changed;
}

bool NativeCodeBasicBlock::CombineSameYtoXCrossBlock(int from)
{
	if (!from)
	{
		if (!mEntryRequiredRegs[CPU_REG_Y])
			return false;
		mEntryRequiredRegs += CPU_REG_X;
		assert(mEntryBlocks.Size() == 1);
	}

	bool	changed = false;

	for (int i = from; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesYReg())
			return changed;

		mIns[i].mLive |= LIVE_CPU_REG_X;

		if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
		{
			mIns[i].mMode = ASMIM_ABSOLUTE_X;
			changed = true;
		}
		if (mIns[i].mType == ASMIT_TYA)
		{
			mIns[i].mType = ASMIT_TXA;
			changed = true;
		}
		else if (mIns[i].mType == ASMIT_STY)
		{
			mIns[i].mType = ASMIT_STX;
			changed = true;
		}
	}

	mExitRequiredRegs += CPU_REG_X;

	if (mTrueJump && mTrueJump->CombineSameYtoXCrossBlock(0))
		changed = true;
	if (mFalseJump && !mFalseJump->CombineSameYtoXCrossBlock(0))
		changed = true;

	return changed;
}

bool NativeCodeBasicBlock::JoinXYCascade(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool	restart;
		
		do {
			restart = false;
			int predXPos = -1, predYPos = -1;

			for (int i = 0; i + 2 < mIns.Size(); i++)
			{
				if (mIns[i + 0].mType == ASMIT_TXA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
				{
					if (predXPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)) && ((mIns[predXPos + 2].mAddress + 1) & 0xff) == mIns[i + 2].mAddress)
					{
						// Remove add
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

						// Insert INX
						mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));

						// Insert TAX
						mIns[predXPos + 2].mLive &= ~LIVE_CPU_REG_X;
						mIns.Insert(predXPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));

						// Restart
						restart = true;
						predXPos = -1;
						predYPos = -1;

						changed = true;
					}
					else if (predXPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)) && ((mIns[predXPos + 2].mAddress - 1) & 0xff) == mIns[i + 2].mAddress)
					{
						// Remove add
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

						// Insert DEX
						mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));

						// Insert TAX
						mIns[predXPos + 2].mLive &= ~LIVE_CPU_REG_X;
						mIns.Insert(predXPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));

						// Restart
						restart = true;
						predXPos = -1;
						predYPos = -1;

						changed = true;
					}
					else
						predXPos = i;
				}
				else if (mIns[i + 0].ReferencesXReg())
					predXPos = -1;
				else if (mIns[i + 0].mType == ASMIT_TYA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
				{
					if (predYPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)) && ((mIns[predYPos + 2].mAddress + 1) & 0xff) == mIns[i + 2].mAddress)
					{
						// Remove add
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

						// Insert INY
						mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));

						// Insert TAX
						mIns[predYPos + 2].mLive &= ~LIVE_CPU_REG_Y;
						mIns.Insert(predYPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));

						// Restart
						restart = true;
						predXPos = -1;
						predYPos = -1;

						changed = true;
					}
					else if (predYPos >= 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)) && ((mIns[predYPos + 2].mAddress - 1) & 0xff) == mIns[i + 2].mAddress)
					{
						// Remove add
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

						// Insert DEY
						mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));

						// Insert TAX
						mIns[predYPos + 2].mLive &= ~LIVE_CPU_REG_Y;
						mIns.Insert(predYPos + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));

						// Restart
						restart = true;
						predXPos = -1;
						predYPos = -1;

						changed = true;
					}
					else
						predYPos = i;
				}
				else if (mIns[i + 0].ReferencesYReg())
					predYPos = -1;
			}
		} while (restart);

		if (mTrueJump && mTrueJump->JoinXYCascade())
			changed = true;
		if (mFalseJump && mFalseJump->JoinXYCascade())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::GlobalLoadStoreForwarding(bool zpage, const NativeCodeInstruction & als, const NativeCodeInstruction & xls, const NativeCodeInstruction & yls)
{
	bool	changed = false;

	if (!mVisited)
	{
		mNumEntered++;

		if (mLoopHead)
		{
			mALSIns.mType = ASMIT_INV;
			mXLSIns.mType = ASMIT_INV;
			mYLSIns.mType = ASMIT_INV;
		}
		else if (mNumEntered == 1)
		{
			mALSIns = als;
			mXLSIns = xls;
			mYLSIns = yls;
		}
		else
		{
			if (als.mType == ASMIT_INV || (mALSIns.mType != ASMIT_INV && !mALSIns.SameEffectiveAddress(als))) mALSIns.mType = ASMIT_INV;
			if (xls.mType == ASMIT_INV || (mXLSIns.mType != ASMIT_INV && !mXLSIns.SameEffectiveAddress(xls))) mXLSIns.mType = ASMIT_INV;
			if (yls.mType == ASMIT_INV || (mYLSIns.mType != ASMIT_INV && !mYLSIns.SameEffectiveAddress(yls))) mYLSIns.mType = ASMIT_INV;
		}

		if (!mLoopHead && mNumEntered != mNumEntries)
			return false;

		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (mALSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
				mIns[i + 1].SameEffectiveAddress(mALSIns) && mIns[i + 1].IsCommutative())
			{
				ins.mType = mIns[i + 1].mType;
				mIns[i + 1].mType = ASMIT_NOP;
				mIns[i + 1].mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (mALSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 2 < mIns.Size() &&
				(mIns[i + 1].mType == ASMIT_CLC || mIns[i + 1].mType == ASMIT_SEC) &&
				mIns[i + 2].SameEffectiveAddress(mALSIns) && mIns[i + 2].IsCommutative())
			{
				mIns[i + 2].CopyMode(ins);
				ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (mXLSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
				mIns[i + 1].SameEffectiveAddress(mXLSIns) && mIns[i + 1].IsCommutative())
			{
				mIns[i + 1].CopyMode(ins);
				ins.mType = ASMIT_TXA;
				ins.mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (mYLSIns.mType != ASMIT_INV && ins.mType == ASMIT_LDA && i + 1 < mIns.Size() &&
				mIns[i + 1].SameEffectiveAddress(mYLSIns) && mIns[i + 1].IsCommutative())
			{
				mIns[i + 1].CopyMode(ins);
				ins.mType = ASMIT_TYA;
				ins.mMode = ASMIM_IMPLIED;
				changed = true;
			}

			if (ins.mType == ASMIT_STA)
			{
				if (mALSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mALSIns) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
				{
					if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
						mALSIns = ins;
					if (mXLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mXLSIns))
						mXLSIns.mType = ASMIT_INV;
					if (mYLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mYLSIns))
						mYLSIns.mType = ASMIT_INV;
				}
			}
			else if (ins.mType == ASMIT_LDA)
			{
				if (mALSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mALSIns) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_ORA;
					ins.mMode = ASMIM_IMMEDIATE;
					ins.mAddress = 0;
					changed = true;
				}
				else if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
					mALSIns = ins;
				else
					mALSIns.mType = ASMIT_INV;
			}
			else if (ins.mType == ASMIT_STX)
			{
				if (mXLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mXLSIns) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
				{
					if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
						mXLSIns = ins;
					if (mALSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mALSIns))
						mALSIns.mType = ASMIT_INV;
					if (mYLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mYLSIns))
						mYLSIns.mType = ASMIT_INV;
				}
			}
			else if (ins.mType == ASMIT_LDX)
			{
				if (mXLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mXLSIns) && !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					ins.mAddress = 0;
					changed = true;
				}
				else
				{
					if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_Y) && !(ins.mFlags & NCIF_VOLATILE))
						mXLSIns = ins;
					else
						mXLSIns.mType = ASMIT_INV;
					if (mALSIns.mType != ASMIT_INV && mALSIns.mMode == ASMIM_ABSOLUTE_X)
						mALSIns.mType = ASMIT_INV;
					if (mYLSIns.mType != ASMIT_INV && mYLSIns.mMode == ASMIM_ABSOLUTE_X)
						mYLSIns.mType = ASMIT_INV;
				}
			}
			else if (ins.mType == ASMIT_STY)
			{
				if (mYLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mYLSIns) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
				{
					if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X) && !(ins.mFlags & NCIF_VOLATILE))
						mYLSIns = ins;
					if (mALSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mALSIns))
						mALSIns.mType = ASMIT_INV;
					if (mXLSIns.mType != ASMIT_INV && ins.MayBeSameAddress(mXLSIns))
						mXLSIns.mType = ASMIT_INV;
				}
			}
			else if (ins.mType == ASMIT_LDY)
			{
				if (mYLSIns.mType != ASMIT_INV && ins.SameEffectiveAddress(mYLSIns) && !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					ins.mAddress = 0;
					changed = true;
				}
				else
				{
					if (((zpage && ins.mMode == ASMIM_ZERO_PAGE) || ins.mMode == ASMIM_ABSOLUTE || ins.mMode == ASMIM_ABSOLUTE_X) && !(ins.mFlags & NCIF_VOLATILE))
						mYLSIns = ins;
					else
						mYLSIns.mType = ASMIT_INV;
					if (mALSIns.mType != ASMIT_INV && mALSIns.mMode == ASMIM_ABSOLUTE_Y)
						mALSIns.mType = ASMIT_INV;
					if (mXLSIns.mType != ASMIT_INV && mXLSIns.mMode == ASMIM_ABSOLUTE_Y)
						mXLSIns.mType = ASMIT_INV;
				}
			}
			else if (ins.mType == ASMIT_TAY)
			{
				if (mALSIns.mMode == ASMIM_ABSOLUTE_Y)
					mALSIns.mType = ASMIT_INV;
				if (mXLSIns.mMode == ASMIM_ABSOLUTE_Y)
					mXLSIns.mType = ASMIT_INV;
				mYLSIns = mALSIns;
			}
			else if (ins.mType == ASMIT_TAX)
			{
				if (mALSIns.mMode == ASMIM_ABSOLUTE_X)
					mALSIns.mType = ASMIT_INV;
				if (mYLSIns.mMode == ASMIM_ABSOLUTE_X)
					mYLSIns.mType = ASMIT_INV;
				mXLSIns = mALSIns;
			}
			else if (ins.mType == ASMIT_TYA)
			{
				mALSIns = mYLSIns;
			}
			else if (ins.mType == ASMIT_TXA)
			{
				mALSIns = mXLSIns;
			}
			else
			{
				if (ins.ChangesAccu())
					mALSIns.mType = ASMIT_INV;
				if (ins.ChangesXReg())
				{
					mXLSIns.mType = ASMIT_INV;
					if (mALSIns.mMode == ASMIM_ABSOLUTE_X)
						mALSIns.mType = ASMIT_INV;
					if (mYLSIns.mMode == ASMIM_ABSOLUTE_X)
						mYLSIns.mType = ASMIT_INV;
				}
				if (ins.ChangesYReg())
				{
					mYLSIns.mType = ASMIT_INV;
					if (mALSIns.mMode == ASMIM_ABSOLUTE_Y)
						mALSIns.mType = ASMIT_INV;
					if (mXLSIns.mMode == ASMIM_ABSOLUTE_Y)
						mXLSIns.mType = ASMIT_INV;
				}
				if (ins.ChangesAddress())
				{
					if (mALSIns.mType != ASMIT_INV && mALSIns.MayBeSameAddress(ins))
						mALSIns.mType = ASMIT_INV;
					if (mXLSIns.mType != ASMIT_INV && mXLSIns.MayBeSameAddress(ins))
						mXLSIns.mType = ASMIT_INV;
					if (mYLSIns.mType != ASMIT_INV && mYLSIns.MayBeSameAddress(ins))
						mYLSIns.mType = ASMIT_INV;
				}
			}
		}

		if (mTrueJump && mTrueJump->GlobalLoadStoreForwarding(zpage, mALSIns, mXLSIns, mYLSIns))
			changed = true;
		if (mFalseJump && mFalseJump->GlobalLoadStoreForwarding(zpage, mALSIns, mXLSIns, mYLSIns))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::RegisterValueForwarding(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		FastNumberSet	xreg(261), yreg(261), areg(261);

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[i].mType == ASMIT_LDX)
				{
					if (xreg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						xreg.Clear();
						xreg += mIns[i].mAddress;
					}
				}
				else if (mIns[i].mType == ASMIT_STX)
				{
					if (xreg[mIns[i].mAddress])
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						xreg += mIns[i].mAddress;
						yreg -= mIns[i].mAddress;
						areg -= mIns[i].mAddress;
					}
				}
				else if (mIns[i].mType == ASMIT_LDY)
				{
					if (yreg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						yreg.Clear();
						yreg += mIns[i].mAddress;
					}
				}
				else if (mIns[i].mType == ASMIT_STY)
				{
					if (yreg[mIns[i].mAddress])
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						yreg += mIns[i].mAddress;
						xreg -= mIns[i].mAddress;
						areg -= mIns[i].mAddress;
					}
				}
				else if (mIns[i].mType == ASMIT_LDA)
				{
					if (areg[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						areg.Clear();
						areg += mIns[i].mAddress;
					}
				}
				else if (mIns[i].mType == ASMIT_STA)
				{
					if (areg[mIns[i].mAddress])
					{
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						areg += mIns[i].mAddress;
						xreg -= mIns[i].mAddress;
						yreg -= mIns[i].mAddress;
					}
				}
				else if (mIns[i].ChangesAddress())
				{
					xreg -= mIns[i].mAddress;
					yreg -= mIns[i].mAddress;
					areg -= mIns[i].mAddress;
				}
				else if (mIns[i].ChangesAccu())
				{
					areg.Clear();
				}
			}
			else if (mIns[i].mType == ASMIT_JSR)
			{
				xreg.Clear();
				yreg.Clear();
				areg.Clear();
			}
			else if (mIns[i].ChangesXReg())
			{
				xreg.Clear();
			}
			else if (mIns[i].ChangesYReg())
			{
				yreg.Clear();
			}
			else if (mIns[i].ChangesAccu())
			{
				areg.Clear();
			}
		}

		if (mTrueJump && mTrueJump->RegisterValueForwarding())
			changed = true;
		if (mFalseJump && mFalseJump->RegisterValueForwarding())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ForwardZpXIndex(bool full)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int	xreg = -1, xoffset = 0, xpred = 0;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (xreg == mIns[i].mAddress)
				{
					if (xoffset == 0)
					{
						for (int j = xpred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;

						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (xoffset == 1 && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_INX)
					{
						for (int j = xpred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (xoffset == 2 && i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_INX)
					{
						for (int j = xpred; j < i; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;

						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
						xoffset = 0;
					xpred = i;
				}
				else
				{
					xreg = mIns[i].mAddress;
					xoffset = 0;
					xpred = i;
				}
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 3].mType == ASMIT_TAX)
			{
				if (mIns[i + 1].mAddress == xreg && mIns[i + 2].mAddress == xoffset + 1 && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
				{
					for (int j = xpred; j < i + 3; j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INX;
					changed = true;
				}
				else
				{
					xreg = mIns[i + 1].mAddress;
					xoffset = mIns[i + 2].mAddress;
					xpred = i + 3;
					i += 3;
				}
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == xreg &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == xoffset + 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == xreg &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
			{
				for (int j = xpred; j < i + 3; j++)
					mIns[j].mLive |= LIVE_CPU_REG_X;
				mIns[i + 0].mType = ASMIT_INX;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 3].mType = ASMIT_STX;

				xoffset++;
				xpred = i + 1;

				changed = true;
			}
			else if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == xreg &&
				mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == xreg && xoffset == 0)
			{
				for (int j = xpred; j < i + 1; j++)
					mIns[j].mLive |= LIVE_CPU_REG_X;
				mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
				mIns[i + 1].mType = ASMIT_STX;

				xoffset++;
				xpred = i + 1;

				changed = true;
			}
			else if (mIns[i].mType == ASMIT_INX)
			{
				xoffset = (xoffset + 1) & 255;
			}
			else if (mIns[i].mType == ASMIT_DEX)
			{
				xoffset = (xoffset - 1) & 255;
			}
			else if (mIns[i].ChangesXReg())
			{
				xreg = -1;
			}
			else if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
			{
				xreg = -1;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->ForwardZpXIndex(full))
			changed = true;

		if (mFalseJump && mFalseJump->ForwardZpXIndex(full))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ReplaceXRegWithYReg(int start, int end)
{
	bool	changed = false;

	//CheckLive();
	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.ReplaceXRegWithYReg())
			changed = true;
	}
	//CheckLive();

	return changed;
}

bool NativeCodeBasicBlock::CanReplaceYRegWithXReg(int start, int end)
{
	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if ((ins.mLive & LIVE_CPU_REG_X) && (ins.mLive & LIVE_CPU_REG_Y))
			return false;

		if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ABSOLUTE_X)
			return false;

		if (ins.mMode == ASMIM_INDIRECT_Y)
			return false;

		if (ins.mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_X))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CanReplaceXRegWithYReg(int start, int end)
{
	for (int i = start; i < end; i++)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if ((ins.mLive & LIVE_CPU_REG_X) && (ins.mLive & LIVE_CPU_REG_Y))
			return false;

		if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ABSOLUTE_Y)
			return false;

		if (ins.mMode == ASMIM_INDIRECT_X)
			return false;

		if (ins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y))
			return false;

	}

	return true;
}

bool NativeCodeBasicBlock::CanGlobalSwapXY(void)
{
	if (!mVisited)
	{
		mVisited = true;

		if (mEntryRegX || mEntryRegY)
			return false;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.mMode == ASMIM_INDIRECT_Y)
				return false;
			if (ins.mMode == ASMIM_INDIRECT_X)
				return false;
			if (ins.mMode == ASMIM_ABSOLUTE_X && (ins.mType != ASMIT_LDY && !HasAsmInstructionMode(ins.mType, ASMIM_ABSOLUTE_Y)))
				return false;
			if (ins.mType == ASMIT_JSR && (ins.mFlags & (NCIF_USE_CPU_REG_X | NCIF_USE_CPU_REG_Y | NCIF_USE_ZP_32_X)))
				return false;
		}

		if (mTrueJump && !mTrueJump->CanGlobalSwapXY())
			return false;
		if (mFalseJump && !mFalseJump->CanGlobalSwapXY())
			return false;
	}

	return true;
}



bool NativeCodeBasicBlock::IsSimpleSubExpression(int at, NativeSimpleSubExpression& ex)
{
	ex.mIndex = at;

	if (at + 2 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[at + 2].mType == ASMIT_STA && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
			(mIns[at + 1].mMode == ASMIM_IMMEDIATE || mIns[at + 1].mMode == ASMIM_ZERO_PAGE) && (mIns[at + 1].mType == ASMIT_AND || mIns[at + 1].mType == ASMIT_ORA || mIns[at + 1].mType == ASMIT_EOR))
		{
			ex.mType = mIns[at + 1].mType;
			ex.mValue = mIns[at + 1].mAddress;
			ex.mMode = mIns[at + 1].mMode;
			ex.mOp = &(mIns[at + 1]);
			ex.mSrc = &(mIns[at + 0]);
			ex.mDst = &(mIns[at + 2]);
			return true;
		}
	}
	if (at + 3 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
			(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) && 
			(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
			!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
		{
			ex.mType = mIns[at + 2].mType;
			ex.mValue = mIns[at + 2].mAddress;
			ex.mMode = mIns[at + 2].mMode;
			ex.mSrc = &(mIns[at + 0]);
			ex.mOp = &(mIns[at + 2]);
			ex.mDst = &(mIns[at + 3]);
			return true;
		}
	}
	if (at + 3 < mIns.Size())
	{
		if (mIns[at + 1].mType == ASMIT_LDA && (mIns[at + 1].mMode == ASMIM_ZERO_PAGE || mIns[at + 1].mMode == ASMIM_ABSOLUTE) &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
			(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
			(mIns[at + 0].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 0].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
			!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
		{
			ex.mType = mIns[at + 2].mType;
			ex.mValue = mIns[at + 2].mAddress;
			ex.mMode = mIns[at + 2].mMode;
			ex.mSrc = &(mIns[at + 1]);
			ex.mOp = &(mIns[at + 2]);
			ex.mDst = &(mIns[at + 3]);
			return true;
		}
	}
	if (at + 3 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_STA && mIns[at + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
			(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
			(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
			!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
		{
			ex.mType = mIns[at + 2].mType;
			ex.mValue = mIns[at + 2].mAddress;
			ex.mMode = mIns[at + 2].mMode;
			ex.mSrc = &(mIns[at + 0]);
			ex.mOp = &(mIns[at + 2]);
			ex.mDst = &(mIns[at + 3]);
			return true;
		}
	}
	if (at + 2 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_LDX && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[at + 2].mType == ASMIT_STX && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 1].mType == ASMIT_INX)
		{
			ex.mType = ASMIT_ADC;
			ex.mValue = 1;
			ex.mMode = ASMIM_IMMEDIATE;
			ex.mOp = &(mIns[at + 1]);
			ex.mSrc = &(mIns[at + 0]);
			ex.mDst = &(mIns[at + 2]);
			return true;
		}
	}
	if (at + 2 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_LDY && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[at + 2].mType == ASMIT_STY && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 1].mType == ASMIT_INY)
		{
			ex.mType = ASMIT_ADC;
			ex.mValue = 1;
			ex.mMode = ASMIM_IMMEDIATE;
			ex.mOp = &(mIns[at + 1]);
			ex.mSrc = &(mIns[at + 0]);
			ex.mDst = &(mIns[at + 2]);
			return true;
		}
	}	
	if (at + 3 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE || mIns[at + 0].mMode == ASMIM_ABSOLUTE_X) &&
			mIns[at + 3].mType == ASMIT_TAY &&
			(mIns[at + 2].mMode == ASMIM_IMMEDIATE || mIns[at + 2].mMode == ASMIM_ZERO_PAGE) &&
			(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
			!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
		{
			ex.mType = mIns[at + 2].mType;
			ex.mValue = mIns[at + 2].mAddress;
			ex.mMode = mIns[at + 2].mMode;
			ex.mSrc = &(mIns[at + 0]);
			ex.mOp = &(mIns[at + 2]);
			ex.mDst = &(mIns[at + 3]);
			return true;
		}
	}

	return false;
}

int NativeSimpleSubExpressions::FindCommon(const NativeSimpleSubExpression& ex) const
{
	if (ex.mSrc->mType == ASMIT_LDA || ex.mSrc->mType == ASMIT_LDX || ex.mSrc->mType == ASMIT_LDY)
	{
		for (int i = 0; i < mExps.Size(); i++)
		{
			if (mExps[i].mType == ex.mType && mExps[i].mMode == ex.mMode && mExps[i].mValue == ex.mValue && ex.mSrc->SameEffectiveAddress(*(mExps[i].mSrc)))
			{
				if (mExps[i].mDst->mMode == ASMIM_IMPLIED)
				{
					if (mExps[i].mDst->mType == ex.mDst->mType)
						return i;
				}
				else
					return i;
			}
		}
	}

	return -1;
}

bool NativeSimpleSubExpression::MayBeChangedBy(const NativeCodeInstruction& ins)
{
	if (ins.ChangesAddress())
	{
		if (mSrc->MayBeChangedOnAddress(ins))
			return true;
		if (&ins != mDst && mDst->MayBeChangedOnAddress(ins))
			return true;
		if (mMode == ASMIM_ZERO_PAGE && ins.ChangesZeroPage(mValue))
			return true;
	}
	if (ins.ChangesYReg())
	{
		if (&ins != mDst && mDst->mType == ASMIT_TAY)
			return true;
		if (mSrc->mMode == ASMIM_ABSOLUTE_Y)
			return true;
	}
	if (ins.ChangesXReg())
	{
		if (&ins != mDst && mDst->mType == ASMIT_TAX)
			return true;
		if (mSrc->mMode == ASMIM_ABSOLUTE_X)
			return true;
	}

	return false;
}

void NativeSimpleSubExpressions::Filter(const NativeCodeInstruction& ins)
{
	if (ins.mType == ASMIT_JSR)
		mExps.SetSize(0);
	else
	{
		int i = 0;
		while (i < mExps.Size())
		{
			if (mExps[i].MayBeChangedBy(ins))
				mExps.Remove(i);
			else
				i++;
		}
	}
}

bool NativeCodeBasicBlock::PropagateCommonSubExpression(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		NativeSimpleSubExpressions	exps;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeSimpleSubExpression	ex;
			if (IsSimpleSubExpression(i, ex))
			{
				int j = exps.FindCommon(ex);
				if (j >= 0)
				{
					if (ex.mDst->mType == ASMIT_TAY)
					{
						for (int k = exps.mExps[j].mIndex; k < i + 2; k++)
							mIns[k].mLive |= LIVE_CPU_REG_Y;
						ex.mOp->mLive |= LIVE_CPU_REG_Y;
						ex.mDst->mType = ASMIT_NOP;
					}
					else if (ex.mDst->mType == ASMIT_TAX)
					{
						for (int k = exps.mExps[j].mIndex; k < i + 2; k++)
							mIns[k].mLive |= LIVE_CPU_REG_X;
						ex.mOp->mLive |= LIVE_CPU_REG_Y;
						ex.mDst->mType = ASMIT_NOP;
					}
					else
					{
						*ex.mSrc = NativeCodeInstruction(ex.mDst->mIns, ex.mSrc->mType, *(exps.mExps[j].mDst));
						ex.mSrc = exps.mExps[j].mSrc;
						ex.mOp->mType = ASMIT_NOP;
						ex.mOp->mMode = ASMIM_IMPLIED;
					}
					changed = true;
				}
				exps.mExps.Push(ex);
			}
			else
				exps.Filter(mIns[i]);
		}

		if (mTrueJump && mTrueJump->PropagateCommonSubExpression())
			changed = true;
		if (mFalseJump && mFalseJump->PropagateCommonSubExpression())
			changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::CollectAccuDominatedBlocks(ExpandingArray<NativeCodeBasicBlock*>& dblocks)
{
	if (mPatched)
		return;

	for (int i = 0; i < mEntryBlocks.Size(); i++)
		if (!mEntryBlocks[i]->mPatchChecked)
			return;

	mPatched = true;
	dblocks.Push(this);

	if (!ChangesAccu())
	{
		mPatchChecked = true;
		if (mTrueJump) mTrueJump->CollectAccuDominatedBlocks(dblocks);
		if (mFalseJump) mFalseJump->CollectAccuDominatedBlocks(dblocks);
	}
}

bool NativeCodeBasicBlock::PropagateCrossBlockAccuExpression(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int sz = mIns.Size();
		if (sz >= 3 &&
			(mIns[sz - 3].mType == ASMIT_LDA || mIns[sz - 3].mType == ASMIT_STA) && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz - 2].IsLogic() && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
			!mIns[sz - 1].ChangesAccu())
		{
			mProc->ResetPatched();
			mPatchChecked = true;

			ExpandingArray<NativeCodeBasicBlock*>	dblocks;
			if (mTrueJump) mTrueJump->CollectAccuDominatedBlocks(dblocks);
			if (mFalseJump) mFalseJump->CollectAccuDominatedBlocks(dblocks);

			for (int i = 0; i < dblocks.Size(); i++)
			{
				NativeCodeBasicBlock* b = dblocks[i];
				if (b->mIns.Size() >= 2 &&
					b->mIns[0].mType == ASMIT_LDA && b->mIns[0].mMode == ASMIM_ZERO_PAGE && b->mIns[0].mAddress == mIns[sz - 3].mAddress &&
					b->mIns[1].IsSame(mIns[sz - 2]) && !(b->mIns[1].mLive & LIVE_CPU_REG_Z))
				{
					b->mIns[0].mType = ASMIT_NOP; b->mIns[0].mMode = ASMIM_IMPLIED;
					b->mIns[1].mType = ASMIT_NOP; b->mIns[1].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->PropagateCrossBlockAccuExpression())
			changed = true;
		if (mFalseJump && mFalseJump->PropagateCrossBlockAccuExpression())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ShortSwapXY(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_Y))
			{
				if (mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode))
				{
					mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
					changed = true;
				}
				else if (mIns[i + 0].mType == ASMIT_TAX)
				{
					mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
					changed = true;
				}
			}
			else if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_X))
			{
				if (mIns[i + 0].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode))
				{
					mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
					changed = true;
				}
				else if (mIns[i + 0].mType == ASMIT_TAY)
				{
					mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->ShortSwapXY())
			changed = true;
		if (mFalseJump && mFalseJump->ShortSwapXY())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::LocalSwapXY(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int pre = -1;

		if (mEntryRequiredRegs[CPU_REG_X] || mEntryRequiredRegs[CPU_REG_Y])
			pre = -2;

		for (int i = 0; i < mIns.Size(); i++)
		{
			uint32 live = mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y);
			if (live)
			{
				if (pre == -1)
					pre = i;
			}
			else if (!live)
			{
				if (pre >= 0)
				{
					int k = pre;
					while (k <= i && mIns[k].CanSwapXYReg())
						k++;
					if (k > i)
					{
						for (int k = pre; k <= i; k++)
						{
							if (mIns[k].SwapXYReg())
								changed = true;
						}
					}
				}
				pre = -1;
			}
		}

		if (mTrueJump && mTrueJump->LocalSwapXY())
			changed = true;
		if (mFalseJump && mFalseJump->LocalSwapXY())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::GlobalSwapXY(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.mMode == ASMIM_ABSOLUTE_X)
			{
				ins.mMode = ASMIM_ABSOLUTE_Y;
				changed = true;
			}
			else if (ins.mMode == ASMIM_ABSOLUTE_Y)
			{
				ins.mMode = ASMIM_ABSOLUTE_X;
				changed = true;
			}

			switch (ins.mType)
			{
			case ASMIT_LDX:
				ins.mType = ASMIT_LDY;
				changed = true;
				break;
			case ASMIT_STX:
				ins.mType = ASMIT_STY;
				changed = true;
				break;
			case ASMIT_CPX:
				ins.mType = ASMIT_CPY;
				changed = true;
				break;
			case ASMIT_INX:
				ins.mType = ASMIT_INY;
				changed = true;
				break;
			case ASMIT_DEX:
				ins.mType = ASMIT_DEY;
				changed = true;
				break;
			case ASMIT_TAX:
				ins.mType = ASMIT_TAY;
				changed = true;
				break;
			case ASMIT_TXA:
				ins.mType = ASMIT_TYA;
				changed = true;
				break;

			case ASMIT_LDY:
				ins.mType = ASMIT_LDX;
				changed = true;
				break;
			case ASMIT_STY:
				ins.mType = ASMIT_STX;
				changed = true;
				break;
			case ASMIT_CPY:
				ins.mType = ASMIT_CPX;
				changed = true;
				break;
			case ASMIT_INY:
				ins.mType = ASMIT_INX;
				changed = true;
				break;
			case ASMIT_DEY:
				ins.mType = ASMIT_DEX;
				changed = true;
				break;
			case ASMIT_TAY:
				ins.mType = ASMIT_TAX;
				changed = true;
				break;
			case ASMIT_TYA:
				ins.mType = ASMIT_TXA;
				changed = true;
				break;
			}
		}

		if (mTrueJump && !mTrueJump->GlobalSwapXY())
			changed = true;
		if (mFalseJump && !mFalseJump->GlobalSwapXY())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::AlternateXXUsage(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 3 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
				mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X &&
				!(mIns[i + 3].mLive & LIVE_CPU_REG_Y))
			{
				mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
				changed = true;
			}
			else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
				mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y &&
				!(mIns[i + 3].mLive & LIVE_CPU_REG_X))
			{
				mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
				mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->AlternateXXUsage())
			changed = true;
		if (mFalseJump && mFalseJump->AlternateXXUsage())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::UntangleXYUsage(bool final)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (final)
		{
			for (int i = 0; i + 2 < mIns.Size(); i++)
			{
				if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
					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[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				}
			}
		}

		int	xins = -1, yins = -1;
		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			NativeCodeInstruction& nins(mIns[i + 1]);

			if (ins.mType == ASMIT_LDX)
			{				
				if (yins >= 0 && mIns[yins].SameEffectiveAddress(ins) && nins.mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(nins.mType, ASMIM_ABSOLUTE_Y))
				{
					if (nins.mLive & LIVE_CPU_REG_Z)
					{
						ins.mLive |= LIVE_CPU_REG_Y;
						nins.mMode = ASMIM_ABSOLUTE_Y;
					}
					else
					{
						mIns.Insert(i, NativeCodeInstruction(nins.mIns, nins.mType, ASMIM_ABSOLUTE_Y, nins.mAddress, nins.mLinkerObject, nins.mFlags));
						mIns[i + 1].mLive |= mIns[i].mLive;
						mIns.Remove(i + 2);
					}
					for (int j = yins; j < i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_Y;
					changed = true;
				}
				else
					xins = i;
			}
			else if (ins.mType == ASMIT_LDY)
			{
				if (xins >= 0 && mIns[xins].SameEffectiveAddress(ins) && nins.mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(nins.mType, ASMIM_ABSOLUTE_X))
				{
					if (nins.mLive & LIVE_CPU_REG_Z)
					{
						ins.mLive = LIVE_CPU_REG_X;
						nins.mMode = ASMIM_ABSOLUTE_X;
					}
					else
					{
						mIns.Insert(i, NativeCodeInstruction(nins.mIns, nins.mType, ASMIM_ABSOLUTE_X, nins.mAddress, nins.mLinkerObject, nins.mFlags));
						mIns[i + 1].mLive |= mIns[i].mLive;
						mIns.Remove(i + 2);
					}
					for (int j = xins; j < i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
					changed = true;
				}
				else
					yins = i;
			}
			else
			{
				if (xins >= 0 && (mIns[xins].MayBeChangedOnAddress(ins) || ins.ChangesXReg()))
					xins = -1;
				if (yins >= 0 && (mIns[yins].MayBeChangedOnAddress(ins) || ins.ChangesYReg()))
					yins = -1;
			}
		}

		if (mTrueJump && mTrueJump->UntangleXYUsage(final))
			changed = true;
		if (mFalseJump && mFalseJump->UntangleXYUsage(final))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeXYPairUsage(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		if (mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_X] && !mExitRequiredRegs[CPU_REG_Y])
		{
			int	yreg = -1, xreg = -1, areg = -1;
			for (int i = 0; i < mIns.Size(); i++)
			{
				NativeCodeInstruction	& ins(mIns[i]);

				if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg ||
					ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
				{
					bool	checkx = ins.mType == ASMIT_LDY && (ins.mLive & LIVE_CPU_REG_X);
					bool	checky = ins.mType == ASMIT_LDX && (ins.mLive & LIVE_CPU_REG_Y);
					bool	fail = false;

					int	j = i;
					while (j + 1 < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && mIns[j + 1].CanSwapXYReg() && !fail)
					{
						if (checkx && (mIns[j].mType == ASMIT_INX || mIns[j].mType == ASMIT_DEX) ||
							checky && (mIns[j].mType == ASMIT_INY || mIns[j].mType == ASMIT_DEY))
							fail = true;
						if (checkx && mIns[j].ChangesXReg())
							checkx = false;
						if (checky && mIns[j].ChangesYReg())
							checky = false;

						j++;
					}
					if (!fail && (j + 1 == mIns.Size() || !(mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y))))
					{
						bool	tox = ins.mType == ASMIT_LDY, toy = ins.mType == ASMIT_LDX;
						for (int k = i; k <= j; k++)
						{
							if (mIns[k].ChangesXReg())
								tox = false;
							if (mIns[k].ChangesYReg())
								toy = false;

							if (tox)
								mIns[k].ReplaceYRegWithXReg();
							else if (toy)
								mIns[k].ReplaceXRegWithYReg();
							else
								mIns[k].SwapXYReg();
						}

						CheckLive();

						changed = true;
					}
				}

				if (ins.mType == ASMIT_LDY)
				{
					if (ins.mMode == ASMIM_ZERO_PAGE)
						yreg = ins.mAddress;
					else
						yreg = -1;
				}
				else if (ins.mType == ASMIT_LDX)
				{
					if (ins.mMode == ASMIM_ZERO_PAGE)
						xreg = ins.mAddress;
					else
						xreg = -1;
				}
				else if (ins.mType == ASMIT_LDA)
				{
					if (ins.mMode == ASMIM_ZERO_PAGE)
						areg = ins.mAddress;
					else
						areg = -1;
				}
				else if (ins.mType == ASMIT_TAX)
					xreg = areg;
				else if (ins.mType == ASMIT_TAY)
					yreg = areg;
				else if (ins.mType == ASMIT_JSR)
					xreg = yreg = areg = false;
				else if (ins.ChangesAccu())
					areg = -1;
				else if (ins.ChangesXReg())
					xreg = -1;
				else if (ins.ChangesYReg())
					yreg = -1;
				else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
				{
					if (ins.mAddress == areg)
						areg = -1;
					if (ins.mAddress == xreg)
						xreg = -1;
					if (ins.mAddress == yreg)
						yreg = -1;
				}
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->OptimizeXYPairUsage())
			changed = true;

		if (mFalseJump && mFalseJump->OptimizeXYPairUsage())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveImmediateStoreUp(int at)
{
	bool	usex = mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
	bool	usey = mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;
	bool	vol = mIns[at + 1].mFlags & NCIF_VOLATILE;

	int val = mIns[at].mAddress;
	int i = at;
	while (i > 0)
	{
		i--;
		if (mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == val)
		{
			if (mIns[i].mType == ASMIT_LDA && (mIns[i].mLive & LIVE_CPU_REG_A))
			{
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_A;
				mIns.Remove(at + 1, 2);
				return true;
			}
			else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_STX, mIns[at + 1].mMode))
			{
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STX, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_X;
				mIns.Remove(at + 1, 2);
				return true;
			}
			else if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_STY, mIns[at + 1].mMode))
			{
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STY, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
				mIns.Remove(at + 1, 2);
				return true;
			}
		}
		
		if (mIns[i].MayReference(mIns[at + 1]))
			return false;
		else if (usex && mIns[i].ChangesXReg())
			return false;
		else if (usey && mIns[i].ChangesYReg())
			return false;
		else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
			return false;
		else if (vol && (mIns[i].mFlags & NCIF_VOLATILE))
			return false;
	}
	return false;
}

bool NativeCodeBasicBlock::MoveImmediateStoreDown(int at)
{
	bool	usex = mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
	bool	usey = mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;
	bool	vol = mIns[at + 1].mFlags & NCIF_VOLATILE;

	int val = mIns[at].mAddress;
	int i = at + 2;
	while (i < mIns.Size())
	{
		if (mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == val)
		{
			if (mIns[i].mType == ASMIT_LDA && (mIns[i].mLive & LIVE_CPU_REG_A))
			{
				if (usex)
				{
					for (int j = at; j <= i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
				}
				else if (usey)
				{
					for (int j = at; j <= i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_Y;
				}

				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_A;
				mIns.Remove(at, 2);
				return true;
			}
			else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_STX, mIns[at + 1].mMode))
			{
				if (usey)
				{
					for (int j = at; j <= i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_Y;
				}
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STX, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_X;
				mIns.Remove(at, 2);
				return true;
			}
			else if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_STY, mIns[at + 1].mMode))
			{
				if (usex)
				{
					for (int j = at; j <= i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
				}
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STY, mIns[at + 1]));
				mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
				mIns.Remove(at, 2);
				return true;
			}
		}

		if (mIns[i].MayReference(mIns[at + 1]))
			return false;
		else if (usex && mIns[i].ChangesXReg())
			return false;
		else if (usey && mIns[i].ChangesYReg())
			return false;
		else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
			return false;
		else if (vol && (mIns[i].mFlags & NCIF_VOLATILE))
			return false;
		else if (mIns[i].mFlags & NCIF_MEMMAP)
			return false;

		i++;
	}
	return false;
}

bool NativeCodeBasicBlock::RecycleImmediates(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (mIns[i].mMode == ASMIM_IMMEDIATE)
			{
				if ((mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
                    (mIns[i].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) ||
				    (mIns[i].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z))))
				{
					if (MoveImmediateStoreDown(i) || MoveImmediateStoreUp(i))
					{
						CheckLive();
						changed = true;
					}
				}
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->RecycleImmediates())
			changed = true;

		if (mFalseJump && mFalseJump->RecycleImmediates())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveLoadStoreDown(int at)
{
	bool	usex = 
		mIns[at + 0].mMode == ASMIM_ABSOLUTE_X || mIns[at + 0].mMode == ASMIM_INDIRECT_X || mIns[at + 0].mMode == ASMIM_ZERO_PAGE_X ||
		mIns[at + 1].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_INDIRECT_X || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_X;
	bool	usey =
		mIns[at + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 0].mMode == ASMIM_INDIRECT_Y || mIns[at + 0].mMode == ASMIM_ZERO_PAGE_Y ||
		mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_INDIRECT_Y || mIns[at + 1].mMode == ASMIM_ZERO_PAGE_Y;

	int i = at + 2;
	while (i < mIns.Size())
	{
		if ((mIns[i].SameEffectiveAddress(mIns[at + 0]) || mIns[i].SameEffectiveAddress(mIns[at + 1])) && mIns[i].mType == ASMIT_LDA)
		{
			if (usex)
			{
				for (int j = at; j <= i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_X;
			}
			else if (usey)
			{
				for (int j = at; j <= i; j++)
					mIns[j].mLive |= LIVE_CPU_REG_Y;
			}

			mIns.Remove(i);
			if (i != at + 2)
			{
				mIns.Insert(i + 0, NativeCodeInstruction(mIns[at + 0].mIns, ASMIT_LDA, mIns[at + 0]));
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
				mIns.Remove(at, 2);
			}
			else
				mIns[at + 1].mLive |= LIVE_CPU_REG_A;
			return true;
		}

		if (mIns[i].MayReference(mIns[at + 1]) || mIns[at].MayBeChangedOnAddress(mIns[i]))
			return false;
		else if (usex && mIns[i].ChangesXReg())
			return false;
		else if (usey && mIns[i].ChangesYReg())
			return false;
		else if (mIns[at].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at].mAddress) || mIns[i].ChangesZeroPage(mIns[at].mAddress + 1)))
			return false;
		else if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
			return false;
		else if (mIns[i].mFlags & NCIF_MEMMAP)
			return false;

		i++;
	}
	return false;
}

bool NativeCodeBasicBlock::RecycleLoadStore(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && 
				!mIns[i].MayBeChangedOnAddress(mIns[i + 1]) && !(mIns[i].mFlags & NCIF_VOLATILE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				if (MoveLoadStoreDown(i))
					changed = true;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->RecycleLoadStore())
			changed = true;

		if (mFalseJump && mFalseJump->RecycleLoadStore())
			changed = true;
	}

	return changed;
}


void NativeCodeBasicBlock::BuildUseChangeSets(int start, int end, unsigned & used, unsigned & changed, uint32 & flags)
{
	used = 0;
	changed = 0;
	flags = 0;

	for (int i = start; i < end; i++)
	{
		flags |= mIns[i].mFlags;

		if (mIns[i].RequiresCarry() && !(changed & LIVE_CPU_REG_C))
			used |= LIVE_CPU_REG_C;
		if (mIns[i].RequiresXReg() && !(changed & LIVE_CPU_REG_X))
			used |= LIVE_CPU_REG_X;
		if (mIns[i].RequiresYReg() && !(changed & LIVE_CPU_REG_Y))
			used |= LIVE_CPU_REG_Y;

		if (mIns[i].ChangesCarry())
			changed |= LIVE_CPU_REG_C;
		if (mIns[i].ChangesXReg())
			changed |= LIVE_CPU_REG_X;
		if (mIns[i].ChangesYReg())
			changed |= LIVE_CPU_REG_Y;
	}
}

bool NativeCodeBasicBlock::CanSwapInstructions(int at)
{
	if (mIns[at].RequiresAccu() && mIns[at + 1].ChangesAccu())
		return false;
	if (mIns[at].RequiresXReg() && mIns[at + 1].ChangesXReg())
		return false;
	if (mIns[at].RequiresYReg() && mIns[at + 1].ChangesYReg())
		return false;
	if (mIns[at].RequiresCarry() && mIns[at + 1].ChangesCarry())
		return false;

	if (mIns[at + 1].RequiresAccu() && mIns[at].ChangesAccu())
		return false;
	if (mIns[at + 1].RequiresXReg() && mIns[at].ChangesXReg())
		return false;
	if (mIns[at + 1].RequiresYReg() && mIns[at].ChangesYReg())
		return false;
	if (mIns[at + 1].RequiresCarry() && mIns[at].ChangesCarry())
		return false;

	if ((mIns[at + 1].mLive & LIVE_CPU_REG_A) && mIns[at].ChangesAccu())
		return false;
	if ((mIns[at + 1].mLive & LIVE_CPU_REG_X) && mIns[at].ChangesXReg())
		return false;
	if ((mIns[at + 1].mLive & LIVE_CPU_REG_Y) && mIns[at].ChangesYReg())
		return false;
	if ((mIns[at + 1].mLive & LIVE_CPU_REG_C) && mIns[at].ChangesCarry())
		return false;
	if ((mIns[at + 1].mLive & LIVE_CPU_REG_Z) && mIns[at].ChangesZFlag())
		return false;

	if (mIns[at].MayBeChangedOnAddress(mIns[at + 1]) ||
		mIns[at + 1].MayBeChangedOnAddress(mIns[at]) ||
		mIns[at + 1].MayReference(mIns[at]))
		return false;

	return true;
}

bool NativeCodeBasicBlock::CanExchangeSegments(int start, int mid, int end)
{
	unsigned usedFront, changedFront, usedBack, changedBack;
	uint32		flagsFront, flagsBack;

	BuildUseChangeSets(start, mid, usedFront, changedFront, flagsFront);
	BuildUseChangeSets(mid, end, usedBack, changedBack, flagsBack);

	if (flagsFront & flagsBack & NCIF_VOLATILE)
		return false;
	if (flagsFront & NCIF_ALIASING)
	{
		for (int i = mid; i < end; i++)
			if (mIns[i].mType == ASMIT_JSR)
				return false;
	}
	if (flagsBack & NCIF_ALIASING)
	{
		for (int i = start; i < mid; i++)
			if (mIns[i].mType == ASMIT_JSR)
				return false;
	}

	if (usedFront & changedBack)
		return false;
	if (usedBack & changedFront)
		return false;
	if (mIns[end - 1].mLive & changedFront)
		return false;

	return true;
}

bool NativeCodeBasicBlock::MoveAccuTrainDown(int end, int start)
{
	int i = end;
	while (i > 0)
	{
		i--;

		for (int j = end + 1; j < start; j++)
		{
			if (mIns[j].MayBeChangedOnAddress(mIns[i], true) || mIns[i].MayBeChangedOnAddress(mIns[j], true))
				return false;
			if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[j].ReferencesZeroPage(mIns[i].mAddress))
				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;

		CheckLive();

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				apos[mIns[i].mAddress] = i;
			}
			else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && apos[mIns[i + 1].mAddress] >= 0 && HasAsmInstructionMode(mIns[i + 1].mType, mIns[i].mMode))
			{
				int addr = mIns[i + 1].mAddress;

				CheckLive();
				if (MoveAccuTrainDown(apos[addr], i))
				{
					if (mIns[i].RequiresXReg())
						mIns[i].mLive |= LIVE_CPU_REG_X;
					if (mIns[i].RequiresYReg())
						mIns[i].mLive |= LIVE_CPU_REG_Y;

					mIns[i + 1].CopyMode(mIns[i]);
					mIns[i] = NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr);
					changed = true;
					CheckLive();

					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;

				CheckLive();
				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;
					CheckLive();

					for (int j = 0; j < 256; j++)
						apos[j] = -1;
				}
				else
					apos[mIns[i].mAddress] = -1;
			}
			else if (i + 1  < mIns.Size() && mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && apos[mIns[i + 1].mAddress] >= 0)
			{
				int addr = mIns[i + 1].mAddress;

				CheckLive();
				if (MoveAccuTrainDown(apos[addr], i))
				{
					if (mIns[i + 1].RequiresXReg())
						mIns[i + 1].mLive |= LIVE_CPU_REG_X;
					if (mIns[i + 1].RequiresYReg())
						mIns[i + 1].mLive |= LIVE_CPU_REG_Y;

					changed = true;
					CheckLive();

					for (int j = 0; j < 256; j++)
						apos[j] = -1;
				}
				else
					apos[mIns[i + 1].mAddress] = -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;

				CheckLive();
				if (MoveAccuTrainDown(apos[addr], i))
				{
					if (mIns[i].RequiresXReg())
					{
						mIns[i].mLive |= LIVE_CPU_REG_X;
						mIns[i + 1].mLive |= LIVE_CPU_REG_X;
					}
					if (mIns[i].RequiresYReg())
					{
						mIns[i].mLive |= LIVE_CPU_REG_Y;
						mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
					}

					mIns[i + 2].CopyMode(mIns[i]);
					mIns[i] = NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr);
					changed = true;
					CheckLive();

					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;
			}
			
			if (mIns[i].mType == ASMIT_JSR)
			{
				for (int j = 0; j < 256; j++)
				{
					if (apos[j] >= 0 && mIns[i].ReferencesZeroPage(j))
						apos[j] = -1;
				}
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->MoveAccuTrainsDown())
			changed = true;
		if (mFalseJump && mFalseJump->MoveAccuTrainsDown())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveAccuTrainUp(int at, int end)
{
	CheckLive();

	bool needXY = (mIns[end - 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) != 0;
	
	int addr = mIns[at].mAddress;
	if (mIns[at].mLive & LIVE_CPU_REG_C)
		at--;

	int	i = at;
	while (i > 0)
	{
		i--;
		if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			if (mIns[i].mType == ASMIT_LDA)
				i++;

			if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
				return false;

			int live = mIns[i].mLive;

			for (int j = i; j < at; j++)
				mIns[j].mLive |= mIns[end - 1].mLive;

			for (int j = at; j < end; j++)
			{
				NativeCodeInstruction	ins(mIns[j]);
				ins.mLive |= live;

				mIns.Remove(j);
				i++;
				mIns.Insert(i, ins);
			}

			CheckLive();

			return true;
		}

		if (mIns[i].mType == ASMIT_JSR)
		{
			if (needXY)
				return false;
			
		}

		for (int j = at; j < end; j++)
		{
			if (mIns[j].RequiresXReg() && mIns[i].ChangesXReg() || mIns[j].ChangesXReg() && mIns[i].RequiresXReg())
				return false;
			if (mIns[j].RequiresYReg() && mIns[i].ChangesYReg() || mIns[j].ChangesYReg() && mIns[i].RequiresYReg())
				return false;
			if (mIns[j].MayBeChangedOnAddress(mIns[i], true) || mIns[i].MayBeChangedOnAddress(mIns[j], true))
				return false;
			if (mIns[i].mType == ASMIT_JSR && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesAddress() && mIns[i].ReferencesZeroPage(mIns[j].mAddress))
				return false;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::MoveAccuTrainsUp(void) 
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		FastNumberSet	wzero(256);

		int i = 0;
		while (i < mIns.Size())
		{
			if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
					wzero -= mIns[i].mAddress;
				else
					wzero += mIns[i].mAddress;
				i++;
			}
			else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && wzero[mIns[i].mAddress] && 
				(!(mIns[i].mLive & LIVE_CPU_REG_C) || i > 0 && (mIns[i-1].mType == ASMIT_CLC || mIns[i-1].mType == ASMIT_SEC)))
			{
				int j = i;
				while (j < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && mIns[j].mType != ASMIT_JSR)
					j++;

				if (j < mIns.Size() && mIns[j].mType != ASMIT_JSR)
				{
					j++;
					if (MoveAccuTrainUp(i, j))
					{
						i = j + 1;
						changed = true;
					}
					else
						i++;
				}
				else
					i++;
			}
			else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				wzero += mIns[i].mAddress;
				i++;
			}
			else if (mIns[i].mType == ASMIT_JSR)
			{
				for (int j = 0; j < 256; j++)
				{
					if (wzero[j] && mIns[i].ChangesZeroPage(j))
						wzero -= j;
				}
#if 0
				for (int j = 0; j < 4; j++)
				{
					wzero -= BC_REG_ACCU + j;
					wzero -= BC_REG_WORK + j;
				}

				if (!(mIns[i].mFlags & NCIF_RUNTIME) || (mIns[i].mFlags & NCIF_FEXEC))
				{
					wzero -= BC_REG_ADDR;
					wzero -= BC_REG_ADDR + 1;
				}

//				wzero.Clear();
#endif
				i++;
			}
			else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
			{
				wzero -= mIns[i].mAddress;
				i++;
			}
			else
				i++;
		}

		CheckLive();

		if (mTrueJump && mTrueJump->MoveAccuTrainsUp())
			changed = true;
		if (mFalseJump && mFalseJump->MoveAccuTrainsUp())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::AlternateXYUsage(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int start = 0;

		CheckLive();

		int	predYPos = -1, predXPos = -1, currYPos = -1, currXPos = -1, predYEnd = -1, predXEnd = -1;

		for (int start = 0; start < mIns.Size(); start++)
		{
			const NativeCodeInstruction& ins(mIns[start]);

			if (ins.mType == ASMIT_LDY)
			{
				if ((ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE) && predYPos >= 0 && ins.SameEffectiveAddress(mIns[predYPos]) && !(ins.mFlags & NCIF_VOLATILE))
				{
					if (CanReplaceYRegWithXReg(predYEnd, start))
					{
						if (ReplaceYRegWithXReg(predYEnd, start))
							changed = true;
					}
				}
				else
				{
					if (currYPos >= 0)
					{
						predYPos = currYPos;
						predYEnd = start;
					}

					if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE)
						currYPos = start;
					else
						currYPos = -1;
				}
			}
			else if (ins.mType == ASMIT_LDX)
			{
				if ((ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE) && predXPos >= 0 && ins.SameEffectiveAddress(mIns[predXPos]) && !(ins.mFlags & NCIF_VOLATILE))
				{
					if (CanReplaceXRegWithYReg(predXEnd, start))
					{
						if (ReplaceXRegWithYReg(predXEnd, start))
							changed = true;
					}
				}
				else
				{
					if (currXPos >= 0)
					{
						predXPos = currXPos;
						predXEnd = start;
					}

					if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ABSOLUTE)
						currXPos = start;
					else
						currXPos = -1;
				}
			}
			else if (ins.mType == ASMIT_JSR)
			{
				currYPos = predYPos = -1;
				currXPos = predXPos = -1;
			}
			else if (ins.ChangesXReg())
			{
				currXPos = -1;
			}
			else if (ins.ChangesYReg())
			{
				currYPos = -1;
			}
			else
			{
				if (predYPos >= 0 && mIns[predYPos].MayBeChangedOnAddress(ins))
					predYPos = -1;
				if (predXPos >= 0 && mIns[predXPos].MayBeChangedOnAddress(ins))
					predXPos = -1;
				if (currYPos >= 0 && mIns[currYPos].MayBeChangedOnAddress(ins))
					currYPos = -1;
				if (currXPos >= 0 && mIns[currXPos].MayBeChangedOnAddress(ins))
					currYPos = -1;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->AlternateXYUsage())
			changed = true;

		if (mFalseJump && mFalseJump->AlternateXYUsage())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SimplifyLoopEnd(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && !mFalseJump && mTrueJump->mLoopHead)
		{
			if (mTrueJump->mIns.Size() == 1 && mTrueJump->mFalseJump && mTrueJump->mTrueJump != mTrueJump)
			{
				mIns.Push(mTrueJump->mIns[0]);
				mBranch = mTrueJump->mBranch;

				if (mTrueJump->mExitRequiredRegs[CPU_REG_A])
					mExitRequiredRegs += CPU_REG_A;
				if (mTrueJump->mExitRequiredRegs[CPU_REG_X])
					mExitRequiredRegs += CPU_REG_X;
				if (mTrueJump->mExitRequiredRegs[CPU_REG_Y])
					mExitRequiredRegs += CPU_REG_Y;

				mTrueJump->RemEntryBlock(this);

				mFalseJump = mTrueJump->mFalseJump;
				mTrueJump = mTrueJump->mTrueJump;

				mTrueJump->AddEntryBlock(this);
				mFalseJump->AddEntryBlock(this);

				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->SimplifyLoopEnd(proc))
			changed = true;
		if (mFalseJump && mFalseJump->SimplifyLoopEnd(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CanHoistStore(const NativeCodeInstruction& ains) const
{
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (ains.MayBeSameAddress(mIns[i]))
			return false;

		if (ains.mType == ASMIT_STY && mIns[i].ChangesYReg() ||
			ains.mType == ASMIT_STX && mIns[i].ChangesXReg())
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CanBytepassLoad(const NativeCodeInstruction& ains, int from) const
{
	for (int i = from; i < mIns.Size(); i++)
	{
		if (ains.MayBeChangedOnAddress(mIns[i]))
			return false;

		if (ains.mType == ASMIT_LDY && mIns[i].ReferencesYReg() ||
			ains.mType == ASMIT_LDX && mIns[i].ReferencesXReg())
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::JoinDiamondArithmetic(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		NativeCodeBasicBlock* ezero = nullptr, * enzero = nullptr;
		if (mEntryBlocks.Size() == 2 && !mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump)
		{
			if (mEntryBlocks[0]->mIns.Size() > 0 && mEntryBlocks[0]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[0]->mIns.Last().mMode == ASMIM_IMMEDIATE && mEntryBlocks[0]->mIns.Last().mAddress == 0)
			{
				ezero = mEntryBlocks[0];
				enzero = mEntryBlocks[1];
			}
			else if (mEntryBlocks[1]->mIns.Size() > 0 && mEntryBlocks[1]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[1]->mIns.Last().mMode == ASMIM_IMMEDIATE && mEntryBlocks[1]->mIns.Last().mAddress == 0)
			{
				ezero = mEntryBlocks[1];
				enzero = mEntryBlocks[0];
			}

			if (ezero)
			{
				if (mIns.Size() > 2 && mIns[0].mType == ASMIT_CLC && mIns[1].mType == ASMIT_ADC && (mIns[1].mMode == ASMIM_ZERO_PAGE || mIns[1].mMode == ASMIM_IMMEDIATE || mIns[1].mMode == ASMIM_ABSOLUTE))
				{
					ezero->mIns[ezero->mIns.Size() - 1].CopyMode(mIns[1]);
					ezero->mIns.Push(mIns[0]);
					ezero->mExitRequiredRegs += CPU_REG_C;
					enzero->mIns.Push(mIns[0]);
					enzero->mIns.Push(mIns[1]);
					enzero->mExitRequiredRegs += CPU_REG_C;
					mIns.Remove(0, 2);
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->JoinDiamondArithmetic()) changed = true;
		if (mFalseJump && mFalseJump->JoinDiamondArithmetic()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
		{
			if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 && mTrueJump->mTrueJump->mNumEntries == 2)
			{
				NativeCodeBasicBlock* mblock = mTrueJump->mTrueJump;

				if (mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
					mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
				{
					if (mTrueJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mType == ASMIT_AND && !(mTrueJump->mIns[0].mAddress & ~mFalseJump->mIns[0].mAddress))
					{
						mTrueJump->mTrueJump->mIns.Insert(0, mFalseJump->mIns[0]);
						mFalseJump->mIns.SetSize(0, true);
						changed = true;
					}
					else if (mTrueJump->mIns[0].mType == ASMIT_AND && mFalseJump->mIns[0].mType == ASMIT_LDA && !(mFalseJump->mIns[0].mAddress & ~mTrueJump->mIns[0].mAddress))
					{
						mTrueJump->mTrueJump->mIns.Insert(0, mTrueJump->mIns[0]);
						mTrueJump->mIns.SetSize(0, true);
						changed = true;
					}
				}

				if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && mTrueJump->mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
				{
					int sz = mIns.Size() - 1;
					while (sz >= 0 && !mIns[sz].ReferencesYReg())
						sz--;
					if (sz >= 0 && mIns[sz].mType == ASMIT_LDY && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
					{
						if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz]))
						{
							if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
							{
								mExitRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mExitRequiredRegs += mIns[sz].mAddress;
								mFalseJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mFalseJump->mExitRequiredRegs += mIns[sz].mAddress;
							}
							mIns[sz].mLive |= LIVE_MEM;

							mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDY, mIns[sz]));
							changed = true;
						}
					}
				}

				if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mTrueJump->mEntryRequiredRegs[CPU_REG_X])
				{
					int sz = mIns.Size() - 1;
					while (sz >= 0 && !mIns[sz].ReferencesXReg())
						sz--;
					if (sz >= 0 && mIns[sz].mType == ASMIT_LDX && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
					{
						if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz]))
						{
							if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
							{
								mExitRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mTrueJump->mExitRequiredRegs += mIns[sz].mAddress;
								mFalseJump->mEntryRequiredRegs += mIns[sz].mAddress;
								mFalseJump->mExitRequiredRegs += mIns[sz].mAddress;
							}
							mIns[sz].mLive |= LIVE_MEM;

							mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDX, mIns[sz]));
							changed = true;
						}
					}
				}

				if (mblock->mIns.Size() > 0 && mblock->mIns[0].mType == ASMIT_STX && (mblock->mIns[0].mMode == ASMIM_ZERO_PAGE || mblock->mIns[0].mMode == ASMIM_ABSOLUTE) && !(mblock->mIns[0].mLive & LIVE_CPU_REG_X) &&
					mTrueJump->CanHoistStore(mblock->mIns[0]) && mFalseJump->CanHoistStore(mblock->mIns[0]))
				{
					if (mblock->mIns[0].mMode == ASMIM_ZERO_PAGE)
					{
						mExitRequiredRegs += mblock->mIns[0].mAddress;
						mTrueJump->mEntryRequiredRegs += mblock->mIns[0].mAddress;
						mTrueJump->mExitRequiredRegs += mblock->mIns[0].mAddress;
						mFalseJump->mEntryRequiredRegs += mblock->mIns[0].mAddress;
						mFalseJump->mExitRequiredRegs += mblock->mIns[0].mAddress;
						mblock->mEntryRequiredRegs += mblock->mIns[0].mAddress;
					}

					mIns.Push(mblock->mIns[0]);
					mblock->mIns.Remove(0);
					mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
					changed = true;
				}
			}
#if 1
			if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && mTrueJump->mNumEntries == 1)
			{
				int sz = mIns.Size() - 1;
				while (sz >= 0 && !mIns[sz].ReferencesYReg())
					sz--;
				if (sz >= 0 && mIns[sz].mType == ASMIT_LDY && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
				{
					int i = sz + 1;
					while (i < mIns.Size() && !mIns[sz].MayBeChangedOnAddress(mIns[i]))
						i++;
					if (i == mIns.Size())
					{
						mIns[sz].mLive |= mIns[mIns.Size() - 1].mLive;
						if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
						{
							mExitRequiredRegs += mIns[sz].mAddress;
							mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
						}
						mTrueJump->mIns.Insert(0, mIns[sz]);
						mIns.Remove(sz);
						changed = true;
					}
				}
			}
			if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && mTrueJump->mNumEntries == 1)
			{
				int sz = mIns.Size() - 1;
				while (sz >= 0 && !mIns[sz].ReferencesXReg())
					sz--;
				if (sz >= 0 && mIns[sz].mType == ASMIT_LDX && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z))
				{
					int i = sz + 1;
					while (i < mIns.Size() && !mIns[sz].MayBeChangedOnAddress(mIns[i]))
						i++;
					if (i == mIns.Size())
					{
						mIns[sz].mLive |= mIns[mIns.Size() - 1].mLive;
						if (mIns[sz].mMode == ASMIM_ZERO_PAGE)
						{
							mExitRequiredRegs += mIns[sz].mAddress;
							mTrueJump->mEntryRequiredRegs += mIns[sz].mAddress;
						}
						mTrueJump->mIns.Insert(0, mIns[sz]);
						mIns.Remove(sz);
						changed = true;
					}
				}
			}

			if (mIns.Size() >= 3)
			{
				int sz = mIns.Size();
				if (mIns[sz - 3].mType == ASMIT_TAX &&
					mIns[sz - 2].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 2].mMode) &&
					mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode) &&
					!(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
				{
					if ((mTrueJump->mNumEntries == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TXA && !(mTrueJump->mIns[0].mLive & LIVE_CPU_REG_X) || !(mTrueJump->mEntryRequiredRegs[CPU_REG_X])) &&
						(mFalseJump->mNumEntries == 1 && mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_TXA && !(mFalseJump->mIns[0].mLive & LIVE_CPU_REG_X) || !(mFalseJump->mEntryRequiredRegs[CPU_REG_X])))
					{
						mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
						mIns[sz - 2].mType = ASMIT_LDX; 
						mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;

						if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TXA)
						{
							mTrueJump->mIns[0].mType = ASMIT_ORA;
							mTrueJump->mIns[0].mMode = ASMIM_IMMEDIATE;
							mTrueJump->mIns[0].mAddress = 0;

							mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						}
						if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_TXA)
						{
							mFalseJump->mIns[0].mType = ASMIT_ORA;
							mFalseJump->mIns[0].mMode = ASMIM_IMMEDIATE;
							mFalseJump->mIns[0].mAddress = 0;

							mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						}

						changed = true;
					}
				}

			}

			if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
			{
				NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr;
				if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)
				{
					cblock = mTrueJump;
					eblock = mFalseJump;
				}
				if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump && mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 2)
				{
					cblock = mFalseJump;
					eblock = mTrueJump;
				}

				if (cblock && cblock->mIns.Size() > 0 && eblock->mIns.Size() > 0)
				{
					int cs = cblock->mIns.Size();

					if (cblock->mIns[0].mType == ASMIT_LDA && eblock->mIns[0].mType == ASMIT_LDA && cblock->mIns[cs - 1].mType == ASMIT_STA &&
						cblock->mIns[0].SameEffectiveAddress(eblock->mIns[0]) &&
						cblock->mIns[0].SameEffectiveAddress(cblock->mIns[cs - 1]))
					{
						cblock->mIns[cs - 1].mLive |= LIVE_CPU_REG_A;
						eblock->mIns[0].mLive |= cblock->mIns[0].mLive;
						eblock->mIns[0].mLive |= LIVE_CPU_REG_C;
						mIns.Push(eblock->mIns[0]);
						eblock->mIns.Remove(0);
						cblock->mIns.Remove(0);

						eblock->mEntryRequiredRegs += CPU_REG_A;
						cblock->mEntryRequiredRegs += CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;
						cblock->mExitRequiredRegs += CPU_REG_A;

						changed = true;
					}
					else if (cs == 3 &&
						!cblock->mEntryRequiredRegs[CPU_REG_A] && !eblock->mEntryRequiredRegs[CPU_REG_A] &&
						cblock->mIns[0].mType == ASMIT_TYA &&
						cblock->mIns[1].IsLogic() && cblock->mIns[1].mMode == ASMIM_IMMEDIATE &&
						cblock->mIns[2].mType == ASMIT_TAY && !(cblock->mIns[2].mLive & LIVE_CPU_REG_A))
					{
						int k = mIns.Size() - 1;
						while (k >= 2 && !mIns[k].ReferencesYReg())
							k--;
						if (k >= 2)
						{
							if (mIns[k - 2].mType == ASMIT_TYA &&
								mIns[k - 1].IsLogic() && mIns[k - 1].mMode == ASMIM_IMMEDIATE &&
								mIns[k - 0].mType == ASMIT_TAY && !(mIns[k].mLive & LIVE_CPU_REG_A))
							{
								mIns[k - 2].mLive |= mIns.Last().mLive;
								mIns[k - 1].mLive |= mIns.Last().mLive;
								mIns[k - 0].mLive |= mIns.Last().mLive;

								mIns.Push(mIns[k - 2]);
								mIns.Push(mIns[k - 1]);

								cblock->mIns.Remove(0);
								cblock->mIns.Remove(1);

								eblock->mIns.Insert(0, mIns[k]);

								mIns.Remove(k - 2, 3);

								eblock->mEntryRequiredRegs += CPU_REG_Y;
								cblock->mEntryRequiredRegs += CPU_REG_Y;
								eblock->mEntryRequiredRegs += CPU_REG_A;
								cblock->mEntryRequiredRegs += CPU_REG_A;
								mExitRequiredRegs += CPU_REG_Y;
								mExitRequiredRegs += CPU_REG_A;
								cblock->mExitRequiredRegs += CPU_REG_Y;

								changed = true;
							}
						}
					}
				}
			}
		}
#endif
#if 0
		if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump && mTrueJump->mEntryBlocks.Size() == 1)
		{
			int sz = mIns.Size(), tsz = mTrueJump->mIns.Size();
			if (sz > 0 && mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
				sz--;

			if (sz > 0 && tsz > 0)
			{
				if (mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mTrueJump->mIns[tsz - 1].IsSame(mIns[sz - 1]))
				{
					if (!mTrueJump->ReferencesZeroPage(mIns[sz - 1].mAddress, 0, tsz - 1))
					{
						printf("DoopsieT %d\n", mFalseJump->mEntryBlocks.Size());
					}
				}
			}
		}
#endif
		if (mTrueJump && mFalseJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump && mFalseJump->mEntryBlocks.Size() == 1)
		{
			int sz = mIns.Size(), tsz = mFalseJump->mIns.Size();
			if (sz > 0 && mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
				sz--;

			if (sz > 0 && tsz > 0)
			{
				if (mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[tsz - 1].IsSame(mIns[sz - 1]))
				{
					if (!mFalseJump->ReferencesZeroPage(mIns[sz - 1].mAddress, 0, tsz - 1))
					{
						if (mTrueJump->mEntryBlocks.Size() <= 3 || mTrueJump->mLoopHead)
						{
							if (mTrueJump->mEntryBlocks.Size() > 2)
							{
								NativeCodeBasicBlock* pblock = proc->AllocateBlock();
								pblock->mEntryRequiredRegs = mTrueJump->mEntryRequiredRegs;
								pblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;
								pblock->mTrueJump = mTrueJump;
								mTrueJump->mEntryBlocks.RemoveAll(this);
								mTrueJump->mEntryBlocks.RemoveAll(mFalseJump);
								mTrueJump->mNumEntries -= 2;
								pblock->mEntryBlocks.Push(this);
								pblock->mEntryBlocks.Push(mFalseJump);
								pblock->mNumEntries = 2;
								mTrueJump = pblock;
								mFalseJump->mTrueJump = pblock;
							}
							if (sz < mIns.Size())
								mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
							mTrueJump->mIns.Push(mIns[sz - 1]);
							mIns.Remove(sz - 1);
							mFalseJump->mIns.Remove(tsz - 1);
							mTrueJump->mEntryRequiredRegs += CPU_REG_A;
							mExitRequiredRegs += CPU_REG_A;
							mFalseJump->mExitRequiredRegs += CPU_REG_A;
							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->SimplifyDiamond(proc))
			changed = true;
		if (mFalseJump && mFalseJump->SimplifyDiamond(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CompressSwitchCascade(int lower, int upper, int cmp, AsmInsType branch)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

//		if (CheckFunc)
//			printf("Compress %d : %d..%d, %d\n", mIndex, lower, upper, cmp);
			
		if (mNumEntries > 1)
		{
			lower = 0x00;
			upper = 0xff;
			cmp = -1;
			branch = ASMIT_JMP;			
		}

		int sz = mIns.Size();
		if (sz > 0)
		{
			if (ChangesAccu())
			{
				lower = 0x00;
				upper = 0xff;
				branch = ASMIT_JMP;
			}

			if (mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE)
			{
				int pcmp = cmp;
				cmp = mIns[sz - 1].mAddress;

				if (!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z] && mFalseJump)
				{
					if (cmp != -1 && branch == ASMIT_BNE)
					{
						if (cmp + 1 == upper && upper == mIns[sz - 1].mAddress)
						{
							if (mBranch == ASMIT_BEQ)
								mBranch = ASMIT_BCS;
							else if (mBranch == ASMIT_BNE)
								mBranch = ASMIT_BCC;
							mIns.Remove(sz - 1);
							cmp = pcmp;
							changed = true;
						}
						else if (lower + 1 == cmp && lower == mIns[sz - 1].mAddress)
						{
							if (mBranch == ASMIT_BEQ)
								mBranch = ASMIT_BCC;
							else if (mBranch == ASMIT_BNE)
								mBranch = ASMIT_BCS;
							mIns.Remove(sz - 1);
							cmp = pcmp;
							changed = true;
						}
					}

					if (!changed && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
					{
						NativeCodeBasicBlock* fbranch = mBranch == ASMIT_BEQ ? mFalseJump : mTrueJump;
						if (fbranch->mIns.Size() == 1 && fbranch->mIns[0].mType == ASMIT_CMP && fbranch->mIns[0].mMode == ASMIM_IMMEDIATE &&
							(fbranch->mBranch == ASMIT_BEQ || fbranch->mBranch == ASMIT_BNE) &&
							fbranch->mNumEntries == 1 && !fbranch->mExitRequiredRegs[CPU_REG_C] && !fbranch->mExitRequiredRegs[CPU_REG_Z])
						{
							int fcmp = fbranch->mIns[0].mAddress;
							if (cmp == lower && fcmp == lower + 1)
							{
								mIns[sz - 1].mAddress = fcmp;
								mBranch = mBranch == ASMIT_BEQ ? ASMIT_BCC : ASMIT_BCS;
								cmp = fcmp;
								changed = true;
							}
						}
					}
				}
			}
			else
				cmp = -1;
		}

		if (mFalseJump && cmp != -1)
		{
			if (cmp == upper)
			{
				if (mBranch == ASMIT_BCC)
				{
					mBranch = ASMIT_BNE;
					changed = true;
				}
				else if (mBranch == ASMIT_BCS)
				{
					mBranch = ASMIT_BEQ;
					changed = true;
				}
			}

			if (mBranch == ASMIT_BEQ && lower == cmp && upper == cmp ||
				mBranch == ASMIT_BNE && (cmp < lower || cmp > upper) ||
				mBranch == ASMIT_BCS && cmp <= lower ||
				mBranch == ASMIT_BCC && cmp > upper)
			{
				mFalseJump->mEntryBlocks.RemoveAll(this);
				mFalseJump->mNumEntries--;
				mFalseJump = nullptr;
				mBranch = ASMIT_JMP;
				mTrueJump->CompressSwitchCascade(lower, upper, cmp, ASMIT_JMP);
				return true;
			}

			if (mBranch == ASMIT_BNE && lower == cmp && upper == cmp ||
				mBranch == ASMIT_BEQ && (cmp < lower || cmp > upper) ||
				mBranch == ASMIT_BCC && cmp <= lower ||
				mBranch == ASMIT_BCS && cmp > upper)
			{
				mTrueJump->mEntryBlocks.RemoveAll(this);
				mTrueJump->mNumEntries--;
				mBranch = ASMIT_JMP;
				mTrueJump = mFalseJump;
				mFalseJump = nullptr;
				mTrueJump->CompressSwitchCascade(lower, upper, cmp, ASMIT_JMP);
				return true;
			}

			if (mBranch == ASMIT_BEQ)
			{
				if (mTrueJump->CompressSwitchCascade(cmp, cmp, cmp, ASMIT_BEQ)) changed = true;
				if (cmp == lower) lower++;
				if (cmp == upper) upper--;
				if (mFalseJump->CompressSwitchCascade(lower, upper, cmp, ASMIT_BNE)) changed = true;
				return changed;
			}
			else if (mBranch == ASMIT_BNE)
			{
				if (mFalseJump->CompressSwitchCascade(cmp, cmp, cmp, ASMIT_BEQ)) changed = true;
				if (cmp == lower) lower++;
				if (cmp == upper) upper--;
				if (mTrueJump->CompressSwitchCascade(lower, upper, cmp, ASMIT_BNE)) changed = true;
				return changed;
			}
			else if (mBranch == ASMIT_BCC)
			{
				if (mTrueJump->CompressSwitchCascade(lower, cmp - 1, cmp, ASMIT_BCC)) changed = true;
				if (branch == ASMIT_BNE)
				{
					if (mFalseJump->CompressSwitchCascade(cmp + 1, upper, cmp, ASMIT_BCS)) changed = true;
				}
				else
				{
					if (mFalseJump->CompressSwitchCascade(cmp, upper, cmp, ASMIT_BCS)) changed = true;
				}
				return changed;
			}
			else
			{
				if (mFalseJump->CompressSwitchCascade(lower, cmp - 1, cmp, ASMIT_BCC)) changed = true;
				if (branch == ASMIT_BNE)
				{
					if (mTrueJump->CompressSwitchCascade(cmp + 1, upper, cmp, ASMIT_BCS)) changed = true;
				}
				else
				{
					if (mTrueJump->CompressSwitchCascade(cmp, upper, cmp, ASMIT_BCS)) changed = true;
				}
				return changed;
			}
		}

		if (mTrueJump && mTrueJump->CompressSwitchCascade(lower, upper, cmp, mBranch)) changed = true;
		if (mFalseJump && mFalseJump->CompressSwitchCascade(lower, upper, cmp, InvertBranchCondition(mBranch))) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::Split16BitLoopCount(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

#if 1
		int	sz = mIns.Size();
		if (sz >= 8 && mBranch == ASMIT_BNE)
		{
			if (mIns[sz - 8].mType == ASMIT_CLC &&
				mIns[sz - 7].mType == ASMIT_LDA &&
				mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0xff &&
				mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 7]) &&

				mIns[sz - 4].mType == ASMIT_LDA &&
				mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0xff &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&

				mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 7]) &&

				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 2].mMode) &&

				!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				changed = true;

				NativeCodeBasicBlock* pblock = nullptr;
				if (mEntryBlocks.Size() == 2)
				{
					if (mEntryBlocks[0] == this)
						pblock = mEntryBlocks[1];
					else if (mEntryBlocks[1] == this)
						pblock = mEntryBlocks[0];
				}

				bool	preinc = false;
				if (pblock && !pblock->mFalseJump && mTrueJump == this && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE && !mFalseJump->mEntryRequiredRegs[mIns[sz - 7].mAddress] && !mEntryRequiredRegs[CPU_REG_A])
				{					
					int i = 0;
					while (i < sz - 8 && !mIns[i].ReferencesZeroPage(mIns[sz - 7].mAddress))
						i++;
					if (i == sz - 8)
						preinc = true;
				}

				NativeCodeInstruction	ilow(mIns[sz - 7]);
				NativeCodeInstruction	ihigh(mIns[sz - 4]);

				mIns.SetSize(sz - 8);

				if (preinc)
				{
					NativeCodeBasicBlock* dblock = proc->AllocateBlock();
					NativeCodeBasicBlock* zblock = proc->AllocateBlock();

					zblock->mTrueJump = this;

					dblock->mTrueJump = this;
					dblock->mFalseJump = mFalseJump;
					dblock->mBranch = ASMIT_BNE;

					mFalseJump = dblock;

					pblock->mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_LDA, ilow));
					pblock->mBranch = ASMIT_BEQ;
					pblock->mFalseJump = zblock;
					zblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_INC, ihigh));

					mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_DEC, ilow));
					dblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_DEC, ihigh));
				}
				else
				{
					NativeCodeBasicBlock* hblock = proc->AllocateBlock();
					NativeCodeBasicBlock* dblock = proc->AllocateBlock();
					NativeCodeBasicBlock* zblock = proc->AllocateBlock();

					zblock->mTrueJump = mTrueJump;
					zblock->mFalseJump = mFalseJump;
					zblock->mBranch = ASMIT_BNE;

					dblock->mTrueJump = mTrueJump;
					dblock->mFalseJump = zblock;
					dblock->mBranch = ASMIT_BNE;

					hblock->mTrueJump = dblock;
					hblock->mBranch = ASMIT_JMP;
					mTrueJump = dblock;
					mFalseJump = hblock;

					mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_LDA, ilow));

					hblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_DEC, ihigh));

					dblock->mIns.Push(NativeCodeInstruction(ilow.mIns, ASMIT_DEC, ilow));

					zblock->mIns.Push(NativeCodeInstruction(ihigh.mIns, ASMIT_LDA, ihigh));
				}
			}
		}
#endif
		if (mTrueJump && mTrueJump->Split16BitLoopCount(proc))
			changed = true;
		if (mFalseJump && mFalseJump->Split16BitLoopCount(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveStoresBehindCondition(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mEntryBlocks.Size() > 1)
		{
			NativeCodeBasicBlock* eb = mEntryBlocks[0];

			int addr, index, taddr, tindex;
			NativeCodeInstruction	ains;

			if (eb->HasTailSTAInto(addr, index, this))
			{
				int i = 1;
				while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTAInto(taddr, tindex, this) && taddr == addr)
					i++;
				if (i == mEntryBlocks.Size())
				{
					mEntryRequiredRegs += CPU_REG_A;

					mIns.Insert(0, eb->mIns[index]);
					mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						NativeCodeBasicBlock* b = mEntryBlocks[i];
						b->HasTailSTA(taddr, tindex);
						b->mExitRequiredRegs += CPU_REG_A;

						for (int j = tindex + 1; j < b->mIns.Size(); j++)
							b->mIns[j].mLive |= LIVE_CPU_REG_A;
						b->mIns.Remove(tindex);
					}
					changed = true;
				}
			}

			if (eb->HasTailSTXInto(addr, index, this))
			{
				int i = 1;
				while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTXInto(taddr, tindex, this) && taddr == addr)
					i++;
				if (i == mEntryBlocks.Size())
				{
					mEntryRequiredRegs += CPU_REG_X;

					mIns.Insert(0, eb->mIns[index]);
					mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						NativeCodeBasicBlock* b = mEntryBlocks[i];
						b->HasTailSTX(taddr, tindex);
						b->mExitRequiredRegs += CPU_REG_X;
						for (int j = tindex + 1; j < b->mIns.Size(); j++)
							b->mIns[j].mLive |= LIVE_CPU_REG_X;
						b->mIns.Remove(tindex);
					}
					changed = true;
				}
			}

			if (eb->HasTailSTYInto(addr, index, this))
			{
				int i = 1;
				while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTYInto(taddr, tindex, this) && taddr == addr)
					i++;
				if (i == mEntryBlocks.Size())
				{
					mEntryRequiredRegs += CPU_REG_Y;

					mIns.Insert(0, eb->mIns[index]);
					mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						NativeCodeBasicBlock* b = mEntryBlocks[i];
						b->HasTailSTY(taddr, tindex);
						b->mExitRequiredRegs += CPU_REG_Y;
						for (int j = tindex + 1; j < b->mIns.Size(); j++)
							b->mIns[j].mLive |= LIVE_CPU_REG_Y;
						b->mIns.Remove(tindex);
					}
					changed = true;
				}
			}
		}
		
		if (mFalseJump && mTrueJump)
		{
			NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr;
			if (mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump && mFalseJump->mNumEntries == 2 && mTrueJump->mNumEntries == 1)
			{
				cblock = mTrueJump;
				eblock = mFalseJump;
			}
			if (mFalseJump->mTrueJump == mTrueJump && !mFalseJump->mFalseJump && mTrueJump->mNumEntries == 2 && mFalseJump->mNumEntries == 1)
			{
				cblock = mFalseJump;
				eblock = mTrueJump;
			}

			if (eblock && eblock != this)
			{
				NativeCodeInstruction	ins, cins;
				int						index, cindex;

				if (HasTailSTAGlobal(ins, index) && cblock->HasTailSTAGlobal(cins, cindex) && ins.SameEffectiveAddress(cins))
				{
					if (!cblock->ReferencesMemory(ins, 0, cindex))
					{
						mExitRequiredRegs += CPU_REG_A;
						cblock->mExitRequiredRegs += CPU_REG_A;
						eblock->mEntryRequiredRegs += CPU_REG_A;

						uint32	live = LIVE_CPU_REG_A;
						if (ins.ReferencesXReg())
						{
							live += LIVE_CPU_REG_X;
							mExitRequiredRegs += CPU_REG_X;
							cblock->mExitRequiredRegs += CPU_REG_X;
						}
						if (ins.ReferencesYReg())
						{
							live += LIVE_CPU_REG_Y;
							mExitRequiredRegs += CPU_REG_Y;
							cblock->mExitRequiredRegs += CPU_REG_Y;
						}

						eblock->mIns.Insert(0, ins);
						for (int i = index; i < mIns.Size(); i++)
							mIns[i].mLive |= live;
						for (int i = cindex; i < cblock->mIns.Size(); i++)
							cblock->mIns[i].mLive |= live;
						mIns.Remove(index);
						cblock->mIns.Remove(cindex);
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->MoveStoresBehindCondition()) changed = true;
		if (mFalseJump && mFalseJump->MoveStoresBehindCondition()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveStoresBeforeDiamond(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;
		if (mTrueJump && mFalseJump)
		{
			NativeCodeBasicBlock* dblock = nullptr, * eblock = nullptr;

			if (mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump && mFalseJump->mNumEntries == 2 && mTrueJump->mNumEntries == 1)
			{
				dblock = mTrueJump;
				eblock = mFalseJump;
			}
			else if (mFalseJump->mTrueJump == mTrueJump && !mFalseJump->mFalseJump && mTrueJump->mNumEntries == 2 && mFalseJump->mNumEntries == 1)
			{
				dblock = mFalseJump;
				eblock = mTrueJump;
			}

			if (eblock && eblock->mEntryRequiredRegs.Size() > 0)
			{
				bool	avalid = eblock->mEntryRequiredRegs[CPU_REG_A] && !dblock->ChangesAccu();
				bool	xvalid = eblock->mEntryRequiredRegs[CPU_REG_X] && !dblock->ChangesXReg();
				bool	yvalid = eblock->mEntryRequiredRegs[CPU_REG_Y] && !dblock->ChangesYReg();

				int i = 0;
				while (i < eblock->mIns.Size())
				{
					NativeCodeInstruction& ins(eblock->mIns[i]);

					bool	move = false;
					if (avalid)
					{
						if (ins.mType == ASMIT_STA)
							move = true;
						else if (ins.ChangesAccu())
							avalid = false;
					}
					else if (xvalid)
					{
						if (ins.mType == ASMIT_STX)
							move = true;
						else if (ins.ChangesXReg())
							xvalid = false;
					}
					else if (yvalid)
					{
						if (ins.mType == ASMIT_STY)
							move = true;
						else if (ins.ChangesYReg())
							yvalid = false;
					}
					else
						break;

					if (move && eblock->MayBeMovedBeforeBlock(i, ins) && dblock->MayBeMovedBeforeBlock(dblock->mIns.Size(), ins))
					{
						ins.mLive = LIVE_ALL;
						mIns.Push(ins);
						eblock->mIns.Remove(i);
						changed = true;
					}
					else
						i++;
				}
			}
		}

		if (mTrueJump && mTrueJump->MoveStoresBeforeDiamond()) changed = true;
		if (mFalseJump && mFalseJump->MoveStoresBeforeDiamond()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockFlagsForwarding(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		int i = mIns.Size() - 1;
		while (i >= 0)
		{
			if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
			{
				int j = i - 1;
				while (j >= 0 && !mIns[j].ChangesZFlag())
					j--;
				if (j >= 0)
				{
					if (mIns[j].ChangesAccuAndFlag())
					{
						while (j < i)
						{
							mIns[j].mLive |= LIVE_CPU_REG_Z;
							j++;
						}
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (j > 0 && mIns[j - 1].ChangesAccuAndFlag() && CanSwapInstructions(j - 1))
					{
						int live = mIns[j].mLive | mIns[j - 1].mLive;
						mIns[j].mLive |= live;
						mIns[j - 1].mLive |= live;

						NativeCodeInstruction	ins(mIns[j]);
						mIns[j] = mIns[j - 1];
						mIns[j - 1] = ins;

						while (j < i)
						{
							mIns[j].mLive |= LIVE_CPU_REG_Z;
							j++;
						}

						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				else
				{
					int j = 0;
					while (j < mEntryBlocks.Size() && mEntryBlocks[j]->mIns.Size() > 0 && mEntryBlocks[j]->mIns.Last().ChangesAccuAndFlag())
						j++;
					if (j == mEntryBlocks.Size())
					{
						for (int j = 0; j < mEntryBlocks.Size(); j++)
							mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Z;
						mEntryRequiredRegs += CPU_REG_Z;

						j = 0;
						while (j < i)
						{
							mIns[j].mLive |= LIVE_CPU_REG_Z;
							j++;
						}
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
			}

			i--;
		}

		if (mTrueJump && mTrueJump->CrossBlockFlagsForwarding())
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockFlagsForwarding())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::LoopRegisterWrapAround(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mNumEntries == 2)
		{
			NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr, * bblock = nullptr;

			if (mEntryBlocks[0]->mFalseJump)
			{
				eblock = mEntryBlocks[0];
				bblock = mEntryBlocks[1];
			}
			else if (mEntryBlocks[1]->mFalseJump)
			{
				eblock = mEntryBlocks[1];
				bblock = mEntryBlocks[0];
			}

			if (eblock && eblock != this && !bblock->mFalseJump)
			{
				if (eblock->mFalseJump == this)
					cblock = eblock->mTrueJump;
				else
					cblock = eblock->mFalseJump;

				int i = eblock->mIns.Size() - 1;
				while (i >= 0 && !eblock->mIns[i].ChangesXReg())
					i--;
				if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDX && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					int addr = eblock->mIns[i].mAddress;

					int j = 0;
					while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ChangesZeroPage(addr))
						j++;
					if (j < mIns.Size())
					{
						if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
						{
							bblock->mIns.Push(mIns[j]);
							bblock->mExitRequiredRegs += addr;
							mEntryRequiredRegs += addr;
							mIns.Remove(j);
							changed = true;
						}
					}
				}

				i = eblock->mIns.Size() - 1;
				while (i >= 0 && !eblock->mIns[i].ChangesYReg())
					i--;
				if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDY && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					int addr = eblock->mIns[i].mAddress;

					int j = 0;
					while (j < mIns.Size() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesZeroPage(addr))
						j++;
					if (j < mIns.Size())
					{
						if (mIns[j].mType == ASMIT_STY && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
						{
							bblock->mIns.Push(mIns[j]);
							bblock->mExitRequiredRegs += addr;
							mEntryRequiredRegs += addr;
							mIns.Remove(j);
							changed = true;
						}
					}
				}

				i = eblock->mIns.Size() - 1;
				while (i >= 0 && !eblock->mIns[i].ChangesAccu())
					i--;
				if (i >= 0 && eblock->mIns[i].mType == ASMIT_LDA && eblock->mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					int addr = eblock->mIns[i].mAddress;

					int j = 0;
					while (j < mIns.Size() && !mIns[j].ReferencesAccu() && !mIns[j].ChangesZeroPage(addr))
						j++;
					if (j < mIns.Size())
					{
						if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr)
						{
							bblock->mIns.Push(mIns[j]);
							bblock->mExitRequiredRegs += addr;
							mEntryRequiredRegs += addr;
							mIns.Remove(j);
							changed = true;
						}
					}
				}
#if 0
				int esz = eblock->mIns.Size();
				if (mIns.Size() > 0 && esz >= 2 &&
					mIns[0].mType == ASMIT_LDX &&
					eblock->mIns[esz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(eblock->mIns[esz - 2]) &&
					eblock->mIns[esz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, eblock->mIns[esz - 1].mMode) &&
					!(eblock->mIns[esz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
				{
					printf("Doopsie\n");

					bblock->mIns.Push(mIns[0]);
					bblock->mExitRequiredRegs += CPU_REG_X;
					mEntryRequiredRegs += CPU_REG_X;
					mIns.Remove(0);

					eblock->mExitRequiredRegs += CPU_REG_X;
					eblock->mIns[esz - 2].mType = ASMIT_LDX; eblock->mIns[esz - 2].mLive |= LIVE_CPU_REG_X;
					eblock->mIns[esz - 1].mType = ASMIT_CPX; eblock->mIns[esz - 1].mLive |= LIVE_CPU_REG_X;
					changed = true;
				}
#endif
			}
		}

		if (mTrueJump && mTrueJump->LoopRegisterWrapAround())
			changed = true;
		if (mFalseJump && mFalseJump->LoopRegisterWrapAround())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::EliminateDeadLoops(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mNumEntries == 2 && mFalseJump)
		{
			NativeCodeBasicBlock* eblock = nullptr;
			if (mTrueJump == this)
				eblock = mFalseJump;
			else if (mFalseJump == this)
				eblock = mTrueJump;

			if (eblock)
			{
				if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INX || mIns[0].mType == ASMIT_DEX) && mIns[1].mType == ASMIT_CPX)
				{
					if (!(eblock->mEntryRequiredRegs[CPU_REG_X]))
					{
						mLoopHead = false;
						mTrueJump = eblock;
						mBranch = ASMIT_JMP;
						mEntryBlocks.RemoveAll(this);
						mFalseJump = nullptr;
						mNumEntries--;
						changed = true;
					}
				}
				else if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INY || mIns[0].mType == ASMIT_DEY) && mIns[1].mType == ASMIT_CPY)
				{
					if (!(eblock->mEntryRequiredRegs[CPU_REG_Y]))
					{
						mLoopHead = false;
						mTrueJump = eblock;
						mBranch = ASMIT_JMP;
						mEntryBlocks.RemoveAll(this);
						mFalseJump = nullptr;
						mNumEntries--;
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->EliminateDeadLoops())
			changed = true;
		if (mFalseJump && mFalseJump->EliminateDeadLoops())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SinglePathRegisterForwardY(NativeCodeBasicBlock* path, int yreg)
{
	if (path && path->mNumEntries == 1 && path->mTrueJump && !path->mFalseJump && !path->ChangesYReg() && !path->ChangesZeroPage(yreg))
	{
		NativeCodeBasicBlock* mblock = path->mTrueJump;

		if (mblock && mblock->mIns.Size() && mblock->mIns[0].mType == ASMIT_LDY && mblock->mIns[0].mMode == ASMIM_ZERO_PAGE && mblock->mIns[0].mAddress == yreg)
		{
			bool	fail = false;
			for (int i = 0; i < mblock->mEntryBlocks.Size(); i++)
			{
				NativeCodeBasicBlock* eblock = mblock->mEntryBlocks[i];
				if (eblock != path && eblock->mFalseJump)
				{
					fail = true;
					break;
				}
			}
			if (!fail)
			{
				for (int i = 0; i < mblock->mEntryBlocks.Size(); i++)
				{
					NativeCodeBasicBlock* eblock = mblock->mEntryBlocks[i];
					if (eblock != path)
					{
						eblock->mIns.Push(mblock->mIns[0]);
						eblock->mExitRequiredRegs += CPU_REG_Y;
					}
				}

				mblock->mEntryRequiredRegs += CPU_REG_Y;
				mExitRequiredRegs += CPU_REG_Y;
				for (int i = 0; i < path->mIns.Size(); i++)
					path->mIns[i].mLive |= LIVE_CPU_REG_Y;
				path->mEntryRequiredRegs += CPU_REG_Y;
				path->mExitRequiredRegs += CPU_REG_Y;
				int i = mIns.Size() - 1;
				while (i >= 0 && !(mIns[i].mLive & LIVE_CPU_REG_Y))
				{
					mIns[i].mLive |= LIVE_CPU_REG_Y;
					i--;
				}
				mblock->mIns.Remove(0);
				return true;
			}
		}
	}

	return false;
}

bool NativeCodeBasicBlock::CrossBlockRegZPForward(int areg, int xreg, int yreg)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		NativeCodeBasicBlock* pblock = nullptr;
		if (mEntryBlocks.Size() == 1)
			pblock = mEntryBlocks[0];
		else
			areg = xreg = yreg = -1;

		bool	aref = false, xref = false, yref = false;
		int		nareg = areg, nxreg = xreg, nyreg = yreg;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (pblock)
			{
				if (!aref && ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE)
				{
					if (ins.mAddress == xreg)
					{

					}
					else if (ins.mAddress == yreg)
					{

					}
				}
				else if (!xref && ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE)
				{
					if (ins.mAddress == areg)
					{
						if (!pblock->mExitRequiredRegs[CPU_REG_X])
						{
							int j = pblock->mIns.Size();
							while (j > 0 && !(pblock->mIns[j - 1].mLive & LIVE_CPU_REG_Z) && !pblock->mIns[j - 1].ChangesAccu() && !pblock->mIns[j - 1].ReferencesXReg())
								j--;
							if (j > 0 && !(pblock->mIns[j - 1].mLive & LIVE_CPU_REG_Z))
							{
								pblock->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_TAX));
								while (j < pblock->mIns.Size())
								{
									pblock->mIns[j].mLive |= LIVE_CPU_REG_X;
									j++;
								}
								j = 0;
								while (j < i)
								{
									mIns[j].mLive |= LIVE_CPU_REG_X;
									j++;
								}
								pblock->mExitRequiredRegs += CPU_REG_X;
								mEntryRequiredRegs += CPU_REG_X;
								ins.mType = ASMIT_NOP;
								ins.mMode = ASMIM_IMPLIED;
								nyreg = areg;
								changed = true;
							}
						}
					}
				}
				else if (!yref && ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE)
				{
					if (ins.mAddress == areg)
					{
						if (!pblock->mExitRequiredRegs[CPU_REG_Y])
						{
							int j = pblock->mIns.Size();
							while (j > 0 && !(pblock->mIns[j - 1].mLive & LIVE_CPU_REG_Z) && !pblock->mIns[j - 1].ChangesAccu() && !pblock->mIns[j - 1].ReferencesYReg())
								j--;
							if (j > 0 && !(pblock->mIns[j - 1].mLive & LIVE_CPU_REG_Z))
							{
								pblock->mIns.Insert(j, NativeCodeInstruction(ins.mIns, ASMIT_TAY));
								while (j < pblock->mIns.Size())
								{
									pblock->mIns[j].mLive |= LIVE_CPU_REG_Y;
									j++;
								}
								j = 0;
								while (j < i)
								{
									mIns[j].mLive |= LIVE_CPU_REG_Y;
									j++;
								}
								pblock->mExitRequiredRegs += CPU_REG_Y;
								mEntryRequiredRegs += CPU_REG_Y;
								ins.mType = ASMIT_NOP;
								ins.mMode = ASMIM_IMPLIED;
								nyreg = areg;
								changed = true;
							}
						}
					}
				}
			}

			if (nareg >= 0 && (ins.ChangesAccu() || ins.ChangesZeroPage(nareg)))
				nareg = -1;
			if (nxreg >= 0 && (ins.ChangesXReg() || ins.ChangesZeroPage(nxreg)))
				nxreg = -1;
			if (nyreg >= 0 && (ins.ChangesYReg() || ins.ChangesZeroPage(nyreg)))
				nyreg = -1;

			if (areg >= 0 && ins.ChangesZeroPage(areg))
				areg = -1;
			if (xreg >= 0 && ins.ChangesZeroPage(xreg))
				xreg = -1;
			if (yreg >= 0 && ins.ChangesZeroPage(yreg))
				yreg = -1;

			if ((ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA) && ins.mMode == ASMIM_ZERO_PAGE)
				nareg = ins.mAddress;
			if ((ins.mType == ASMIT_LDX || ins.mType == ASMIT_STX) && ins.mMode == ASMIM_ZERO_PAGE)
				nxreg = ins.mAddress;
			if ((ins.mType == ASMIT_LDY || ins.mType == ASMIT_STY) && ins.mMode == ASMIM_ZERO_PAGE)
				nyreg = ins.mAddress;

			if (!aref && ins.ReferencesAccu()) aref = true;
			if (!xref && ins.ReferencesXReg()) xref = true;
			if (!yref && ins.ReferencesYReg()) yref = true;
		}

		if (!changed && areg != -1 && !mEntryRequiredRegs[CPU_REG_A] && !mEntryRequiredRegs[CPU_REG_C])
		{
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (i + 3 < mIns.Size() &&
					mIns[i + 0].mType == ASMIT_CLC &&
					mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == areg &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					if (!ChangesZeroPage(areg, 0, i) && !ReferencesZeroPage(mIns[i + 3].mAddress, 0, i))
					{
						NativeCodeInstruction	cins = mIns[i + 0], ains = mIns[i + 1], sins = mIns[i + 3];
						ains.mType = ASMIT_ADC;
						mIns.Remove(i, 4);
						mIns.Insert(0, cins);
						mIns.Insert(1, ains); 
						mIns.Insert(2, sins);
						return true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockRegZPForward(nareg, nxreg, nyreg))
			return true;
		if (mFalseJump && mFalseJump->CrossBlockRegZPForward(nareg, nxreg, nyreg))
			return true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SinglePathStoreForward(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump)
		{
			NumberSet		touched(NUM_REGS);

			int i = mIns.Size();
			while (i > 0)
			{
				i--;
				if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_A])
				{
					if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
					{
						mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
					{
						mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_X])
				{
					if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
					{
						mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_X;
						mExitRequiredRegs += CPU_REG_X;
						mTrueJump->mEntryRequiredRegs += CPU_REG_X;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
					{
						mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_X;
						mExitRequiredRegs += CPU_REG_X;
						mFalseJump->mEntryRequiredRegs += CPU_REG_X;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && !touched[mIns[i].mAddress] && !touched[CPU_REG_Y])
				{
					if (mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && mTrueJump->mNumEntries == 1)
					{
						mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;
						mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[mIns[i].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[i].mAddress] && mFalseJump->mNumEntries == 1)
					{
						mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, mIns[i]));
						for (int j = i; j < mIns.Size(); j++) mIns[j].mLive |= LIVE_CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;
						mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
						mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}

				if (mIns[i].ChangesAccu()) touched += CPU_REG_A;
				if (mIns[i].ChangesXReg()) touched += CPU_REG_X;
				if (mIns[i].ChangesYReg()) touched += CPU_REG_Y;
				if (mIns[i].mMode == ASMIM_ZERO_PAGE) touched += mIns[i].mAddress;
				if (mIns[i].mMode == ASMIM_INDIRECT_Y)
				{
					touched += mIns[i].mAddress;
					touched += mIns[i].mAddress + 1;
				}
				if (mIns[i].mType == ASMIT_JSR)
					break;
			}
		}
		if (mTrueJump && mTrueJump->SinglePathStoreForward())
			changed = true;
		if (mFalseJump && mFalseJump->SinglePathStoreForward())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SinglePathRegisterForward(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump)
		{
			int	areg = -1, xreg = -1, yreg = -1;
			int aindex = -1, xindex = -1, yindex = -1;

			for (int i = 0; i < mIns.Size(); i++)
			{
				NativeCodeInstruction& ins(mIns[i]);

				if (mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					if (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA)
					{
						areg = mIns[i].mAddress;
						aindex = i;
					}
					else if (mIns[i].mType == ASMIT_LDX || mIns[i].mType == ASMIT_STX)
					{
						xreg = mIns[i].mAddress;
						xindex = i;
					}
					else if (mIns[i].mType == ASMIT_LDY || mIns[i].mType == ASMIT_STY)
					{
						yreg = mIns[i].mAddress;
						yindex = i;
					}
					else if (mIns[i].ChangesAddress())
					{
						if (mIns[i].mAddress == areg)
							areg = -1;
						if (mIns[i].mAddress == xreg)
							xreg = -1;
						if (mIns[i].mAddress == yreg)
							yreg = -1;
					}
				}
				else
				{
					if (areg >= 0 && (mIns[i].ChangesAccu() || mIns[i].ChangesZeroPage(areg)))
						areg = -1;
					if (xreg >= 0 && (mIns[i].ChangesXReg() || mIns[i].ChangesZeroPage(xreg)))
						xreg = -1;
					if (yreg >= 0 && (mIns[i].ChangesYReg() || mIns[i].ChangesZeroPage(yreg)))
						yreg = -1;
				}

				if (areg >= 0 && mIns[i].RequiresAccu()) aindex = -1;
				if (yreg >= 0 && mIns[i].RequiresXReg()) yindex = -1;
				if (xreg >= 0 && mIns[i].RequiresYReg()) xindex = -1;

			}

			if (yreg >= 0)
			{
				if (SinglePathRegisterForwardY(mTrueJump, yreg) || SinglePathRegisterForwardY(mFalseJump, yreg))
					changed = true;
			}

			if (!changed)
			{
				if (areg >= 0 && aindex >= 0 && mIns[aindex].mType == ASMIT_LDA && !(mIns[aindex].mLive & LIVE_CPU_REG_Z))
				{
					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
					{
						NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mTrueJump;
						eblock->mIns.Push(mIns[aindex]);
						mIns.Remove(aindex);
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mNumEntries = 1;
						eblock->mEntryBlocks.Push(this);
						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mEntryBlocks.Push(eblock);
						mTrueJump = eblock;
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mIns.Push(mIns[aindex]);
						mIns.Remove(aindex);
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mNumEntries = 1;
						eblock->mEntryBlocks.Push(this);
						mFalseJump->mEntryBlocks.RemoveAll(this);
						mFalseJump->mEntryBlocks.Push(eblock);
						mFalseJump = eblock;
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->SinglePathRegisterForward())
			changed = true;
		if (mFalseJump && mFalseJump->SinglePathRegisterForward())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockStoreLoadBypass(NativeCodeProcedure* proc)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mTrueJump->mTrueJump && !mFalseJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 0)
		{
			int sz = mIns.Size();

			if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mTrueJump->mIns[0].mLive & LIVE_MEM))
			{
				if (mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mTrueJump->mIns[0].mAddress)
				{
					NativeCodeBasicBlock* lblock = proc->AllocateBlock();

					for (int i = 1; i < mTrueJump->mIns.Size(); i++)
						lblock->mIns.Push(mTrueJump->mIns[i]);
					mTrueJump->mIns.SetSize(1);

					mTrueJump->mTrueJump->RemEntryBlock(mTrueJump);
					mTrueJump->mTrueJump->AddEntryBlock(lblock);
					if (mTrueJump->mFalseJump)
					{
						mTrueJump->mFalseJump->RemEntryBlock(mTrueJump);
						mTrueJump->mFalseJump->AddEntryBlock(lblock);
					}

					lblock->mTrueJump = mTrueJump->mTrueJump;
					lblock->mFalseJump = mTrueJump->mFalseJump;
					lblock->mBranch = mTrueJump->mBranch;
					
					lblock->mNumEntries = 2;
					lblock->mEntryBlocks.Push(this);
					lblock->mEntryBlocks.Push(mTrueJump);

					lblock->mEntryProvidedRegs = mTrueJump->mEntryRequiredRegs;
					lblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;
					lblock->mExitRequiredRegs += CPU_REG_A;

					mTrueJump->mEntryRequiredRegs += CPU_REG_A;

					mTrueJump->RemEntryBlock(this);

					mTrueJump->mFalseJump = nullptr;
					mTrueJump->mTrueJump = lblock;
					mTrueJump->mBranch = ASMIT_JMP;

					mTrueJump = lblock;

					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockStoreLoadBypass(proc))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockStoreLoadBypass(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SimpleInlineCalls(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_JSR)
			{
				if (mIns[i].mLinkerObject && mIns[i].mLinkerObject->mNativeProc)
				{
					NativeCodeProcedure* proc = mIns[i].mLinkerObject->mNativeProc;
					if (proc->mSimpleInline)
					{
						NativeCodeBasicBlock* sins = proc->mEntryBlock->mTrueJump;
						mIns.Remove(i);
						for (int j = 0; j < sins->mIns.Size(); j++)
							mIns.Insert(i + j, sins->mIns[j]);
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->SimpleInlineCalls())
			changed = true;
		if (mFalseJump && mFalseJump->SimpleInlineCalls())
			changed = true;

	}

	return changed;
}

bool NativeCodeBasicBlock::Expand16BitLoopBranch(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
		{
			int sz = mIns.Size();
			if (sz >= 1 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY))
			{
				if (mTrueJump->mTrueJump->mLoopHead && IsDominatedBy(mTrueJump->mTrueJump) ||
					mLoopHead && !mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == this)
				{
					NativeCodeBasicBlock* tblock = mTrueJump->mTrueJump;
					NativeCodeBasicBlock* nblock = mProc->AllocateBlock();
					nblock->Close(mIns[sz - 1].mIns, mFalseJump, mTrueJump->mFalseJump, ASMIT_BEQ);
					mBranch = ASMIT_BCC;
					mFalseJump->RemEntryBlock(this);
					mFalseJump->AddEntryBlock(nblock);
					mTrueJump->RemEntryBlock(this);
					tblock->AddEntryBlock(this);
					mFalseJump = nblock;
					mTrueJump = tblock;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->Expand16BitLoopBranch())
			changed = true;
		if (mFalseJump && mFalseJump->Expand16BitLoopBranch())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ExpandADCShortCascadeToBranch(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 13 < mIns.Size(); i++)
		{
			int sreg, dreg, offset;
			int sregb, dregb, offsetb;

			if (!(mIns[i].mLive & LIVE_CPU_REG_Y))// || !(mIns[i].mLive & LIVE_CPU_REG_X))
			{
				if (Is16BitAddSubImmediate(i, sreg, dreg, offset) && offset >= 0 && offset < 256 && dreg != sreg &&
					Is16BitAddSubImmediate(i + 7, sregb, dregb, offsetb) && offsetb >= offset && offsetb < 256 && dregb != sreg && sreg == sregb)
				{
					mIns.Insert(i, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDA, mIns[i + 1]));
					i++;
					mIns.Insert(i, NativeCodeInstruction(mIns[i + 4].mIns, ASMIT_LDY, mIns[i + 4]));
					i++;

					int offset = 0;
					NativeCodeBasicBlock* pblock = this;

					while (pblock->Is16BitAddSubImmediate(i, sregb, dregb, offsetb) && offsetb >= offset && offsetb < 256 && dregb != sreg && sreg == sregb)
					{
						NativeCodeBasicBlock* eblock = pblock->SplitBlock(i + 4);
						pblock->mIns.Remove(i + 1, 1);
						NativeCodeBasicBlock* iblock = mProc->AllocateBlock();
						pblock->mIns[i + 1].mAddress = offsetb - offset;
						offset = offsetb;
						pblock->mBranch = ASMIT_BCC;
						pblock->mFalseJump = iblock;
						iblock->mIns.Push(NativeCodeInstruction(eblock->mIns[0].mIns, ASMIT_INY));
						iblock->mNumEntries = 1;
						iblock->mEntryBlocks.Push(pblock);
						iblock->Close(eblock->mIns[0].mIns, eblock, nullptr, ASMIT_JMP);
						eblock->mNumEntries++;
						eblock->mEntryBlocks.Push(iblock);
						eblock->mIns.Remove(0, 2);
						eblock->mIns[0].mType = ASMIT_STY;

						pblock = eblock;
						i = 1;
					}

					changed = true;
					break;
				}
			}
		}

		if (mTrueJump && mTrueJump->ExpandADCShortCascadeToBranch())
			changed = true;
		if (mFalseJump && mFalseJump->ExpandADCShortCascadeToBranch())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int	carry = -1;
		if (mEntryRegisterDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			carry = mEntryRegisterDataSet[CPU_REG_C].mValue;

#if 1
		if (mIns.Size() >= 8 && mTrueJump && mFalseJump &&
			(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			int	sz = mIns.Size();

			if (mIns[sz - 8].mType == ASMIT_SEC &&
				mIns[sz - 7].mType == ASMIT_LDA && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE &&
				mIns[sz - 6].mType == ASMIT_SBC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 1 &&
				mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].mMode == ASMIM_ZERO_PAGE && mIns[sz - 5].mAddress == mIns[sz - 7].mAddress &&
				mIns[sz - 3].mType == ASMIT_SBC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 7].mAddress &&
				!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				if (mIns[sz - 4].mType == ASMIT_TXA && mIns[sz - 2].mType == ASMIT_TAX ||
					mIns[sz - 4].mType == ASMIT_TYA && mIns[sz - 2].mType == ASMIT_TAY || 
					mIns[sz - 4].mType == ASMIT_LDA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
					mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 4].mAddress)
				{
					NativeCodeBasicBlock* dhblock = mProc->AllocateBlock();
					NativeCodeBasicBlock* dlblock = mProc->AllocateBlock();
					NativeCodeBasicBlock* chblock = mProc->AllocateBlock();

					dhblock->mBranch = ASMIT_JMP; dhblock->mTrueJump = dlblock;
					dlblock->mBranch = ASMIT_BNE; dlblock->mFalseJump = chblock;
					chblock->mBranch = ASMIT_BNE;

					if (mBranch == ASMIT_BEQ)
					{
						dlblock->mTrueJump = mFalseJump;
						chblock->mTrueJump = mFalseJump;
						chblock->mFalseJump = mTrueJump;
					}
					else
					{
						dlblock->mTrueJump = mTrueJump;
						chblock->mTrueJump = mTrueJump;
						chblock->mFalseJump = mFalseJump;
					}

					mBranch = ASMIT_BNE;
					mTrueJump->RemEntryBlock(this);
					mFalseJump->RemEntryBlock(this);

					mTrueJump = dlblock;
					mFalseJump = dhblock;

					dlblock->AddEntryBlock(this);
					dhblock->AddEntryBlock(this);
					dlblock->AddEntryBlock(dhblock);
					chblock->AddEntryBlock(dlblock);

					dlblock->mTrueJump->AddEntryBlock(dlblock);
					chblock->mTrueJump->AddEntryBlock(chblock);
					chblock->mFalseJump->AddEntryBlock(chblock);

					dlblock->mIns.Push(NativeCodeInstruction(mIns[sz - 7].mIns, ASMIT_DEC, mIns[sz - 7]));
					switch (mIns[sz - 4].mType)
					{
					case ASMIT_TXA:
						dhblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_DEX));
						chblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_TXA));
						break;
					case ASMIT_TYA:
						dhblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_DEY));
						chblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_TYA));
						break;
					case ASMIT_LDA:
						dhblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_DEC, mIns[sz - 4]));
						chblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_LDA, mIns[sz - 4]));
						break;
					}

					mIns[sz - 8] = mIns[sz - 7];
					mIns.SetSize(sz - 7);

					changed = true;
				}
			}
		}
#endif

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				const InterInstruction* iins(mIns[i].mIns);

				rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TXA));
				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCC;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA &&
				mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				const InterInstruction* iins(mIns[i].mIns);

				rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TXA));
				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCS;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TYA &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				const InterInstruction* iins(mIns[i].mIns);

				rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TYA));
				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCC;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TYA &&
				mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				const InterInstruction* iins(mIns[i].mIns);

				rblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_TYA));
				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCS;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}

			if (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 == 0 &&
				mIns[i + 2].mType == ASMIT_ROL && 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_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				mIns[i + 0].mType = ASMIT_NOP;
				mIns[i + 1].mType = ASMIT_LDX;
				mIns[i + 2].mType = ASMIT_NOP;
				mIns[i + 3].mType = ASMIT_STX;
				mIns[i + 4].mType = ASMIT_NOP;

				const InterInstruction* iins(mIns[i].mIns);

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 2);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCC;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
#if 1
			if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TAY &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 4].mType == ASMIT_TYA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				mIns[i + 0].mType = ASMIT_NOP;
				mIns[i + 1].mType = ASMIT_LDY;
				mIns[i + 2].mType = ASMIT_NOP;
				mIns[i + 3].mType = ASMIT_STY;
				mIns[i + 4].mType = ASMIT_NOP;

				const InterInstruction* iins(mIns[i].mIns);

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 2);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCC;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}


			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 == 0 &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				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_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				mIns[i + 0].mType = ASMIT_NOP;
				mIns[i + 1].mType = ASMIT_LDX;
				mIns[i + 2].mType = ASMIT_NOP;
				mIns[i + 3].mType = ASMIT_STX;
				mIns[i + 4].mType = ASMIT_NOP;

				const InterInstruction* iins(mIns[i].mIns);

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 2);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCS;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}

			if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TAY &&
				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 + 1].mAddress == 0 &&
				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_C | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;

				mIns[i + 0].mType = ASMIT_NOP;
				mIns[i + 1].mType = ASMIT_LDY;
				mIns[i + 2].mType = ASMIT_NOP;
				mIns[i + 3].mType = ASMIT_STY;
				mIns[i + 4].mType = ASMIT_NOP;

				const InterInstruction* iins(mIns[i].mIns);

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY));
				for (int j = i + 3; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 2);

				mTrueJump = rblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BCS;

				eblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 4 == mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
				!(mIns[i + 3].mLive & LIVE_CPU_REG_A) &&
				mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_C] && 
				(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
			{
				mIns[i + 3].mType = ASMIT_INC;
				mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

				if (mBranch == ASMIT_BCC)
					mBranch = ASMIT_BNE;
				else
					mBranch = ASMIT_BEQ;

				changed = true;
				break;

			}
			else if (i + 4 == mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
				!(mIns[i + 3].mLive & LIVE_CPU_REG_A) &&
				mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_C] &&
				(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
			{
				mIns[i + 3].mType = ASMIT_INC;
				mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

				if (mBranch == ASMIT_BCC)
					mBranch = ASMIT_BNE;
				else
					mBranch = ASMIT_BEQ;

				changed = true;
				break;

			}
#endif
#if 1
			if (i + 5 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ABSOLUTE_X &&
					mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
					mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
					mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
					mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
					mIns[i + 5].mType == ASMIT_TAX && mIns[i + 5].mMode == ASMIM_IMPLIED && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
				{
					changed = true;

					NativeCodeBasicBlock* mblock = proc->AllocateBlock();
					NativeCodeBasicBlock* rblock = proc->AllocateBlock();

					rblock->mTrueJump = mTrueJump;
					rblock->mFalseJump = mFalseJump;
					rblock->mBranch = mBranch;

					for (int j = i + 6; j < mIns.Size(); j++)
						rblock->mIns.Push(mIns[j]);

					mIns.SetSize(i + 1);
					mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0));
					mIns[i + 1].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X;

					mTrueJump = mblock;
					mFalseJump = rblock;
					mBranch = ASMIT_BMI;

					mblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0xff));

					mblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					break;
				}
			}
#endif
#if 1
			if (i + 2 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x00 &&
					mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
					mIns[i + 2].mType == ASMIT_TAX && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
				{
					changed = true;

					NativeCodeBasicBlock* mblock = proc->AllocateBlock();
					NativeCodeBasicBlock* rblock = proc->AllocateBlock();

					rblock->mTrueJump = mTrueJump;
					rblock->mFalseJump = mFalseJump;
					rblock->mBranch = mBranch;

					for (int j = i + 3; j < mIns.Size(); j++)
						rblock->mIns.Push(mIns[j]);

					mIns.SetSize(i + 1);
					mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0));
					mIns[i + 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_X;

					mTrueJump = mblock;
					mFalseJump = rblock;
					mBranch = ASMIT_BCC;

					mblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0xff));

					mblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					break;
				}
			}
#endif
#if 1
			if (i + 6 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
					mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
					mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
					mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
					mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
					mIns[i + 6].mType == ASMIT_ROL && mIns[i + 6].mMode == ASMIM_IMPLIED)
				{
					changed = true;

					NativeCodeBasicBlock* eblock = proc->AllocateBlock();
					NativeCodeBasicBlock* neblock = proc->AllocateBlock();
					NativeCodeBasicBlock* rblock = proc->AllocateBlock();

					rblock->mTrueJump = mTrueJump;
					rblock->mFalseJump = mFalseJump;
					rblock->mBranch = mBranch;

					for (int j = i + 7; j < mIns.Size(); j++)
						rblock->mIns.Push(mIns[j]);
					mIns.SetSize(i + 1);
					mIns[i + 0].mLive |= LIVE_CPU_REG_C;
					mIns[i + 0].mType = ASMIT_ASL;

					mTrueJump = neblock;
					mFalseJump = eblock;
					mBranch = ASMIT_BCS;

					eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));

					eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					break;
				}
#if 1
				if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
					mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
					mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
					mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
				{
					changed = true;

					NativeCodeBasicBlock* neblock = proc->AllocateBlock();
					NativeCodeBasicBlock* rblock = proc->AllocateBlock();

					neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 4].mAddress));

					rblock->mTrueJump = mTrueJump;
					rblock->mFalseJump = mFalseJump;
					rblock->mBranch = mBranch;

					for (int j = i + 5; j < mIns.Size(); j++)
						rblock->mIns.Push(mIns[j]);
					mIns.SetSize(i + 1);
					mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
					mIns[i + 0].mType = ASMIT_AND;
					mIns[i + 0].mMode = ASMIM_IMMEDIATE;
					mIns[i + 0].mAddress = 0x80;

					mTrueJump = rblock;
					mFalseJump = neblock;
					mBranch = ASMIT_BEQ;

					neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					break;
				}
#endif
				if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
					mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
					mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
					mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff &&
					mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
					mIns[i + 6].mType == ASMIT_ROL && mIns[i + 6].mMode == ASMIM_IMPLIED)
				{
					changed = true;

					NativeCodeBasicBlock* eblock = proc->AllocateBlock();
					NativeCodeBasicBlock* neblock = proc->AllocateBlock();
					NativeCodeBasicBlock* rblock = proc->AllocateBlock();

					rblock->mTrueJump = mTrueJump;
					rblock->mFalseJump = mFalseJump;
					rblock->mBranch = mBranch;

					for (int j = i + 7; j < mIns.Size(); j++)
						rblock->mIns.Push(mIns[j]);
					mIns.SetSize(i + 1);
					mIns[i + 0].mLive |= LIVE_CPU_REG_C;
					mIns.Insert(i + 0, NativeCodeInstruction(mIns[i].mIns, ASMIT_ASL));

					mTrueJump = neblock;
					mFalseJump = eblock;
					mBranch = ASMIT_BCS;

					eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));

					eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
					break;
				}
			}
#endif

#if 1
			if (i + 5 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x00 &&
				mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
				mIns[i + 2].mType == ASMIT_EOR && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_CLC &&
				mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01 &&
				mIns[i + 5].mType == ASMIT_AND && mIns[i + 5].mMode == ASMIM_IMMEDIATE)
			{
				changed = true;

				NativeCodeBasicBlock* csblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				csblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 5].mAddress));

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

				mTrueJump = rblock;
				mFalseJump = csblock;
				mBranch = ASMIT_BCC;

				csblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif

#if 1
			if (i + 6 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_CLC &&
					mIns[i + 1].mType == ASMIT_LDA &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();


					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					if (mIns[i + 6].mLive & LIVE_CPU_REG_A)
						fblock->mIns.Push(mIns[i + 4]);

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);

					iblock->mIns.Push(mIns[i + 6]);
					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 6]);
					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (carry == 0 &&
					mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
					mIns[i + 3].mType == ASMIT_LDA &&
					mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
					mIns[i + 5].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 5]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 5].mMode) &&
					!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_INC; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;

					for (int j = i + 6; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 5]);
					mIns.SetSize(i + 3);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 2].mIns;
					break;
				}


				if (mIns[i + 0].mType == ASMIT_CLC &&
					mIns[i + 1].mType == ASMIT_LDA &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_DEC, mIns[i + 3].mMode) &&
					HasAsmInstructionMode(ASMIT_DEC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					fblock->mIns.Push(mIns[i + 1]);
					fblock->mIns[0].mType = ASMIT_DEC;

					mIns[i + 0].mType = ASMIT_NOP;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 6]);
					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_DEC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (mIns[i + 0].mType == ASMIT_TXA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_TAX &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INX; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					fblock->mIns.Push(mIns[i + 4]);

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 6]);


					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_INC;

					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (mIns[i + 0].mType == ASMIT_TXA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & LIVE_CPU_REG_X) &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP;
					mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X;
					mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					fblock->mIns.Push(mIns[i + 4]);

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 6]);


					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_INC;

					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (mIns[i + 0].mType == ASMIT_TYA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & LIVE_CPU_REG_Y) &&
					mIns[i + 4].mType == ASMIT_TXA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_TAX &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; 
					mIns[i + 1].mType = ASMIT_NOP;
					mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_Y;
					mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					fblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA));

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));

					mIns.SetSize(i + 4);

					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

				if (mIns[i + 0].mType == ASMIT_TYA &&
					mIns[i + 1].mType == ASMIT_CLC &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_TAY &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_INY; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

					fblock->mIns.Push(mIns[i + 4]);

					for (int j = i + 7; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 6]);


					mIns.SetSize(i + 4);
					iblock->mIns[0].mType = ASMIT_INC;

					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BNE;
					mBranchIns = mIns[i + 3].mIns;
					break;
				}

			}
#endif

#if 1
			if (i + 5 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
				mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 5].mType == ASMIT_EOR && mIns[i + 5].mMode == ASMIM_IMMEDIATE)
			{
				uint8 veq = mIns[i + 4].mAddress ^ mIns[i + 5].mAddress, vne = mIns[i + 5].mAddress;

				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				for (int j = i + 6; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i + 0].mLive |= LIVE_CPU_REG_Z;

				mTrueJump = neblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BNE;
				mBranchIns = mIns[i + 0].mIns;

				if (veq != 0)
					eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TAX &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
				mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED &&
				mIns[i + 3].mType == ASMIT_TAY &&
				mIns[i + 4].mType == ASMIT_TXA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				changed = true;

				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				const InterInstruction* iins = mIns[i].mIns;

				for (int j = i + 5; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);
				mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));

				mTrueJump = iblock;
				mFalseJump = rblock;
				mBranch = ASMIT_BCS;
				mBranchIns = iins;

				iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));

				iblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}
			if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TAY &&
				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_TAX &&
				mIns[i + 4].mType == ASMIT_TYA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y)))
			{
				changed = true;

				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				const InterInstruction* iins = mIns[i].mIns;

				for (int j = i + 5; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);
				mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_IMMEDIATE, 0));

				mTrueJump = iblock;
				mFalseJump = rblock;
				mBranch = ASMIT_BCS;
				mBranchIns = iins;

				iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));

				iblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}

#endif
#if 1
			if (i + 3 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED)
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				for (int j = i + 4; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i + 0].mLive |= LIVE_CPU_REG_Z;

				mTrueJump = neblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BNE;
				mBranchIns = mIns[i + 0].mIns;

				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TAY &&
				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 == 0 &&
				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_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 6].mType == ASMIT_TYA &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				rblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, mIns[i + 5]));
				for (int j = i + 7; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i + 0].mType = ASMIT_ORA; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0x00; 
				mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;

				mTrueJump = eblock;
				mFalseJump = neblock;
				mBranch = ASMIT_BPL;
				mBranchIns = mIns[i + 0].mIns;

				eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0x00));
				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0xff));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 4 < mIns.Size() &&
				(mIns[i + 0].mType == ASMIT_CPX || mIns[i + 0].mType == ASMIT_CPY) && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x01 &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x00 &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_AND && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
			{
				uint8 veq = mIns[i + 3].mAddress ^ mIns[i + 4].mAddress, vne = mIns[i + 4].mAddress;

				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				for (int j = i + 5; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				if (mIns[i + 0].mType == ASMIT_CPX)
					mIns[i + 0].mType = ASMIT_TXA;
				else if (mIns[i + 0].mType == ASMIT_CPY)
					mIns[i + 0].mType = ASMIT_TYA;
				mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 0].mLive |= LIVE_CPU_REG_Z;

				mTrueJump = neblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BNE;
				mBranchIns = mIns[i + 0].mIns;

				if (veq != 0)
					eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 4 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
				mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE)
			{
				uint8 veq = mIns[i + 4].mAddress, vne = 0;

				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				for (int j = i + 5; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i + 0].mLive |= LIVE_CPU_REG_Z;

				mTrueJump = neblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BNE;
				mBranchIns = mIns[i + 0].mIns;

				if (veq != 0)
					eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, veq));
				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vne));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 4 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
				mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff)
			{
				changed = true;

				NativeCodeBasicBlock* eblock = proc->AllocateBlock();
				NativeCodeBasicBlock* neblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				for (int j = i + 5; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i + 0].mLive |= LIVE_CPU_REG_Z;

				mTrueJump = neblock;
				mFalseJump = eblock;
				mBranch = ASMIT_BNE;
				mBranchIns = mIns[i + 0].mIns;

				neblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0xff));

				eblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				neblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif
#if 1
			if (i + 3 < mIns.Size() &&
				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_EOR && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
			{
				changed = true;

				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				const InterInstruction* iins = mIns[i].mIns;

				for (int j = i + 4; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i);
				mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_IMMEDIATE, 0));

				mTrueJump = iblock;
				mFalseJump = rblock;
				mBranch = ASMIT_BCS;
				mBranchIns = iins;

				iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_IMMEDIATE, 0xff));

				iblock->Close(iins, rblock, nullptr, ASMIT_JMP);
				break;
			}

#endif
#if 1
			if (i + 3 < mIns.Size() &&
				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 + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE)
			{
				uint8 vcc = mIns[i + 2].mAddress ^ mIns[i + 3].mAddress, vcs = mIns[i + 3].mAddress;

				changed = true;

				NativeCodeBasicBlock* ccblock = proc->AllocateBlock();
				NativeCodeBasicBlock* rblock = proc->AllocateBlock();

				rblock->mTrueJump = mTrueJump;
				rblock->mFalseJump = mFalseJump;
				rblock->mBranch = mBranch;
				rblock->mBranchIns = mBranchIns;

				const InterInstruction* iins = mIns[i].mIns;

				for (int j = i + 4; j < mIns.Size(); j++)
					rblock->mIns.Push(mIns[j]);
				mIns.SetSize(i + 1);
				mIns[i].mAddress = vcs;

				mTrueJump = rblock;
				mFalseJump = ccblock;
				mBranch = ASMIT_BCS;

				ccblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, vcc));
				ccblock->Close(mIns[i].mIns, rblock, nullptr, ASMIT_JMP);
				break;
			}
#endif

#if 1
			if (i + 12 < mIns.Size())
			{
				// Check for sign extending
				if (mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
					mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
					mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
					mIns[i + 4].mType == ASMIT_EOR && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0xff)
				{
					// Extended byte is saved
					if (mIns[i + 5].mType == ASMIT_STA || mIns[i + 5].mType == ASMIT_TAX || mIns[i + 5].mType == ASMIT_TAY)
					{
						// There is an addition direct after it
						if (mIns[i + 6].mType == ASMIT_LDA && mIns[i + 7].mType == ASMIT_CLC && mIns[i + 8].mType == ASMIT_ADC && mIns[i + 9].mType == ASMIT_STA && 
							mIns[i + 11].mType == ASMIT_ADC && mIns[i + 12].mType == ASMIT_STA && !(mIns[i + 12].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
						{
							// Uses the sign extended source
							if (mIns[i + 6].SameEffectiveAddress(mIns[i + 0]) || mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
							{
								// Using the result of the sign extension for the upper byte add
								if (mIns[i + 5].mType == ASMIT_TAX && mIns[i + 10].mType == ASMIT_TXA && !(mIns[i + 10].mLive & LIVE_CPU_REG_X) ||
									mIns[i + 5].mType == ASMIT_TAY && mIns[i + 10].mType == ASMIT_TYA && !(mIns[i + 10].mLive & LIVE_CPU_REG_Y) ||
									mIns[i + 5].mType == ASMIT_STA && mIns[i + 10].mType == ASMIT_LDA && mIns[i + 5].SameEffectiveAddress(mIns[i + 10]) && !(mIns[i + 10].mLive & LIVE_MEM))
								{
									// Can change to inc
									if (mIns[i + 11].SameEffectiveAddress(mIns[i + 12]) && HasAsmInstructionMode(ASMIT_INC, mIns[i + 11].mMode))
									{
										changed = true;

										NativeCodeBasicBlock* iblock = proc->AllocateBlock();
										NativeCodeBasicBlock* dblock = proc->AllocateBlock();
										NativeCodeBasicBlock* ablock = proc->AllocateBlock();
										NativeCodeBasicBlock* fblock = proc->AllocateBlock();

										fblock->mTrueJump = mTrueJump;
										fblock->mFalseJump = mFalseJump;
										fblock->mBranch = mBranch;

										dblock->mIns.Push(mIns[i + 11]);
										dblock->mIns[0].mType = ASMIT_DEC;
										dblock->mTrueJump = ablock;
										dblock->mBranch = ASMIT_JMP;

										ablock->mIns.Push(mIns[i + 7]);
										ablock->mIns.Push(mIns[i + 8]);
										ablock->mIns.Push(mIns[i + 9]);
										if (mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
										{
											ablock->mIns[1].CopyMode(mIns[i + 6]);
										}

										ablock->mBranch = ASMIT_BCC;
										ablock->mTrueJump = fblock;
										ablock->mFalseJump = iblock;

										iblock->mIns.Push(mIns[i + 11]);
										iblock->mIns[0].mType = ASMIT_INC;
										iblock->mTrueJump = fblock;
										iblock->mBranch = ASMIT_JMP;

										mTrueJump = ablock;
										mFalseJump = dblock;
										mBranch = ASMIT_BPL;

										for (int j = i + 13; j < mIns.Size(); j++)
											fblock->mIns.Push(mIns[j]);
										mIns.SetSize(i + 1);
										break;
									}
									else if (mIns[i + 5].mType == ASMIT_TAX && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 11].mMode) && HasAsmInstructionMode(ASMIT_STX, mIns[i + 12].mMode))
									{
										// Can't do direct inc, so fallback to x register
										changed = true;

										NativeCodeBasicBlock* iblock = proc->AllocateBlock();
										NativeCodeBasicBlock* dblock = proc->AllocateBlock();
										NativeCodeBasicBlock* ablock = proc->AllocateBlock();
										NativeCodeBasicBlock* fblock = proc->AllocateBlock();

										fblock->mTrueJump = mTrueJump;
										fblock->mFalseJump = mFalseJump;
										fblock->mBranch = mBranch;

										dblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
										dblock->mTrueJump = ablock;
										dblock->mBranch = ASMIT_JMP;

										ablock->mIns.Push(mIns[i + 7]);
										ablock->mIns.Push(mIns[i + 8]);
										ablock->mIns.Push(mIns[i + 9]);
										if (mIns[i + 8].SameEffectiveAddress(mIns[i + 0]))
										{
											ablock->mIns[1].CopyMode(mIns[i + 6]);
										}

										ablock->mBranch = ASMIT_BCC;
										ablock->mTrueJump = fblock;
										ablock->mFalseJump = iblock;

										iblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
										iblock->mTrueJump = fblock;
										iblock->mBranch = ASMIT_JMP;

										mTrueJump = ablock;
										mFalseJump = dblock;
										mBranch = ASMIT_BPL;

										fblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, mIns[i + 12]));
										for (int j = i + 13; j < mIns.Size(); j++)
											fblock->mIns.Push(mIns[j]);

										mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i + 11]));
										mIns[i + 1].mLive |= LIVE_CPU_REG_X;
										mIns.SetSize(i + 2);

										break;

									}
								}
							}
						}
					}
				}
			}
#endif
			if (i + 2 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && 
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock	*	iblock = proc->AllocateBlock();
					NativeCodeBasicBlock	* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins = mIns[0].mIns;

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 2]);
					mIns.SetSize(i);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
					mIns[i + 1].mType == ASMIT_ADC && 
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 2]) &&
					HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins = mIns[0].mIns;

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 2]);
					mIns.SetSize(i);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
					HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins = mIns[0].mIns;

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 2]);
					mIns.SetSize(i);
					iblock->mIns[0].mType = ASMIT_DEC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCS;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_TXA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_TAX &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns.SetSize(i);

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_TYA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 2; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns.SetSize(i);

					fblock->mIns[0].mType = ASMIT_STY;

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_TXA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 2; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns.SetSize(i);

					fblock->mIns[0].mType = ASMIT_STX;

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_TYA &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_TAY &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns.SetSize(i);

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
					mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_TAY &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns[i].mType = ASMIT_LDY; 
					mIns.SetSize(i + 1);

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && 
					mIns[i + 1].mType == ASMIT_ADC && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
					mIns[i + 2].mType == ASMIT_TAY &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					mIns[i] = mIns[i + 1];
					mIns[i].mType = ASMIT_LDY;
					mIns.SetSize(i + 1);

					iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY));
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCC;
					mBranchIns = iins;
					break;
				}
				else if (mIns[i + 0].mType == ASMIT_LDA &&
					mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
					HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) &&
					!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					changed = true;

					NativeCodeBasicBlock* iblock = proc->AllocateBlock();
					NativeCodeBasicBlock* fblock = proc->AllocateBlock();

					fblock->mTrueJump = mTrueJump;
					fblock->mFalseJump = mFalseJump;
					fblock->mBranch = mBranch;
					fblock->mBranchIns = mBranchIns;

					const InterInstruction* iins(mIns[i].mIns);

					for (int j = i + 3; j < mIns.Size(); j++)
						fblock->mIns.Push(mIns[j]);
					iblock->mIns.Push(mIns[i + 2]);
					mIns.SetSize(i);
					iblock->mIns[0].mType = ASMIT_DEC;
					iblock->mTrueJump = fblock;
					iblock->mBranch = ASMIT_JMP;

					mTrueJump = fblock;
					mFalseJump = iblock;
					mBranch = ASMIT_BCS;
					mBranchIns = iins;
					break;
				}

			}

			if (mIns[i].mType == ASMIT_CLC)
				carry = 0;
			else if (mIns[i].mType == ASMIT_SEC)
				carry = 0;
			else if (mIns[i].ChangesCarry())
				carry = -1;
		}

#if 1
		if (mIns.Size() >= 4 && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs.Size() > 0)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 4].mType == ASMIT_TYA &&
				mIns[sz - 3].mType == ASMIT_CLC &&
				mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
				mIns[sz - 1].mType == ASMIT_TAY && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
				(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
				!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
			{
				mIns[sz - 4].mType = ASMIT_INY; mIns[sz - 4].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
				if (mBranch == ASMIT_BCC)
					mBranch = ASMIT_BNE;
				else
					mBranch = ASMIT_BEQ;
				mIns.SetSize(sz - 3);
				changed = true;
			}
		}
#endif

#if 1
		if (mIns.Size() >= 4 && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs.Size() > 0)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 4].mType == ASMIT_LDA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 4].mAddress &&
				mIns[sz - 1].mType == ASMIT_CPY &&
				(mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ) &&
				!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
			{
				if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] ||
					mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
				{
					NativeCodeBasicBlock* iblock = SplitAt(sz - 4);
					iblock->mIns[0].mType = ASMIT_INC;
					iblock->mIns[1].mType = ASMIT_NOP; iblock->mIns[1].mMode = ASMIM_IMPLIED;
					iblock->mIns[2].mType = ASMIT_LDA;
					NativeCodeBasicBlock* eblock = iblock->SplitAt(2);

					mBranch = ASMIT_BCC;
					mFalseJump = mTrueJump;
					mTrueJump = eblock;
					eblock->mEntryBlocks.Push(this);
					eblock->mNumEntries++;

					changed = true;
				}
			}
		}
#endif


		if (mIns.Size() >= 2 && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs.Size() > 0)
		{
			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) &&
				!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
			{
				changed = true;

				int	addr = mIns[sz - 1].mAddress ^ 0x80;

				const InterInstruction* iins(mIns[sz - 1].mIns);

				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				iblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CMP, ASMIM_IMMEDIATE, addr));
				mIns.SetSize(sz - 2);
				mIns.Push(NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0x00));

				iblock->mTrueJump = mTrueJump;
				iblock->mFalseJump = mFalseJump;
				iblock->mBranch = mBranch;
				
				if (mBranch == ASMIT_BCS)
				{
					mBranch = ASMIT_BPL;
					if (addr & 0x80)
						mFalseJump = iblock;
					else
						mTrueJump = iblock;
				}
				else
				{
					mBranch = ASMIT_BMI;
					if (addr & 0x80)
						mTrueJump = iblock;
					else
						mFalseJump = iblock;
				}
			}

		}

		if (mIns.Size() >= 1 && mExitRequiredRegs.Size() > 0)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 1].mType == ASMIT_CMP && mBranch == ASMIT_BNE)
			{
				if (mTrueJump->mIns.Size() == 1 && mTrueJump->mBranch == ASMIT_BCC && mTrueJump->mFalseJump == mFalseJump)
				{
					if (mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !mFalseJump->mEntryRequiredRegs[mTrueJump->mIns[0].mAddress])
					{
						if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE)
						{
							mIns.Insert(sz - 1, mTrueJump->mIns[0]);
							mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
						}
						else
							mIns.Push(mTrueJump->mIns[0]);
						mExitRequiredRegs += mTrueJump->mIns[0].mAddress;

						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mNumEntries--;
						mBranch = ASMIT_BCC;
						mTrueJump = mTrueJump->mTrueJump;
						mTrueJump->mNumEntries++;
						mTrueJump->mEntryBlocks.Push(this);

						changed = true;
					}
				}
			}
		}

		if (mExitRequiredRegs.Size() > 0 && mIns.Size() >= 3 && mFalseJump && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
		{
			int	sz = mIns.Size();

			if (mIns[sz - 3].mType == ASMIT_STA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[sz - 2].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_CMP, mIns[sz - 2].mMode) &&
				mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 3].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
			{
				changed = true;

				NativeCodeBasicBlock* cblock = proc->AllocateBlock();
				cblock->Close(mBranchIns, mTrueJump, mFalseJump, mBranch);

				mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
				mIns[sz - 2].mType = ASMIT_CMP; mIns[sz - 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_C;
				mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
				mExitRequiredRegs += CPU_REG_Z;

				if (mBranch == ASMIT_BCC)
				{
					mTrueJump = mFalseJump;
					mFalseJump = cblock;
					cblock->mBranch = ASMIT_BNE;
				}
				else
				{
					mFalseJump = mTrueJump;
					mTrueJump = cblock;
					cblock->mBranch = ASMIT_BEQ;					
				}
			}
		}

		if (mIns.Size() >= 2 && !mFalseJump && mTrueJump && mTrueJump->mTrueJump && mTrueJump->mIns.Size() > 0 && mTrueJump != this)
		{
			int	sz = mIns.Size();
			if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[sz - 1].mType == ASMIT_ADC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 &&
				mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				NativeCodeBasicBlock * tblock = mTrueJump->SplitAt(1);
				mTrueJump->mNumEntries--;
				mTrueJump->mEntryBlocks.RemoveAll(this);

				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				iblock->Close(mBranchIns, tblock, nullptr, ASMIT_JMP);
				iblock->mIns.Push(NativeCodeInstruction(mIns[sz - 2].mIns, ASMIT_INC, mIns[sz - 2]));
				mIns.SetSize(sz - 2);
				mBranch = ASMIT_BCC;
				mTrueJump = tblock;
				mFalseJump = iblock;				

				tblock->mNumEntries += 2;
				tblock->mEntryBlocks.Push(this);
				tblock->mEntryBlocks.Push(iblock);
				iblock->mNumEntries = 1;
				iblock->mEntryBlocks.Push(this);

				changed = true;
			}

		}

		if (mIns.Size() >= 3 && mFalseJump && mBranch == ASMIT_BCC && mExitRequiredRegs.Size())
		{
			int	sz = mIns.Size();
			if (mIns[sz - 3].mType == ASMIT_LDA && 
				mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_STA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 3]) && 
				HasAsmInstructionMode(ASMIT_INC, mIns[sz - 1].mMode) &&
				!(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_C])
			{
				NativeCodeBasicBlock* tblock = this->SplitAt(sz - 3);

				tblock->mBranch = ASMIT_BNE;
				tblock->mIns[0].mType = ASMIT_INC;
				tblock->mIns.SetSize(1);

				mBranch = ASMIT_BCC;
				mFalseJump = tblock;
				mTrueJump = tblock->mTrueJump;
				mTrueJump->mNumEntries++;
				mTrueJump->mEntryBlocks.Push(this);
				changed = true;
			}
			else if (mIns[sz - 3].mType == ASMIT_TXA &&
				mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_TAX &&
				!(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_C])
			{
				NativeCodeBasicBlock* tblock = this->SplitAt(sz - 3);

				tblock->mBranch = ASMIT_BNE;
				tblock->mIns[0].mType = ASMIT_INX;
				tblock->mIns[0].mMode = ASMIM_IMPLIED;
				tblock->mIns[0].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
				tblock->mIns.SetSize(1);

				mBranch = ASMIT_BCC;
				mFalseJump = tblock;
				mTrueJump = tblock->mTrueJump;
				mTrueJump->mNumEntries++;
				mTrueJump->mEntryBlocks.Push(this);
				changed = true;
			}

		}

		if (mIns.Size() >= 3 && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			int	sz = mIns.Size();
			if ((mIns[sz - 3].mType == ASMIT_INC || mIns[sz - 3].mType == ASMIT_DEC) &&
				mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 3]) &&
				mIns[sz - 1].mType == ASMIT_ORA && 
				!(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
			{
				mIns[sz - 3].mLive |= LIVE_CPU_REG_Z;

				NativeCodeBasicBlock* tblock = this->SplitAt(sz - 2);

				if (tblock->mBranch == ASMIT_BEQ)
					mTrueJump = tblock->mFalseJump;
				else
					mTrueJump = tblock->mTrueJump;

				mBranch = ASMIT_BNE;
				mFalseJump = tblock;
				mTrueJump->mNumEntries++;
				mTrueJump->mEntryBlocks.Push(this);
				changed = true;
			}

		}

		if (mIns.Size() >= 8 && mFalseJump && (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ))
		{
			int	sz = mIns.Size();

			if (mIns[sz - 8].mType == ASMIT_LDA &&
				mIns[sz - 7].mType == ASMIT_CLC &&
				mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0xff &&
				mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 8]) &&
				mIns[sz - 4].mType == ASMIT_LDA &&
				mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0xff &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
				mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 5]) &&
				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 2].mMode) &&
				!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				changed = true;

				NativeCodeBasicBlock* eblock, * neblock;
				if (mBranch == ASMIT_BEQ)
				{
					eblock = mTrueJump;
					neblock = mFalseJump;
				}
				else
				{
					eblock = mFalseJump;
					neblock = mTrueJump;
				}

				NativeCodeBasicBlock* hblock = proc->AllocateBlock();
				NativeCodeBasicBlock* lblock = proc->AllocateBlock();
				NativeCodeBasicBlock* oblock = proc->AllocateBlock();

				mBranch = ASMIT_BNE;
				mTrueJump = lblock;
				mFalseJump = hblock;

				hblock->mBranch = ASMIT_JMP;
				hblock->mTrueJump = lblock;

				lblock->mBranch = ASMIT_BNE;
				lblock->mTrueJump = neblock;
				lblock->mFalseJump = oblock;

				oblock->mBranch = ASMIT_BNE;
				oblock->mTrueJump = neblock;
				oblock->mFalseJump = eblock;

				const InterInstruction* iins(mIns[sz - 4].mIns);

				hblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEC, mIns[sz - 4]));
				lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEC, mIns[sz - 5]));
				oblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDA, mIns[sz - 4]));

				mIns[sz - 8].mLive |= LIVE_CPU_REG_Z;
				mIns.SetSize(sz - 7);

#if 0
				fblock->mTrueJump = mTrueJump;
				fblock->mFalseJump = mFalseJump;
				fblock->mBranch = mBranch;

				fblock->mIns.Push(mIns[i + 1]);
				fblock->mIns[0].mType = ASMIT_DEC;

				mIns[i + 0].mType = ASMIT_NOP;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;

				for (int j = i + 7; j < mIns.Size(); j++)
					fblock->mIns.Push(mIns[j]);
				iblock->mIns.Push(mIns[i + 6]);
				mIns.SetSize(i + 4);
				iblock->mIns[0].mType = ASMIT_DEC;
				iblock->mTrueJump = fblock;
				iblock->mBranch = ASMIT_JMP;

				mTrueJump = fblock;
				mFalseJump = iblock;
				mBranch = ASMIT_BNE;
#endif
			}

		}

#if 1
		if (mIns.Size() >= 5 && mFalseJump && mExitRequiredRegs.Size() && (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ))
		{
			int sz = mIns.Size();
			if (mIns[sz - 4].mType == ASMIT_STA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[sz - 3].mType == ASMIT_LDA && !(mIns[sz - 3].mFlags & NCIF_VOLATILE) &&
				mIns[sz - 2].mType == ASMIT_AND && !(mIns[sz - 2].mFlags & NCIF_VOLATILE) && !mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
				mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 4].mAddress &&
				!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)) && !mExitRequiredRegs[CPU_REG_Z])
			{
				NativeCodeBasicBlock* eblock, * neblock;
				if (mBranch == ASMIT_BEQ)
				{
					eblock = mTrueJump;
					neblock = mFalseJump;
				}
				else
				{
					eblock = mFalseJump;
					neblock = mTrueJump;
				}

				NativeCodeBasicBlock* hblock = proc->AllocateBlock();

				mBranch = ASMIT_BEQ;
				mTrueJump = hblock;
				mFalseJump = neblock;

				hblock->mBranch = ASMIT_BEQ;
				hblock->mTrueJump = eblock;
				hblock->mFalseJump = neblock;

				mIns[sz - 4].mType = ASMIT_ORA;
				mIns[sz - 4].mMode = ASMIM_IMMEDIATE;
				mIns[sz - 4].mAddress = 0;
				hblock->mIns.Push(mIns[sz - 3]);
				hblock->mIns.Push(mIns[sz - 2]);
				mIns.SetSize(sz - 3);
				changed = true;
			}
		}
#endif

		if (mIns.Size() >= 2 && mFalseJump && mBranch == ASMIT_BMI)
		{
			int	sz = mIns.Size();
			if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
			{
				if (mExitRequiredRegs[CPU_REG_Z])
				{
					if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BNE)
					{
						mFalseJump = mFalseJump->mFalseJump;
						changed = true;
					}
					else if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BEQ)
					{
						mFalseJump = mFalseJump->mTrueJump;
						changed = true;
					}
				}
				else if (!mExitRequiredRegs[CPU_REG_A])
				{
					mBranch = ASMIT_BCC;
					mIns.SetSize(sz - 2);
					changed = true;
				}
			}
		}

#if 1
		if (mIns.Size() >= 1 && mFalseJump)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY)
			{
				if (mBranch == ASMIT_BEQ)
				{
					if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
					{
						if (mFalseJump->mIns.Size() == 0)
						{
							if (mFalseJump->mBranch == ASMIT_BCC)
							{
								mFalseJump = mFalseJump->mFalseJump;
								changed = true;
							}
							else if (mFalseJump->mBranch == ASMIT_BCS)
							{
								mFalseJump = mFalseJump->mTrueJump;
								changed = true;
							}
						}
						if (mTrueJump->mIns.Size() == 0)
						{
							if (mTrueJump->mBranch == ASMIT_BCC)
							{
								mTrueJump = mTrueJump->mFalseJump;
								changed = true;
							}
							else if (mTrueJump->mBranch == ASMIT_BCS)
							{
								mTrueJump = mTrueJump->mTrueJump;
								changed = true;
							}
						}
					}

					if (mFalseJump->mNumEntries == 1/* && mTrueJump->mNumEntries == 2*/ && mFalseJump->mIns.Size() == 0)
					{
						if (mFalseJump->mBranch == ASMIT_BCC)
						{
							if (mFalseJump->mFalseJump == mTrueJump)
							{
								mBranch = ASMIT_BCS;
								mFalseJump = mFalseJump->mTrueJump;
								changed = true;
							}
						}
						else if (mFalseJump->mBranch == ASMIT_BCS)
						{
							if (mFalseJump->mTrueJump == mTrueJump)
							{
								mBranch = ASMIT_BCS;
								mFalseJump = mFalseJump->mFalseJump;
								changed = true;
							}
						}
					}
				}
				else if (mBranch == ASMIT_BNE)
				{
					if (mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
					{
						if (mFalseJump->mIns.Size() == 0)
						{
							if (mFalseJump->mBranch == ASMIT_BCC)
							{
								mFalseJump = mFalseJump->mFalseJump;
								changed = true;
							}
							else if (mFalseJump->mBranch == ASMIT_BCS)
							{
								mFalseJump = mFalseJump->mTrueJump;
								changed = true;
							}
						}
						if (mTrueJump->mIns.Size() == 0)
						{
							if (mTrueJump->mBranch == ASMIT_BCC)
							{
								mTrueJump = mTrueJump->mFalseJump;
								changed = true;
							}
							else if (mTrueJump->mBranch == ASMIT_BCS)
							{
								mTrueJump = mTrueJump->mTrueJump;
								changed = true;
							}
						}
					}

					if (mTrueJump->mNumEntries == 1/* && mFalseJump->mNumEntries == 2*/ && mTrueJump->mIns.Size() == 0)
					{
						if (mTrueJump->mBranch == ASMIT_BCC)
						{
							if (mTrueJump->mFalseJump == mFalseJump)
							{
								mBranch = ASMIT_BCC;
								mTrueJump = mTrueJump->mTrueJump;
								changed = true;
							}
						}
						else if (mTrueJump->mBranch == ASMIT_BCS)
						{
							if (mTrueJump->mTrueJump == mFalseJump)
							{
								mBranch = ASMIT_BCC;
								mTrueJump = mTrueJump->mFalseJump;
								changed = true;
							}
						}
					}
				}
			}

		}
#endif
		// Simple diamond split
		if (mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
		{
			if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
			{
				if (mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1)
				{
					if (mTrueJump->mIns[0].mType == ASMIT_AND && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
						mFalseJump->mIns[0].mType == ASMIT_ORA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
						(mTrueJump->mIns[0].mAddress ^ mFalseJump->mIns[0].mAddress) == 0xff)
					{
						mIns.Push(mTrueJump->mIns[0]);
						mTrueJump->mIns.SetSize(0);
						changed = true;
					}
					else if (mTrueJump->mIns[0].mType == ASMIT_ORA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
						mFalseJump->mIns[0].mType == ASMIT_AND && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
						(mTrueJump->mIns[0].mAddress ^ mFalseJump->mIns[0].mAddress) == 0xff)
					{
						mIns.Push(mTrueJump->mIns[0]);
						mTrueJump->mIns.SetSize(0);
						changed = true;
					}
				}
			}
		}

		if (mFalseJump && mTrueJump->mIns.Size() == 0 && mFalseJump->mIns.Size() == 0 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS))
		{
			if (mTrueJump->mBranch == ASMIT_BEQ && mFalseJump->mBranch == ASMIT_BNE && mTrueJump->mTrueJump == mFalseJump->mFalseJump)
			{
				NativeCodeBasicBlock* iblock = proc->AllocateBlock();
				iblock->Close(mBranchIns, mTrueJump->mFalseJump, mFalseJump->mTrueJump, mBranch);
				mBranch = ASMIT_BEQ;
				
				mTrueJump = mTrueJump->mTrueJump;
				mFalseJump = iblock;
				changed = true;
			}
		}

		if (mFalseJump && mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump && mTrueJump->mNumEntries == 1)
		{
			int sz = mIns.Size();
			if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_INX)
			{
				NativeCodeBasicBlock* eblock = mTrueJump->mTrueJump;
				int esz = eblock->mIns.Size();
				int i = 0;
				while (i < esz && !eblock->mIns[i].ReferencesXReg())
					i++;
				if (i < esz && eblock->mIns[i].mType == ASMIT_TXA && !(eblock->mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
				{
					if (i + 2 < esz && eblock->mIns[i + 1].mType == ASMIT_CLC && eblock->mIns[i + 2].mType == ASMIT_ADC && !(eblock->mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
					{
						if (eblock->mIns[i + 2].mMode == ASMIM_IMMEDIATE)
						{
							mIns[sz - 1].mAddress += eblock->mIns[i + 2].mAddress;
							eblock->mIns[i + 2].mType = ASMIT_NOP; eblock->mIns[i + 2].mMode = ASMIM_IMPLIED;
							changed = true;
						}
						else if (eblock->mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS)
						{
							mIns[sz - 1].mMode = ASMIM_IMMEDIATE_ADDRESS;
							mIns[sz - 1].mAddress += eblock->mIns[i + 2].mAddress;
							mIns[sz - 1].mFlags = eblock->mIns[i + 2].mFlags;
							mIns[sz - 1].mLinkerObject = eblock->mIns[i + 2].mLinkerObject;
							eblock->mIns[i + 2].mType = ASMIT_NOP; eblock->mIns[i + 2].mMode = ASMIM_IMPLIED;
							changed = true;
						}
					}
				}
			}
		}

		if (mFalseJump && mIns.Size() >= 8 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			int sz = mIns.Size();

			if (mIns[sz - 8].mType == ASMIT_SEC &&
				mIns[sz - 7].mType == ASMIT_LDA &&
				mIns[sz - 6].mType == ASMIT_SBC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 0x01 &&
				mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].SameEffectiveAddress(mIns[sz - 7]) &&
				mIns[sz - 4].mType == ASMIT_LDA &&
				mIns[sz - 3].mType == ASMIT_SBC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
				mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 7]) &&
				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 5].mMode) &&
				HasAsmInstructionMode(ASMIT_DEC, mIns[sz - 1].mMode) &&
				!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				changed = true;

				NativeCodeBasicBlock* hiblock = proc->AllocateBlock();
				NativeCodeBasicBlock* loblock = proc->AllocateBlock();
				NativeCodeBasicBlock* orblock = proc->AllocateBlock();

				NativeCodeBasicBlock* eqblock, * neblock;
				if (mBranch == ASMIT_BEQ)
				{
					eqblock = mTrueJump;
					neblock = mFalseJump;
				}
				else
				{
					neblock = mTrueJump;
					eqblock = mFalseJump;
				}

				hiblock->mBranch = ASMIT_JMP;
				hiblock->mTrueJump = loblock;

				loblock->mBranch = ASMIT_BNE;
				loblock->mTrueJump = neblock;
				loblock->mFalseJump = orblock;

				orblock->mBranch = ASMIT_BNE;
				orblock->mTrueJump = neblock;
				orblock->mFalseJump = eqblock;

				mBranch = ASMIT_BNE;
				mTrueJump = loblock;
				mFalseJump = hiblock;

				hiblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_DEC, mIns[sz - 4]));
				loblock->mIns.Push(NativeCodeInstruction(mIns[sz - 7].mIns, ASMIT_DEC, mIns[sz - 7]));
				orblock->mIns.Push(NativeCodeInstruction(mIns[sz - 4].mIns, ASMIT_LDA, mIns[sz - 4]));

				mIns[sz - 8].mType = ASMIT_NOP;
				mIns.SetSize(sz - 6);
			}
		}

#if 1
		if (mFalseJump && mIns.Size() >= 3)
		{
			int sz = mIns.Size();
			if (mIns[sz - 3].mType == ASMIT_CLC &&
				mIns[sz - 2].mType == ASMIT_ADC && 
				mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 2]))
			{
				if (mTrueJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
				{
					mTrueJump->mIns.Insert(0, mIns[sz - 3]);
					mTrueJump->mIns.Insert(1, mIns[sz - 2]);
					mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0;
					mIns.Remove(sz - 3, 2);
					changed = true;
				}
				else if (mFalseJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
				{
					mFalseJump->mIns.Insert(0, mIns[sz - 3]);
					mFalseJump->mIns.Insert(1, mIns[sz - 2]);
					mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0;
					mIns.Remove(sz - 3, 2);
					changed = true;
				}
			}
		}
#endif

		if (changed && this == mProc->mExitBlock && mTrueJump)
		{
			mLocked = false;
			mProc->mExitBlock = mTrueJump;
			mProc->mExitBlock->mLocked = true;
		}

		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.mType == ASMIT_JSR && (eins.mFlags & LOBJF_ARG_REG_X))
						break;
					else if (eins.ChangesYReg() || (eins.mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(eins.mType, ASMIM_ABSOLUTE_Y)))
					{
						break;
					}
					else if (!(eins.mLive & LIVE_CPU_REG_X))
					{
						end++;
						ReplaceXRegWithYReg(start, end);
						changed = true;
						break;
					}

					end++;
				}

				start = end;
			}
			else
				start++;
		}

		if (mTrueJump && mTrueJump->ReduceLocalXPressure())
			changed = true;

		if (mFalseJump && mFalseJump->ReduceLocalXPressure())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CombineZPPair(int at, int r0, int r1, bool use0, bool use1, bool & used1) 
{
	bool	changed = false;

	int i = at;
	while (i < mIns.Size() && !use0 && !use1)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if (ins.mMode == ASMIM_ZERO_PAGE)
		{
			if (ins.ChangesAddress())
			{
				if (ins.mAddress == r0)
					use1 = true;
				else if (ins.mAddress == r1)
					use0 = true;
			}
			else if (!(ins.mLive & LIVE_MEM))
			{
				if (ins.mAddress == r0)
					use1 = true;
				else if (ins.mAddress == r1)
					use0 = true;
			}
		}
		else
		{
			if (ins.ReferencesZeroPage(r0))
				use0 = true;
			if (ins.ReferencesZeroPage(r1))
				use1 = true;
		}

		i++;
	}

	if (use0 && use1)
		return false;

	if (!use0 && !use1)
	{
		if (!mExitRequiredRegs[r0])
			use1 = true;
		else if (!mExitRequiredRegs[r1])
			use0 = true;
		else
			return false;
	}

	bool	valid0 = true, valid1 = true;

	used1 = use1;

	i = at;
	while (i < mIns.Size() && valid0 && valid1)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if (ins.mMode == ASMIM_ZERO_PAGE)
		{
			if (ins.ChangesAddress())
			{
				if (ins.mAddress == r0)
					valid0 = false;
				else if (ins.mAddress == r1)
					valid1 = false;
			}
			else
			{
				if (use1)
				{
					if (ins.mAddress == r0)
					{
						ins.mAddress = r1;
						changed = true;
					}
					else if (ins.mAddress == r1)
						ins.mLive |= LIVE_MEM;
				}
				else if (use0)
				{
					if (ins.mAddress == r1)
					{
						ins.mAddress = r0;
						changed = true;
					}
					else if (ins.mAddress == r0)
						ins.mLive |= LIVE_MEM;
				}
			}
		}
		else
		{
			if (ins.ChangesZeroPage(r0))
				valid0 = false;
			if (ins.ChangesZeroPage(r1))
				valid1 = false;
		}

		i++;
	}

	return changed;
}

bool NativeCodeBasicBlock::RemoveDoubleZPStore(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool	swap;

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
			{
				if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
				{
					if (swap)
					{
						int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
					}
					changed = true;
				}
			}
			else if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				     mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
			{
				if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
				{
					if (swap)
					{
						int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
					}
					changed = true;
				}
			}
			else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				     mIns[i + 1].mType == ASMIT_STY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress)
			{
				if (CombineZPPair(i + 2, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false, false, swap))
				{
					if (swap)
					{
						int a = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 1].mAddress; mIns[i + 1].mAddress = a;
					}
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->RemoveDoubleZPStore())
			changed = true;

		if (mFalseJump && mFalseJump->RemoveDoubleZPStore())
			changed = true;
	}

	return changed;
}

struct ValueNumbers
{
	int		zvalues[256], avalue, xvalue, yvalue;
	int		ivalue = 0;

	void Reset(void)
	{
		for (int i = 0; i < 256; i++)
			zvalues[i] = ivalue++;
		avalue = ivalue++;
		xvalue = ivalue++;
		yvalue = ivalue++;
	}

};

bool NativeCodeBasicBlock::LocalZeroPageValueNumbering(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		ValueNumbers	vn;
		vn.Reset();

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins = mIns[i];

			if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.avalue == vn.zvalues[ins.mAddress])
				{
					if (ins.mLive & LIVE_CPU_REG_Z)
					{
						ins.mType = ASMIT_ORA;
						ins.mMode = ASMIM_IMMEDIATE;
						ins.mAddress = 0;
						changed = true;
					}
					else
					{
						ins.mType = ASMIT_NOP;
						ins.mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				else
					vn.avalue = vn.zvalues[ins.mAddress];
			}
			else if (ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.xvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.xvalue = vn.zvalues[ins.mAddress];
			}
			else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.yvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.yvalue = vn.zvalues[ins.mAddress];
			}
			else if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.avalue == vn.zvalues[ins.mAddress])
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.zvalues[ins.mAddress] = vn.avalue;
			}
			else if (ins.mType == ASMIT_STX && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.xvalue == vn.zvalues[ins.mAddress])
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.zvalues[ins.mAddress] = vn.xvalue;
			}
			else if (ins.mType == ASMIT_STY && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (vn.yvalue == vn.zvalues[ins.mAddress])
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.zvalues[ins.mAddress] = vn.yvalue;
			}
			else if (ins.mType == ASMIT_TAX)
			{
				if (vn.avalue == vn.xvalue && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.xvalue = vn.avalue;
			}
			else if (ins.mType == ASMIT_TAY)
			{
				if (vn.avalue == vn.yvalue && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.yvalue = vn.avalue;
			}
			else if (ins.mType == ASMIT_TXA)
			{
				if (vn.xvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.avalue = vn.xvalue;
			}
			else if (ins.mType == ASMIT_TYA)
			{
				if (vn.yvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else
					vn.avalue = vn.yvalue;
			}
			else if (ins.mType == ASMIT_JSR)
				vn.Reset();
			else
			{
				if (ins.mMode == ASMIM_INDIRECT_Y && !(ins.mLive & LIVE_MEM))
				{
					int i = 0;
					while (i < 255 && (i == ins.mAddress || vn.zvalues[i] != vn.zvalues[ins.mAddress] || vn.zvalues[i + 1] != vn.zvalues[ins.mAddress + 1]))
						i++;
					if (i < 255)
					{
						ins.mAddress = i;
					}
				}

				if (ins.ChangesAccu())
					vn.avalue = vn.ivalue++;
				if (ins.ChangesXReg())
					vn.xvalue = vn.ivalue++;
				if (ins.ChangesYReg())
					vn.yvalue = vn.ivalue++;
				if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
					vn.zvalues[ins.mAddress] = vn.ivalue++;
			}
		}


		if (mTrueJump && mTrueJump->LocalZeroPageValueNumbering())
			changed = true;

		if (mFalseJump && mFalseJump->LocalZeroPageValueNumbering())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CanReverseCrossBlockChangeAToY(const NativeCodeBasicBlock* block, int depth)
{
	if (mFalseJump)
	{
		if (block == mTrueJump && (mFalseJump->mEntryRequiredRegs[CPU_REG_A] || mFalseJump->mEntryRequiredRegs[CPU_REG_Y]))
			return false;
		if (block == mFalseJump && (mTrueJump->mEntryRequiredRegs[CPU_REG_A] || mTrueJump->mEntryRequiredRegs[CPU_REG_Y]))
			return false;
	}

	if (depth > 10)
		return false;

	for (int i = mIns.Size() - 1; i >= 0; i--)
	{
		if (mIns[i].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode))
			return true;
		else if (mIns[i].mType == ASMIT_TYA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
			return true;
		else if (mIns[i].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[i].mMode))
			;
		else if (mIns[i].ReferencesAccu() || mIns[i].ReferencesYReg())
			return false;
	}

	if (!mEntryBlocks.Size())
		return false;

	for (int i = 0; i < mEntryBlocks.Size(); i++)
		if (!mEntryBlocks[i]->CanReverseCrossBlockChangeAToY(this, depth + 1))
			return false;

	return true;
}

void NativeCodeBasicBlock::ReverseCrossBlockChangeAToY(void)
{
	if (!mPatched)
	{
		mPatched = true;

		mExitRequiredRegs += CPU_REG_Y;

		for (int i = mIns.Size() - 1; i >= 0; i--)
		{
			mIns[i].mLive |= LIVE_CPU_REG_Y;
			if (mIns[i].mType == ASMIT_LDA)
			{
				mIns[i].mType = ASMIT_LDY;
				return;
			}
			if (mIns[i].mType == ASMIT_TYA)
			{
				mIns[i].mType = ASMIT_NOP;
				return;
			}
			else if (mIns[i].mType == ASMIT_CMP)
			{
				mIns[i].mType = ASMIT_CPY;
			}
		}

		mEntryRequiredRegs += CPU_REG_Y;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			mEntryBlocks[i]->ReverseCrossBlockChangeAToY();
	}
}

bool NativeCodeBasicBlock::CanReverseCrossBlockChangeAToX(const NativeCodeBasicBlock* block, int depth)
{
	if (mFalseJump)
	{
		if (block == mTrueJump && (mFalseJump->mEntryRequiredRegs[CPU_REG_A] || mFalseJump->mEntryRequiredRegs[CPU_REG_X]))
			return false;
		if (block == mFalseJump && (mTrueJump->mEntryRequiredRegs[CPU_REG_A] || mTrueJump->mEntryRequiredRegs[CPU_REG_X]))
			return false;
	}

	if (depth > 10)
		return false;

	for (int i = mIns.Size() - 1; i >= 0; i--)
	{
		if (mIns[i].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode))
			return true;
		else if (mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
			return true;
		else if (mIns[i].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[i].mMode))
			;
		else if (mIns[i].ReferencesAccu() || mIns[i].ReferencesXReg())
			return false;
	}

	if (!mEntryBlocks.Size())
		return false;

	for (int i = 0; i < mEntryBlocks.Size(); i++)
		if (!mEntryBlocks[i]->CanReverseCrossBlockChangeAToX(this, depth + 1))
			return false;

	return true;
}

void NativeCodeBasicBlock::ReverseCrossBlockChangeAToX(void)
{
	if (!mPatched)
	{
		mPatched = true;

		mExitRequiredRegs += CPU_REG_X;

		for (int i = mIns.Size() - 1; i >= 0; i--)
		{
			mIns[i].mLive |= LIVE_CPU_REG_X;
			if (mIns[i].mType == ASMIT_LDA)
			{
				mIns[i].mType = ASMIT_LDX;
				return;
			}
			if (mIns[i].mType == ASMIT_TXA)
			{
				mIns[i].mType = ASMIT_NOP;
				return;
			}
			else if (mIns[i].mType == ASMIT_CMP)
			{
				mIns[i].mType = ASMIT_CPX;
			}
		}

		mEntryRequiredRegs += CPU_REG_X;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			mEntryBlocks[i]->ReverseCrossBlockChangeAToX();
	}
}

bool NativeCodeBasicBlock::ReverseZeroPageRecycling(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 2 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
				mIns[i + 1].IsArithmetic() && !mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 1]))
			{
				int as = mIns[i + 0].mAddress, ad = mIns[i + 2].mAddress;

				int j = i - 1;
				while (j >= 0 && !(mIns[j].ReferencesZeroPage(as) || mIns[j].ReferencesZeroPage(ad)))
					j--;
				if (j >= 0 && mIns[j].IsStore() && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == as)
				{
					mIns[j].mAddress = ad;
					mIns[i].mAddress = ad;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->ReverseZeroPageRecycling())
			changed = true;

		if (mFalseJump && mFalseJump->ReverseZeroPageRecycling())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ReverseCrossBlockRegisterUnification(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool	afromx = false, afromy = false;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
		{
			if (mEntryBlocks[i]->mIns.Size() > 0)
			{
				if (mEntryBlocks[i]->mIns.Last().mType == ASMIT_TXA)
					afromx = true;
				else if (mEntryBlocks[i]->mIns.Last().mType == ASMIT_TYA)
					afromy = true;
			}
		}
		bool	refx = false, refy = false;
		int i = 0;
		while (i < mIns.Size() && !(refx && refy))
		{
			if (!refy && mIns[i].mType == ASMIT_TAY && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				int k = 0;
				while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanReverseCrossBlockChangeAToY(this))
					k++;
				if (k == mEntryBlocks.Size())
				{
					mProc->ResetPatched();
					for (k = 0; k < mEntryBlocks.Size(); k++)
						mEntryBlocks[k]->ReverseCrossBlockChangeAToY();
					for (k = 0; k < i; k++)
						mIns[k].mLive |= LIVE_CPU_REG_Y;
					mEntryRequiredRegs += CPU_REG_Y;
					mIns[i].mType = ASMIT_NOP;
					changed = true;
					break;
				}
			}
			else if (!refx && mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				int k = 0;
				while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanReverseCrossBlockChangeAToX(this))
					k++;
				if (k == mEntryBlocks.Size())
				{
					mProc->ResetPatched();
					for (k = 0; k < mEntryBlocks.Size(); k++)
						mEntryBlocks[k]->ReverseCrossBlockChangeAToX();
					for (k = 0; k < i; k++)
						mIns[k].mLive |= LIVE_CPU_REG_X;
					mEntryRequiredRegs += CPU_REG_X;
					mIns[i].mType = ASMIT_NOP;
					changed = true;
					break;
				}
			}
#if 1
			else if (afromy && !refy && mIns[i].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i].mMode) && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
			{
				int k = 0;
				while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanReverseCrossBlockChangeAToY(this))
					k++;
				if (k == mEntryBlocks.Size())
				{
					mProc->ResetPatched();
					for (k = 0; k < mEntryBlocks.Size(); k++)
						mEntryBlocks[k]->ReverseCrossBlockChangeAToY();
					for (k = 0; k < i; k++)
						mIns[k].mLive |= LIVE_CPU_REG_Y;
					mEntryRequiredRegs += CPU_REG_Y;
					mIns[i].mType = ASMIT_STY;
					changed = true;
					break;
				}
			}
			else if (afromx && !refx && mIns[i].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i].mMode) && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
			{
				int k = 0;
				while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanReverseCrossBlockChangeAToX(this))
					k++;
				if (k == mEntryBlocks.Size())
				{
					mProc->ResetPatched();
					for (k = 0; k < mEntryBlocks.Size(); k++)
						mEntryBlocks[k]->ReverseCrossBlockChangeAToX();
					for (k = 0; k < i; k++)
						mIns[k].mLive |= LIVE_CPU_REG_X;
					mEntryRequiredRegs += CPU_REG_X;
					mIns[i].mType = ASMIT_STX;
					changed = true;
					break;
				}
			}
#endif
			if (mIns[i].ReferencesAccu())
				break;
			if (mIns[i].ReferencesXReg())
				refx = true;
			if (mIns[i].ReferencesYReg())
				refy = true;

			i++;
		}

		if (mTrueJump && mTrueJump->ReverseCrossBlockRegisterUnification())
			changed = true;

		if (mFalseJump && mFalseJump->ReverseCrossBlockRegisterUnification())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::LocalRegisterXYMap(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		int		xregs[256], yregs[256];
		for (int i = 0; i < 256; i++)
			xregs[i] = yregs[i] = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && (mIns[i].mMode != ASMIM_ZERO_PAGE || (xregs[mIns[i].mAddress] < 0 && xregs[mIns[i].mAddress] < 0) || (mIns[i + 1].mLive & LIVE_MEM)))
			{
				if (mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					if (xregs[mIns[i + 1].mAddress] >= 0 && !(mIns[i + 1].mLive & LIVE_MEM))
					{
						int		addr = mIns[i + 1].mAddress;
						mIns[i + 1].CopyMode(mIns[i]);

						if (mIns[i + 1].RequiresYReg())
							mIns[i].mLive |= LIVE_CPU_REG_Y;
						else if (mIns[i + 1].RequiresXReg())
							mIns[i].mLive |= LIVE_CPU_REG_X;

						mIns[i].mMode = ASMIM_ZERO_PAGE;
						mIns[i].mAddress = addr;
					}
					else if (yregs[mIns[i + 1].mAddress] >= 0 && !(mIns[i + 1].mLive & LIVE_MEM))
					{
						int		addr = mIns[i + 1].mAddress;
						mIns[i + 1].CopyMode(mIns[i]);

						if (mIns[i + 1].RequiresYReg())
							mIns[i].mLive |= LIVE_CPU_REG_Y;
						else if (mIns[i + 1].RequiresXReg())
							mIns[i].mLive |= LIVE_CPU_REG_X;

						mIns[i].mMode = ASMIM_ZERO_PAGE;
						mIns[i].mAddress = addr;
					}
				}
			}

			CheckLive();

			const NativeCodeInstruction& ins(mIns[i]);

			if (ins.ChangesXReg())
			{
				for (int i = 0; i < 256; i++)
					xregs[i] = -1;
			}
			if (ins.ChangesYReg())
			{
				for (int i = 0; i < 256; i++)
					yregs[i] = -1;
			}

			if (ins.mMode == ASMIM_ZERO_PAGE)
			{
				switch (ins.mType)
				{
				case ASMIT_STA:
#if 0
					if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4 ||
						ins.mAddress >= BC_REG_WORK && ins.mAddress < BC_REG_WORK + 4)
					{
					}
					else
#endif
					{
						if (!(ins.mLive & LIVE_CPU_REG_X))
						{
							if (xregs[ins.mAddress] < 0)
								xregs[ins.mAddress] = i;
						}
						if (!(ins.mLive & LIVE_CPU_REG_Y))
						{
							if (yregs[ins.mAddress] < 0)
								yregs[ins.mAddress] = i;
						}
					}
					break;
				case ASMIT_LDA:
					if (xregs[ins.mAddress] >= 0 && !(ins.mLive & LIVE_MEM))
					{
						changed = true;

						for (int j = xregs[ins.mAddress]; j <= i; j++)
						{
							NativeCodeInstruction& rins(mIns[j]);
							if (rins.mMode == ASMIM_ZERO_PAGE && rins.mAddress == ins.mAddress)
							{
								switch (rins.mType)
								{
								case ASMIT_STA:
									rins.mType = ASMIT_TAX;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_LDA:
									rins.mType = ASMIT_TXA;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_INC:
									rins.mType = ASMIT_INX;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_DEC:
									rins.mType = ASMIT_DEX;
									rins.mMode = ASMIM_IMPLIED;
									break;
								}
							}
							rins.mLive |= LIVE_CPU_REG_X;
						}

						CheckLive();

						for (int i = 0; i < 256; i++)
							xregs[i] = -1;
					}
					else if (yregs[ins.mAddress] >= 0 && !(ins.mLive & LIVE_MEM))
					{
						changed = true;

						for (int j = yregs[ins.mAddress]; j <= i; j++)
						{
							NativeCodeInstruction& rins(mIns[j]);
							if (rins.mMode == ASMIM_ZERO_PAGE && rins.mAddress == ins.mAddress)
							{
								switch (rins.mType)
								{
								case ASMIT_STA:
									rins.mType = ASMIT_TAY;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_LDA:
									rins.mType = ASMIT_TYA;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_INC:
									rins.mType = ASMIT_INY;
									rins.mMode = ASMIM_IMPLIED;
									break;
								case ASMIT_DEC:
									rins.mType = ASMIT_DEY;
									rins.mMode = ASMIM_IMPLIED;
									break;
								}
							}
							rins.mLive |= LIVE_CPU_REG_Y;
						}

						CheckLive();

						for (int i = 0; i < 256; i++)
							yregs[i] = -1;
					}
					break;
				case ASMIT_INC:
				case ASMIT_DEC:
					break;
				default:
					xregs[ins.mAddress + 0] = -1;
					yregs[ins.mAddress + 0] = -1;
					break;
				}
			}
			else if (ins.mMode == ASMIM_INDIRECT_Y)
			{
				xregs[ins.mAddress + 0] = -1;
				xregs[ins.mAddress + 1] = -1;
				yregs[ins.mAddress + 0] = -1;
				yregs[ins.mAddress + 1] = -1;
			}
			else if (ins.mType == ASMIT_JSR)
			{
				for (int i = 0; i < 4; i++)
				{
					xregs[BC_REG_ACCU + i] = -1;
					yregs[BC_REG_ACCU + i] = -1;
					xregs[BC_REG_WORK + i] = -1;
					yregs[BC_REG_WORK + i] = -1;
				}
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->LocalRegisterXYMap())
			changed = true;

		if (mFalseJump && mFalseJump->LocalRegisterXYMap())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CanReplaceExitAccuWithX(NativeCodeBasicBlock* target)
{
	if (mTrueJump && target != mTrueJump && (mTrueJump->mEntryRequiredRegs[CPU_REG_X] || mTrueJump->mEntryRequiredRegs[CPU_REG_A]))
		return false;
	if (mFalseJump && target != mFalseJump && (mFalseJump->mEntryRequiredRegs[CPU_REG_X] || mFalseJump->mEntryRequiredRegs[CPU_REG_A]))
		return false;

	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mType == ASMIT_LDA)
		{
			if (HasAsmInstructionMode(ASMIT_LDX, ins.mMode))
				return true;
		}
		if (ins.ReferencesXReg() || ins.ReferencesAccu())
			return false;
		i--;
	}

	return false;
}

bool NativeCodeBasicBlock::CanReplaceExitAccuWithY(NativeCodeBasicBlock* target)
{
	if (mTrueJump && target != mTrueJump && (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] || mTrueJump->mEntryRequiredRegs[CPU_REG_A]))
		return false;
	if (mFalseJump && target != mFalseJump && (mFalseJump->mEntryRequiredRegs[CPU_REG_Y] || mFalseJump->mEntryRequiredRegs[CPU_REG_A]))
		return false;

	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mType == ASMIT_LDA)
		{
			if (HasAsmInstructionMode(ASMIT_LDY, ins.mMode))
				return true;
		}
		if (ins.ReferencesYReg() || ins.ReferencesAccu())
			return false;
		i--;
	}

	return false;
}

void NativeCodeBasicBlock::ReplaceExitAccuWithX(NativeCodeBasicBlock* target)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		NativeCodeInstruction& ins(mIns[i]);
		ins.mLive |= LIVE_CPU_REG_X;
		if (ins.mType == ASMIT_LDA)
		{
			ins.mType = ASMIT_LDX;
			mExitRequiredRegs += CPU_REG_X;
			return;
		}
		i--;
	}
}

void NativeCodeBasicBlock::ReplaceExitAccuWithY(NativeCodeBasicBlock* target)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		NativeCodeInstruction& ins(mIns[i]);
		ins.mLive |= LIVE_CPU_REG_Y;
		if (ins.mType == ASMIT_LDA)
		{
			ins.mType = ASMIT_LDY;
			mExitRequiredRegs += CPU_REG_Y;
			return;
		}
		i--;
	}
}

bool NativeCodeBasicBlock::ReverseLoadAccuToRegXY(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mIns.Size() > 2)
		{
			if (mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE && (mIns[1].mType == ASMIT_TAX || mIns[1].mType == ASMIT_TAY) && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				if (mIns[1].mType == ASMIT_TAY) 
				{
					int i = 0;
					while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanReplaceExitAccuWithY(this))
						i++;
					if (i == mEntryBlocks.Size())
					{
						for (int j = 0; j < mEntryBlocks.Size(); j++)
							mEntryBlocks[j]->ReplaceExitAccuWithY(this);
						mEntryRequiredRegs += CPU_REG_Y;
						mIns[0].mType = ASMIT_STY; mIns[0].mLive |= LIVE_CPU_REG_Y;
						mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
				else
				{
					int i = 0;
					while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanReplaceExitAccuWithX(this))
						i++;
					if (i == mEntryBlocks.Size())
					{
						for (int j = 0; j < mEntryBlocks.Size(); j++)
							mEntryBlocks[j]->ReplaceExitAccuWithX(this);
						mEntryRequiredRegs += CPU_REG_X;
						mIns[0].mType = ASMIT_STX; mIns[0].mLive |= LIVE_CPU_REG_X;
						mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
			}
		}


		if (mTrueJump && mTrueJump->ReverseLoadAccuToRegXY())
			changed = true;
		if (mFalseJump && mFalseJump->ReverseLoadAccuToRegXY())
			changed = true;
	}

	return changed;
}



bool NativeCodeBasicBlock::LoopRegisterXYMap(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mEntryBlocks.Size() > 1)
		{
			NativeCodeBasicBlock* pblock = nullptr;
			ExpandingArray<NativeCodeBasicBlock*>	 lblocks, pblocks, eblocks;

			bool	addprefix = false;
			for (int i = 0; i < mEntryBlocks.Size(); i++)
			{
				NativeCodeBasicBlock* b = mEntryBlocks[i];

				if (b == this || b->IsDominatedBy(this))
					lblocks.Push(b);
				else
				{
					if (b->mFalseJump)
						addprefix = true;
					pblocks.Push(b);
				}
			}

			if (lblocks.Size() > 0)
			{
				if (pblocks.Size() > 1 || addprefix)
				{
					pblock = mProc->AllocateBlock();
					pblock->mEntryRequiredRegs = mEntryRequiredRegs;
					pblock->mExitRequiredRegs = mEntryRequiredRegs;
					pblock->Close(pblocks[0]->mBranchIns, this, nullptr, ASMIT_JMP);
					AddEntryBlock(pblock);
					for (int i = 0; i < pblocks.Size(); i++)
					{
						NativeCodeBasicBlock* b = pblocks[i];
						if (this == b->mTrueJump)
						{
							b->mTrueJump = pblock;
							RemEntryBlock(b);
							pblock->AddEntryBlock(b);
						}
						if (this == b->mFalseJump)
						{
							b->mFalseJump = pblock;
							RemEntryBlock(b);
							pblock->AddEntryBlock(b);
						}
					}
				}
				else if (pblocks.Size() == 1)
					pblock = pblocks[0];

				if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
				{
					mProc->ResetPatched();
					mPatched = true;

					if (!lblocks.Contains(this))
						lblocks.Push(this);

					for (int i = 0; i < lblocks.Size(); i++)
						lblocks[i]->mPatched = true;
					pblock->mPatched = true;

					int i = 0;
					while (i < lblocks.Size())
					{
						NativeCodeBasicBlock* block = lblocks[i];
						for (int j = 0; j < block->mEntryBlocks.Size(); j++)
						{
							NativeCodeBasicBlock* cblock = block->mEntryBlocks[j];
							if (!cblock->mPatched)
							{
								cblock->mPatched = true;
								lblocks.Push(cblock);
							}
						}
						i++;
					}

					bool	inner = true;

					NativeCodeBasicBlock* eblock = nullptr;
					i = 0;
					while (i < lblocks.Size())
					{
						NativeCodeBasicBlock* b = lblocks[i];
						if (b->mLoopHead && b != this)
						{
							inner = false;
							break;
						}
						if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
						{
							NativeCodeBasicBlock* eblock = lblocks.Contains(b->mFalseJump) ? b->mTrueJump : b->mFalseJump;
							if (eblock->mEntryBlocks.Size() > 1)
							{							
								int k = 0;
								while (k < eblock->mEntryBlocks.Size() && lblocks.Contains(eblock->mEntryBlocks[k]))
									k++;

								if (k != eblock->mEntryBlocks.Size())
								{
									NativeCodeBasicBlock* eb = mProc->AllocateBlock();
									eb->mEntryRequiredRegs = eblock->mEntryRequiredRegs;
									eb->mExitRequiredRegs = eblock->mEntryRequiredRegs;
									eb->Close(eblock->mBranchIns, eblock, nullptr, ASMIT_JMP);
									eb->AddEntryBlock(b);
									eblock->AddEntryBlock(eb);
									eblock->RemEntryBlock(b);
									if (b->mFalseJump == eblock)
										b->mFalseJump = eb;
									else
										b->mTrueJump = eb;
									eblocks.Push(eb);
								}
								else
									eblocks.Push(eblock);
							}
							else
								eblocks.Push(eblock);
						}
						i++;
					}

					if (inner && eblocks.Size() > 0)
					{
						bool	xfree = !mEntryRequiredRegs[CPU_REG_X], yfree = !mEntryRequiredRegs[CPU_REG_Y];

						if (xfree || yfree)
						{
							int	iregs[256];
							for (int i = 0; i < 256; i++)
								iregs[i] = 0;
							const InterInstruction* iins[256];


							for (int i = 0; i < lblocks.Size(); i++)
							{
								NativeCodeBasicBlock* b(lblocks[i]);

								for (int j = 0; j < b->mIns.Size(); j++)
								{
									const NativeCodeInstruction& ins(b->mIns[j]);

									if (ins.ReferencesXReg() || ins.ChangesXReg())
										xfree = false;
									if (ins.ReferencesYReg() || ins.ChangesYReg())
										yfree = false;
									if (ins.mMode == ASMIM_INDIRECT_Y)
									{
										iregs[ins.mAddress + 0] = -1;
										iregs[ins.mAddress + 1] = -1;
									}
									else if (ins.mMode == ASMIM_ZERO_PAGE && iregs[ins.mAddress] >= 0)
									{
										if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
										{
											iins[ins.mAddress] = ins.mIns;
											iregs[ins.mAddress] += 5;
										}
										else if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA)
										{
											iins[ins.mAddress] = ins.mIns;
											iregs[ins.mAddress] += 3;
										}
										else if (ins.IsCommutative() && j > 0 && b->mIns[j - 1].mType == ASMIT_LDA && (b->mIns[j - 1].mMode == ASMIM_IMMEDIATE || b->mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
										{
											iins[ins.mAddress] = ins.mIns;
											iregs[ins.mAddress] += 3;
										}
										else
											iregs[ins.mAddress] = -1;
									}
								}
							}

							if (xfree || yfree)
							{
								int mini = 0;
								int mina = 3;
								for (int i = 1; i < 256; i++)
								{
									if (iregs[i] > mina)
									{
										mina = iregs[i];
										mini = i;
									}
								}

								if (mini > 0)
								{
									if (xfree)
									{
										pblock->mIns.Push(NativeCodeInstruction(iins[mini], ASMIT_LDX, ASMIM_ZERO_PAGE, mini));
										if (pblock->mExitRequiredRegs[CPU_REG_Z])
										{
											int i = pblock->mIns.Size() - 1;
											while (i >= 0 && !(pblock->mIns[i].ChangesAccu()))
											{
												pblock->mIns[i].mLive |= LIVE_CPU_REG_A;
												i--;
											}
											pblock->mIns.Push(NativeCodeInstruction(iins[mini], ASMIT_ORA, ASMIM_IMMEDIATE, 0));
										}

										pblock->mExitRequiredRegs += CPU_REG_X;
										for (int i = 0; i < eblocks.Size(); i++)
										{
											eblocks[i]->mIns.Insert(0, NativeCodeInstruction(iins[mini], ASMIT_STX, ASMIM_ZERO_PAGE, mini));
											eblocks[i]->mEntryRequiredRegs += CPU_REG_X;
										}
									}
									else
									{
										pblock->mIns.Push(NativeCodeInstruction(iins[mini], ASMIT_LDY, ASMIM_ZERO_PAGE, mini));
										if (pblock->mExitRequiredRegs[CPU_REG_Z])
											pblock->mIns.Push(NativeCodeInstruction(iins[mini], ASMIT_ORA, ASMIM_IMMEDIATE, 0));

										pblock->mExitRequiredRegs += CPU_REG_Y;
										for (int i = 0; i < eblocks.Size(); i++)
										{
											eblocks[i]->mIns.Insert(0, NativeCodeInstruction(iins[mini], ASMIT_STY, ASMIM_ZERO_PAGE, mini));
											eblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
										}
									}

									for (int i = 0; i < lblocks.Size(); i++)
									{
										NativeCodeBasicBlock* b(lblocks[i]);

										if (xfree)
										{
											b->mEntryRequiredRegs += CPU_REG_X;
											b->mExitRequiredRegs += CPU_REG_X;
										}
										else
										{
											b->mEntryRequiredRegs += CPU_REG_Y;
											b->mExitRequiredRegs += CPU_REG_Y;
										}

										for (int j = 0; j < b->mIns.Size(); j++)
										{
											NativeCodeInstruction& ins(b->mIns[j]);

											if (xfree)
												ins.mLive |= LIVE_CPU_REG_X;
											else
												ins.mLive |= LIVE_CPU_REG_Y;

											if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == mini)
											{
												if (ins.IsCommutative())
												{
													ins.CopyMode(b->mIns[j - 1]);
													if (xfree)
														b->mIns[j - 1].mType = ASMIT_TXA;
													else
														b->mIns[j - 1].mType = ASMIT_TYA;
													b->mIns[j - 1].mMode = ASMIM_IMPLIED;
												}
												else
												{
													switch (ins.mType)
													{
													case ASMIT_INC:
														if (xfree)
															ins.mType = ASMIT_INX;
														else
															ins.mType = ASMIT_INY;
														ins.mMode = ASMIM_IMPLIED;
														break;
													case ASMIT_DEC:
														if (xfree)
															ins.mType = ASMIT_DEX;
														else
															ins.mType = ASMIT_DEY;
														ins.mMode = ASMIM_IMPLIED;
														break;
													case ASMIT_LDA:
														if (xfree)
															ins.mType = ASMIT_TXA;
														else
															ins.mType = ASMIT_TYA;
														ins.mMode = ASMIM_IMPLIED;
														break;
													case ASMIT_STA:
														if (xfree)
															ins.mType = ASMIT_TAX;
														else
															ins.mType = ASMIT_TAY;
														ins.mMode = ASMIM_IMPLIED;
														break;
													}
												}
											}
										}
									}

									changed = true;
								}
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->LoopRegisterXYMap()) changed = true;
		if (mFalseJump && mFalseJump->LoopRegisterXYMap()) changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::GlobalRegisterXYCheck(int* xregs, int* yregs)
{
	if (!mVisited)
	{
		mVisited = true;

		int	yreg = -1;
		int xreg = -1;

		int	iinc = mLoopHead ? 2 : 1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			const NativeCodeInstruction& ins(mIns[i]);
			if (ins.mMode == ASMIM_ZERO_PAGE)
			{
				switch (ins.mType)
				{
				case ASMIT_LDA:
					if (yregs[ins.mAddress] >= 0)
						yregs[ins.mAddress] += iinc;
					if (xregs[ins.mAddress] >= 0)
						xregs[ins.mAddress] += iinc;
					break;
				case ASMIT_LDY:
					if (yregs[ins.mAddress] >= 0)
					{
						yregs[ins.mAddress] += 2 * iinc;
						yreg = ins.mAddress;
					}
					for (int i = 1; i < 256; i++)
						if (i != ins.mAddress)
							yregs[i] = -1;

					xregs[ins.mAddress] = -1;
					break;
				case ASMIT_LDX:
					if (xregs[ins.mAddress] >= 0)
					{
						xregs[ins.mAddress] += 2 * iinc;
						xreg = ins.mAddress;
					}
					for (int i = 1; i < 256; i++)
						if (i != ins.mAddress)
							xregs[i] = -1;

					yregs[ins.mAddress] = -1;
					break;
				case ASMIT_STA:
					if (yreg == ins.mAddress)
						yreg = -1;
					if (xreg == ins.mAddress)
						xreg = -1;

					if (ins.mLive & LIVE_CPU_REG_Z)
					{
						xregs[ins.mAddress + 0] = -1;
						yregs[ins.mAddress + 0] = -1;
					}
					else
					{
						if (yregs[ins.mAddress] >= 0)
							yregs[ins.mAddress] += iinc;
						if (xregs[ins.mAddress] >= 0)
							xregs[ins.mAddress] += iinc;
					}
					break;
				case ASMIT_INC:
				case ASMIT_DEC:
					if (yreg == ins.mAddress)
						yreg = -1;
					if (xreg == ins.mAddress)
						xreg = -1;

					if (yregs[ins.mAddress] >= 0)
						yregs[ins.mAddress] += 3 * iinc;
					if (xregs[ins.mAddress] >= 0)
						xregs[ins.mAddress] += 3 * iinc;
					break;
				default:
					xregs[ins.mAddress + 0] = -1;
					yregs[ins.mAddress + 0] = -1;
					break;
				}
			}
			else if (ins.mMode == ASMIM_INDIRECT_Y)
			{
				for (int i = 1; i < 256; i++)
					if (i != yreg)
						yregs[i] = -1;

				xregs[ins.mAddress + 0] = -1;
				xregs[ins.mAddress + 1] = -1;
				yregs[ins.mAddress + 0] = -1;
				yregs[ins.mAddress + 1] = -1;
			}
			else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y)
			{

			}
			else
			{
				if (ins.RequiresXReg())
				{
					for (int i = 1; i < 256; i++)
						if (i != xreg)
							xregs[i] = -1;
				}
				if (ins.RequiresYReg())
				{
					for (int i = 1; i < 256; i++)
						if (i != yreg)
							yregs[i] = -1;
				}
				if (ins.ChangesXReg())
					xregs[0] = -1;
				if (ins.ChangesYReg())
					yregs[0] = -1;
			}
		}

		if (xregs[0] >= 0 || yregs[0] >= 0)
		{
			if (mTrueJump)
				mTrueJump->GlobalRegisterXYCheck(xregs, yregs);
			if (mFalseJump)
				mFalseJump->GlobalRegisterXYCheck(xregs, yregs);
		}
	}
}

bool NativeCodeBasicBlock::RemapZeroPage(const uint8* remap)
{
	bool	modified = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			int	addr;

			switch (mIns[i].mMode)
			{
			case ASMIM_ZERO_PAGE:
			case ASMIM_INDIRECT_Y:
				addr = remap[mIns[i].mAddress];
				if (addr != mIns[i].mAddress)
				{
					mIns[i].mAddress = addr;
					modified = true;
				}
				break;
			case ASMIM_ABSOLUTE:
				if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
				{
					LinkerObject* lo = mIns[i].mLinkerObject;

					for (int j = 0; j < lo->mNumTemporaries; j++)
					{
						addr = remap[lo->mTemporaries[j]];
						if (addr != lo->mTemporaries[j])
						{
							lo->mTemporaries[j] = addr;
							modified = true;
						}
					}

					if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
						mIns[i].mParam = remap[mIns[i].mParam];
				}
				break;
			}
		}

		if (mTrueJump && mTrueJump->RemapZeroPage(remap))
			modified = true;

		if (mFalseJump && mFalseJump->RemapZeroPage(remap))
			modified = true;
	}

	return modified;
}

bool NativeCodeBasicBlock::SameTail(const NativeCodeInstruction& ins) const
{
	if (mIns.Size() > 0)
		return mIns[mIns.Size() - 1].IsSame(ins);
	else
		return false;
}

bool NativeCodeBasicBlock::HasTailSTAX16(int& addr, int& index) const
{
	int sz = mIns.Size();
	if (sz >= 4)
	{
		sz -= 4;
		if (mIns[sz + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[sz + 0].mMode) &&
			mIns[sz + 1].mType == ASMIT_STA && mIns[sz + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz + 2].mType == ASMIT_LDA && 
			mIns[sz + 3].mType == ASMIT_STA && mIns[sz + 3].mMode == ASMIM_ZERO_PAGE && mIns[sz + 3].mAddress == mIns[sz + 1].mAddress + 1 &&
			!mIns[sz + 1].SameEffectiveAddress(mIns[sz + 2]))
		{
			addr = mIns[sz + 1].mAddress;
			index = sz;
			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::HasTailSTA(int& addr, int& index) const
{
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		if (mIns[i].ChangesAccu())
			return false;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
		{
			index = i;
			addr = mIns[i].mAddress;

			i++;
			while (i < mIns.Size())
			{
				if (mIns[i].ReferencesZeroPage(addr))
					return false;
				i++;
			}
			return true;
		}
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTX(int& addr, int& index) const
{
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		if (mIns[i].ChangesXReg())
			return false;
		if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
		{
			index = i;
			addr = mIns[i].mAddress;

			i++;
			while (i < mIns.Size())
			{
				if (mIns[i].ReferencesZeroPage(addr))
					return false;
				i++;
			}
			return true;
		}
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTY(int& addr, int& index) const
{
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		if (mIns[i].ChangesYReg())
			return false;
		if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
		{
			index = i;
			addr = mIns[i].mAddress;

			i++;
			while (i < mIns.Size())
			{
				if (mIns[i].ReferencesZeroPage(addr))
					return false;
				i++;
			}
			return true;
		}
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTAInto(int& addr, int& index, NativeCodeBasicBlock* tblock) const
{
	if (HasTailSTA(addr, index))
	{
		if (mFalseJump)
		{
			if (tblock == mFalseJump)
				return !mTrueJump->mEntryRequiredRegs[addr];
			else
				return !mFalseJump->mEntryRequiredRegs[addr];
		}
		else
			return true;
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTXInto(int& addr, int& index, NativeCodeBasicBlock* tblock) const
{
	if (HasTailSTX(addr, index))
	{
		if (mFalseJump)
		{
			if (tblock == mFalseJump)
				return !mTrueJump->mEntryRequiredRegs[addr];
			else
				return !mFalseJump->mEntryRequiredRegs[addr];
		}
		else
			return true;
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTYInto(int& addr, int& index, NativeCodeBasicBlock* tblock) const
{
	if (HasTailSTY(addr, index))
	{
		if (mFalseJump)
		{
			if (tblock == mFalseJump)
				return !mTrueJump->mEntryRequiredRegs[addr];
			else
				return !mFalseJump->mEntryRequiredRegs[addr];
		}
		else
			return true;
	}
	return false;

}

bool NativeCodeBasicBlock::HasTailAccuReg(int addr) const
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		if ((mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return true;
		if (mIns[i].ChangesAccu() || mIns[i].ChangesZeroPage(addr))
			return false;
		i--;
	}
	return false;
}

bool NativeCodeBasicBlock::HasTailSTAGlobal(NativeCodeInstruction & ins, 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;
			ins = mIns[i];

			i++;
			while (i < mIns.Size())
			{
				if (mIns[i].MayReference(ins, true))
					return false;
				else if (ins.ReferencesXReg() && mIns[i].ChangesXReg())
					return false;
				else if (ins.ReferencesYReg() && mIns[i].ChangesYReg())
					return false;
				i++;
			}
			return true;
		}
	}
	return false;
}

bool NativeCodeBasicBlock::CanMovePairBefore(int at)
{
	int i = at;
	while (i > 0)
	{
		i--;
		if (mIns[i].mType == ASMIT_JSR)
			return false;
		if (mIns[i].ReferencesZeroPage(mIns[at].mAddress))
			return false;
		if (mIns[i].MayBeSameAddress(mIns[at + 1], true))
			return false;
		if (mIns[at + 1].RequiresYReg() && mIns[i].ChangesYReg())
			return false;
		if (mIns[at + 1].RequiresXReg() && mIns[i].ChangesXReg())
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CanMoveStoreUp(int addr, const NativeCodeInstruction& ins, int& at)
{
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			at = i;
			return true;
		}
		if (mIns[i].ReferencesZeroPage(addr))
			return false;
		if (mIns[i].MayBeSameAddress(ins, true))
			return false;
		if (ins.RequiresYReg() && mIns[i].ChangesYReg())
			return false;
		if (ins.RequiresXReg() && mIns[i].ChangesXReg())
			return false;
	}

	return false;
}

bool NativeCodeBasicBlock::JoinCommonHeadSequence(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mEntryBlocks.Size() > 1 && mIns.Size() > 0 && !mLoopHead)
		{
			int ei = 0;
			while (ei < mEntryBlocks.Size() && !mEntryBlocks[ei]->mFalseJump)
				ei++;

			if (ei == mEntryBlocks.Size())
			{
#if 1
				if (mIns[0].mType == ASMIT_STA)
				{
					NativeCodeBasicBlock* e0 = mEntryBlocks[0];
					int s0 = e0->mIns.Size();
					if (s0 >= 2 && e0->mIns[s0 - 1].IsCommutative() && e0->mIns[s0 - 2].mType == ASMIT_LDA)
					{
						bool	match = true;
						for (int i = 1; i < mEntryBlocks.Size(); i++)
						{
							NativeCodeBasicBlock* eb = mEntryBlocks[i];
							int sz = eb->mIns.Size();
							if (sz >= 2 && eb->mIns[sz - 1].mType == e0->mIns[s0 - 1].mType && eb->mIns[sz - 2].mType == ASMIT_LDA && eb->mIns[sz - 2].SameEffectiveAddress(e0->mIns[s0 - 2]))
								;
							else
							{
								match = false;
								break;
							}
						}
						if (match)
						{
							mIns.Insert(0, NativeCodeInstruction(e0->mIns[s0 - 1].mIns, e0->mIns[s0 - 1].mType, e0->mIns[s0 - 2]));
							for (int i = 0; i < mEntryBlocks.Size(); i++)
							{
								NativeCodeBasicBlock* eb = mEntryBlocks[i];
								int sz = eb->mIns.Size();
								eb->mIns[sz - 2].CopyMode(eb->mIns[sz - 1]);
								eb->mIns[sz - 1].mType = ASMIT_NOP; eb->mIns[sz - 1].mMode = ASMIM_IMPLIED;
							}
							changed = true;
						}
					}
					if (!changed && s0 >= 2 && e0->mIns[s0 - 1].IsAddSub() && e0->mIns[s0 - 1].mMode == ASMIM_IMMEDIATE && e0->mIns[s0 - 2].mType == ASMIT_LDA)
					{
						bool	match = true;
						for (int i = 1; i < mEntryBlocks.Size(); i++)
						{
							NativeCodeBasicBlock* eb = mEntryBlocks[i];
							int sz = eb->mIns.Size();
							if (sz >= 2 && eb->mIns[sz - 1].IsAddSub() && eb->mIns[sz - 1].mMode == ASMIM_IMMEDIATE && eb->mIns[sz - 2].mType == ASMIT_LDA && eb->mIns[sz - 2].SameEffectiveAddress(e0->mIns[s0 - 2]))
								;
							else
							{
								match = false;
								break;
							}
						}
						if (match)
						{
							mIns.Insert(0, NativeCodeInstruction(e0->mIns[s0 - 1].mIns, ASMIT_ADC, e0->mIns[s0 - 2]));
							for (int i = 0; i < mEntryBlocks.Size(); i++)
							{
								NativeCodeBasicBlock* eb = mEntryBlocks[i];
								int sz = eb->mIns.Size();
								eb->mIns[sz - 2].mType = ASMIT_LDA; eb->mIns[sz - 2].mMode = ASMIM_IMMEDIATE;
								eb->mIns[sz - 2].mAddress = (eb->mIns[sz - 1].mType == ASMIT_ADC) ? eb->mIns[sz - 1].mAddress : (eb->mIns[sz - 1].mAddress ^ 0xff);
								eb->mIns[sz - 1].mType = ASMIT_NOP; eb->mIns[sz - 1].mMode = ASMIM_IMPLIED;
							}
							changed = true;
						}
					}
				}
#endif
#if 1
				for (int i = 0; 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_STA && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
					{
						if (CanMovePairBefore(i))
						{
							ei = 0;
							while (ei < mEntryBlocks.Size() && mEntryBlocks[ei]->CanMoveStoreUp(mIns[i].mAddress, mIns[i + 1], mEntryBlocks[ei]->mTemp))
								ei++;
							if (ei == mEntryBlocks.Size())
							{
								for (int ei = 0; ei < mEntryBlocks.Size(); ei++)
								{
									int live = mEntryBlocks[ei]->mIns[mEntryBlocks[ei]->mTemp].mLive;
									mEntryBlocks[ei]->mIns[mEntryBlocks[ei]->mTemp] = mIns[i + 1];
									mEntryBlocks[ei]->mIns[mEntryBlocks[ei]->mTemp].mLive |= live;
								}
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
								changed = true;
							}
						}
					}
				}
#endif
			}
		}

		if (mTrueJump && mTrueJump->JoinCommonHeadSequence()) changed = true;
		if (mFalseJump && mFalseJump->JoinCommonHeadSequence()) changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::AddEntryBlock(NativeCodeBasicBlock* block)
{
	assert(mEntryBlocks.Size() == mNumEntries);
	int	i = mEntryBlocks.IndexOf(block);
	assert(i < 0);
	mEntryBlocks.Push(block);
	mNumEntries++;
}

void NativeCodeBasicBlock::RemEntryBlock(NativeCodeBasicBlock* block)
{
	assert(mEntryBlocks.Size() == mNumEntries);
	int	i = mEntryBlocks.IndexOf(block);
	assert(i >= 0);
	mEntryBlocks.Remove(i);
	mNumEntries--;
}


NativeCodeBasicBlock * NativeCodeBasicBlock::SplitMatchingTails(NativeCodeProcedure* proc)
{
	NativeCodeBasicBlock* nblock = nullptr;

	for (int i = 0; i < mEntryBlocks.Size() - 1; i++)
	{
		NativeCodeBasicBlock* bi(mEntryBlocks[i]);

		if (bi->mBranch == ASMIT_JMP && bi->mIns.Size() > 0)
		{
			for (int j = i + 1; j < mEntryBlocks.Size(); j++)
			{
				NativeCodeBasicBlock* bj(mEntryBlocks[j]);

				if (bj->mBranch == ASMIT_JMP && bj->mIns.Size() > 0)
				{
					if (bi->mIns[bi->mIns.Size() - 1].IsSame(bj->mIns[bj->mIns.Size() - 1])/* &&
						bi->mIns[bi->mIns.Size() - 2].IsSame(bj->mIns[bj->mIns.Size() - 2])*/)
					{
						if (!nblock)
						{
							nblock = proc->AllocateBlock();
							nblock->mBranch = ASMIT_JMP;
							nblock->mVisited = false;
							nblock->mTrueJump = this;

							nblock->mEntryBlocks.Push(bi);
							nblock->mNumEntries++;

							nblock->mEntryRequiredRegs = mEntryRequiredRegs;
							nblock->mExitRequiredRegs = mEntryRequiredRegs;

							bi->mTrueJump = nblock;
							mEntryBlocks[i] = nullptr;
							mNumEntries--;
						}

						nblock->mEntryBlocks.Push(bj);
						nblock->mNumEntries++;

						bj->mTrueJump = nblock;
						mEntryBlocks[j] = nullptr;
						mNumEntries--;
					}
				}
			}

			if (nblock)
			{
				int	i = 0;
				while (i < mEntryBlocks.Size())
				{
					if (mEntryBlocks[i])
						i++;
					else
						mEntryBlocks.Remove(i);
				}

				mEntryBlocks.Push(nblock);
				mNumEntries++;

				return nblock;
			}
		}
	}

	return nullptr;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::AddDominatorBlock(NativeCodeProcedure* proc, NativeCodeBasicBlock* pblock)
{
	if (pblock->mFalseJump)
	{
		NativeCodeBasicBlock* tblock = proc->AllocateBlock();
		tblock->mBranch = ASMIT_JMP;
		tblock->mTrueJump = this;
		tblock->mEntryBlocks.Push(pblock);

		mEntryBlocks[mEntryBlocks.IndexOf(pblock)] = tblock;

		tblock->mEntryRequiredRegs = mEntryRequiredRegs;
		tblock->mExitRequiredRegs = mEntryRequiredRegs;

		if (pblock->mTrueJump == this)
			pblock->mTrueJump = tblock;
		if (pblock->mFalseJump == this)
			pblock->mFalseJump = tblock;

		return tblock;
	}
	else
		return pblock;
}

static bool ReferencedOnPath(const NativeCodeBasicBlock* block, int start, int end, int address)
{
	for (int i = start; i < end; i++)
		if (block->mIns[i].ReferencesZeroPage(address))
			return true;
	return false;
}

static bool ChangedOnPath(const NativeCodeBasicBlock* block, int start, int end, int address)
{
	for (int i = start; i < end; i++)
		if (block->mIns[i].ChangesZeroPage(address))
			return true;
	return false;
}

static bool ChangesAccuOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
	for (int i = start; i < end; i++)
		if (block->mIns[i].ChangesAccu())
			return true;
	return false;
}

static bool ReferencedsRegOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
	for (int i = start; i < end; i++)
		if (block->mIns[i].ReferencesYReg())
			return true;
	return false;
}


void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins)
{
	mIns.Insert(0, ins);
	if (mEntryRequiredRegs[CPU_REG_A])
		mIns[0].mLive |= LIVE_CPU_REG_A;
	if (mEntryRequiredRegs[CPU_REG_X])
		mIns[0].mLive |= LIVE_CPU_REG_X;
	if (mEntryRequiredRegs[CPU_REG_Y])
		mIns[0].mLive |= LIVE_CPU_REG_Y;
	if (mEntryRequiredRegs[CPU_REG_C])
		mIns[0].mLive |= LIVE_CPU_REG_C;
	if (ins.mMode == ASMIM_ZERO_PAGE && ins.UsesAddress())
		mEntryRequiredRegs += ins.mAddress;
}

bool NativeCodeBasicBlock::ShortcutBlockExit(void)
{
	bool changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (!mLoopHead && mTrueJump && mFalseJump && !mTrueJump->mLoopHead && !mFalseJump->mLoopHead)
		{
			for (int i = 0; i < mTrueJump->mEntryBlocks.Size(); i++)
			{
				NativeCodeBasicBlock* eblock = mTrueJump->mEntryBlocks[i];
				if (eblock != this)
				{
					if (eblock->mTrueJump == mTrueJump && eblock->mFalseJump == mFalseJump && eblock->mBranch == mBranch)
					{
						int n = mIns.Size(), m = eblock->mIns.Size();
						if (m > 0 && n >= m)
						{
							while (m > 0 && mIns[n - 1].IsSame(eblock->mIns[m - 1]))
							{
								n--;
								m--;
							}

							if (m == 0)
							{
								mTrueJump->mNumEntries--;
								mTrueJump->mEntryBlocks.RemoveAll(this);
								mFalseJump->mNumEntries--;
								mFalseJump->mEntryBlocks.RemoveAll(this);
								mFalseJump = nullptr;
								mTrueJump = eblock;
								eblock->mNumEntries++;
								eblock->mEntryBlocks.Push(this);

								mIns.SetSize(n);
								mBranch = ASMIT_JMP;
								changed = true;
								break;
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->ShortcutBlockExit())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutBlockExit())
			changed = true;

	}

	return changed;
}

bool NativeCodeBasicBlock::ShortcutORACascade(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		if (mTrueJump && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			NativeCodeBasicBlock* block;
			if (mBranch == ASMIT_BEQ)
				block = mFalseJump;
			else
				block = mTrueJump;

			int sz = mIns.Size();
			if (sz > 0 && (block->mBranch == ASMIT_BEQ || block->mBranch == ASMIT_BNE))
			{
				NativeCodeBasicBlock* nblock;

				if (block->mBranch == ASMIT_BEQ)
					nblock = block->mFalseJump;
				else
					nblock = block->mTrueJump;

				if (!nblock->mEntryRequiredRegs[CPU_REG_A])
				{
					if (mIns[sz - 1].ChangesAccuAndFlag())
					{
						int j = 0;
						while (j < block->mIns.Size() && block->mIns[j].mType == ASMIT_ORA)
							j++;
						if (j == block->mIns.Size())
						{

							block->RemEntryBlock(this);
							nblock->AddEntryBlock(this);
							if (mBranch == ASMIT_BEQ)
								mFalseJump = nblock;
							else
								mTrueJump = nblock;
							nblock->CheckLive();

							changed = true;
						}
					}
					else if (mIns[sz - 1].IsShiftOrInc() && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
					{
						if (!block->ChangesZeroPage(mIns[sz - 1].mAddress))
						{
							int j = block->mIns.Size();
							while (j > 0 && block->mIns[j - 1].mType == ASMIT_ORA)
								j--;
							if (j > 0 && (block->mIns[j - 1].mType == ASMIT_LDA || block->mIns[j - 1].mType == ASMIT_TXA || block->mIns[j - 1].mType == ASMIT_TYA))
								j--;
							if (j == 0)
							{
								while (j < block->mIns.Size() && !block->mIns[j].SameEffectiveAddress(mIns[sz - 1]))
									j++;
								if (j < block->mIns.Size())
								{
									NativeCodeBasicBlock* nblock;

									if (block->mBranch == ASMIT_BEQ)
										nblock = block->mFalseJump;
									else
										nblock = block->mTrueJump;

									block->RemEntryBlock(this);
									nblock->AddEntryBlock(this);
									if (mBranch == ASMIT_BEQ)
										mFalseJump = nblock;
									else
										mTrueJump = nblock;
									nblock->CheckLive();

									changed = true;
								}
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->ShortcutORACascade())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutORACascade())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SplitSinglePath(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int sz = mIns.Size();
		if (sz >= 3 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && mExitRequiredRegs.Size() && !mExitRequiredRegs[CPU_REG_C])
		{
			if (mIns[sz - 3].mType == ASMIT_TAY &&
				mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
			{
				NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
				eblock->mBranch = ASMIT_JMP;
				if (mBranch == ASMIT_BEQ)
				{
					eblock->mTrueJump = mFalseJump;
					mFalseJump = eblock;
				}
				else
				{
					eblock->mTrueJump = mTrueJump;
					mTrueJump = eblock;
				}

				mIns[sz - 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
				eblock->mIns.Push(mIns[sz - 2]);
				mIns.SetSize(sz - 2);

				eblock->mNumEntries = 1;
				eblock->mEntryBlocks.Push(this);
				eblock->mTrueJump->mEntryBlocks.RemoveAll(this);
				eblock->mTrueJump->mEntryBlocks.Push(eblock);

				eblock->mExitProvidedRegs = mExitProvidedRegs;
				changed = true;
			}
			else if (mIns[sz - 3].mType == ASMIT_TAX &&
				mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
				mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0)
			{
				NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
				eblock->mBranch = ASMIT_JMP;
				if (mBranch == ASMIT_BEQ)
				{
					eblock->mTrueJump = mFalseJump;
					mFalseJump = eblock;
				}
				else
				{
					eblock->mTrueJump = mTrueJump;
					mTrueJump = eblock;
				}

				mIns[sz - 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
				eblock->mIns.Push(mIns[sz - 2]);
				mIns.SetSize(sz - 2);

				eblock->mNumEntries = 1;
				eblock->mEntryBlocks.Push(this);
				eblock->mTrueJump->mEntryBlocks.RemoveAll(this);
				eblock->mTrueJump->mEntryBlocks.Push(eblock);

				eblock->mExitProvidedRegs = mExitProvidedRegs;
				changed = true;
			}
		}

		if (mTrueJump && mFalseJump)
		{
			if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE)
			{
				int index;
				NativeCodeBasicBlock* block;

				if (IsExitARegZP(mTrueJump->mIns[0].mAddress, index, block))
				{
					NativeCodeBasicBlock* eblock = mTrueJump->SplitBlock(1);
					eblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;

					mTrueJump->mEntryBlocks.RemoveAll(this);
					mTrueJump->mNumEntries--;

					mTrueJump = eblock;
					mTrueJump->mEntryBlocks.Push(this);
					mTrueJump->mNumEntered++;
					
					changed = true;
				}
			}
			if (!changed && mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_STA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE)
			{
				int index;
				NativeCodeBasicBlock* block;

				if (IsExitARegZP(mFalseJump->mIns[0].mAddress, index, block))
				{
					NativeCodeBasicBlock* eblock = mFalseJump->SplitBlock(1);
					eblock->mExitRequiredRegs = mFalseJump->mEntryRequiredRegs;

					mFalseJump->mEntryBlocks.RemoveAll(this);
					mFalseJump->mNumEntries--;

					mFalseJump = eblock;
					mFalseJump->mEntryBlocks.Push(this);
					mFalseJump->mNumEntered++;

					changed = true;
				}
			}
			if (!changed)
			{
				int sz = mIns.Size();
				if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
				{
					if (mTrueJump->mIns.Size() > 0 && !mTrueJump->mLoopHead && mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mTrueJump->mIns[0].mAddress == mIns[sz - 1].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_X))
					{
						NativeCodeBasicBlock* eblock = mTrueJump->SplitBlock(1);
						eblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;

						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mNumEntries--;

						mTrueJump = eblock;
						mTrueJump->mEntryBlocks.Push(this);
						mTrueJump->mNumEntered++;

						mIns[sz - 1].mType = ASMIT_LDX;
						mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
						mExitRequiredRegs += CPU_REG_X;

						changed = true;
					}
					if (mFalseJump->mIns.Size() > 0 && !mFalseJump->mLoopHead && mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[0].mAddress == mIns[sz - 1].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_X))
					{
						NativeCodeBasicBlock* eblock = mFalseJump->SplitBlock(1);
						eblock->mExitRequiredRegs = mFalseJump->mEntryRequiredRegs;

						mFalseJump->mEntryBlocks.RemoveAll(this);
						mFalseJump->mNumEntries--;

						mFalseJump = eblock;
						mFalseJump->mEntryBlocks.Push(this);
						mFalseJump->mNumEntered++;

						mIns[sz - 1].mType = ASMIT_LDX;
						mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
						mExitRequiredRegs += CPU_REG_X;

						changed = true;
					}
					if (mTrueJump->mIns.Size() > 0 && !mTrueJump->mLoopHead && mTrueJump->mIns[0].mType == ASMIT_LDY && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mTrueJump->mIns[0].mAddress == mIns[sz - 1].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Y))
					{
						NativeCodeBasicBlock* eblock = mTrueJump->SplitBlock(1);
						eblock->mExitRequiredRegs = mTrueJump->mEntryRequiredRegs;

						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mNumEntries--;

						mTrueJump = eblock;
						mTrueJump->mEntryBlocks.Push(this);
						mTrueJump->mNumEntered++;

						mIns[sz - 1].mType = ASMIT_LDY;
						mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;

						changed = true;
					}
					if (mFalseJump->mIns.Size() > 0 && !mFalseJump->mLoopHead && mFalseJump->mIns[0].mType == ASMIT_LDY && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[0].mAddress == mIns[sz - 1].mAddress && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Y))
					{
						NativeCodeBasicBlock* eblock = mFalseJump->SplitBlock(1);
						eblock->mExitRequiredRegs = mFalseJump->mEntryRequiredRegs;

						mFalseJump->mEntryBlocks.RemoveAll(this);
						mFalseJump->mNumEntries--;

						mFalseJump = eblock;
						mFalseJump->mEntryBlocks.Push(this);
						mFalseJump->mNumEntered++;

						mIns[sz - 1].mType = ASMIT_LDY;
						mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;

						changed = true;
					}
				}
			}
		}


		if (mTrueJump && mTrueJump->SplitSinglePath()) changed = true;
		if (mFalseJump && mFalseJump->SplitSinglePath()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::PropagateSinglePath(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

#if 1
		if (mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
		{
			mTempRegs.Reset(mTrueJump->mEntryRequiredRegs.Size());

			bool	changeX = false, changeY = false, changeA = false;
			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);
								changed = true;
							}
							else
								mTempRegs += addr;
						}
						else
							mTempRegs += addr;
					}
				}
				else if (ins.mMode == ASMIM_INDIRECT_Y)
				{
					mTempRegs += ins.mAddress;
					mTempRegs += ins.mAddress + 1;
				}
				else if (ins.mType == ASMIT_JSR)
					break;

				if (!changeX && i >= 2 && (mIns[i - 2].mType == ASMIT_INX && mIns[i].mType == ASMIT_DEX || mIns[i - 2].mType == ASMIT_DEX && mIns[i].mType == ASMIT_INX) && 
					mIns[i - 1].mType == ASMIT_STX && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !mTempRegs[mIns[i - 1].mAddress])
				{
					int addr = mIns[i - 1].mAddress;
					if (mTrueJump->mEntryRequiredRegs[addr] && !mFalseJump->mEntryRequiredRegs[addr] && mTrueJump->mNumEntries == 1 ||
						mFalseJump->mEntryRequiredRegs[addr] && !mTrueJump->mEntryRequiredRegs[addr] && mFalseJump->mNumEntries == 1)
					{
						for (int j = i + 1; j < mIns.Size(); j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;

						if (mTrueJump->mEntryRequiredRegs[addr])
						{
							mTrueJump->mEntryRequiredRegs += CPU_REG_X;
							mTrueJump->PrependInstruction(mIns[i]);
							mTrueJump->PrependInstruction(mIns[i - 1]);
							mTrueJump->PrependInstruction(mIns[i - 2]);
						}
						else
						{
							mFalseJump->mEntryRequiredRegs += CPU_REG_X;
							mFalseJump->PrependInstruction(mIns[i]);
							mFalseJump->PrependInstruction(mIns[i - 1]);
							mFalseJump->PrependInstruction(mIns[i - 2]);
						}

						mIns.Remove(i - 2, 3);
						i -= 2;
						changed = true;
					}
				}

				if (ins.ChangesAccu()) changeA = true;
				if (ins.ChangesXReg()) changeX = true;
				if (ins.ChangesYReg()) changeY = true;
			}
		}
#endif

#if 1
		if (mTrueJump && mFalseJump && mTrueJump->mEntryProvidedRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
		{
			if (mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] ||
				mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
			{
				int i = mIns.Size();
				while (i > 0 && !mIns[i - 1].ReferencesAccu())
					i--;
				if (i > 0 && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_ORA || mIns[i - 1].mType == ASMIT_AND || mIns[i - 1].mType == ASMIT_EOR) && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
				{
					if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
					{
						if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
							mExitRequiredRegs += mIns[i - 1].mAddress;

						if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
						{
							mTrueJump = mTrueJump->UniqueEntryBlock(this);
							mTrueJump->PrependInstruction(mIns[i - 1]);
						}
						else
						{
							mFalseJump = mFalseJump->UniqueEntryBlock(this);
							mFalseJump->PrependInstruction(mIns[i - 1]);
						}
						mIns.Remove(i - 1);
						changed = true;
					}
				}
				else if (i > 0 && mIns[i - 1].mType == ASMIT_TXA && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z) && !ChangesXReg(i))
				{
					for (int j = i; j < mIns.Size(); j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
					mExitRequiredRegs += CPU_REG_X;
					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[i - 1]);
						mTrueJump->mEntryRequiredRegs += CPU_REG_X;
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[i - 1]);
						mFalseJump->mEntryRequiredRegs += CPU_REG_X;
					}
					mIns.Remove(i - 1);
					changed = true;
				}
				else if (i > 1 && mIns[i - 1].mType == ASMIT_EOR && mIns[i - 1].mMode == ASMIM_IMMEDIATE && (mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) && mIns[i - 2].ChangesFlagToAccu())
				{
					if (mIns[i - 1].mAddress & 0x80)
					{
						if (mBranch == ASMIT_BPL)
							mBranch = ASMIT_BMI;
						else
							mBranch = ASMIT_BPL;
					}
					mIns[i - 2].mLive |= LIVE_CPU_REG_Z;

					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[i - 1]);
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[i - 1]);
					}
					mIns.Remove(i - 1);
					changed = true;
				}
				else if (i > 0 && mIns[i - 1].mType == ASMIT_ROR && mIns[i - 1].mMode == ASMIM_IMPLIED && (mBranch == ASMIT_BPL || mBranch == ASMIT_BMI))
				{
					if (mBranch == ASMIT_BPL)
						mBranch = ASMIT_BCC;
					else
						mBranch = ASMIT_BCS;

					mExitRequiredRegs += CPU_REG_C;

					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[i - 1]);
						mTrueJump->mEntryRequiredRegs += CPU_REG_C;
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[i - 1]);
						mFalseJump->mEntryRequiredRegs += CPU_REG_C;
					}
					mIns.Remove(i - 1);
					changed = true;
				}

				int sz = mIns.Size();

				if (sz > 1 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 2].IsShiftOrInc() && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 2]))
				{
					mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_CPU_REG_Z;

					if (mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
						mExitRequiredRegs += mIns[sz - 1].mAddress;

					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[sz - 1]);
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[sz - 1]);
					}
					mIns.Remove(sz - 1);
					changed = true;
				}
				else if (sz > 1 && mIns[sz - 1].mType == ASMIT_ASL && mIns[sz - 1].mMode == ASMIM_IMPLIED && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C] && mIns[sz - 2].ChangesAccuAndFlag())
				{
					if (mBranch == ASMIT_BCC)
						mBranch = ASMIT_BPL;
					else
						mBranch = ASMIT_BMI;

					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[sz - 1]);
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[sz - 1]);
					}
					mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
					mIns.Remove(sz - 1);
					changed = true;
				}
				else if (sz >= 3 && 
					(mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY) && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C) &&
					mIns[sz - 3].mType == ASMIT_LDA && !mIns[sz - 2].ChangesXReg() && !mIns[sz - 2].ChangesYReg() && !mIns[sz - 2].ChangesAddress())
				{
					if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						mTrueJump = mTrueJump->UniqueEntryBlock(this);
						mTrueJump->PrependInstruction(mIns[sz - 2]);
						mTrueJump->PrependInstruction(mIns[sz - 3]);
					}
					else
					{
						mFalseJump = mFalseJump->UniqueEntryBlock(this);
						mFalseJump->PrependInstruction(mIns[sz - 2]);
						mFalseJump->PrependInstruction(mIns[sz - 3]);
					}
					mIns[sz - 1].mType = mIns[sz - 1].mType == ASMIT_CPX ? ASMIT_TXA : ASMIT_TYA;
					mIns[sz - 1].mMode = ASMIM_IMPLIED;
					mIns[sz - 1].mLive |= mIns[sz - 2].mLive | mIns[sz - 2].NeedsLive();
					mIns.Remove(sz - 2);
					mIns.Remove(sz - 3);
					changed = true;
				}
			}
			if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z]||
				mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
			{
				int i = mIns.Size();
				while (i > 0 && !mIns[i - 1].ReferencesXReg())
					i--;
				if (i > 0 && mIns[i - 1].mType == ASMIT_LDX && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
				{
					if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
					{
						if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
							mExitRequiredRegs += mIns[i - 1].mAddress;

						if (mTrueJump->mEntryRequiredRegs[CPU_REG_X])
							mTrueJump->PrependInstruction(mIns[i - 1]);
						else
							mFalseJump->PrependInstruction(mIns[i - 1]);
						mIns.Remove(i - 1);
						changed = true;
					}
				}
				else if (i > 0 && (mIns[i - 1].mType == ASMIT_INX || mIns[i - 1].mType == ASMIT_DEX) && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
				{
					for (int j = i + 1; j < mIns.Size(); j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;

					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_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mNumEntries == 1 ||
				mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mNumEntries == 1)
			{
				int sz = mIns.Size();
				if (sz >= 2 && mIns[sz - 1].mType == ASMIT_TAX && mIns[sz - 2].ChangesFlagToAccu())
				{
					mExitRequiredRegs += CPU_REG_A;
					if (mTrueJump->mEntryRequiredRegs[CPU_REG_X])
					{
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						mTrueJump->PrependInstruction(mIns[sz - 1]);
					}
					else
					{
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						mFalseJump->PrependInstruction(mIns[sz - 1]);
					}
					if (mIns[sz - 1].mLive & LIVE_CPU_REG_Z)
						mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
					mIns.Remove(sz - 1);
					changed = true;
				}
			}

			if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] ||
				mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
			{
				int i = mIns.Size();
				while (i > 0 && !mIns[i - 1].ReferencesYReg())
					i--;
				if (i > 0 && mIns[i - 1].mType == ASMIT_LDY && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
				{
					if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
					{
						if (mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
							mExitRequiredRegs += mIns[i - 1].mAddress;

						if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
							mTrueJump->PrependInstruction(mIns[i - 1]);
						else
							mFalseJump->PrependInstruction(mIns[i - 1]);
						mIns.Remove(i - 1);
						changed = true;
					}
				}
				else if (i > 0 && mIns[i - 1].mType == ASMIT_TAY && !ChangesAccuOnPath(this, i, mIns.Size()))
				{
					if (!(mIns[i - 1].mLive & LIVE_CPU_REG_Z) || i > 2 && mIns[i - 2].ChangesAccuAndFlag())
					{
						if (mIns[i - 1].mLive & LIVE_CPU_REG_Z)
							mIns[i - 2].mLive |= LIVE_CPU_REG_Z;

						mExitRequiredRegs += CPU_REG_A;
						if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
						{
							mTrueJump->mEntryRequiredRegs += CPU_REG_A;
							mTrueJump->PrependInstruction(mIns[i - 1]);
						}
						else
						{
							mFalseJump->mEntryRequiredRegs += CPU_REG_A;
							mFalseJump->PrependInstruction(mIns[i - 1]);
						}
						mIns.Remove(i - 1);
						changed = true;
					}
				}
			}
			if (mTrueJump->mNumEntries == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TAX && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				int sz = mIns.Size();
				if (sz >= 2 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 2].mMode) && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode))
				{
					mIns[sz - 2].mType = ASMIT_LDX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X;
					mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
					mExitRequiredRegs += CPU_REG_X;
					mTrueJump->mEntryRequiredRegs += CPU_REG_X;
					mTrueJump->mIns[0].mType = ASMIT_NOP;
					changed = true;
				}
			}
		}
#endif

		if (!changed && mTrueJump && mFalseJump && mExitRequiredRegs.Size())
		{
			int sz = mIns.Size();
			int i = sz - 1;
			while (i >= 0 && !(mIns[i].ReferencesYReg() || mIns[i].ChangesAccu()))
				i--;
			if (i >= 0 && mIns[i].mType == ASMIT_TAY && !(mIns[i].mLive & LIVE_CPU_REG_Z))
			{
				NativeCodeBasicBlock	* tblock = mTrueJump, * fblock = mFalseJump;
				NativeCodeBasicBlock* ptblock = this, * pfblock = this;
				while (tblock && !(tblock->ChangesAccu() || tblock->ReferencesYReg() || tblock->mFalseJump || tblock->mNumEntries > 1))
				{
					ptblock = tblock;
					tblock = tblock->mTrueJump;
				}
				while (fblock && !(fblock->ChangesAccu() || fblock->ReferencesYReg() || fblock->mFalseJump || fblock->mNumEntries > 1))
				{
					pfblock = fblock;
					fblock = fblock->mTrueJump;
				}

				if (fblock && fblock != this)
				{
					int k = 0;
					while (k < fblock->mIns.Size() && !(fblock->mIns[k].ReferencesYReg() || fblock->mIns[k].ChangesAccu()))
						k++;
					if (k < fblock->mIns.Size() && fblock->mIns[k].mType == ASMIT_TYA && !(fblock->mIns[k].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
					{
						if (k > 0)
						{
							fblock->mIns.Insert(0, NativeCodeInstruction(fblock->mIns[k].mIns, ASMIT_TYA));
							fblock->mIns.Remove(k + 1);
						}

						NativeCodeBasicBlock* shortb = fblock->SplitBlock(1);
						fblock->mExitProvidedRegs += CPU_REG_A;

						fblock->mEntryBlocks.RemoveAll(pfblock);
						shortb->mEntryBlocks.Push(pfblock);
						if (pfblock == this)
							mFalseJump = shortb;
						else
							pfblock->mTrueJump = shortb;
						mExitRequiredRegs += CPU_REG_A;
						NativeCodeBasicBlock* fb = mFalseJump;
						while (fb != shortb)
						{
							fb->mEntryRequiredRegs += CPU_REG_A;
							fb->mExitProvidedRegs += CPU_REG_A;
							for (char j = 0; j < fb->mIns.Size(); j++)
								fb->mIns[j].mLive |= LIVE_CPU_REG_A;
							fb = fb->mTrueJump;
						}

						NativeCodeBasicBlock* pt = mTrueJump->UniqueEntryBlock(this);
						pt->mEntryRequiredRegs += CPU_REG_A;
						pt->mIns.Insert(0, mIns[i]);
						mIns.Remove(i);
						changed = true;
					}
				}
				if (tblock && tblock != this && !changed)
				{
					int k = 0;
					while (k < tblock->mIns.Size() && !(tblock->mIns[k].ReferencesYReg() || tblock->mIns[k].ChangesAccu()))
						k++;
					if (k < tblock->mIns.Size() && tblock->mIns[k].mType == ASMIT_TYA && !(tblock->mIns[k].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
					{
						if (k > 0)
						{
							tblock->mIns.Insert(0, NativeCodeInstruction(tblock->mIns[k].mIns, ASMIT_TYA));
							tblock->mIns.Remove(k + 1);
						}

						NativeCodeBasicBlock* shortb = tblock->SplitBlock(1);
						tblock->mExitProvidedRegs += CPU_REG_A;

						tblock->mEntryBlocks.RemoveAll(ptblock);
						shortb->mEntryBlocks.Push(ptblock);
						if (ptblock == this)
							mTrueJump = shortb;
						else
							ptblock->mTrueJump = shortb;
						mExitRequiredRegs += CPU_REG_A;
						NativeCodeBasicBlock* fb = mTrueJump;
						while (fb != shortb)
						{
							fb->mEntryRequiredRegs += CPU_REG_A;
							fb->mExitProvidedRegs += CPU_REG_A;
							for (char j = 0; j < fb->mIns.Size(); j++)
								fb->mIns[j].mLive |= LIVE_CPU_REG_A;
							fb = fb->mTrueJump;
						}

						NativeCodeBasicBlock* pt = mFalseJump->UniqueEntryBlock(this);
						pt->mEntryRequiredRegs += CPU_REG_A;
						pt->mIns.Insert(0, mIns[i]);
						mIns.Remove(i);
						changed = true;
					}
				}
			}
		}

		if (!changed && mTrueJump && mFalseJump && mExitRequiredRegs.Size())
		{
			int sz = mIns.Size();
			int i = sz - 1;
			while (i >= 0 && !(mIns[i].ChangesYReg() || mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE))
				i--;
			if (i >= 0 && mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				int addr = mIns[i].mAddress;

				NativeCodeBasicBlock* tblock = mTrueJump, * fblock = mFalseJump;
				NativeCodeBasicBlock* ptblock = this, * pfblock = this;
				while (tblock && !(tblock->ChangesYReg() || tblock->ReferencesZeroPage(addr) || tblock->mFalseJump || tblock->mNumEntries > 1))
				{
					ptblock = tblock;
					tblock = tblock->mTrueJump;
				}
				while (fblock && !(fblock->ChangesYReg() || fblock->ReferencesZeroPage(addr) || fblock->mFalseJump || fblock->mNumEntries > 1))
				{
					pfblock = fblock;
					fblock = fblock->mTrueJump;
				}

				if (fblock && fblock != this)
				{
					int k = 0;
					while (k < fblock->mIns.Size() && !(fblock->mIns[k].ChangesYReg() || fblock->mIns[k].ReferencesZeroPage(addr)))
						k++;
					if (k < fblock->mIns.Size() && fblock->mIns[k].mType == ASMIT_LDY && fblock->mIns[k].mMode == ASMIM_ZERO_PAGE && fblock->mIns[k].mAddress == addr && !(fblock->mIns[k].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
					{
						NativeCodeBasicBlock* shortb = fblock->SplitBlock(k + 1);
						fblock->mExitProvidedRegs += CPU_REG_Y;

						NativeCodeBasicBlock* prefixb = fblock->CloneBlock();
						prefixb->mIns.SetSize(k);

						fblock->mEntryBlocks.RemoveAll(pfblock);
						prefixb->mEntryBlocks.Push(pfblock);
						if (pfblock == this)
							mFalseJump = prefixb;
						else
							pfblock->mTrueJump = prefixb;

						mExitRequiredRegs += CPU_REG_Y;
						NativeCodeBasicBlock* fb = mFalseJump;
						while (fb != shortb)
						{
							if (fb->mEntryRequiredRegs.Size() > 0)
							{
								fb->mEntryRequiredRegs += CPU_REG_Y;
								fb->mExitProvidedRegs += CPU_REG_Y;
							}
							for (char j = 0; j < fb->mIns.Size(); j++)
								fb->mIns[j].mLive |= LIVE_CPU_REG_Y;
							fb = fb->mTrueJump;
						}

						NativeCodeBasicBlock* pt = mTrueJump->UniqueEntryBlock(this);
						pt->mEntryRequiredRegs += CPU_REG_Y;
						pt->mIns.Insert(0, mIns[i]);
						pt->mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
						mIns.Remove(i);
						changed = true;

						while (i < mIns.Size())
						{
							mIns[i].mLive |= LIVE_CPU_REG_Y;
							i++;
						}
					}
				}
				if (tblock && tblock != this && !changed)
				{
					int k = 0;
					while (k < tblock->mIns.Size() && !(tblock->mIns[k].ChangesYReg() || tblock->mIns[k].ReferencesZeroPage(addr)))
						k++;
					if (k < tblock->mIns.Size() && tblock->mIns[k].mType == ASMIT_LDY && tblock->mIns[k].mMode == ASMIM_ZERO_PAGE && tblock->mIns[k].mAddress == addr && !(tblock->mIns[k].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
					{
						NativeCodeBasicBlock* shortb = tblock->SplitBlock(k + 1);
						tblock->mExitProvidedRegs += CPU_REG_Y;

						NativeCodeBasicBlock* prefixb = tblock->CloneBlock();
						prefixb->mIns.SetSize(k);

						tblock->mEntryBlocks.RemoveAll(ptblock);
						prefixb->mEntryBlocks.Push(ptblock);
						if (ptblock == this)
							mTrueJump = prefixb;
						else
							ptblock->mTrueJump = prefixb;

						mExitRequiredRegs += CPU_REG_Y;
						NativeCodeBasicBlock* fb = mTrueJump;
						while (fb != shortb)
						{
							if (fb->mEntryRequiredRegs.Size() > 0)
							{
								fb->mEntryRequiredRegs += CPU_REG_Y;
								fb->mExitProvidedRegs += CPU_REG_Y;
							}
							for (char j = 0; j < fb->mIns.Size(); j++)
								fb->mIns[j].mLive |= LIVE_CPU_REG_Y;
							fb = fb->mTrueJump;
						}

						NativeCodeBasicBlock* pt = mFalseJump->UniqueEntryBlock(this);
						pt->mEntryRequiredRegs += CPU_REG_Y;
						pt->mIns.Insert(0, mIns[i]);
						pt->mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
						mIns.Remove(i);
						changed = true;

						while (i < mIns.Size())
						{
							mIns[i].mLive |= LIVE_CPU_REG_Y;
							i++;
						}
					}
				}
			}
		}


		if (mTrueJump && mFalseJump && mExitRequiredRegs.Size())
		{
			uint32	live = 0;
			if (mExitRequiredRegs[CPU_REG_X])
				live |= LIVE_CPU_REG_X;
			if (mExitRequiredRegs[CPU_REG_Y])
				live |= LIVE_CPU_REG_Y;
			if (mExitRequiredRegs[CPU_REG_C])
				live |= LIVE_CPU_REG_C;

			int i = 0;
			while (i < mIns.Size())
			{
#if 1
				if (!mExitRequiredRegs[CPU_REG_A] &&
					i + 1 < mIns.Size() &&
					mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					if (!ReferencedOnPath(this, i + 2, mIns.Size(), mIns[i + 1].mAddress) &&
						!ChangedOnPath(this, i + 2, mIns.Size(), mIns[i + 0].mAddress))
					{
						if (mTrueJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
							!mFalseJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
							mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							for (int j = 0; j < 2; j++)
							{
								mIns[i + j].mLive |= live;
								mTrueJump->mIns.Insert(j, mIns[i + j]);
							}
							mIns.Remove(i + 1);
							changed = true;
							continue;
						}
						else if (mFalseJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
							!mTrueJump->mEntryRequiredRegs[mIns[i + 1].mAddress] &&
							mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							for (int j = 0; j < 2; j++)
							{
								mIns[i + j].mLive |= live;
								mFalseJump->mIns.Insert(j, mIns[i + j]);
							}
							mIns.Remove(i + 1);
							changed = true;
							continue;
						}
					}					
				}
#endif
#if 1
				if (!mExitRequiredRegs[CPU_REG_A] &&
					i + 6 < mIns.Size() &&
					mIns[i + 0].mType == ASMIT_CLC &&
					mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE &&
					!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
				{
					if (!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 3].mAddress) &&
						!ReferencedOnPath(this, i + 7, mIns.Size(), mIns[i + 6].mAddress) &&
						!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 1].mAddress) &&
						!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 2].mAddress) &&
						!ChangedOnPath(this, i + 7, mIns.Size(), mIns[i + 4].mAddress))
					{
						if (mTrueJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && mTrueJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
							!mFalseJump->mEntryRequiredRegs[mIns[i + 3].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[i + 6].mAddress] &&
							!mTrueJump->mEntryRequiredRegs[CPU_REG_C] &&
							!mTrueJump->mEntryRequiredRegs[CPU_REG_Z] &&
							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->mEntryRequiredRegs[CPU_REG_Z] &&
							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->mEntryRequiredRegs[CPU_REG_Z] &&
							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->mEntryRequiredRegs[CPU_REG_Z] &&
							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 (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 + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE && 
		mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && 
		mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == mIns[at + 1].mAddress + 1 &&
		mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE && 
		mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress == mIns[at + 3].mAddress + 1 &&
		!(mIns[at + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
	{
		sreg = mIns[at + 1].mAddress;
		dreg = mIns[at + 3].mAddress;
		offset = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::CanForward16BitAddSubImmediate(int sreg, int dreg, int offset, int& index) const
{
	int	i = mIns.Size() - 1;
	while (i >= 6)
	{
		int	asreg, adreg, aoffset;
		if (Is16BitAddSubImmediate(i - 6, asreg, adreg, aoffset) && asreg == sreg && adreg == dreg && aoffset == offset)
		{
			index = i - 6;
			return true;
		}

		if (mIns[i].ReferencesZeroPage(dreg) || mIns[i].ReferencesZeroPage(dreg + 1) || mIns[i].ChangesZeroPage(sreg) || mIns[i].ChangesZeroPage(sreg + 1))
			return false;

		i--;
	}

	return false;
}

bool NativeCodeBasicBlock::CanForwardLoadStore(const NativeCodeInstruction& lins, const NativeCodeInstruction& sins, int& index) const
{
	int	i = mIns.Size() - 1;
	while (i > 0)
	{
		if (lins.MayBeChangedOnAddress(mIns[i]))
			return false;
		if (mIns[i].MayBeSameAddress(sins))
		{
			index = i - 1;
			if (mIns[i].mType == ASMIT_STA && mIns[i - 1].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_A) ||
				mIns[i].mType == ASMIT_STX && mIns[i - 1].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_X) ||
				mIns[i].mType == ASMIT_STY && mIns[i - 1].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
			{
				if (!(mIns[i].mLive & LIVE_CPU_REG_Z) && mIns[i].SameEffectiveAddress(sins) && mIns[i - 1].SameEffectiveAddress(lins))
					return true;
			}
			return false;
		}
		if (mIns[i].mType == ASMIT_JSR)
			return false;
		if (sins.MayBeChangedOnAddress(mIns[i]) || mIns[i].MayBeChangedOnAddress(sins))
			return false;
		i--;
	}

	return false;
}

bool NativeCodeBasicBlock::CanForwardZPMove(int saddr, int daddr, int & index) const
{
	int	i = mIns.Size() - 1;
	while (i > 0)
	{
		if (mIns[i].ChangesZeroPage(saddr))
			return false;
		if (mIns[i].ChangesZeroPage(daddr))
		{
			index = i - 1;
			return 
				(mIns[i].mType == ASMIT_STA && mIns[i - 1].mType == ASMIT_LDA && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == saddr && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
				(mIns[i].mType == ASMIT_STX && mIns[i - 1].mType == ASMIT_LDX && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == saddr && !(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)));
		}
		if (mIns[i].ReferencesZeroPage(daddr))
			return false;
		i--;
	}

	return false;
}

bool NativeCodeBasicBlock::CheckShortcutPointerAddForward(int at)
{
	int i = at + 6;

	while (i < mIns.Size())
	{
		if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress)
		{
			if (!(mIns[i].mLive & LIVE_MEM))
			{
				mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
				mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
				mIns[at + 5].mAddress = mIns[at + 4].mAddress; mIns[at + 4].mLive |= LIVE_MEM;

				for (int j = at + 6; j <= i; j++)
				{
					if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 1].mAddress)
						mIns[j].mAddress = mIns[at + 0].mAddress;
				}

				return true;
			}
		}
		else if (mIns[i].ChangesZeroPage(mIns[at + 0].mAddress) ||
			mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress) ||
			mIns[i].ReferencesZeroPage(mIns[at + 4].mAddress) ||
			mIns[i].ReferencesZeroPage(mIns[at + 5].mAddress))
			return false;

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::ShortcutPointerAddForward(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 6 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_CLC &&
				mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS &&
				mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress + 1 && !(mIns[i + 4].mLive & LIVE_MEM) &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
			{
				if (CheckShortcutPointerAddForward(i))
					changed = true;
			}
		}
				
		if (mTrueJump && mTrueJump->ShortcutPointerAddForward())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutPointerAddForward())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveIndirectLoadZeroStoreDown(int at)
{
	int yval = mIns[at].mAddress;

	for (int i = at + 3; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at + 2].mAddress)
		{
			if (mIns[i].mLive & LIVE_CPU_REG_Y)
				return false;
			mIns.Insert(i, mIns[at]);
			mIns.Insert(i + 1, mIns[at + 1]);
			mIns[i + 2].mType = ASMIT_STA;
			mIns[i].mLive |= mIns[i + 2].mLive;
			mIns[i + 1].mLive |= mIns[i + 2].mLive;
			mIns.Remove(at + 1, 2);
			return true;
		}

		if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1) || mIns[i].ReferencesZeroPage(mIns[at + 2].mAddress))
			return false;

		if (mIns[i].mType == ASMIT_JSR)
			return false;

		if (mIns[i].ChangesAddress())
		{
			if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress)
			{
				if (yval == -1 || yval == mIns[at].mAddress)
					return false;
			}
			else if (mIns[at + 1].MayBeChangedOnAddress(mIns[i]))
				return false;
		}

		if (mIns[i].ChangesYReg())
		{
			if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
				yval = mIns[i].mAddress;
			else if (mIns[i].mType == ASMIT_INY && yval >= 0)
				yval = (yval + 1) & 255;
			else if (mIns[i].mType == ASMIT_DEY && yval >= 0)
				yval = (yval - 1) & 255;
			else
				yval = -1;
		}

	}

	return false;
}

bool NativeCodeBasicBlock::SortIndirectStoreDown(int at)
{
	int i = at + 3;
	while (i + 1 < mIns.Size())
	{
		if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
			mIns[i + 1].mAddress == mIns[at + 2].mAddress &&
			!(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
		{
			if (mIns[i + 0].mAddress < mIns[at + 1].mAddress)
			{
				mIns.Insert(i + 2, mIns[at + 0]);
				mIns.Insert(i + 3, mIns[at + 1]);
				mIns.Insert(i + 4, mIns[at + 2]);
				mIns[i + 2].mLive |= mIns[i + 1].mLive;
				mIns[i + 3].mLive |= mIns[i + 1].mLive;
				mIns[i + 4].mLive |= mIns[i + 1].mLive;
				if (mIns[at + 2].mLive & LIVE_CPU_REG_A)
					mIns.Remove(at + 1, 2);
				else
					mIns.Remove(at, 3);
				return true;
			}
			else if (mIns[i].mAddress == mIns[at + 1].mAddress)
				return false;
			else
				i += 2;
		}
		else
		{
			if (mIns[i].MayBeSameAddress(mIns[at + 2]))
				return false;
			else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress() && (mIns[i].mAddress == mIns[at + 2].mAddress || mIns[i].mAddress == mIns[at + 2].mAddress + 1))
				return false;

			i++;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::SortIndirectStores(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int i = 0;
		while (i + 2 < mIns.Size())
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
				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 (SortIndirectStoreDown(i))
					changed = true;
				else
					i++;
			}
			else
				i++;
		}

		if (mTrueJump && mTrueJump->SortIndirectStores()) changed = true;
		if (mFalseJump && mFalseJump->SortIndirectStores()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MoveLoadZeroStoreIndirectUp(int at)
{
	int i = at - 1;
	while (i >= 0 && !(mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress))
		i--;

	if (i >= 0 && mIns[i].mType == ASMIT_STA && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y)))
	{
		int yval = -1;
		for (int j = i + 1; j < at; j++)
		{
			if (mIns[j].mType == ASMIT_JSR)
				return false;
			if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1))
				return false;

			if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress)
			{
				if (yval == -1 || yval == mIns[at + 1].mAddress)
					return false;
			}
			else if (mIns[j].MayBeSameAddress(mIns[at + 2]))
				return false;

			if (mIns[j].ChangesYReg())
			{
				if (mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE)
					yval = mIns[j].mAddress;
				else if (mIns[j].mType == ASMIT_INY && yval >= 0)
					yval = (yval + 1) & 255;
				else if (mIns[j].mType == ASMIT_DEY && yval >= 0)
					yval = (yval - 1) & 255;
				else
					yval = -1;
			}
		}

		NativeCodeInstruction	i0 = mIns[at + 1], i1 = mIns[at + 2];
		mIns.Remove(at + 1, 2);

		mIns.Insert(i + 1, i0);
		mIns.Insert(i + 2, i1);
		mIns[i].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= mIns[i].mLive;
		mIns[i + 2].mLive |= mIns[i].mLive;

		return true;
	}

	return false;
}


bool NativeCodeBasicBlock::ShortcutIndirectLoadStore(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 2 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
				mIns[i + 2].mAddress != mIns[i + 1].mAddress && mIns[i + 2].mAddress != mIns[i + 1].mAddress + 1)
			{
				if (MoveIndirectLoadZeroStoreDown(i))
					changed = true;
			}
			else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				if (MoveLoadZeroStoreIndirectUp(i))
					changed = true;
			}
		}

		if (mTrueJump && mTrueJump->ShortcutIndirectLoadStore())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutIndirectLoadStore())
			changed = true;
	}

	return changed;
}

#if 0
static int NativeCodeExpressionID;

struct NativeCodeExpression
{
	int							mIndex;
	AsmInsType					mType;
	NativeCodeInstruction	*	mIns;
	int							mLeft, mRight;
	int							mReg;

	NativeCodeExpression(AsmInsType type, NativeCodeInstruction* ins)
		: mIndex(NativeCodeExpressionID++), mType(type), mIns(ins), mLeft(-1), mRight(-1), mReg(-1)
	{
	}

	NativeCodeExpression(AsmInsType type, int left, int right)
		: mIndex(NativeCodeExpressionID++), mType(type), mIns(nullptr), mLeft(left), mRight(right), mReg(reg)
	{
	}
};

struct NativeCodeExpressions
{
	ExpandingArray<NativeCodeExpression>	mExps;

	void KillReg(int reg);
	void KillYReg(void);
	void KillXReg(void);
	void KillAddr(const NativeCodeInstruction& ins);
	int AddLoad(const NativeCodeInstruction& ins);
};


void NativeCodeExpressions::KillReg(int reg)
{
	int i = 0;
	while (i < mExps.Size())
	{
		if (mExps[i].mReg == reg)
			mExps.Remove(i);
		else if (mExps[i].mIns)
		{
			if (reg == CPU_REG_Y && mExps[i].mIns->RequiresYReg())
				mExps.Remove(i);
			else if (reg == CPU_REG_X && mExps[i].mIns->RequiresXReg())
				mExps.Remove(i);
			else if (mExps[i].mIns->ReferencesZeroPage(reg))
				mExps.Remove(i);
			else
				i++;
		}
		else
			i++;
	}
}

void NativeCodeExpressions::KillYReg(void)
{
	int i = 0;
	while (i < mExps.Size())
	{
		if (mExps[i].mIns && mExps[i].mIns->RequiresYReg())
			mExps.Remove(i);
		else
			i++;
	}
}

void NativeCodeExpressions::KillAddr(const NativeCodeInstruction& ins)
{
	int i = 0;
	while (i < mExps.Size())
	{
		if (mExps[i].mIns && mExps[i].mIns->MayBeChangedOnAddress(ins))
			mExps.Remove(i);
		else
			i++;
	}
}

int NativeCodeExpressions::AddLoad(const NativeCodeInstruction& ins)
{
	int	i = 0;
	while (i < mExps.Size() && !(mExps[i].mType == ASMIT_LDA && mExps[i].mIns->SameAddress(ins))
		i++;
	if (i < mExps.Size())
		return mExps[i].mIndex;
	else
	{
		NativeCodeExpressions	e(ASMIT_LDA, &ins);
		mExps.Push(e);
		return e.mIndex;
	}
}

bool NativeCodeBasicBlock::CommonSubExpressionElimination(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		NativeCodeExpressions	exps;

		int	aexp = -1, xexp = -1, yexp = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);



			switch (ins.mType)
			{
			case ASMIT_LDA:
				aexp = exps.AddLoad(ins);
				break;
			case ASMIT_LDX:
				aexp = exps.AddLoad(ins);
				break;
			case ASMIT_LDY:
				aexp = exps.AddLoad(ins);
				break;
			}
		}

		if (mTrueJump && mTrueJump->CommonSubExpressionElimination())
			changed = true;
		if (mFalseJump && mFalseJump->CommonSubExpressionElimination())
			changed = true;
	}

	return changed;
}

#endif

bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock* nblock, const NativeCodeBasicBlock* fblock) const
{
	if (mExitRequiredRegs[CPU_REG_X])
		return false;

	if (mTrueJump && mTrueJump != nblock && mTrueJump != fblock && mTrueJump->mEntryRequiredRegs[addr])
		return false;
	if (mFalseJump && mFalseJump != nblock && mFalseJump != fblock && mFalseJump->mEntryRequiredRegs[addr])
		return false;

	int i = mIns.Size();
	while (i > 0)
	{
		i--;

		if (mIns[i].ChangesXReg())
			return false;

		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return true;
		
		if (mIns[i].ReferencesZeroPage(addr) || mIns[i].RequiresXReg())
			return false;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->CanChangeTailZPStoreToX(addr, this);
	else
		return false;
}

void NativeCodeBasicBlock::ChangeTailZPStoreToX(int addr)
{
	mExitRequiredRegs += CPU_REG_X;

	int i = mIns.Size();
	while (i > 0)
	{
		i--;

		mIns[i].mLive |= LIVE_CPU_REG_X;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			mIns[i].mType = ASMIT_TAX;
			mIns[i].mMode = ASMIM_IMPLIED;
			return;
		}
	}

	if (mEntryBlocks.Size() == 1)
	{
		mEntryRequiredRegs += CPU_REG_X;
		mEntryBlocks[0]->ChangeTailZPStoreToX(addr);
		return;
	}

	assert(false);
}

bool NativeCodeBasicBlock::CanChangeTailZPStoreToY(int addr, const NativeCodeBasicBlock* nblock, const NativeCodeBasicBlock* fblock) const
{
	if (mExitRequiredRegs[CPU_REG_Y])
		return false;

	if (mTrueJump && mTrueJump != nblock && mTrueJump != fblock && mTrueJump->mEntryRequiredRegs[addr])
		return false;
	if (mFalseJump && mFalseJump != nblock && mFalseJump != fblock && mFalseJump->mEntryRequiredRegs[addr])
		return false;

	int i = mIns.Size();
	while (i > 0)
	{
		i--;

		if (mIns[i].ChangesYReg())
			return false;

		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return true;

		if (mIns[i].ReferencesZeroPage(addr) || mIns[i].RequiresYReg())
			return false;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->CanChangeTailZPStoreToY(addr, this);
	else
		return false;
}

void NativeCodeBasicBlock::ChangeTailZPStoreToY(int addr)
{
	mExitRequiredRegs += CPU_REG_Y;

	int i = mIns.Size();
	while (i > 0)
	{
		i--;

		mIns[i].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			mIns[i].mType = ASMIT_TAY;
			mIns[i].mMode = ASMIM_IMPLIED;
			return;
		}
	}

	if (mEntryBlocks.Size() == 1)
	{
		mEntryBlocks[0]->ChangeTailZPStoreToY(addr);
		return;
	}

	assert(false);
}

bool NativeCodeBasicBlock::IsExitYRegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_LDY))
		{
			if (addr == mIns[i].mAddress)
			{
				block = this;
				index = i;
				return true;
			}
			return false;
		}
		else if (mIns[i].ChangesYReg())
			return false;
		else if (mIns[i].ChangesZeroPage(addr))
			return false;

		i--;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->IsExitYRegZP(addr, index, block);

	return false;
}

bool NativeCodeBasicBlock::IsExitXRegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_LDX))
		{
			if (addr == mIns[i].mAddress)
			{
				block = this;
				index = i;
				return true;
			}
			return false;
		}
		else if (mIns[i].ChangesXReg())
			return false;
		else if (mIns[i].ChangesZeroPage(addr))
			return false;

		i--;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->IsExitXRegZP(addr, index, block);

	return false;
}

bool NativeCodeBasicBlock::IsARegZP(int at, int addr, int& index, NativeCodeBasicBlock*& block)
{
	int i = at - 1;
	while (i >= 0)
	{
		if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA))
		{
			if (addr == mIns[i].mAddress)
			{
				block = this;
				index = i;
				return true;
			}
			return false;
		}
		else if (mIns[i].ChangesAccu())
			return false;
		else if (mIns[i].ChangesZeroPage(addr))
			return false;

		i--;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->IsExitARegZP(addr, index, block);

	return false;
}

bool NativeCodeBasicBlock::IsExitARegZP(int addr, int& index, NativeCodeBasicBlock*& block)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA))
		{
			if (addr == mIns[i].mAddress)
			{
				block = this;
				index = i;
				return true;
			}
			return false;
		}
		else if (mIns[i].ChangesAccu())
			return false;
		else if (mIns[i].ChangesZeroPage(addr))
			return false;

		i--;
	}

	if (mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->IsExitARegZP(addr, index, block);

	return false;
}

void NativeCodeBasicBlock::MarkLiveBlockChain(int index, NativeCodeBasicBlock* block, uint32 live, uint32 reg)
{
	mExitRequiredRegs += reg;
	if (this == block)
	{
		for (int i = index; i < mIns.Size(); i++)
			mIns[i].mLive |= live;
	}
	else
	{
		for (int i = 0; i < mIns.Size(); i++)
			mIns[i].mLive |= live;
		mEntryRequiredRegs += reg;
		mEntryBlocks[0]->MarkLiveBlockChain(index, block, live, reg);
	}
}

bool NativeCodeBasicBlock::CanJoinEntryLoadStoreZP(int saddr, int daddr)
{
	mChecked = true;

	// Avoid moving code into loops
	if (mLoopHead && (mTrueJump == this || mFalseJump == this))
		return false;

	if (mFalseJump && mExitRequiredRegs[daddr])
		return false;

	int at = mIns.Size() - 1;
	while (at >= 0)
	{
		NativeCodeInstruction	& ins = mIns[at];
		if (ins.ReferencesZeroPage(daddr))
			return false;
		if (ins.ChangesZeroPage(saddr))
		{
			if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY)
				return true;
			else
				return false;
		}
		at--;
	}

	if (!mLoopHead && mEntryBlocks.Size() > 0 && daddr >= BC_REG_FPARAMS && daddr < BC_REG_FPARAMS_END)
	{
		for (int i = 0; i < mEntryBlocks.Size(); i++)
		{
			if (!mEntryBlocks[i]->CanJoinEntryLoadStoreZP(saddr, daddr))
				return false;
		}

		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::DoJoinEntryLoadStoreZP(int saddr, int daddr)
{
	if (!mChecked)
		return true;
	mChecked = false;

	int at = mIns.Size() - 1;
	while (at >= 0)
	{
		NativeCodeInstruction& ins = mIns[at];
		if (ins.ChangesZeroPage(saddr))
		{
			if (ins.mType == ASMIT_STA)
			{
				ins.mLive |= LIVE_CPU_REG_A;
				mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STA, ASMIM_ZERO_PAGE, daddr));
				mExitRequiredRegs += daddr;
				return true;
			}
			else if (ins.mType == ASMIT_STX)
			{
				ins.mLive |= LIVE_CPU_REG_X;
				mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STX, ASMIM_ZERO_PAGE, daddr));
				mExitRequiredRegs += daddr;
				return true;
			}
			else if (ins.mType == ASMIT_STY)
			{
				ins.mLive |= LIVE_CPU_REG_Y;
				mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_STY, ASMIM_ZERO_PAGE, daddr));
				mExitRequiredRegs += daddr;
				return true;
			}
		}
		at--;
	}

	if (!mLoopHead)
	{
		for (int i = 0; i < mEntryBlocks.Size(); i++)
		{
			if (!mEntryBlocks[i]->DoJoinEntryLoadStoreZP(saddr, daddr))
				return false;
		}

		mEntryRequiredRegs += daddr;
		mExitRequiredRegs += daddr;
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::JoinEntryLoadStoreZP(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		if (!mLoopHead && mEntryBlocks.Size() > 0 && mEntryBlocks.Size() < 64 && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
		{
			for (int i = 0; i + 1 < mIns.Size(); i++)
			{
				if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) ||
					mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
				{
					int saddr = mIns[i].mAddress, daddr = mIns[i + 1].mAddress;
					if (!ReferencesZeroPage(saddr, 0, i) && !ReferencesZeroPage(daddr, 0, i))
					{
						int n = 0;
						uint64	mask = 0;
						for (int j = 0; j < mEntryBlocks.Size(); j++)
						{
							if (mEntryBlocks[j]->CanJoinEntryLoadStoreZP(saddr, daddr))
							{
								mask |= 1ull << j;
								n++;
							}
						}

						if (n == mEntryBlocks.Size())
						{
							for (int j = 0; j < mEntryBlocks.Size(); j++)
							{
								mEntryBlocks[j]->DoJoinEntryLoadStoreZP(saddr, daddr);
								mEntryBlocks[j]->mExitRequiredRegs += daddr;
							}
							mEntryRequiredRegs += daddr;
							changed = true;
							mIns.Remove(i, 2);
							i--;
						}
						else if (n >= 2)
						{
							NativeCodeBasicBlock* xblock = mProc->AllocateBlock();

							int j = mEntryBlocks.Size();
							while (j > 0)
							{
								j--;
								NativeCodeBasicBlock* eb = mEntryBlocks[j];

								if (mask & (1ull << j))
								{
									eb->DoJoinEntryLoadStoreZP(saddr, daddr);
									eb->mExitRequiredRegs += daddr;
								}
								else
								{
									if (eb->mTrueJump == this)
										eb->mTrueJump = xblock;
									if (eb->mFalseJump == this)
										eb->mFalseJump = xblock;
									mEntryBlocks.Remove(j);
									xblock->mEntryBlocks.Push(eb);
									xblock->mNumEntries++;
								}
							}

							xblock->mEntryRequiredRegs = mEntryRequiredRegs;
							xblock->mExitRequiredRegs = mEntryRequiredRegs;
							xblock->mExitRequiredRegs += daddr;

							if (!mEntryRequiredRegs[CPU_REG_A])
							{
								xblock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
								xblock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
							}
							else
							{
								xblock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
								xblock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
							}

							xblock->Close(mIns[i].mIns, this, nullptr, ASMIT_JMP);
							mEntryBlocks.Push(xblock);
							mNumEntries++;

							mEntryRequiredRegs += daddr;
							changed = true;
							mIns.Remove(i, 2);
							i--;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->JoinEntryLoadStoreZP())
			changed = true;
		if (mFalseJump && mFalseJump->JoinEntryLoadStoreZP())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::JoinTailCodeSequences(bool loops)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();
		if (mTrueJump) mTrueJump->CheckLive();
		if (mFalseJump) mFalseJump->CheckLive();

#if 1
		if (mEntryBlocks.Size() > 1)
		{
			int i = 0;
			while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mBranch == ASMIT_JMP)
				i++;
			if (i == mEntryBlocks.Size())
			{
				NativeCodeBasicBlock* eb = mEntryBlocks[0];

				if (mEntryRequiredRegs.Size() && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && !mEntryRequiredRegs[CPU_REG_C])
				{
					for (int i = eb->mIns.Size() - 7; i >= 0; i--)
					{
						int	sreg, dreg, offset;
						if (eb->Is16BitAddSubImmediate(i, sreg, dreg, offset))
						{
							int	j = 0;
							while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForward16BitAddSubImmediate(sreg, dreg, offset, mEntryBlocks[j]->mTemp))
								j++;

							if (j == mEntryBlocks.Size())
							{
								for (int k = 0; k < 7; k++)
									mIns.Insert(k, eb->mIns[i + k]);

								for (int j = 0; j < mEntryBlocks.Size(); j++)
									mEntryBlocks[j]->mIns.Remove(mEntryBlocks[j]->mTemp, 7);

								if (mEntryRequiredRegs[CPU_REG_A])
								{
									mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_TAX));
									for (int i = 1; i < 8; i++)
										mIns[i].mLive |= LIVE_CPU_REG_X;
									mIns.Insert(8, NativeCodeInstruction(mIns[0].mIns, ASMIT_TXA));
								}

								changed = true;
							}
						}
					}
				}

				if (changed)
					CheckLive();

				while (eb->mIns.Size() > 0)
				{
					int	addr, index, taddr, tindex;
					if (!mEntryRequiredRegs[CPU_REG_X] && eb->HasTailSTAX16(addr, index))
					{
						i = 1;
						while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTAX16(taddr, tindex) && taddr == addr)
							i++;
						if (i == mEntryBlocks.Size())
						{
							mEntryRequiredRegs += CPU_REG_A;
							mEntryRequiredRegs += CPU_REG_X;

							mIns.Insert(0, eb->mIns[index + 3]);
							mIns.Insert(0, eb->mIns[index + 1]);

							mIns[0].mType = ASMIT_STX;
							mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
							mIns[1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
							if (mEntryRequiredRegs[CPU_REG_C])
							{
								mIns[0].mLive |= LIVE_CPU_REG_C;
								mIns[1].mLive |= LIVE_CPU_REG_C;
							}
							if (mEntryRequiredRegs[CPU_REG_Z])
							{
								mIns[0].mLive |= LIVE_CPU_REG_Z;
								mIns[1].mLive |= LIVE_CPU_REG_Z;
							}
							for (int i = 0; i < mEntryBlocks.Size(); i++)
							{
								NativeCodeBasicBlock* b = mEntryBlocks[i];
								b->HasTailSTAX16(taddr, tindex);

								b->mExitRequiredRegs += CPU_REG_A;
								b->mExitRequiredRegs += CPU_REG_X;

								assert(b->mIns[tindex].mMode != ASMIM_ABSOLUTE_X);
								b->mIns[tindex + 0].mType = ASMIT_LDX;
								for (int j = tindex; j < b->mIns.Size(); j++)
									b->mIns[j].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;

								b->mIns.Remove(tindex + 3);
								b->mIns.Remove(tindex + 1);
							}
							changed = true;
						}
					}

					NativeCodeInstruction& ins(eb->mIns[eb->mIns.Size() - 1]);
					i = 1;
					while (i < mEntryBlocks.Size() && mEntryBlocks[i]->SameTail(ins))
						i++;
					if (i == mEntryBlocks.Size())
					{
						if (ins.RequiresAccu())
							mEntryRequiredRegs += CPU_REG_A;
						if (ins.RequiresYReg())
							mEntryRequiredRegs += CPU_REG_Y;
						if (ins.RequiresXReg())
							mEntryRequiredRegs += CPU_REG_X;
						if (ins.ChangesZFlag())
							mEntryRequiredRegs -= CPU_REG_Z;
						if (ins.ChangesCarry())
							mEntryRequiredRegs -= CPU_REG_C;
						if (ins.RequiresCarry())
							mEntryRequiredRegs += CPU_REG_C;

						mIns.Insert(0, ins);

						for (int i = 0; i < mEntryBlocks.Size(); i++)
						{
							NativeCodeBasicBlock* b = mEntryBlocks[i];

							if (ins.RequiresAccu())
								b->mExitRequiredRegs += CPU_REG_A;
							if (ins.RequiresYReg())
								b->mExitRequiredRegs += CPU_REG_Y;
							if (ins.RequiresXReg())
								b->mExitRequiredRegs += CPU_REG_X;
							if (ins.ChangesZFlag())
								b->mExitRequiredRegs -= CPU_REG_Z;
							if (ins.ChangesCarry())
								b->mExitRequiredRegs -= CPU_REG_C;
							if (ins.RequiresCarry())
								b->mExitRequiredRegs += CPU_REG_C;

							b->mIns.SetSize(b->mIns.Size() - 1);
						}
						changed = true;
					}
					else
					{
						if (eb->HasTailSTA(addr, index))
						{
							i = 1;
							while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTA(taddr, tindex) && taddr == addr)
								i++;
							if (i == mEntryBlocks.Size())
							{
								mEntryRequiredRegs += CPU_REG_A;

								mIns.Insert(0, eb->mIns[index]);
								mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
								for (int i = 0; i < mEntryBlocks.Size(); i++)
								{
									NativeCodeBasicBlock* b = mEntryBlocks[i];
									b->HasTailSTA(taddr, tindex);
									b->mExitRequiredRegs += CPU_REG_A;

									for (int j = tindex + 1; j < b->mIns.Size(); j++)
										b->mIns[j].mLive |= LIVE_CPU_REG_A;
									b->mIns.Remove(tindex);
								}
								changed = true;
							}
						}

						if (eb->HasTailSTX(addr, index))
						{
							i = 1;
							while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTX(taddr, tindex) && taddr == addr)
								i++;
							if (i == mEntryBlocks.Size())
							{
								mEntryRequiredRegs += CPU_REG_X;

								mIns.Insert(0, eb->mIns[index]);
								mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
								for (int i = 0; i < mEntryBlocks.Size(); i++)
								{
									NativeCodeBasicBlock* b = mEntryBlocks[i];
									b->HasTailSTX(taddr, tindex);
									b->mExitRequiredRegs += CPU_REG_X;
									for (int j = tindex + 1; j < b->mIns.Size(); j++)
										b->mIns[j].mLive |= LIVE_CPU_REG_X;
									b->mIns.Remove(tindex);
								}
								changed = true;
							}
						}

						if (eb->HasTailSTY(addr, index))
						{
							i = 1;
							while (i < mEntryBlocks.Size() && mEntryBlocks[i]->HasTailSTY(taddr, tindex) && taddr == addr)
								i++;
							if (i == mEntryBlocks.Size())
							{
								mEntryRequiredRegs += CPU_REG_Y;

								mIns.Insert(0, eb->mIns[index]);
								mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
								for (int i = 0; i < mEntryBlocks.Size(); i++)
								{
									NativeCodeBasicBlock* b = mEntryBlocks[i];
									b->HasTailSTY(taddr, tindex);
									b->mExitRequiredRegs += CPU_REG_Y;
									for (int j = tindex + 1; j < b->mIns.Size(); j++)
										b->mIns[j].mLive |= LIVE_CPU_REG_Y;
									b->mIns.Remove(tindex);
								}
								changed = true;
							}
						}

						break;
					}
				}

				if (changed)
					CheckLive();

				if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
				{
					for (int i = eb->mIns.Size() - 1; i > 0; i--)
					{
						if (eb->mIns[i - 1].mType == ASMIT_LDA && eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && eb->mIns[i - 0].mType == ASMIT_STA && eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE ||
							eb->mIns[i - 1].mType == ASMIT_LDX && eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && eb->mIns[i - 0].mType == ASMIT_STX && eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE)
						{
							int	saddr = eb->mIns[i - 1].mAddress, daddr = eb->mIns[i - 0].mAddress;
							int	j = 0;
							while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForwardZPMove(saddr, daddr, mEntryBlocks[j]->mTemp))
								j++;

							if (j == mEntryBlocks.Size())
							{
								const InterInstruction* iins(eb->mIns[i].mIns);

								if (!mEntryRequiredRegs[CPU_REG_A])
								{
									for (int j = 0; j < mEntryBlocks.Size(); j++)
										mEntryBlocks[j]->mIns[mEntryBlocks[j]->mTemp].mLive |= LIVE_MEM;

									mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDA, ASMIM_ZERO_PAGE, saddr));
									mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, daddr));
									changed = true;
								}
								else if (!mEntryRequiredRegs[CPU_REG_X])
								{
									for (int j = 0; j < mEntryBlocks.Size(); j++)
										mEntryBlocks[j]->mIns[mEntryBlocks[j]->mTemp].mLive |= LIVE_MEM;

									mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, saddr));
									mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, daddr));
									changed = true;
								}
							}
						}
					}
					if (changed)
						CheckLive();
				}
#if 1
				if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X] || !mEntryRequiredRegs[CPU_REG_Y]))
				{
					for (int i = eb->mIns.Size() - 1; i > 0; i--)
					{
						if ((eb->mIns[i - 1].mType == ASMIT_LDA && eb->mIns[i - 0].mType == ASMIT_STA ||
							 eb->mIns[i - 1].mType == ASMIT_LDX && eb->mIns[i - 0].mType == ASMIT_STX ||
							 eb->mIns[i - 1].mType == ASMIT_LDY && eb->mIns[i - 0].mType == ASMIT_STY) &&
							(eb->mIns[i - 1].mMode == ASMIM_ZERO_PAGE || eb->mIns[i - 1].mMode == ASMIM_ABSOLUTE) &&
							(eb->mIns[i - 0].mMode == ASMIM_ZERO_PAGE || eb->mIns[i - 0].mMode == ASMIM_ABSOLUTE))
						{
							int	j = 0;
							while (j < mEntryBlocks.Size() && mEntryBlocks[j]->CanForwardLoadStore(eb->mIns[i - 1], eb->mIns[i - 0], mEntryBlocks[j]->mTemp))
								j++;

							if (j == mEntryBlocks.Size())
							{
								const InterInstruction* iins(eb->mIns[i].mIns);

								if (!mEntryRequiredRegs[CPU_REG_A])
								{
									mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDA, eb->mIns[i - 1]));
									mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STA, eb->mIns[i]));
									changed = true;
								}
								else if (!mEntryRequiredRegs[CPU_REG_X])
								{
									mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDX, eb->mIns[i - 1]));
									mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STX, eb->mIns[i]));
									changed = true;
								}
								else if (!mEntryRequiredRegs[CPU_REG_Y])
								{
									mIns.Insert(0, NativeCodeInstruction(iins, ASMIT_LDY, eb->mIns[i - 1]));
									mIns.Insert(1, NativeCodeInstruction(iins, ASMIT_STY, eb->mIns[i]));
									changed = true;
								}

								for (int j = 0; j < mEntryBlocks.Size(); j++)
									mEntryBlocks[j]->mIns.Remove(mEntryBlocks[j]->mTemp, 2);
							}
						}
					}
					if (changed)
						CheckLive();
				}
#endif
			}

			if (mEntryBlocks.Size() >= 1)
			{
				NativeCodeBasicBlock* eb = mEntryBlocks[0];

				if (eb->mIns.Size())
				{
					NativeCodeInstruction& ins(eb->mIns[eb->mIns.Size() - 1]);
					if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE &&
						(eb->mBranch == ASMIT_JMP ||
							eb->mTrueJump == this && eb->mFalseJump && !eb->mFalseJump->mEntryRequiredRegs[ins.mAddress] ||
							eb->mFalseJump == this && eb->mTrueJump && !eb->mTrueJump->mEntryRequiredRegs[ins.mAddress]))
					{
						int i = 1;
						while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().IsSame(ins) &&
							(mEntryBlocks[i]->mBranch == ASMIT_JMP ||
								mEntryBlocks[i]->mTrueJump == this && mEntryBlocks[i]->mFalseJump && !mEntryBlocks[i]->mFalseJump->mEntryRequiredRegs[ins.mAddress] ||
								mEntryBlocks[i]->mFalseJump == this && mEntryBlocks[i]->mTrueJump && !mEntryBlocks[i]->mTrueJump->mEntryRequiredRegs[ins.mAddress]))
							i++;
						if (i == mEntryBlocks.Size())
						{
							mEntryRequiredRegs += CPU_REG_A;
							mEntryRequiredRegs -= ins.mAddress;

							mIns.Insert(0, ins);
							for (int i = 0; i < mEntryBlocks.Size(); i++)
							{
								NativeCodeBasicBlock* meb = mEntryBlocks[i];
								meb->mExitRequiredRegs += CPU_REG_A;
								meb->mIns.SetSize(meb->mIns.Size() - 1);								
							}

							changed = true;
						}
					}
				}
			}

			CheckLive();

			if (mEntryBlocks.Size() > 2)
			{
				NativeCodeBasicBlock* nblock = SplitMatchingTails(mProc);
				if (nblock)
				{
					if (nblock->JoinTailCodeSequences(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())
					{
						while (sz > 0)
						{
							sz--;
							eblock->mIns[sz].mLive |= LIVE_CPU_REG_Z;
							if (eblock->mIns[sz].ChangesZFlag())
								break;
						}
						eblock->mExitRequiredRegs += CPU_REG_Z;
						mEntryRequiredRegs += CPU_REG_Z;
						mIns.Remove(0);
						changed = true;
					}
				}
			}
		}
#endif

#if 1
		if (mTrueJump && mFalseJump && mTrueJump->mTrueJump && !mTrueJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump &&
			mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)

		{
			// TAX, SHL -> .... LDX --> TXA
			//          \------------->
			//
			int	nins = mIns.Size(), tins = mTrueJump->mIns.Size(), fins = mFalseJump->mIns.Size();
			if (nins > 1 && tins > 0 && fins > 0 && mFalseJump->mIns[0].mType == ASMIT_TXA &&
				mIns[nins - 2].mType == ASMIT_TAX && !mIns[nins - 1].ChangesAccu() && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
			{
				mTrueJump->mIns.Push(NativeCodeInstruction(mFalseJump->mIns[0].mIns, ASMIT_TXA));
				mFalseJump->mIns[0].mType = ASMIT_NOP; mFalseJump->mIns[0].mMode = ASMIM_IMPLIED;
				mIns[nins - 1].mLive |= LIVE_CPU_REG_A;
				mIns[nins - 2].mLive |= LIVE_CPU_REG_A;
				mFalseJump->mEntryRequiredRegs += CPU_REG_A;
				mTrueJump->mExitRequiredRegs += CPU_REG_A;
				changed = true;
			}
		}

#endif

		CheckLive();

		if (mTrueJump && mFalseJump)
		{
			int	addr, index;
			if (HasTailSTX(addr, index))
			{
				if (mTrueJump->mEntryRequiredRegs[addr] && !mFalseJump->mEntryRequiredRegs[addr] && mTrueJump->mNumEntries == 1)
				{
					mTrueJump->mEntryProvidedRegs += CPU_REG_X;
					for (int i = index; i < mIns.Size(); i++)
						mIns[i].mLive |= LIVE_CPU_REG_X;
					mIns[index].mLive |= mIns[mIns.Size() - 1].mLive;

					mExitRequiredRegs += CPU_REG_X;
					mTrueJump->mEntryRequiredRegs += CPU_REG_X;

					mTrueJump->mIns.Insert(0, mIns[index]);
					mIns.Remove(index);
					changed = true;

					mTrueJump->CheckLive();
					mFalseJump->CheckLive();

				}
				else if (mFalseJump->mEntryRequiredRegs[addr] && !mTrueJump->mEntryRequiredRegs[addr] && mFalseJump->mNumEntries == 1)
				{
					mFalseJump->mEntryProvidedRegs += CPU_REG_X;
					for (int i = index; i < mIns.Size(); i++)
						mIns[i].mLive |= LIVE_CPU_REG_X;
					mIns[index].mLive |= mIns[mIns.Size() - 1].mLive;

					mExitRequiredRegs += CPU_REG_X;
					mFalseJump->mEntryRequiredRegs += CPU_REG_X;

					mFalseJump->mIns.Insert(0, mIns[index]);
					mIns.Remove(index);
					changed = true;

					mTrueJump->CheckLive();
					mFalseJump->CheckLive();

				}
			}
		}

#if 1
		if (mTrueJump && mFalseJump && mIns.Size() >= 2)
		{
			int	nins = mIns.Size();
			if (mIns[nins - 2].mType == ASMIT_LDA && mIns[nins - 2].mMode == ASMIM_IMMEDIATE &&
				mIns[nins - 1].mType == ASMIT_CMP && mIns[nins - 1].mMode == ASMIM_ZERO_PAGE && (mIns[nins - 1].mLive & LIVE_MEM) && !(mIns[nins - 1].mLive & LIVE_CPU_REG_A) &&
				!mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
			{
				int im = mIns[nins - 2].mAddress;

				mIns[nins - 2].CopyMode(mIns[nins - 1]);
				mIns[nins - 2].mLive |= LIVE_MEM;
				mIns[nins - 1].mMode = ASMIM_IMMEDIATE;
				mIns[nins - 1].mFlags = NCIF_LOWER | NCIF_UPPER;

				if (mBranch == ASMIT_BCC)
				{
					if (im == 255)
					{
						mIns[nins - 1].mType = ASMIT_SEC;
						mIns[nins - 1].mMode = ASMIM_IMPLIED;
					}
					else
					{
						mIns[nins - 1].mAddress = im + 1;
						mBranch = ASMIT_BCS;
					}
				}
				else if (mBranch == ASMIT_BCS)
				{
					if (im == 255)
					{
						mIns[nins - 1].mType = ASMIT_SEC;
						mIns[nins - 1].mMode = ASMIM_IMPLIED;
					}
					else
					{
						mIns[nins - 1].mAddress = im + 1;
						mBranch = ASMIT_BCC;
					}
				}
				else
					mIns[nins - 1].mAddress = im;

				
				changed = true;
			}
		}
#endif
		CheckLive();

		if (mTrueJump && mFalseJump)
		{
			if (mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 && !mExitRequiredRegs[CPU_REG_Z] && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
				mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
			{
				if (!mTrueJump->mIns[0].ChangesCarry() && mTrueJump->mIns[0].IsSame(mFalseJump->mIns[0]))
				{
					int live = mTrueJump->mIns[0].mLive | mFalseJump->mIns[0].mLive;
					mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C | live;
					mIns.Push(mTrueJump->mIns[0]);
					mTrueJump->mIns.Remove(0);
					mFalseJump->mIns.Remove(0);
					if (live & LIVE_CPU_REG_A)
					{
						mExitRequiredRegs += CPU_REG_A;
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
					}
					if (live & LIVE_CPU_REG_X)
					{
						mExitRequiredRegs += CPU_REG_X;
						mTrueJump->mEntryRequiredRegs += CPU_REG_X;
						mFalseJump->mEntryRequiredRegs += CPU_REG_X;
					}
					if (live & LIVE_CPU_REG_Y)
					{
						mExitRequiredRegs += CPU_REG_Y;
						mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
						mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
					}
					if (live & LIVE_CPU_REG_Z)
					{
						mExitRequiredRegs += CPU_REG_Z;
						mTrueJump->mEntryRequiredRegs += CPU_REG_Z;
						mFalseJump->mEntryRequiredRegs += CPU_REG_Z;
					}

					changed = true;

					CheckLive();
				}
			}
		}
#if 1
		if (mTrueJump && mFalseJump && mIns.Size() >= 2 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			int nins = mIns.Size();
			if (mIns[nins - 2].mType == ASMIT_LDA && mIns[nins - 1].mType == ASMIT_CMP && !(mIns[nins - 1].mLive & LIVE_CPU_REG_A) && !mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C])
			{
				if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mNumEntries == 1 && mTrueJump->mIns[0].SameEffectiveAddress(mIns[nins - 1]))
				{
					mIns[nins - 1].CopyMode(mIns[nins - 2]); 
					mIns[nins - 2].CopyMode(mTrueJump->mIns[0]); mIns[nins - 2].mLive |= mIns[nins - 1].NeedsLive();
					mIns[nins - 1].mLive |= LIVE_CPU_REG_A;
					mExitRequiredRegs += CPU_REG_A;
					mTrueJump->mEntryRequiredRegs += CPU_REG_A;
					if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z)
					{
						mTrueJump->mIns[0].mType = ASMIT_ORA;
						mTrueJump->mIns[0].mMode = ASMIM_IMMEDIATE;
						mTrueJump->mIns[0].mAddress = 0;
					}
					else
						mTrueJump->mIns.Remove(0);
					changed = true;

					CheckLive();
				}
				else if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mNumEntries == 1 && mFalseJump->mIns[0].SameEffectiveAddress(mIns[nins - 1]))
				{
					mIns[nins - 1].CopyMode(mIns[nins - 2]);
					mIns[nins - 2].CopyMode(mFalseJump->mIns[0]); mIns[nins - 2].mLive |= mIns[nins - 1].NeedsLive();
					mIns[nins - 1].mLive |= LIVE_CPU_REG_A;
					mExitRequiredRegs += CPU_REG_A;
					mFalseJump->mEntryRequiredRegs += CPU_REG_A;
					if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_Z)
					{
						mFalseJump->mIns[0].mType = ASMIT_ORA;
						mFalseJump->mIns[0].mMode = ASMIM_IMMEDIATE;
						mFalseJump->mIns[0].mAddress = 0;
					}
					else
						mFalseJump->mIns.Remove(0);
					changed = true;

					CheckLive();
				}
			}
		}
#endif

		if (mTrueJump) mTrueJump->CheckLive();
		if (mFalseJump) mFalseJump->CheckLive();
#if 1
		if (loops && mIns.Size() >= 1 && mEntryBlocks.Size() == 2)
		{
			NativeCodeBasicBlock* pblock = mEntryBlocks[0], * lblock = mEntryBlocks[1];
			int	ps = pblock->mIns.Size(), ls = lblock->mIns.Size();

			if (ls >= 2)
			{
				if (mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
						lblock->mIns[ls - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, lblock->mIns[ls - 1].mMode) && !(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(mProc, pblock);

						pblock->mIns.Push(mIns[0]);
						mIns.Remove(0);

						lblock->mExitRequiredRegs += CPU_REG_Y;
						pblock->mExitRequiredRegs += CPU_REG_Y;
						mEntryRequiredRegs += CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;

						changed = true;
					}
					else if (lblock->mIns[ls - 1].mType == ASMIT_LDA && lblock->mIns[ls - 1].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 1].mAddress == mIns[0].mAddress &&
						!(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A))
					{
						lblock->mIns[ls - 1].mType = ASMIT_LDY; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_Y;

						pblock = AddDominatorBlock(mProc, pblock);

						pblock->mIns.Push(mIns[0]);
						mIns.Remove(0);

						lblock->mExitRequiredRegs += CPU_REG_Y;
						pblock->mExitRequiredRegs += CPU_REG_Y;
						mEntryRequiredRegs += CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;

						changed = true;
					}
				}
				else if (mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
						lblock->mIns[ls - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, lblock->mIns[ls - 1].mMode) && !(lblock->mIns[ls - 1].mLive & LIVE_CPU_REG_A))
					{
						lblock->mIns[ls - 2].mType = ASMIT_LDX; lblock->mIns[ls - 2].mLive |= LIVE_CPU_REG_X;
						lblock->mIns[ls - 1].mType = ASMIT_CPX; lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_X;

						pblock = AddDominatorBlock(mProc, pblock);

						pblock->mIns.Push(mIns[0]);
						mIns.Remove(0);

						lblock->mExitRequiredRegs += CPU_REG_X;
						pblock->mExitRequiredRegs += CPU_REG_X;
						mEntryRequiredRegs += CPU_REG_X;
						mExitRequiredRegs += CPU_REG_X;

						changed = true;
					}
				}
				else if (mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_Z))
				{
					if (lblock->mIns[ls - 2].mType == ASMIT_LDA && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress &&
						lblock->mIns[ls - 1].mType == ASMIT_CMP)
					{
						pblock = AddDominatorBlock(mProc, pblock);

						pblock->mIns.Push(mIns[0]);
						mIns.Remove(0);

						lblock->mExitRequiredRegs += CPU_REG_A;
						pblock->mExitRequiredRegs += CPU_REG_A;
						mEntryRequiredRegs += CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;

						lblock->mIns[ls - 1].mLive |= LIVE_CPU_REG_A;

						changed = true;
					}
				}
				
				if (!changed && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
				{
					if (lblock->mIns[ls - 2].mType == ASMIT_STY && lblock->mIns[ls - 2].mMode == ASMIM_ZERO_PAGE && lblock->mIns[ls - 2].mAddress == mIns[0].mAddress && lblock->mIns[ls - 1].mType == ASMIT_CPY)
					{
						pblock = AddDominatorBlock(mProc, pblock);

						pblock->mIns.Push(mIns[0]);
						mIns.Remove(0);

						pblock->mExitRequiredRegs += CPU_REG_Y;
						lblock->mExitRequiredRegs += CPU_REG_Y;
						mEntryRequiredRegs += CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;
					}
				}
			}
		}
#endif
#if 1
		if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mEntryBlocks.Size() > 1 && !(mIns[0].mLive & LIVE_MEM))
		{
			if (mEntryRequiredRegs.Size() > 0 && !mEntryRequiredRegs[CPU_REG_X])
			{
				int i = 0;
				while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanChangeTailZPStoreToX(mIns[0].mAddress, this))
					i++;
				if (i == mEntryBlocks.Size())
				{
					for (int i = 0; i < mEntryBlocks.Size(); i++)
						mEntryBlocks[i]->ChangeTailZPStoreToX(mIns[0].mAddress);
					mEntryRequiredRegs += CPU_REG_X;
					mIns[0].mType = ASMIT_TXA;
					mIns[0].mMode = ASMIM_IMPLIED;
					changed = true;

					CheckLive();
				}
			}
			if (!changed && mEntryRequiredRegs.Size() > 0 && !mEntryRequiredRegs[CPU_REG_Y])
			{
				int i = 0;
				while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanChangeTailZPStoreToY(mIns[0].mAddress, this))
					i++;
				if (i == mEntryBlocks.Size())
				{
					for (int i = 0; i < mEntryBlocks.Size(); i++)
						mEntryBlocks[i]->ChangeTailZPStoreToY(mIns[0].mAddress);
					mEntryRequiredRegs += CPU_REG_Y;
					mIns[0].mType = ASMIT_TYA;
					mIns[0].mMode = ASMIM_IMPLIED;
					changed = true;

					CheckLive();
				}
			}
		}

		if (mIns.Size() >= 1 && mTrueJump && !mFalseJump && mTrueJump->mIns.Size() > 0)
		{
			int sz = mIns.Size();
			if (mIns[sz - 1].mType == ASMIT_STA && mTrueJump->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mTrueJump->mIns[0]))
			{
				int i = 0;
				while (i < mTrueJump->mEntryBlocks.Size() && !mTrueJump->mEntryBlocks[i]->mFalseJump)
					i++;
				if (i == mTrueJump->mEntryBlocks.Size())
				{
					bool	zlive = mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z;

					for (int j = 0; j < mTrueJump->mEntryBlocks.Size(); j++)
					{
						if (mTrueJump->mEntryBlocks[j] != this)
						{
							mTrueJump->mEntryBlocks[j]->mIns.Push(mTrueJump->mIns[0]);
							mTrueJump->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_A;
						}

						if (zlive)
						{
							mTrueJump->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Z;
							int k = mTrueJump->mEntryBlocks[j]->mIns.Size();
							while (k > 0)
							{
								k--;
								if (mTrueJump->mEntryBlocks[j]->mIns[k].ChangesZFlag())
								{
									if (mTrueJump->mEntryBlocks[j]->mIns[k].ChangesAccuAndFlag())
										mTrueJump->mEntryBlocks[j]->mIns[k].mLive |= LIVE_CPU_REG_Z;
									else
										mTrueJump->mEntryBlocks[j]->mIns.Insert(k + 1, NativeCodeInstruction(mTrueJump->mIns[0].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
									break;
								}
								mTrueJump->mEntryBlocks[j]->mIns[k].mLive |= LIVE_CPU_REG_Z;
							}
						}
					}
					mExitRequiredRegs += CPU_REG_A;

					if (zlive)
						mExitRequiredRegs += CPU_REG_Z;

					mTrueJump->mIns.Remove(0);
					mTrueJump->mEntryRequiredRegs += CPU_REG_A;

					if (zlive)
						mTrueJump->mEntryRequiredRegs += CPU_REG_Z;

					changed = true;

					CheckLive();
				}
			}
		}
#endif

		if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mMode & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && mEntryBlocks.Size() == 2)
		{
			if (!mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump && mEntryBlocks[0]->mIns.Size() > 0 && mEntryBlocks[1]->mIns.Size() > 0)
			{
				if (mEntryBlocks[0]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[0]->mIns.Last().SameEffectiveAddress(mIns[0]))
				{
					mEntryBlocks[1]->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));
					mIns.Remove(0);
					changed = true;
				}
				else if (mEntryBlocks[1]->mIns.Last().mType == ASMIT_LDA && mEntryBlocks[1]->mIns.Last().SameEffectiveAddress(mIns[0]))
				{
					mEntryBlocks[0]->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));
					mIns.Remove(0);
					changed = true;
				}
			}
		}
#if 1
		if (mFalseJump && mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 &&
			mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mTrueJump->mIns[0].mLive & LIVE_MEM) &&
			mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mFalseJump->mIns[0].mLive & LIVE_MEM) &&
			mTrueJump->mIns[0].mAddress == mFalseJump->mIns[0].mAddress)
		{
			if (mExitRequiredRegs.Size() > 0 && !mExitRequiredRegs[CPU_REG_X])
			{
				if (CanChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress, mTrueJump, mFalseJump))
				{
					ChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress);

					mExitRequiredRegs += CPU_REG_X;

					mTrueJump->mEntryProvidedRegs += CPU_REG_X;
					mFalseJump->mEntryProvidedRegs += CPU_REG_X;

					mTrueJump->mEntryRequiredRegs += CPU_REG_X;
					mFalseJump->mEntryRequiredRegs += CPU_REG_X;

					mTrueJump->mIns[0].mType = ASMIT_TXA;
					mTrueJump->mIns[0].mMode = ASMIM_IMPLIED;

					mFalseJump->mIns[0].mType = ASMIT_TXA;
					mFalseJump->mIns[0].mMode = ASMIM_IMPLIED;

					changed = true;

					CheckLive();
				}
			}
		}
#endif
		CheckLive();

		if (mEntryBlocks.Size() == 1 && mIns.Size() >= 1 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_CPU_REG_Z))
		{
			NativeCodeBasicBlock* eb = mEntryBlocks[0];
			int index, addr;
			if (eb->HasTailSTA(addr, index) && addr == mIns[0].mAddress)
			{
				for (int i = index; i < eb->mIns.Size(); i++)
					eb->mIns[i].mLive |= LIVE_CPU_REG_A;
				eb->mExitRequiredRegs += CPU_REG_A;
				mEntryRequiredRegs += CPU_REG_A;
				mIns.Remove(0);
				changed = true;
			}
			else if (eb->HasTailSTY(addr, index) && addr == mIns[0].mAddress)
			{
				for (int i = index; i < eb->mIns.Size(); i++)
					eb->mIns[i].mLive |= LIVE_CPU_REG_Y;
				eb->mExitRequiredRegs += CPU_REG_Y;
				mEntryRequiredRegs += CPU_REG_Y;
				mIns[0].mType = ASMIT_TYA;
				mIns[0].mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (eb->HasTailSTX(addr, index) && addr == mIns[0].mAddress)
			{
				for (int i = index; i < eb->mIns.Size(); i++)
					eb->mIns[i].mLive |= LIVE_CPU_REG_X;
				eb->mExitRequiredRegs += CPU_REG_X;
				mEntryRequiredRegs += CPU_REG_X;
				mIns[0].mType = ASMIT_TXA;
				mIns[0].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}
#if 1
		if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mEntryRegA)
		{
			int	i = 0;
			while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mEntryBlocks[i]->mIns.Last().mMode) && !mEntryBlocks[i]->mFalseJump)
				i++;
			if (i == mEntryBlocks.Size())
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					NativeCodeBasicBlock* b = mEntryBlocks[i];
					int						sz = b->mIns.Size();
					b->mIns[sz - 1].mType = ASMIT_LDX;
					b->mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
					b->mExitRequiredRegs += CPU_REG_X;
					changed = true;
				}

				mEntryRequiredRegs += CPU_REG_X;
				mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
			}
		}
#endif
#if 1
		if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAY && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mEntryRegA)
		{
			int	i = 0;
			while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mEntryBlocks[i]->mIns.Last().mMode) && !mEntryBlocks[i]->mFalseJump)
				i++;
			if (i == mEntryBlocks.Size())
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					NativeCodeBasicBlock* b = mEntryBlocks[i];
					int						sz = b->mIns.Size();
					b->mIns[sz - 1].mType = ASMIT_LDY;
					b->mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
					b->mExitRequiredRegs += CPU_REG_Y;
					changed = true;
				}

				mEntryRequiredRegs += CPU_REG_Y;
				mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
			}
		}
#endif
#if 1
		if (mIns.Size() >= 1 && mIns[0].mMode == ASMIM_ABSOLUTE_X && !(mIns[0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
		{
			int	i = 0;
			while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_LDX && mEntryBlocks[i]->mIns.Last().mMode == ASMIM_IMMEDIATE && !mEntryBlocks[i]->mFalseJump)
				i++;
			if (i == mEntryBlocks.Size())
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					NativeCodeBasicBlock* b = mEntryBlocks[i];
					int						sz = b->mIns.Size();
					int						index = b->mIns[sz - 1].mAddress;
					b->mIns[sz - 1] = mIns[0];
					b->mIns[sz - 1].mMode = ASMIM_ABSOLUTE;
					b->mIns[sz - 1].mAddress += index;
					changed = true;
				}

				mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
			}
		}
#endif

#if 1
		if (mIns.Size() >= 1 && mIns.Last().mType == ASMIT_STA && mIns.Last().mMode == ASMIM_ZERO_PAGE && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
		{
			const NativeCodeInstruction& ins(mIns.Last());

			if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
			{
				mTrueJump->mIns.Insert(0, ins);
				mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C;
				mIns.Remove(mIns.Size() - 1);
				mExitRequiredRegs += CPU_REG_A;
				mTrueJump->mEntryRequiredRegs += CPU_REG_A;
				mTrueJump->CheckLive();
				changed = true;
			}
			else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
			{
				mFalseJump->mIns.Insert(0, ins);
				mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
				mIns.Remove(mIns.Size() - 1);
				mExitRequiredRegs += CPU_REG_A;
				mFalseJump->mEntryRequiredRegs += CPU_REG_A;
				mFalseJump->CheckLive();
				changed = true;
			}
		}
#endif
		if (mIns.Size() >= 1 && mBranch == ASMIT_BNE && (mIns.Last().mType == ASMIT_INC || mIns.Last().mType == ASMIT_DEC) && mIns.Last().mMode == ASMIM_ZERO_PAGE)
		{
			NativeCodeBasicBlock* b = mTrueJump;

			if (b->mIns.Size() == 2 && !b->mExitRequiredRegs[CPU_REG_A])
			{
				if ((b->mIns[0].mType == ASMIT_LDA || b->mIns[0].mType == ASMIT_TXA || b->mIns[0].mType == ASMIT_TYA) &&
					b->mIns[1].mType == ASMIT_ORA && b->mIns[1].SameEffectiveAddress(mIns.Last()))
				{
					if (b->mBranch == ASMIT_BEQ)
					{
						b->mNumEntries--;
						b->mEntryBlocks.RemoveAll(this);
						mTrueJump = b->mFalseJump;
						mTrueJump->mNumEntries++;
						mTrueJump->mEntryBlocks.Push(this);
						changed = true;
					}
					else if (b->mBranch == ASMIT_BNE)
					{
						b->mNumEntries--;
						b->mEntryBlocks.RemoveAll(this);
						mTrueJump = b->mTrueJump;
						mTrueJump->mNumEntries++;
						mTrueJump->mEntryBlocks.Push(this);
						changed = true;
					}
				}
			}
		}

#if 1
		if (mIns.Size() >= 2 && mFalseJump)
		{
			int ns = mIns.Size();
			if ((mIns[ns - 2].mType == ASMIT_INY || mIns[ns - 2].mType == ASMIT_DEY) && mIns[ns - 1].mType == ASMIT_TYA)
			{
				if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
				{
					mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns[ns - 1].mType = ASMIT_NOP;
					mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
				else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
				{
					mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns[ns - 1].mType = ASMIT_NOP;
					mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
			}
			else if ((mIns[ns - 2].mType == ASMIT_INX || mIns[ns - 2].mType == ASMIT_DEX) && mIns[ns - 1].mType == ASMIT_TXA)
			{
				if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
				{
					mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns[ns - 1].mType = ASMIT_NOP;
					mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
				else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
				{
					mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					mIns[ns - 1].mType = ASMIT_NOP;
					mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
			}
		}
#endif
#if 1
		if (mIns.Size() >= 2 && mFalseJump)
		{
			int ns = mIns.Size();

			if (mIns[ns - 2].mType == ASMIT_LDA && mIns[ns - 1].mType == ASMIT_CMP && mIns[ns - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[ns - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].SameEffectiveAddress(mIns[ns - 1]) ||
					mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[ns - 1]))
				{
					NativeCodeInstruction	ins = mIns[ns - 1];
					mIns[ns - 1].CopyMode(mIns[ns - 2]);
					mIns[ns - 2].CopyMode(ins);

					if (mIns[ns - 1].RequiresXReg())
						mIns[ns - 2].mLive |= LIVE_CPU_REG_X;
					if (mIns[ns - 1].RequiresYReg())
						mIns[ns - 2].mLive |= LIVE_CPU_REG_Y;
					changed = true;
				}
			}
		}
#endif
		if (mIns.Size() >= 2 && mEntryBlocks.Size() == 1)
		{
			if (mIns[0].mType == ASMIT_TYA && mIns[1].IsShift() && mIns[1].mMode == ASMIM_IMPLIED)
			{
				NativeCodeBasicBlock* block = mEntryBlocks[0];
				int ns = block->mIns.Size();
				if (ns >= 2 && block->mIns[ns - 2].mType == ASMIT_TAY && block->mIns[ns - 1].IsSame(mIns[1]))
				{
					mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
					mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
					block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
					changed = true;
				}
			}
		}
		if (mIns.Size() >= 1 && mEntryBlocks.Size() == 1)
		{
			if (mIns[0].IsShift() && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_MEM))
			{
				NativeCodeBasicBlock* block = mEntryBlocks[0];
				int ns = block->mIns.Size();
				if (ns >= 2 && 
					block->mIns[ns - 2].mType == ASMIT_STA && block->mIns[ns - 2].SameEffectiveAddress(mIns[0]) && 
					block->mIns[ns - 1].mType == mIns[0].mType && block->mIns[ns - 1].mMode == ASMIM_IMPLIED && !(mIns[0].mLive & LIVE_MEM))
				{
					mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
					block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
					changed = true;
				}
			}
		}
#if 1
		if (mIns.Size() >= 2)
		{
			int ns = mIns.Size();
			const NativeCodeInstruction& ins(mIns[ns - 2]);

			CheckLive();

			if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && mTrueJump && mFalseJump && !mIns[ns-1].UsesZeroPage(ins.mAddress) && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
			{
				if (!mIns[ns - 1].ChangesAccu())
				{
					if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
					{
						mIns[ns - 1].mLive |= LIVE_CPU_REG_A;
						mTrueJump->mIns.Insert(0, ins);
						mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C | mIns[ns - 1].mLive;
						mIns.Remove(ns - 2);
						mExitRequiredRegs += CPU_REG_A;
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						mTrueJump->CheckLive();
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
					{
						mIns[ns - 1].mLive |= LIVE_CPU_REG_A;
						mFalseJump->mIns.Insert(0, ins);
						mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C | mIns[ns - 1].mLive;
						mIns.Remove(ns - 2);
						mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						mFalseJump->CheckLive();
						changed = true;
					}
				}
				else if (ns >= 3 && mIns[ns - 3].mType == ASMIT_LDA && mIns[ns - 3].mMode == ASMIM_ZERO_PAGE && !(mIns[ns - 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_A)))
				{
					if (mTrueJump->mEntryRequiredRegs[ins.mAddress] && !mFalseJump->mEntryRequiredRegs[ins.mAddress] && mTrueJump->mEntryBlocks.Size() == 1)
					{
						mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X;
						mIns[ns - 2].mType = ASMIT_STX;
						mIns[ns - 1].mLive |= LIVE_CPU_REG_X;
						mTrueJump->mIns.Insert(0, ins);
						mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_C;
						if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
							mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_A;
						mIns.Remove(ns - 2);
						mExitRequiredRegs += CPU_REG_X;
						mTrueJump->mEntryRequiredRegs += CPU_REG_X;
						mTrueJump->CheckLive();
						changed = true;
					}
					else if (mFalseJump->mEntryRequiredRegs[ins.mAddress] && !mTrueJump->mEntryRequiredRegs[ins.mAddress] && mFalseJump->mEntryBlocks.Size() == 1)
					{
						mIns[ns - 3].mType = ASMIT_LDX; mIns[ns - 3].mLive |= LIVE_CPU_REG_X;
						mIns[ns - 2].mType = ASMIT_STX;
						mIns[ns - 1].mLive |= LIVE_CPU_REG_X;
						mFalseJump->mIns.Insert(0, ins);
						mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
						if (mFalseJump->mEntryRequiredRegs[CPU_REG_A])
							mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_A;
						mIns.Remove(ns - 2);
						mExitRequiredRegs += CPU_REG_X;
						mFalseJump->mEntryRequiredRegs += CPU_REG_X;
						mFalseJump->CheckLive();
						changed = true;
					}
				}
			}
			CheckLive();
		}
#endif

#if 1
		if (mLoopHead && mIns.Size() > 0 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mEntryBlocks.Size() == 2 && !(mIns[0].mLive & LIVE_CPU_REG_Z))
		{
			NativeCodeBasicBlock* dblock = nullptr, * lblock = nullptr;
			if (mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump)
			{
				lblock = mEntryBlocks[0];
				dblock = mEntryBlocks[1];
			}
			else if (mEntryBlocks[1]->mFalseJump && !mEntryBlocks[0]->mFalseJump)
			{
				lblock = mEntryBlocks[0];
				dblock = mEntryBlocks[1];
			}

			if (lblock && lblock != this)
			{
				int	ls = lblock->mIns.Size();
				if (ls > 0 && lblock->mIns[ls - 1].mType == ASMIT_CMP)
					ls--;
				if (ls > 0 && lblock->mIns[ls - 1].IsSame(mIns[0]))
				{
					dblock->mIns.Push(mIns[0]);
					mIns.Remove(0);
					mEntryRequiredRegs += CPU_REG_A;
					dblock->mExitRequiredRegs += CPU_REG_A;
					lblock->mExitRequiredRegs += CPU_REG_A;
					changed = true;
				}
			}


		}
#endif

#if 1
		if (mTrueJump && mFalseJump && mTrueJump->mLoopHead && mIns.Size() >= 3 && mTrueJump->mNumEntries == 2)
		{
			int ns = mIns.Size();

			if (mIns[ns - 1].mType == ASMIT_CPX && mIns[ns - 2].mType == ASMIT_LDX && mIns[ns - 3].mType == ASMIT_INC && mIns[ns - 2].SameEffectiveAddress(mIns[ns - 3]))
			{
				NativeCodeBasicBlock* pb = mTrueJump->mEntryBlocks[0] == this ? mTrueJump->mEntryBlocks[1] : mTrueJump->mEntryBlocks[0];
				if (pb->mIns.Size() > 0)
				{
					int ps = pb->mIns.Size();
					if (pb->mIns[ps - 1].mType == ASMIT_STX && pb->mIns[ps - 1].SameEffectiveAddress(mIns[ns - 3]))
					{
						mTrueJump->mIns.Insert(0, pb->mIns[ps - 1]);
						mTrueJump->mEntryRequiredRegs += CPU_REG_X;

						mFalseJump->BuildSingleExit(mProc, this);
						
						mFalseJump->mIns.Insert(0, pb->mIns[ps - 1]);
						mFalseJump->mEntryRequiredRegs += CPU_REG_X;

						pb->mExitProvidedRegs += CPU_REG_X;
						mExitProvidedRegs += CPU_REG_Y;

						ns = mIns.Size();

						mIns[ns - 3] = mIns[ns - 2];
						mIns[ns - 2].mType = ASMIT_INX; mIns[ns - 2].mMode = ASMIM_IMPLIED;
						changed = true;

						mTrueJump->CheckLive();
						mFalseJump->CheckLive();
					}
				}
			}
			else if (mIns[ns - 1].mType == ASMIT_CPY && mIns[ns - 2].mType == ASMIT_LDY && mIns[ns - 3].mType == ASMIT_INC && mIns[ns - 2].SameEffectiveAddress(mIns[ns - 3]))
			{
				NativeCodeBasicBlock* pb = mTrueJump->mEntryBlocks[0] == this ? mTrueJump->mEntryBlocks[1] : mTrueJump->mEntryBlocks[0];
				if (pb->mIns.Size() > 0)
				{
					int ps = pb->mIns.Size();
					if (pb->mIns[ps - 1].mType == ASMIT_STY && pb->mIns[ps - 1].SameEffectiveAddress(mIns[ns - 3]))
					{
						mTrueJump->mIns.Insert(0, pb->mIns[ps - 1]);
						mTrueJump->mEntryRequiredRegs += CPU_REG_Y;

						mFalseJump->BuildSingleExit(mProc, this);

						mFalseJump->mIns.Insert(0, pb->mIns[ps - 1]);
						mFalseJump->mEntryRequiredRegs += CPU_REG_Y;

						pb->mExitProvidedRegs += CPU_REG_Y;
						mExitProvidedRegs += CPU_REG_Y;

						ns = mIns.Size();

						mIns[ns - 3] = mIns[ns - 2];
						mIns[ns - 2].mType = ASMIT_INY; mIns[ns - 2].mMode = ASMIM_IMPLIED;
						changed = true;

						mTrueJump->CheckLive();
						mFalseJump->CheckLive();
					}
				}
			}
			CheckLive();
		}
#endif

#if 1
		if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
		{
			if (mTrueJump->mIns.Size() > mFalseJump->mIns.Size())
			{
				if (mTrueJump->mTrueJump != mFalseJump && mFalseJump->mIns.Size() > 0)
				{
					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 && mTrueJump->mIns.Size() > 0)
				{
					int	i = 0, offset = mFalseJump->mIns.Size() - mTrueJump->mIns.Size();
					while (i < mTrueJump->mIns.Size() && mTrueJump->mIns[i].IsSame(mFalseJump->mIns[i + offset]))
						i++;
					if (i == mTrueJump->mIns.Size())
					{
						if (mFalseJump->mTrueJump)
							mFalseJump->mTrueJump->RemEntryBlock(mFalseJump);
						mFalseJump->mTrueJump = mTrueJump;
						if (mFalseJump->mTrueJump)
							mFalseJump->mTrueJump->AddEntryBlock(mFalseJump);
						mFalseJump->mIns.SetSize(offset);
						changed = true;
					}
				}
			}
		}
#endif
#if 1
		if (mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump && !mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump)
		{
			int s = mIns.Size(), ts = mTrueJump->mIns.Size();
			if (s > 1 && ts > 0)
			{
				if (mIns[s - 2].mType == ASMIT_STA && mIns[s - 2].mMode == ASMIM_ZERO_PAGE &&
					mTrueJump->mIns[ts - 1].mType == ASMIT_STA && mTrueJump->mIns[ts - 1].mMode == ASMIM_ZERO_PAGE && mTrueJump->mIns[ts - 1].mAddress == mIns[s - 2].mAddress)
				{
				}
			}
		}
		if (mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump)
		{
			mTrueJump->CheckLive();
			mFalseJump->CheckLive();

			int s = mIns.Size(), ts = mFalseJump->mIns.Size();
			if (s > 1 && ts > 0)
			{
				if (mIns[s - 2].mType == ASMIT_STA && mIns[s - 2].mMode == ASMIM_ZERO_PAGE &&
					mFalseJump->mIns[ts - 1].mType == ASMIT_STA && mFalseJump->mIns[ts - 1].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[ts - 1].mAddress == mIns[s - 2].mAddress &&
					mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && mFalseJump->mIns[0].mAddress == mIns[s - 2].mAddress)
				{
					if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(ASMIT_LDY, mIns[s - 1].mMode))
					{
						mIns[s - 1].mType = ASMIT_LDY;
						mTrueJump->mIns.Insert(0, mIns[s - 2]);
						mIns.Remove(s - 2);
						mFalseJump->mIns.Remove(ts - 1);
						mFalseJump->mIns.Remove(0);
						mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						mTrueJump->mEntryProvidedRegs += CPU_REG_A;
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						changed = true;

						mTrueJump->CheckLive();
						mFalseJump->CheckLive();
					}
					else if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)) && HasAsmInstructionMode(ASMIT_LDX, mIns[s - 1].mMode))
					{
						mIns[s - 1].mType = ASMIT_LDX;
						mTrueJump->mIns.Insert(0, mIns[s - 2]);
						mIns.Remove(s - 2);
						mFalseJump->mIns.Remove(ts - 1);
						mFalseJump->mIns.Remove(0);
						mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mExitRequiredRegs += CPU_REG_A;
						mFalseJump->mEntryRequiredRegs += CPU_REG_A;
						mTrueJump->mEntryProvidedRegs += CPU_REG_A;
						mTrueJump->mEntryRequiredRegs += CPU_REG_A;
						changed = true;

						mTrueJump->CheckLive();
						mFalseJump->CheckLive();
					}
				}
			}

		}
#endif
#if 1
		if (mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump && mFalseJump->mNumEntries == 1)
		{
			int s = mIns.Size();
			if (s > 0 && mIns[s - 1].mType == ASMIT_CMP && mIns[s - 1].mMode == ASMIM_IMMEDIATE && !(mIns[s - 1].mLive & LIVE_CPU_REG_X))
			{
				while (mTrueJump->mIns.Size() > 1 && mFalseJump->mIns.Size() > 1 &&

					((mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[1].mType == ASMIT_STA && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
					 (mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[1].mType == ASMIT_STX && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
					((mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[1].mType == ASMIT_STA && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
					 (mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[1].mType == ASMIT_STX && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
					mTrueJump->mIns[0].SameEffectiveAddress(mFalseJump->mIns[0]) && mTrueJump->mIns[1].SameEffectiveAddress(mFalseJump->mIns[1]) &&
					HasAsmInstructionMode(ASMIT_LDX, mTrueJump->mIns[0].mMode) && HasAsmInstructionMode(ASMIT_STX, mTrueJump->mIns[1].mMode))
				{
					uint32	live = mIns[s - 1].mLive | LIVE_CPU_REG_A;
					if (mIns[s - 1].RequiresYReg())
						live |= LIVE_CPU_REG_Y;
					if (s >= 2)
						live |= mIns[s - 2].mLive;

					mTrueJump->mIns[0].mType = ASMIT_LDX;
					mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_X | live;
					mTrueJump->mIns[1].mType = ASMIT_STX;
					mTrueJump->mIns[1].mLive |= live;

					mIns.Insert(s - 1, mTrueJump->mIns[0]);
					mIns.Insert(s, mTrueJump->mIns[1]);
					s += 2;
					mTrueJump->mIns.Remove(0); mTrueJump->mIns.Remove(0);
					mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);

					CheckLive();
					mTrueJump->CheckLive();
					mFalseJump->CheckLive();

					changed = true;
				}
			}
			else if (s > 0 && mIns[s - 1].mType == ASMIT_LDA && !(mIns[s - 1].mLive & LIVE_CPU_REG_X))
			{
				while (mTrueJump->mIns.Size() > 1 && mFalseJump->mIns.Size() > 1 &&

					((mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[1].mType == ASMIT_STA && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
						(mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[1].mType == ASMIT_STX && !(mTrueJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
					((mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[1].mType == ASMIT_STA && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) ||
						(mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[1].mType == ASMIT_STX && !(mFalseJump->mIns[1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))) &&
					mTrueJump->mIns[0].SameEffectiveAddress(mFalseJump->mIns[0]) && mTrueJump->mIns[1].SameEffectiveAddress(mFalseJump->mIns[1]) &&
					HasAsmInstructionMode(ASMIT_LDX, mTrueJump->mIns[0].mMode) && HasAsmInstructionMode(ASMIT_STX, mTrueJump->mIns[1].mMode) &&
					!mIns[s - 1].MayBeChangedOnAddress(mTrueJump->mIns[1]))
				{
					uint32	live = mIns[s - 1].mLive;
					if (mIns[s - 1].RequiresYReg())
						live |= LIVE_CPU_REG_Y;
					if (s >= 2)
						live |= mIns[s - 2].mLive;

					mTrueJump->mIns[0].mType = ASMIT_LDX;
					mTrueJump->mIns[0].mLive |= LIVE_CPU_REG_X | live;
					mTrueJump->mIns[1].mType = ASMIT_STX;
					mTrueJump->mIns[1].mLive |= live;


					mIns.Insert(s - 1, mTrueJump->mIns[0]);
					mIns.Insert(s, mTrueJump->mIns[1]);
					s += 2;
					mTrueJump->mIns.Remove(0); mTrueJump->mIns.Remove(0);
					mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);

					CheckLive();
					mTrueJump->CheckLive();
					mFalseJump->CheckLive();

					changed = true;
				}
			}
		}
#endif

		if (mEntryBlocks.Size() == 1 && mIns.Size() >= 3)
		{
			NativeCodeBasicBlock* eblock = mEntryBlocks[0];
			int es = eblock->mIns.Size();
			while (es > 0 && !eblock->mIns[es - 1].ChangesAccu())
				es--;
			if (es > 0 && eblock->mIns[es - 1].mType == ASMIT_LDA && (eblock->mIns[es - 1].mMode == ASMIM_ZERO_PAGE || eblock->mIns[es - 1].mMode == ASMIM_ABSOLUTE))
			{
				int i = es;
				es--;
				while (i < eblock->mIns.Size() && !eblock->mIns[es].MayBeChangedOnAddress(eblock->mIns[i]))
					i++;

				if (i == eblock->mIns.Size())
				{
					if (mIns[2].mType == ASMIT_STA && mIns[2].SameEffectiveAddress(eblock->mIns[es]) && !(mIns[2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
					{
						if (mIns[0].mType == ASMIT_SEC && mIns[1].mType == ASMIT_SBC && mIns[1].mMode == ASMIM_IMMEDIATE && mIns[1].mAddress == 1)
						{
							mIns[0].mType = ASMIT_NOP;
							mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
							mIns[2].mType = ASMIT_DEC;
							changed = true;
						}
						else if (mIns[0].mType == ASMIT_CLC && mIns[1].mType == ASMIT_ADC && mIns[1].mMode == ASMIM_IMMEDIATE && mIns[1].mAddress == 1)
						{
							mIns[0].mType = ASMIT_NOP;
							mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
							mIns[2].mType = ASMIT_INC;
							changed = true;
						}
					}
				}
			}
		}

		if (mEntryBlocks.Size() == 1 && mIns.Size() > 0)
		{
			if (mIns[0].mType == ASMIT_TAY && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				NativeCodeBasicBlock* pblock = mEntryBlocks[0];
				if (pblock->mTrueJump && pblock->mFalseJump && pblock->mIns.Size() > 0 && !pblock->mExitRequiredRegs[CPU_REG_Y])
				{
					if (this == pblock->mTrueJump && !pblock->mFalseJump->mEntryRequiredRegs[CPU_REG_A] ||
						this == pblock->mFalseJump && !pblock->mTrueJump->mEntryRequiredRegs[CPU_REG_A])
					{
						int si = pblock->mIns.Size();
						if (pblock->mIns[si - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, pblock->mIns[si - 1].mMode))
							si--;

						if (si > 0 && pblock->mIns[si - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, pblock->mIns[si - 1].mMode))
						{
							pblock->mIns[si - 1].mType = ASMIT_LDY;
							pblock->mIns[si - 1].mLive |= LIVE_CPU_REG_Y;
							if (si != pblock->mIns.Size())
							{
								pblock->mIns[si].mType = ASMIT_CPY;
								pblock->mIns[si].mLive |= LIVE_CPU_REG_Y;
							}
							pblock->mExitRequiredRegs += CPU_REG_Y;
							mEntryRequiredRegs += CPU_REG_Y;
							mIns[0].mType = ASMIT_NOP;
							changed = true;
						}
					}
				}
			}
		}

#if 1
		if (mEntryBlocks.Size() > 1 && mIns.Size() > 0)
		{
			int fi = 0;
			while (fi < mIns.Size() && !mIns[fi].ReferencesYReg())
				fi++;

			if (fi < mIns.Size() && mIns[fi].mType == ASMIT_LDY && mIns[fi].mMode == ASMIM_ZERO_PAGE && !(mIns[fi].mLive & LIVE_CPU_REG_Z) && !ChangesZeroPage(mIns[fi].mAddress, 0, fi))
			{
				int		ei = 0;
				int		index;
				bool	found = false, fail = false;
				NativeCodeBasicBlock* block;

				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					if (mEntryBlocks[i]->IsExitYRegZP(mIns[fi].mAddress, index, block))
						found = true;
					else if (mEntryBlocks[i]->mFalseJump)
						fail = true;
				}

				if (found && !fail)
				{
					for (int i = 0; i < fi; i++)
						mIns[i].mLive |= LIVE_CPU_REG_Y;

					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						if (mEntryBlocks[i]->IsExitYRegZP(mIns[fi].mAddress, index, block))
						{
							mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_Y, CPU_REG_Y);
						}
						else
						{
							mEntryBlocks[i]->mIns.Push(mIns[fi]);
							mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_Y;
						}
					}

					mEntryRequiredRegs += CPU_REG_Y;
					mIns.Remove(fi);
					changed = true;
				}
			}

			fi = 0;
			while (fi < mIns.Size() && !mIns[fi].ReferencesXReg())
				fi++;

			if (fi < mIns.Size() && mIns[fi].mType == ASMIT_LDX && mIns[fi].mMode == ASMIM_ZERO_PAGE && !(mIns[fi].mLive & LIVE_CPU_REG_Z) && !ChangesZeroPage(mIns[fi].mAddress, 0, fi))
			{
				int		ei = 0;
				int		index;
				bool	found = false, fail = false;
				NativeCodeBasicBlock* block;

				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					if (mEntryBlocks[i]->IsExitXRegZP(mIns[fi].mAddress, index, block))
						found = true;
					else if (mEntryBlocks[i]->mFalseJump)
						fail = true;
				}

				if (found && !fail)
				{
					for (int i = 0; i < fi; i++)
						mIns[i].mLive |= LIVE_CPU_REG_X;

					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						if (mEntryBlocks[i]->IsExitXRegZP(mIns[fi].mAddress, index, block))
						{
							mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_X, CPU_REG_X);
						}
						else
						{
							mEntryBlocks[i]->mIns.Push(mIns[fi]);
							mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_X;
							mEntryBlocks[i]->mExitRequiredRegs -= CPU_REG_Z;
						}
					}

					mEntryRequiredRegs -= CPU_REG_Z;
					mEntryRequiredRegs += CPU_REG_X;
					mIns.Remove(fi);
					changed = true;
				}
			}
			
			fi = 0;
			while (fi < mIns.Size() && !mIns[fi].ReferencesAccu())
				fi++;

			if (fi < mIns.Size() && mIns[fi].mType == ASMIT_LDA && mIns[fi].mMode == ASMIM_ZERO_PAGE && !(mIns[fi].mLive & LIVE_CPU_REG_Z) && !ChangesZeroPage(mIns[fi].mAddress, 0, fi))
			{
				int		ei = 0;
				int		index;
				bool	found = false, fail = false;
				NativeCodeBasicBlock* block;

				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					if (mEntryBlocks[i]->IsExitARegZP(mIns[fi].mAddress, index, block))
						found = true;
					else if (mEntryBlocks[i]->mFalseJump)
						fail = true;
				}

				if (found && !fail)
				{
					for (int i = 0; i < fi; i++)
						mIns[i].mLive |= LIVE_CPU_REG_A;

					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						if (mEntryBlocks[i]->IsExitARegZP(mIns[fi].mAddress, index, block))
						{
							mEntryBlocks[i]->MarkLiveBlockChain(index, block, LIVE_CPU_REG_A, CPU_REG_A);
						}
						else
						{
							mEntryBlocks[i]->mIns.Push(mIns[fi]);
							if (mEntryBlocks[i]->mExitRequiredRegs[CPU_REG_X])
								mEntryBlocks[i]->mIns[mEntryBlocks[i]->mIns.Size() - 1].mLive |= LIVE_CPU_REG_X;
							if (mEntryBlocks[i]->mExitRequiredRegs[CPU_REG_Y])
								mEntryBlocks[i]->mIns[mEntryBlocks[i]->mIns.Size() - 1].mLive |= LIVE_CPU_REG_Y;
							mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_A;
						}
					}

					mEntryRequiredRegs += CPU_REG_A;
					mIns.Remove(fi);
					changed = true;
				}
			}
		}
#endif

#if 1
		if (mEntryBlocks.Size() > 1 && mIns.Size() > 0)
		{
			if (mIns[0].mType == ASMIT_STA)
			{
				int ts;
				if ((ts = mEntryBlocks[0]->mIns.Size()) >= 2 &&
					mEntryBlocks[0]->mIns[ts - 2].mType == ASMIT_LDA && 
					mEntryBlocks[0]->mIns[ts - 2].mMode == ASMIM_ZERO_PAGE &&
					mEntryBlocks[0]->mIns[ts - 1].mType == ASMIT_ADC &&
					!mEntryBlocks[0]->mFalseJump)
				{
					int addr = mEntryBlocks[0]->mIns[ts - 2].mAddress;

					int i = 1;
					while (i < mEntryBlocks.Size() &&
						(ts = mEntryBlocks[i]->mIns.Size()) >= 2 &&
						mEntryBlocks[i]->mIns[ts - 2].mType == ASMIT_LDA &&
						mEntryBlocks[i]->mIns[ts - 2].mMode == ASMIM_ZERO_PAGE &&
						mEntryBlocks[i]->mIns[ts - 2].mAddress == addr &&
						mEntryBlocks[i]->mIns[ts - 1].mType == ASMIT_ADC &&
						!mEntryBlocks[i]->mFalseJump)
						i++;
					if (i == mEntryBlocks.Size())
					{
						ts = mEntryBlocks[0]->mIns.Size();
						mIns.Insert(0, NativeCodeInstruction(mEntryBlocks[0]->mIns[ts - 2].mIns, ASMIT_ADC, mEntryBlocks[0]->mIns[ts - 2]));

						for (int i = 0; i < mEntryBlocks.Size(); i++)
						{
							ts = mEntryBlocks[i]->mIns.Size();
							mEntryBlocks[i]->mIns[ts - 1].mType = ASMIT_LDA;
							mEntryBlocks[i]->mIns[ts - 1].mLive |= LIVE_CPU_REG_C;
							mEntryBlocks[i]->mIns[ts - 2].mType = ASMIT_NOP;
							mEntryBlocks[i]->mIns[ts - 2].mMode = ASMIM_IMPLIED;
							mEntryBlocks[i]->mExitRequiredRegs += addr;
							mEntryBlocks[i]->mExitRequiredRegs += CPU_REG_C;
						}
						mEntryRequiredRegs += addr;
						mEntryRequiredRegs += CPU_REG_C;
						changed = true;
					}
				}
			}
		}
#endif
#if 0
		if (mFalseJump && mIns.Size() > 1)
		{
			int sz = mIns.Size();
			if (mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80)
			{
				if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BPL)
				{
					if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_AND && mTrueJump->mEntryBlocks.Size() == 2)
					{
						NativeCodeBasicBlock* pblock = mTrueJump->mEntryBlocks[0];
						if (pblock == this)
							pblock = mTrueJump->mEntryBlocks[1];
						if (!pblock->mFalseJump)
						{
							pblock->mIns.Push(mTrueJump->mIns[0]);
							mTrueJump->mIns.Remove(0);
							changed = true;
						}
					}
				}
			}
		}
#endif

		if (mFalseJump && !mFalseJump->mFalseJump && mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 2 && mTrueJump->mIns.Size() > 0 && mIns.Size() > 0)
		{
			int sz = mIns.Size();

			if (mTrueJump->mIns[0].mType == ASMIT_TAX && !mFalseJump->ReferencesXReg() && !mFalseJump->ReferencesAccu() && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				if (mIns[sz - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 1].mMode))
				{
					mIns[sz - 1].mType = ASMIT_LDX;
					mIns[sz - 1].mLive |= LIVE_CPU_REG_X;
					mTrueJump->mIns[0].mType = ASMIT_NOP;
					mExitRequiredRegs += CPU_REG_X;
					mTrueJump->mEntryRequiredRegs += CPU_REG_X;
					mFalseJump->mEntryRequiredRegs += CPU_REG_X;
					mFalseJump->mExitRequiredRegs += CPU_REG_X;
					for (int i = 0; i < mFalseJump->mIns.Size(); i++)
						mFalseJump->mIns[i].mLive |= LIVE_CPU_REG_X;
					changed = true;
				}
			}
			else if (mTrueJump->mIns[0].mType == ASMIT_TAY && !mFalseJump->ReferencesYReg() && !mFalseJump->ReferencesAccu() && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				if (mIns[sz - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[sz - 1].mMode))
				{
					mIns[sz - 1].mType = ASMIT_LDY;
					mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;
					mTrueJump->mIns[0].mType = ASMIT_NOP;
					mExitRequiredRegs += CPU_REG_Y;
					mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
					mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
					mFalseJump->mExitRequiredRegs += CPU_REG_Y;
					for (int i = 0; i < mFalseJump->mIns.Size(); i++)
						mFalseJump->mIns[i].mLive |= LIVE_CPU_REG_Y;
					changed = true;
				}
			}
		}

		if (mEntryBlocks.Size() == 1 && mIns.Size() > 0 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			NativeCodeBasicBlock* pblock = mEntryBlocks[0];
			NativeCodeBasicBlock* nblock = pblock->mTrueJump == this ? pblock->mFalseJump : pblock->mTrueJump;
			if (!nblock || (!nblock->mEntryRequiredRegs[CPU_REG_A] && !nblock->mEntryRequiredRegs[CPU_REG_X]))
			{
				int ps = pblock->mIns.Size();
				if (ps > 0 && pblock->mIns[ps - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, pblock->mIns[ps - 1].mMode))
				{
					pblock->mIns[ps - 1].mType = ASMIT_LDX;
					pblock->mIns[ps - 1].mLive |= LIVE_CPU_REG_X;
					pblock->mExitRequiredRegs += CPU_REG_X;
					mEntryRequiredRegs += CPU_REG_X;
					mIns[0].mType = ASMIT_NOP;
					changed = true;
				}
			}
		}

		if (mFalseJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump && mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 2)
		{
			int sz = mIns.Size();
			if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 &&
				mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
				mTrueJump->mIns.Size() >= 1 && mTrueJump->mIns[0].mType == ASMIT_EOR)
			{
				mIns[sz - 1].CopyMode(mTrueJump->mIns[0]);
				mFalseJump->mEntryRequiredRegs += CPU_REG_A;
				mFalseJump->mIns[0].mType = ASMIT_EOR;
				mTrueJump->mIns[0].mType = ASMIT_NOP; mTrueJump->mIns[0].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}

		if (mEntryBlocks.Size() > 1 && !mEntryRequiredRegs[CPU_REG_A])
		{
			int ia = 0;
			while (ia < mIns.Size() && !mIns[ia].ChangesAccu())
				ia++;
			if (ia < mIns.Size() && mIns[ia].mType == ASMIT_LDA && mIns[ia].mMode == ASMIM_ZERO_PAGE && !(mIns[ia].mLive & LIVE_CPU_REG_Z) && !ChangesZeroPage(mIns[ia].mAddress, 0, ia))
			{
				int j = 0;
				while (j < mEntryBlocks.Size() && mEntryBlocks[j]->HasTailAccuReg(mIns[ia].mAddress))
					j++;
				if (j == mEntryBlocks.Size())
				{
					for (int i = 0; i < ia; i++)
						mIns[i].mLive |= LIVE_CPU_REG_A;
					mIns.Remove(ia);
					mEntryRequiredRegs += CPU_REG_A;
					for (int j = 0; j < mEntryBlocks.Size(); j++)
					{
						NativeCodeBasicBlock* eblock = mEntryBlocks[j];
						eblock->mExitRequiredRegs += CPU_REG_A;
						int k = eblock->mIns.Size() - 1;
						while (k >= 0 && !(eblock->mIns[k].mLive & LIVE_CPU_REG_A))
						{
							eblock->mIns[k].mLive |= LIVE_CPU_REG_A;
							k--;
						}
					}
					changed = true;
				}
			}
		}

		CheckLive();
		mProc->CheckBlocks();

		if (mTrueJump && mTrueJump->JoinTailCodeSequences(loops))
			changed = true;
		if (mFalseJump && mFalseJump->JoinTailCodeSequences(loops))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MayBeMovedBeforeBlock(int at)
{
	int i = at;
	while (i > 0)
	{
		i--;
		if (!mIns[at].MayBeMovedBefore(mIns[i]))
			return false;		
	}

	return true;
}

bool NativeCodeBasicBlock::MayBeMovedBeforeBlock(int at, const NativeCodeInstruction& ins)
{
	int i = at;
	while (i > 0)
	{
		i--;
		if (!ins.MayBeMovedBefore(mIns[i]))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::SafeInjectSequenceFromBack(NativeCodeBasicBlock* block, int start, int end)
{
	uint32	changes = 0;
	uint32	requires = 0;

	bool	hasvolatile = false;

	for (int i = start; i < end; i++)
	{
		const NativeCodeInstruction& ins(block->mIns[i]);
		if (ins.RequiresAccu() && !(changes & LIVE_CPU_REG_A)) requires |= LIVE_CPU_REG_A;
		if (ins.RequiresXReg() && !(changes & LIVE_CPU_REG_X)) requires |= LIVE_CPU_REG_X;
		if (ins.RequiresYReg() && !(changes & LIVE_CPU_REG_Y)) requires |= LIVE_CPU_REG_Y;
		if (ins.RequiresCarry() && !(changes & LIVE_CPU_REG_C)) requires |= LIVE_CPU_REG_C;
		if (ins.ChangesAccu()) changes |= LIVE_CPU_REG_A;
		if (ins.ChangesXReg()) changes |= LIVE_CPU_REG_X;
		if (ins.ChangesYReg()) changes |= LIVE_CPU_REG_Y;
		if (ins.ChangesCarry()) changes |= LIVE_CPU_REG_C;
		if (ins.ChangesZFlag()) changes |= LIVE_CPU_REG_Z;

		if (ins.mFlags & NCIF_VOLATILE) hasvolatile = true;
	}

	uint32	live = 0;
	if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		live |= LIVE_CPU_REG_C;
	if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BMI || mBranch == ASMIT_BPL)
		live |= LIVE_CPU_REG_Z;
	if (mExitRequiredRegs[CPU_REG_A])
		live |= LIVE_CPU_REG_A;
	if (mExitRequiredRegs[CPU_REG_X])
		live |= LIVE_CPU_REG_X;
	if (mExitRequiredRegs[CPU_REG_Y])
		live |= LIVE_CPU_REG_Y;
	if (mExitRequiredRegs[CPU_REG_C])
		live |= LIVE_CPU_REG_C;

	int at = mIns.Size();
	while (at > 0 && (live & changes))
	{
		at--;
		const NativeCodeInstruction& ins(mIns[at]);
		if (ins.ChangesAccu())
		{
			if (requires & LIVE_CPU_REG_A)
				return false;
			live &= ~LIVE_CPU_REG_A;
		}
		if (ins.ChangesXReg())
		{
			if (requires & LIVE_CPU_REG_X)
				return false;
			live &= ~LIVE_CPU_REG_X;
		}
		if (ins.ChangesYReg())
		{
			if (requires & LIVE_CPU_REG_Y)
				return false;
			live &= ~LIVE_CPU_REG_Y;
		}
		if (ins.ChangesCarry())
		{
			if (requires & LIVE_CPU_REG_C)
				return false;
			live &= ~LIVE_CPU_REG_C;
		}
		if (ins.ChangesZFlag()) live &= ~LIVE_CPU_REG_Z;

		if (ins.RequiresAccu())
			live |= LIVE_CPU_REG_A;
		if (ins.RequiresXReg())
			live |= LIVE_CPU_REG_X;
		if (ins.RequiresYReg())
			live |= LIVE_CPU_REG_Y;
		if (ins.RequiresCarry())
			live |= LIVE_CPU_REG_C;

		if (hasvolatile && (ins.mFlags & NCIF_VOLATILE)) return false;
	}

	if (!(live & changes))
	{
		for (int i = start; i < end; i++)
		{
			for (int j = at; j < mIns.Size(); j++)
			{
				if (block->mIns[i].MayBeChangedOnAddress(mIns[j]) || mIns[j].MayBeChangedOnAddress(block->mIns[i]))
					return false;
			}
		}

		for (int i = start; i < end; i++)
		{
			mIns.Insert(at, block->mIns[i]); 
			mIns[at].mLive |= live;
			at++;
		}
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::MayBeMovedBeforeBlock(int start, int end)
{
	uint32	changes = 0;
	uint32	requires = 0;

	if (start == 0)
		return true;
	
	bool	hasvolatile = false;

	for (int i = start; i < end; i++)
	{
		const NativeCodeInstruction& ins(mIns[i]);
		if (ins.RequiresAccu() && !(changes & LIVE_CPU_REG_A)) requires |= LIVE_CPU_REG_A;
		if (ins.RequiresXReg() && !(changes & LIVE_CPU_REG_X)) requires |= LIVE_CPU_REG_X;
		if (ins.RequiresYReg() && !(changes & LIVE_CPU_REG_Y)) requires |= LIVE_CPU_REG_Y;
		if (ins.RequiresCarry() && !(changes & LIVE_CPU_REG_C)) requires |= LIVE_CPU_REG_C;
		if (ins.ChangesAccu()) changes |= LIVE_CPU_REG_A;
		if (ins.ChangesXReg()) changes |= LIVE_CPU_REG_X;
		if (ins.ChangesYReg()) changes |= LIVE_CPU_REG_Y;
		if (ins.ChangesCarry()) changes |= LIVE_CPU_REG_C;
		if (ins.ChangesZFlag()) changes |= LIVE_CPU_REG_Z;

		if (ins.mFlags & NCIF_VOLATILE) hasvolatile = true;
	}

	for (int i = 0; i < start; i++)
	{
		const NativeCodeInstruction& ins(mIns[i]);
		if (ins.ChangesAccu() && (requires & LIVE_CPU_REG_A))
			return false;
		if (ins.ChangesXReg() && (requires & LIVE_CPU_REG_X))
			return false;
		if (ins.ChangesYReg() && (requires & LIVE_CPU_REG_Y))
			return false;
		if (ins.ChangesCarry() && (requires & LIVE_CPU_REG_C))
			return false;

		if (hasvolatile && (ins.mFlags & NCIF_VOLATILE)) return false;

		for (int j = start; j < end; j++)
		{
			if (mIns[i].MayBeChangedOnAddress(mIns[j]) || mIns[j].MayBeChangedOnAddress(mIns[i]) || 
				mIns[i].MayReference(mIns[j]) || mIns[j].MayReference(mIns[i]))
				return false;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::JoinConditionSequence(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mIns.Size() == 2 && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
		{
			if (mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE &&
				mIns[1].mType == ASMIT_AND && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[1].mLive & LIVE_CPU_REG_A))
			{
				NativeCodeBasicBlock* zblock;
				if (mBranch == ASMIT_BEQ)
					zblock = mTrueJump;
				else
					zblock = mFalseJump;

				int i = 0;
				while (i < mEntryBlocks.Size())
				{
					NativeCodeBasicBlock* eblock = mEntryBlocks[i];
					int zp0 = eblock->RetrieveZPValue(mIns[0].mAddress, eblock->mIns.Size() - 1);
					int zp1 = eblock->RetrieveZPValue(mIns[1].mAddress, eblock->mIns.Size() - 1);

					if (zp0 == 0 || zp1 == 0)
					{
						if (eblock->mTrueJump == this)
						{
							mNumEntries--;
							mEntryBlocks.Remove(i);
							eblock->mTrueJump = zblock;
							zblock->mNumEntries++;
							zblock->mEntryBlocks.Push(eblock);
						}
						if (eblock->mFalseJump == this)
						{
							mNumEntries--;
							mEntryBlocks.Remove(i);
							eblock->mFalseJump = zblock;
							zblock->mNumEntries++;
							zblock->mEntryBlocks.Push(eblock);
						}

						changed = true;
					}
					else
						i++;
				}
			}
		}

		int sz = mIns.Size();
		if (sz > 0 && mIns[sz - 1].mType == ASMIT_BIT && mFalseJump && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			if (mBranch == ASMIT_BPL && mTrueJump == mFalseJump->mTrueJump && mFalseJump->mNumEntries == 1 && !mFalseJump->mFalseJump)
			{
				if (mFalseJump->mIns.Size() == 3 &&
					mFalseJump->mIns[0].mType == ASMIT_LDA &&
					mFalseJump->mIns[1].mType == ASMIT_ORA && mFalseJump->mIns[1].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[1].mAddress == 0x80 &&
					mFalseJump->mIns[2].mType == ASMIT_STA && mFalseJump->mIns[2].SameEffectiveAddress(mFalseJump->mIns[0]) &&
					!(mFalseJump->mIns[2].mLive & LIVE_CPU_REG_A))
				{
					mIns[sz - 1].mType = ASMIT_LDA; mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
					mIns.Push(NativeCodeInstruction(mFalseJump->mIns[0].mIns, ASMIT_AND, ASMIM_IMMEDIATE, 0x80));
					mIns.Push(NativeCodeInstruction(mFalseJump->mIns[0].mIns, ASMIT_ORA, mFalseJump->mIns[0]));
					mIns.Push(NativeCodeInstruction(mFalseJump->mIns[0].mIns, ASMIT_STA, mFalseJump->mIns[0]));
					mBranch = ASMIT_JMP;
					mFalseJump = nullptr;
					changed = true;
				}
			}
			else if (mBranch == ASMIT_BMI && mFalseJump == mTrueJump->mTrueJump && mTrueJump->mNumEntries == 1 && !mTrueJump->mFalseJump)
			{
				if (mTrueJump->mIns.Size() == 3 &&
					mTrueJump->mIns[0].mType == ASMIT_LDA &&
					mTrueJump->mIns[1].mType == ASMIT_ORA && mTrueJump->mIns[1].mMode == ASMIM_IMMEDIATE && mTrueJump->mIns[1].mAddress == 0x80 &&
					mTrueJump->mIns[2].mType == ASMIT_STA && mTrueJump->mIns[2].SameEffectiveAddress(mTrueJump->mIns[0]) &&
					!(mTrueJump->mIns[2].mLive & LIVE_CPU_REG_A))
				{
					mIns[sz - 1].mType = ASMIT_LDA; mIns[sz - 1].mLive |= LIVE_CPU_REG_A;
					mIns.Push(NativeCodeInstruction(mTrueJump->mIns[0].mIns, ASMIT_AND, ASMIM_IMMEDIATE, 0x80));
					mIns.Push(NativeCodeInstruction(mTrueJump->mIns[0].mIns, ASMIT_ORA, mTrueJump->mIns[0]));
					mIns.Push(NativeCodeInstruction(mTrueJump->mIns[0].mIns, ASMIT_STA, mTrueJump->mIns[0]));
					mBranch = ASMIT_JMP;
					mTrueJump = mFalseJump;
					mFalseJump = nullptr;
					changed = true;
				}
			}
		}


		if (mTrueJump && mTrueJump->JoinConditionSequence())
			changed = true;
		if (mFalseJump && mFalseJump->JoinConditionSequence())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::JoinCommonBranchCodeSequences(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 &&
			mTrueJump != this && mFalseJump != this &&
			mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
		{
			int i = 0;
			while (i < mTrueJump->mIns.Size())
			{
				int j = 0;
				while (j < mFalseJump->mIns.Size() && !mFalseJump->mIns[j].IsSame(mTrueJump->mIns[i]))
					j++;
				if (j < mFalseJump->mIns.Size())
				{
					int n = 0;
					int live = LIVE_CPU_REG_C | LIVE_CPU_REG_Z;

					while (i + n < mTrueJump->mIns.Size() && j + n < mFalseJump->mIns.Size() &&
						mTrueJump->mIns[i + n].IsSame(mFalseJump->mIns[j + n]))
					{
						if (mTrueJump->mIns[i + n].ChangesAccu()) live |= LIVE_CPU_REG_A;
						if (mTrueJump->mIns[i + n].ChangesXReg()) live |= LIVE_CPU_REG_X;
						if (mTrueJump->mIns[i + n].ChangesYReg()) live |= LIVE_CPU_REG_Y;

						if (!((mTrueJump->mIns[i + n].mLive & live) || (mFalseJump->mIns[j + n].mLive & live)))
							break;
						n++;
					}

					if (i + n < mTrueJump->mIns.Size() && j + n < mFalseJump->mIns.Size() && mTrueJump->mIns[i + n].IsSame(mFalseJump->mIns[j + n]))
					{
						if (mTrueJump->MayBeMovedBeforeBlock(i, i + n + 1) && mFalseJump->MayBeMovedBeforeBlock(j, j + n + 1))
						{
							if (SafeInjectSequenceFromBack(mTrueJump, i, i + n + 1))
							{
								for (int k = 0; k < i; k++)
									mTrueJump->mIns[k].mLive |= mTrueJump->mIns[i].mLive;
								for (int k = 0; k < j; k++)
									mFalseJump->mIns[k].mLive |= mFalseJump->mIns[j].mLive;
								if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_A)
								{
									mExitRequiredRegs += CPU_REG_A;
									mTrueJump->mEntryRequiredRegs += CPU_REG_A;
									mFalseJump->mEntryRequiredRegs += CPU_REG_A;
								}
								if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_X)
								{
									mExitRequiredRegs += CPU_REG_X;
									mTrueJump->mEntryRequiredRegs += CPU_REG_X;
									mFalseJump->mEntryRequiredRegs += CPU_REG_X;
								}
								if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_Y)
								{
									mExitRequiredRegs += CPU_REG_Y;
									mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
									mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
								}
								if (mTrueJump->mIns[i].mLive & LIVE_CPU_REG_C)
								{
									mExitRequiredRegs += CPU_REG_C;
									mTrueJump->mEntryRequiredRegs += CPU_REG_C;
									mFalseJump->mEntryRequiredRegs += CPU_REG_C;
								}

								mTrueJump->mIns.Remove(i, n + 1);
								mFalseJump->mIns.Remove(j, n + 1);
								changed = true;
							}
							else
								i++;
						}
						else
							i++;
					}
					else
						i++;
				}
				else
					i++;
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->JoinCommonBranchCodeSequences())
			changed = true;
		if (mFalseJump && mFalseJump->JoinCommonBranchCodeSequences())
			changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::DoCrossBlockAShortcut(int addr)
{
	mExitRequiredRegs += CPU_REG_A;
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		mIns[i].mLive |= LIVE_CPU_REG_A;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return;
	}
}

bool NativeCodeBasicBlock::CanCrossBlockAShortcut(int addr)
{
	if (mExitRequiredRegs[CPU_REG_A])
		return false;

	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		if (mIns[i].ChangesAccu())
			return false;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return true;

		if (mIns[i].ReferencesZeroPage(addr))
			return false;
	}

	return false;
}


void NativeCodeBasicBlock::DoCrossBlockXShortcut(int addr)
{
	mExitRequiredRegs += CPU_REG_X;
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		mIns[i].mLive |= LIVE_CPU_REG_X;
		if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAX));
			return;
		}
	}
}

bool NativeCodeBasicBlock::CanCrossBlockXShortcut(int addr)
{
	if (mExitRequiredRegs[CPU_REG_X])
		return false;

	bool	xref = 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 !xref;		
			
		if (mIns[i].ReferencesZeroPage(addr))
			return false;
		if (mIns[i].ReferencesXReg())
			xref = true;
	}

	return false;
}

void NativeCodeBasicBlock::DoCrossBlockYShortcut(int addr)
{
	mExitRequiredRegs += CPU_REG_Y;
	int i = mIns.Size();
	while (i > 0)
	{
		i--;
		mIns[i].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
			return;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_TAY));
			return;
		}
	}
}

bool NativeCodeBasicBlock::CanCrossBlockYShortcut(int addr)
{
	if (mExitRequiredRegs[CPU_REG_Y])
		return false;

	bool	yref = 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 !yref;

		if (mIns[i].ReferencesZeroPage(addr))
			return false;
		if (mIns[i].ReferencesYReg())
			yref = true;
	}

	return false;
}

bool NativeCodeBasicBlock::CrossBlockRegisterAlias(bool sameAX, bool sameAY)
{
	bool	changed = false;
	if (!mVisited)
	{
		assert(mLocked || mNumEntries == mEntryBlocks.Size());

		if (mLoopHead)
		{
			sameAX = false;
			sameAY = false;
		}
		else
		{
			if (mNumEntered == 0)
			{
				mSameAX = sameAX;
				mSameAY = sameAY;
			}
			else
			{
				if (!sameAX)
					mSameAX = false;
				if (!sameAY)
					mSameAY = false;
			}
			mNumEntered++;
			if (mNumEntered != mNumEntries)
				return false;
			sameAX = mSameAX;
			sameAY = mSameAY;
		}

		mVisited = true;

		bool	direct = false;
		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			switch (ins.mType)
			{
			case ASMIT_TAY:
				if (sameAY && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				sameAY = true;
				break;
			case ASMIT_TAX:
				if (sameAX && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				sameAX = true;
				break;
			case ASMIT_TYA:
				if (sameAY && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				sameAY = true;
				sameAX = false;
				direct = true;
				break;
			case ASMIT_TXA:
				if (sameAX && !(ins.mLive & LIVE_CPU_REG_Z))
				{
					ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				sameAY = false;
				sameAX = true;
				direct = true;
				break;
			case ASMIT_CMP:
				if (!(ins.mLive & LIVE_CPU_REG_A))
				{
					if (sameAY && (ins.mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(ASMIT_CPY, ins.mMode))
					{
						ins.mType = ASMIT_CPY;
						changed = true;
					}
					else if (sameAX && (ins.mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(ASMIT_CPX, ins.mMode))
					{
						ins.mType = ASMIT_CPX;
						changed = true;
					}
				}
				break;
			case ASMIT_CPX:
				if (!direct && !(ins.mLive & LIVE_CPU_REG_X))
				{
					if (sameAX && (ins.mLive & LIVE_CPU_REG_A))
					{
						ins.mType = ASMIT_CMP;
						changed = true;
					}
				}
				break;
			case ASMIT_CPY:
				if (!direct && !(ins.mLive & LIVE_CPU_REG_Y))
				{
					if (sameAY && (ins.mLive & LIVE_CPU_REG_A))
					{
						ins.mType = ASMIT_CMP;
						changed = true;
					}
				}
				break;
			default:
				if (ins.ChangesAccu())
				{
					sameAY = false;
					sameAX = false;
				}
				if (ins.ChangesXReg())
					sameAX = false;
				if (ins.ChangesYReg())
					sameAY = false;
				break;
			}
		}


		if (mTrueJump && mTrueJump->CrossBlockRegisterAlias(sameAX, sameAY))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockRegisterAlias(sameAX, sameAY))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockYAliasProgpagation(const int* yalias)
{
	bool changed = false;

	if (!mVisited)
	{
		if (mLoopHead || !yalias)
		{
			for (int i = 0; i < 256; i++)
				mYAlias[i] = -1;
		}
		else
		{
			if (mNumEntered == 0)
			{
				for (int i = 0; i < 256; i++)
					mYAlias[i] = yalias[i];
			}
			else
			{
				for (int i = 0; i < 256; i++)
					if (mYAlias[i] != yalias[i])
						mYAlias[i] = -1;
			}

			mNumEntered++;
			if (mNumEntered < mNumEntries)
				return false;
		}

		mVisited = true;

		int yoffset = 0;
		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (ins.mType == ASMIT_INY)
				yoffset = (yoffset + 1) & 0xff;
			else if (ins.mType == ASMIT_DEY)
				yoffset = (yoffset - 1) & 0xff;
			else if (ins.mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
				mYAlias[ins.mAddress] = yoffset;
			else if (ins.mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
				mYAlias[ins.mAddress] = -1;
			else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (mYAlias[ins.mAddress] != -1)
				{
					int diff = (mYAlias[ins.mAddress] - yoffset) & 0xff;
					if (diff == 0x01)
					{
						ins.mType = ASMIT_INY;
						ins.mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (diff == 0xff)
					{
						ins.mType = ASMIT_DEY;
						ins.mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (diff == 0x00 && !(ins.mLive & LIVE_CPU_REG_Z))
					{
						ins.mType = ASMIT_NOP;
						ins.mMode = ASMIM_IMPLIED;
						changed = true;
					}

					yoffset = mYAlias[ins.mAddress];
				}
				else
				{
					for (int i = 0; i < 256; i++)
						mYAlias[i] = -1;

					yoffset = 0;
					mYAlias[ins.mAddress] = yoffset;
				}
			}
			else if (ins.mType == ASMIT_TAY && i > 0 && (mIns[i - 1].mType == ASMIT_STA || mIns[i - 1].mType == ASMIT_LDA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE)
			{
				for (int i = 0; i < 256; i++)
					mYAlias[i] = -1;
				yoffset = 0;
				mYAlias[mIns[i - 1].mAddress] = yoffset;
			}
			else if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE && mYAlias[ins.mAddress] != -1 && i + 1 < mIns.Size())
			{
				if (mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mYAlias[ins.mAddress] == yoffset || !(mIns[i + 1].mLive & LIVE_CPU_REG_C)))
				{
					ins.mType = ASMIT_TYA;
					ins.mMode = ASMIM_IMPLIED;
					mIns[i + 1].mAddress = (mIns[i + 1].mAddress + mYAlias[ins.mAddress] - yoffset) & 0xff;
					changed = true;
				}
			}
			else if (ins.ChangesYReg())
			{
				for (int i = 0; i < 256; i++)
					mYAlias[i] = -1;
				yoffset = 0;
			}
		}

		if (yoffset > 0)
		{
			for (int i = 0; i < 256; i++)
			{
				if (mYAlias[i] >= 0)
					mYAlias[i] = (mYAlias[i] - yoffset) & 0xff;
					
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockYAliasProgpagation(mYAlias))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockYAliasProgpagation(mYAlias))
			changed = true;
	}

	return changed;
}


void NativeCodeBasicBlock::BypassAccuLoadStoreXY(void)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
			{
				if (!(mIns[i].mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && HasAsmInstructionMode(ASMIT_STX, mIns[i + 1].mMode))
				{
					mIns[i].mType = ASMIT_LDX; mIns[i].mLive |= LIVE_CPU_REG_X;
					mIns[i + 1].mType = ASMIT_STX;
				}
				else if (!(mIns[i].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode) && HasAsmInstructionMode(ASMIT_STY, mIns[i + 1].mMode))
				{
					mIns[i].mType = ASMIT_LDY; mIns[i].mLive |= LIVE_CPU_REG_Y;
					mIns[i + 1].mType = ASMIT_STY;
				}
			}
		}

		if (mTrueJump) mTrueJump->BypassAccuLoadStoreXY();
		if (mFalseJump) mFalseJump->BypassAccuLoadStoreXY();

	}
}


bool NativeCodeBasicBlock::CrossBlockXYShortcut(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (!mLoopHead && mEntryBlocks.Size() > 1)
		{
			CheckLive();

			bool	xvalid = !mEntryRequiredRegs[CPU_REG_X];
			bool	yvalid = !mEntryRequiredRegs[CPU_REG_Y];
			bool	avalid = !mEntryRequiredRegs[CPU_REG_A];

			int i = 0;
			while (i < mIns.Size() && (xvalid || yvalid || avalid))
			{
				if (xvalid && mIns[i].ChangesAccu())
				{
					if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						int k = i;
						while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
							k--;
						if (k == 0)
						{
							k = 0;
							while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockAShortcut(mIns[i].mAddress))
								k++;
							if (k == mEntryBlocks.Size())
							{
								for (int k = 0; k < mEntryBlocks.Size(); k++)
									mEntryBlocks[k]->DoCrossBlockAShortcut(mIns[i].mAddress);
								changed = true;
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								mEntryRequiredRegs += CPU_REG_A;
								for (int k = 0; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_A;
							}
						}
					}
					xvalid = false;
				}
				if (xvalid && mIns[i].ChangesXReg())
				{
					if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						int k = i;
						while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
							k--;
						if (k == 0)
						{
							k = 0;
							while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockXShortcut(mIns[i].mAddress))
								k++;
							if (k == mEntryBlocks.Size())
							{
								for (int k = 0; k < mEntryBlocks.Size(); k++)
									mEntryBlocks[k]->DoCrossBlockXShortcut(mIns[i].mAddress);
								changed = true;
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								mEntryRequiredRegs += CPU_REG_X;
								for (int k = 0; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_X;
							}
						}
					}
					xvalid = false;
				}
				if (yvalid && mIns[i].ChangesYReg())
				{
					if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						int k = i;
						while (k > 0 && !mIns[k - 1].ReferencesZeroPage(mIns[i].mAddress))
							k--;
						if (k == 0)
						{
							k = 0;
							while (k < mEntryBlocks.Size() && mEntryBlocks[k]->CanCrossBlockYShortcut(mIns[i].mAddress))
								k++;
							if (k == mEntryBlocks.Size())
							{
								for (int k = 0; k < mEntryBlocks.Size(); k++)
									mEntryBlocks[k]->DoCrossBlockYShortcut(mIns[i].mAddress);
								changed = true;
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								mEntryRequiredRegs += CPU_REG_Y;
								for (int k = 0; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_Y;
							}
						}
					}
					yvalid = false;
				}

				i++;
			}

			CheckLive();
		}

		if (mTrueJump && mTrueJump->CrossBlockXYShortcut())
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockXYShortcut())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockIncToZeroShortcut(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int sz = mIns.Size();
		if (mFalseJump && mIns.Size() > 0 && mIns[sz - 1].mType == ASMIT_INC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
		{
			NativeCodeBasicBlock* eblock = nullptr, * nblock = nullptr;

			if (mBranch == ASMIT_BNE)
			{
				eblock = mFalseJump;
				nblock = mTrueJump;
			}
			else if (mBranch == ASMIT_BEQ)
			{
				eblock = mTrueJump;
				nblock = mFalseJump;
			}
			if (eblock && !eblock->mFalseJump && eblock->mTrueJump == nblock && !eblock->ChangesZeroPage(mIns[sz - 1].mAddress))
			{
				if (nblock->mIns.Size() == 2 &&
					nblock->mFalseJump &&
					(nblock->mIns[0].mType == ASMIT_LDA || nblock->mIns[0].mType == ASMIT_TXA || nblock->mIns[0].mType == ASMIT_TYA) &&
					nblock->mIns[1].mType == ASMIT_ORA)
				{
					if (nblock->mIns[0].SameEffectiveAddress(mIns[sz - 1]) || nblock->mIns[1].SameEffectiveAddress(mIns[sz - 1]))
					{
						NativeCodeBasicBlock* tblock = nullptr;
						if (nblock->mBranch == ASMIT_BNE)
							tblock = nblock->mTrueJump;
						else if (nblock->mBranch == ASMIT_BEQ)
							tblock = nblock->mFalseJump;

						if (tblock && !tblock->mEntryRequiredRegs[CPU_REG_A])
						{
							tblock->AddEntryBlock(this);
							nblock->RemEntryBlock(this);
							if (mBranch == ASMIT_BNE)
								mTrueJump = tblock;
							else
								mFalseJump = tblock;
							changed = true;
						}
					}
				}
			}
		}
		else if (mFalseJump && sz >= 8 && 
			mIns[sz - 8].mType == ASMIT_CLC && 
			mIns[sz - 7].mType == ASMIT_LDA && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE && mIns[sz - 6].mAddress == 1 &&
			mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].mMode == ASMIM_ZERO_PAGE && mIns[sz - 5].mAddress == mIns[sz - 7].mAddress &&
			mIns[sz - 4].mType == ASMIT_LDA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
			mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 4].mAddress &&
			mIns[sz - 1].mType == ASMIT_ORA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 7].mAddress)
		{
			NativeCodeBasicBlock* eblock = nullptr, * nblock = nullptr;

			if (mBranch == ASMIT_BNE)
			{
				eblock = mFalseJump;
				nblock = mTrueJump;
			}
			else if (mBranch == ASMIT_BEQ)
			{
				eblock = mTrueJump;
				nblock = mFalseJump;
			}

			if (nblock && !nblock->mEntryRequiredRegs[CPU_REG_A])
			{
				NativeCodeBasicBlock* iblock = mProc->AllocateBlock();
				iblock->AddEntryBlock(this);
				iblock->mIns.Push(mIns[sz - 8]);
				iblock->mIns.Push(mIns[sz - 4]);
				iblock->mIns.Push(mIns[sz - 6]);
				iblock->mIns.Push(mIns[sz - 2]);
				iblock->Close(mIns[sz - 1].mIns, nblock, eblock, ASMIT_BNE);

				nblock->AddEntryBlock(iblock);
				eblock->AddEntryBlock(iblock);

				iblock->mIns[2].mLive |= LIVE_CPU_REG_Z;
				iblock->mIns[3].mLive |= LIVE_CPU_REG_Z;

				mIns[sz - 6].mLive |= LIVE_CPU_REG_Z;
				mIns[sz - 5].mLive |= LIVE_CPU_REG_Z;

				mIns.SetSize(sz - 4);
				mTrueJump = nblock;
				mFalseJump = iblock;
				mBranch = ASMIT_BNE;

				mExitRequiredRegs += CPU_REG_C;

				CheckLive();

				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockIncToZeroShortcut())
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockIncToZeroShortcut())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockXYPreservation(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && mTrueJump->mTrueJump && !mTrueJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump &&
			mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2)
		{
			NativeCodeBasicBlock* tblock = mTrueJump, * fblock = mFalseJump;

			if (!mExitRequiredRegs[CPU_REG_Y] && !fblock->mEntryRequiredRegs[CPU_REG_X])
			{
				int si = mIns.Size() - 1;
				while (si >= 0 && !mIns[si].ChangesXReg())
					si--;

				if (si >= 0 && mIns[si].mType == ASMIT_LDX && mIns[si].mMode == ASMIM_ZERO_PAGE)
				{
					int	addr = mIns[si].mAddress;

					int i = si;
					while (i < mIns.Size() && !mIns[i].ChangesZeroPage(addr))
						i++;
					if (i == mIns.Size())
					{
						int fi = 0;
						while (fi < fblock->mIns.Size() && !fblock->mIns[fi].ChangesXReg())
							fi++;
						if (fi < fblock->mIns.Size() && fblock->mIns[fi].mType == ASMIT_LDX && fblock->mIns[fi].mMode == ASMIM_ZERO_PAGE && fblock->mIns[fi].mAddress == addr)
						{
							i = 0;
							while (i < fi && !fblock->mIns[i].ChangesZeroPage(addr))
								i++;
							if (i == fi)
							{
								int ti = 0;
								while (ti < tblock->mIns.Size() && !tblock->mIns[ti].ChangesXReg())
									ti++;
								if (ti < tblock->mIns.Size())
								{
									int i = 0;
									while (i < tblock->mIns.Size() && !tblock->mIns[i].ChangesYReg() && !tblock->mIns[i].ChangesZeroPage(addr))
										i++;

									if (i == tblock->mIns.Size())
									{
										tblock->ReplaceXRegWithYReg(ti, tblock->mIns.Size());
										changed = true;
									}
								}
							}
						}
					}
				}
			}
		}


		if (mTrueJump && mTrueJump->CrossBlockXYPreservation())
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockXYPreservation())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::EliminateMicroBlocks(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mIns.Size() > 0 && mIns.Size() <= 2 && mTrueJump && !mFalseJump)
		{
			if (mIns[0].mType == ASMIT_STA && !(mIns[0].mLive & LIVE_CPU_REG_A))
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					NativeCodeBasicBlock* block = mEntryBlocks[i];
					int sz = block->mIns.Size();
					if (sz > 0 && !block->mFalseJump)
					{
						if (block->mIns[sz - 1].mType == ASMIT_TYA && HasAsmInstructionMode(ASMIT_STY, mIns[0].mMode))
						{
							block->mIns[sz - 1] = NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]);
							if (mIns.Size() > 1)
								block->mIns.Push(mIns[1]);
							block->mTrueJump->RemEntryBlock(block);
							mTrueJump->AddEntryBlock(block);
							block->mTrueJump = mTrueJump;
							changed = true;
						}
						else if (block->mIns[sz - 1].mType == ASMIT_TXA && HasAsmInstructionMode(ASMIT_STX, mIns[0].mMode))
						{
							block->mIns[sz - 1] = NativeCodeInstruction(mIns[0].mIns, ASMIT_STX, mIns[0]);
							if (mIns.Size() > 1)
								block->mIns.Push(mIns[1]);
							block->mTrueJump->RemEntryBlock(block);
							mTrueJump->AddEntryBlock(block);
							block->mTrueJump = mTrueJump;
							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->EliminateMicroBlocks())
			changed = true;
		if (mFalseJump && mFalseJump->EliminateMicroBlocks())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CombineAlternateLoads(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && 
			mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
			mTrueJump->mTrueJump == mFalseJump->mTrueJump &&
			!mTrueJump->mFalseJump && !mFalseJump->mFalseJump &&
			mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
		{
			if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
				mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
			{
				mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
				mIns.Push(mFalseJump->mIns[0]);
				mFalseJump->mIns.Remove(0);
				mExitRequiredRegs += CPU_REG_A;
				mFalseJump->mEntryRequiredRegs += CPU_REG_A;
				changed = true;
			}
			else if (mTrueJump->mIns[0].mType == ASMIT_LDX && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
				mFalseJump->mIns[0].mType == ASMIT_LDX && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
			{
				mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
				mIns.Push(mFalseJump->mIns[0]);
				mFalseJump->mIns.Remove(0);
				mExitRequiredRegs += CPU_REG_X;
				mFalseJump->mEntryRequiredRegs += CPU_REG_X;
				changed = true;
			}
			else if (mTrueJump->mIns[0].mType == ASMIT_LDY && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
				mFalseJump->mIns[0].mType == ASMIT_LDY && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
			{
				mFalseJump->mIns[0].mLive |= LIVE_CPU_REG_C;
				mIns.Push(mFalseJump->mIns[0]);
				mFalseJump->mIns.Remove(0);
				mExitRequiredRegs += CPU_REG_Y;
				mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->CombineAlternateLoads())
			changed = true;
		if (mFalseJump && mFalseJump->CombineAlternateLoads())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::FoldLoopEntry(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump && mIns.Size() >= 1)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 1].mType == ASMIT_LDA)
			{
				if (mTrueJump->mIns.Size() == 1 && mTrueJump != this)
				{
					if (mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[sz - 1]))
					{
						if (mBranch == mTrueJump->mBranch &&  mFalseJump == mTrueJump->mFalseJump && mTrueJump == mTrueJump->mTrueJump ||
							mBranch == InvertBranchCondition(mTrueJump->mBranch) && mFalseJump == mTrueJump->mTrueJump && mTrueJump == mTrueJump->mFalseJump)
						{
							mIns[sz - 1].mType = ASMIT_NOP;
							mIns[sz - 1].mMode = ASMIM_IMPLIED;
							mBranch = ASMIT_JMP;
							mFalseJump->RemEntryBlock(this);
							mFalseJump = nullptr;
							changed = true;
						}
					}
				}
				if (!changed && mFalseJump->mIns.Size() == 1 && mFalseJump != this)
				{
					if (mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].SameEffectiveAddress(mIns[sz - 1]))
					{
						if (mBranch == mFalseJump->mBranch && mFalseJump == mFalseJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump ||
							mBranch == InvertBranchCondition(mFalseJump->mBranch) && mFalseJump == mFalseJump->mTrueJump && mTrueJump == mFalseJump->mFalseJump)
						{
							mIns[sz - 1].mType = ASMIT_NOP;
							mIns[sz - 1].mMode = ASMIM_IMPLIED;
							mBranch = ASMIT_JMP;
							mTrueJump->RemEntryBlock(this);
							mTrueJump = mFalseJump;
							mFalseJump = nullptr;
							changed = true;
						}
					}
				}
			}
		}
		if (!changed && mTrueJump && mFalseJump && mIns.Size() >= 2)
		{
			int	sz = mIns.Size();

			if (mIns[sz - 2].mType == ASMIT_LDA && ((mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE) || (mIns[sz - 1].IsShift() && mIns[sz - 1].mMode == ASMIM_IMPLIED)))
			{
				if (mTrueJump->mIns.Size() == 2 && mTrueJump != this)
				{
					if (mTrueJump->mIns[0].IsSame(mIns[sz - 2]) && mTrueJump->mIns[1].IsSame(mIns[sz - 1]))
					{
						if (mBranch == mTrueJump->mBranch && mFalseJump == mTrueJump->mFalseJump && mTrueJump == mTrueJump->mTrueJump ||
							mBranch == InvertBranchCondition(mTrueJump->mBranch) && mFalseJump == mTrueJump->mTrueJump && mTrueJump == mTrueJump->mFalseJump)
						{
							mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
							mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
							mBranch = ASMIT_JMP;
							mFalseJump->RemEntryBlock(this);
							mFalseJump = nullptr;
							changed = true;
						}
					}
				}
				if (!changed && mFalseJump->mIns.Size() == 2 && mFalseJump != this)
				{
					if (mFalseJump->mIns[0].IsSame(mIns[sz - 2]) && mFalseJump->mIns[1].IsSame(mIns[sz - 1]))
					{
						if (mBranch == mFalseJump->mBranch && mFalseJump == mFalseJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump ||
							mBranch == InvertBranchCondition(mFalseJump->mBranch) && mFalseJump == mFalseJump->mTrueJump && mTrueJump == mFalseJump->mFalseJump)
						{
							mIns[sz - 1].mType = ASMIT_NOP;
							mIns[sz - 1].mMode = ASMIM_IMPLIED;
							mBranch = ASMIT_JMP;
							mTrueJump->RemEntryBlock(this);
							mTrueJump = mFalseJump;
							mFalseJump = nullptr;
							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->FoldLoopEntry())
			changed = true;
		if (mFalseJump && mFalseJump->FoldLoopEntry())
			changed = true;
	}
	
	return changed;
}

bool NativeCodeBasicBlock::BypassRegisterConditionBlock(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;
		
		if (mTrueJump && mFalseJump && mIns.Size() > 0)
		{			
			NativeCodeBasicBlock* eblock = nullptr, * cblock = nullptr;

			if (mTrueJump->mTrueJump == mFalseJump && !mTrueJump->mFalseJump)
			{
				cblock = mTrueJump;
				eblock = mFalseJump;
			}
			else if (mFalseJump->mTrueJump == mTrueJump && !mFalseJump->mFalseJump)
			{
				cblock = mFalseJump;
				eblock = mTrueJump;
			}

			if (cblock && cblock->mNumEntries == 1 && eblock->mNumEntries == 2)
			{
				if (cblock->mIns.Size() > 0 && !cblock->mEntryRequiredRegs[CPU_REG_Y] && 
					mIns.Last().mType == ASMIT_TAY && cblock->mIns.Last().mType == ASMIT_TAY && !(mIns.Last().mLive & LIVE_CPU_REG_Z))
				{
					eblock->mIns.Insert(0, NativeCodeInstruction(mIns.Last().mIns, ASMIT_TAY));
					mIns[mIns.Size() - 1].mType = ASMIT_NOP;
					cblock->mIns[cblock->mIns.Size() - 1].mType = ASMIT_NOP;

					mExitRequiredRegs += CPU_REG_A;
					cblock->mExitRequiredRegs += CPU_REG_A;
					eblock->mEntryRequiredRegs += CPU_REG_A;
					changed = true;
				}
				if (cblock->mIns.Size() > 0 && !cblock->mEntryRequiredRegs[CPU_REG_X] &&
					mIns.Last().mType == ASMIT_TAX && cblock->mIns.Last().mType == ASMIT_TAX && !(mIns.Last().mLive & LIVE_CPU_REG_Z))
				{
					eblock->mIns.Insert(0, NativeCodeInstruction(mIns.Last().mIns, ASMIT_TAX));
					mIns[mIns.Size() - 1].mType = ASMIT_NOP;
					cblock->mIns[cblock->mIns.Size() - 1].mType = ASMIT_NOP;

					mExitRequiredRegs += CPU_REG_A;
					cblock->mExitRequiredRegs += CPU_REG_A;
					eblock->mEntryRequiredRegs += CPU_REG_A;
					changed = true;
				}

#if 0
				if (cblock->mIns.Size() >= 1 && eblock->mIns.Size() >= 1)
				{
					int	csz = cblock->mIns.Size() - 1;

					if (cblock->mIns[csz].mType == ASMIT_LDA && cblock->mIns[csz].mMode == ASMIM_ZERO_PAGE &&
						eblock->mIns[0].mType == ASMIT_STA && eblock->mIns[0].mMode == ASMIM_ZERO_PAGE && eblock->mIns[0].mAddress == cblock->mIns[csz].mAddress && !(eblock->mIns[0].mLive & LIVE_CPU_REG_A))
					{
						mIns.Push(NativeCodeInstruction(ASMIT_STA, eblock->mIns[0]));
						cblock->mIns.Remove(csz);
						cblock->mExitRequiredRegs -= CPU_REG_A;
						changed = true;
					}
				}
#endif
				if (mExitRequiredRegs[CPU_REG_A])
				{
					if (!cblock->ReferencesAccu())
					{
						int i = mIns.Size() - 1;
						while (i >= 0 && !mIns[i].ReferencesAccu())
							i--;
						if (i >= 0 && mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
						{
							if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
							{
								eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, mIns[i]));
								mIns.Remove(i);
								changed = true;
								mExitRequiredRegs -= CPU_REG_A;
								CheckLive();
							}
						}
					}
					else if (!eblock->mEntryRequiredRegs[CPU_REG_A])
					{
						int i = mIns.Size() - 1;
						while (i >= 0 && !mIns[i].ReferencesAccu())
							i--;
						if (i >= 0 && mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
						{
							if (!ChangesXReg(i + 1))
							{
								cblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA));
								mIns.Remove(i);
								while (i < mIns.Size())
									mIns[i++].mLive |= LIVE_CPU_REG_X;

								changed = true;
								mExitRequiredRegs -= CPU_REG_A;
								mExitRequiredRegs += CPU_REG_X;
								cblock->mEntryRequiredRegs += CPU_REG_X;
								CheckLive();
							}
						}
						else if (i >= 0 && mIns[i].mType == ASMIT_TYA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
						{
							if (!ChangesYReg(i + 1))
							{
								cblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA));
								mIns.Remove(i);
								while (i < mIns.Size())
									mIns[i++].mLive |= LIVE_CPU_REG_Y;

								changed = true;
								mExitRequiredRegs -= CPU_REG_A;
								mExitRequiredRegs += CPU_REG_Y;
								cblock->mEntryRequiredRegs += CPU_REG_Y;
								CheckLive();
							}
						}
					}
				}

				if (mExitRequiredRegs[CPU_REG_Y])
				{
					if (!cblock->ReferencesYReg())
					{
						int i = mIns.Size() - 1;
						while (i >= 0 && !mIns[i].ReferencesYReg())
							i--;
						if (i >= 0 && mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
						{
							if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
							{
								eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, mIns[i]));
								mIns.Remove(i);
								changed = true;
								mExitRequiredRegs -= CPU_REG_Y;
								CheckLive();
							}
						}
					}
				}

				if (mExitRequiredRegs[CPU_REG_X])
				{
					if (!cblock->ReferencesXReg())
					{
						int i = mIns.Size() - 1;
						while (i >= 0 && !mIns[i].ReferencesXReg())
							i--;
						if (i >= 0 && mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
						{
							if (!ChangesZeroPage(mIns[i].mAddress, i + 1) && !cblock->ChangesZeroPage(mIns[i].mAddress))
							{
								eblock->mIns.Insert(0, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i]));
								mIns.Remove(i);
								changed = true;
								mExitRequiredRegs -= CPU_REG_X;
								CheckLive();
							}
						}
					}
				}

#if 1
				CheckLive();

				if (eblock->mIns.Size() > 0 && eblock->mIns[0].mType == ASMIT_LDY && eblock->mIns[0].mMode == ASMIM_ZERO_PAGE && 
					!(eblock->mIns[0].mLive & LIVE_MEM) && !cblock->ReferencesYReg() && cblock->mIns.Size() > 0 && !mExitRequiredRegs[CPU_REG_Y])
				{
					NativeCodeInstruction& ins = cblock->mIns[cblock->mIns.Size() - 1];
					if ((ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) && ins.SameEffectiveAddress(eblock->mIns[0]) && !ChangedOnPath(cblock, 0, cblock->mIns.Size() - 1, ins.mAddress))
					{
						int	i = mIns.Size();
						bool	fail = false;
						while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
						{
							if (mIns[i - 1].ReferencesYReg() || mIns[i - 1].ChangesZeroPage(ins.mAddress))
							{
								fail = true;
								break;
							}
							i--;
						}

						if (!fail)
						{
							mIns.Insert(i, eblock->mIns[0]);
							mIns[i].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C;

							eblock->mIns.Remove(0);
							if (ins.mType == ASMIT_INC)
								ins.mType = ASMIT_INY;
							else if (ins.mType == ASMIT_DEC)
								ins.mType = ASMIT_DEY;
							ins.mMode = ASMIM_IMPLIED;

							while (i < mIns.Size())
							{
								mIns[i].mLive |= LIVE_CPU_REG_Y;
								i++;
							}

							for (i = 0; i < cblock->mIns.Size(); i++)
								cblock->mIns[i].mLive |= LIVE_CPU_REG_Y;
							changed = true;							
							cblock->mEntryRequiredRegs += CPU_REG_Y;
							cblock->mExitRequiredRegs += CPU_REG_Y;
							eblock->mEntryRequiredRegs += CPU_REG_Y;
							CheckLive();
						}
					}
				}
#endif
			}
		}
			

		if (mTrueJump && mTrueJump->BypassRegisterConditionBlock())
			changed = true;
		if (mFalseJump && mFalseJump->BypassRegisterConditionBlock())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::FindPageStartAddress(int at, int reg, int& addr)
{
	int	j = at - 2;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_IMMEDIATE && 
			mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg + 1)
		{
			addr = mIns[j + 0].mAddress << 8;
			return true;
		}
		if (mIns[j + 1].mMode == ASMIM_ZERO_PAGE && (mIns[j + 1].mAddress == reg || mIns[j + 1].mAddress == reg + 1) && mIns[j + 1].ChangesAddress())
			return false;
		if (mIns[j + 1].mType == ASMIT_JSR)
			return false;

		j--;
	}

	if (mFromJump)
		return mFromJump->FindPageStartAddress(mFromJump->mIns.Size(), reg, addr);
	else
		return false;
}

bool NativeCodeBasicBlock::FindGlobalAddress(int at, int reg, int& apos)
{
	int j = at - 4;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 0].mFlags & NCIF_LOWER) && mIns[j + 0].mLinkerObject &&
			mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg &&
			mIns[j + 2].mType == ASMIT_LDA && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_UPPER) && mIns[j + 2].mLinkerObject == mIns[j + 0].mLinkerObject &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg + 1)
		{
			apos = j + 0;
			return true;
		}
		if (mIns[j + 3].mMode == ASMIM_ZERO_PAGE && (mIns[j + 3].mAddress == reg || mIns[j + 3].mAddress == reg + 1) && mIns[j + 3].ChangesAddress())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::FindImmediateStore(int at, int reg, const NativeCodeInstruction*& ains)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_LDA && (mIns[j + 0].mMode == ASMIM_IMMEDIATE || mIns[j + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
			mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == reg)
		{
			ains = &(mIns[j + 0]);
			return true;
		}
		else if (mIns[j + 1].ChangesZeroPage(reg))
			return false;
		j--;
	}

	return false;
}

int NativeCodeBasicBlock::FindImmediateGlobalStore(int at, const NativeCodeInstruction& ins)
{
	at--;
	while (at >= 0 && !ins.MayBeChangedOnAddress(mIns[at]))
		at--;
	if (at > 0 && mIns[at].mMode == ASMIM_ABSOLUTE && mIns[at].mLinkerObject == ins.mLinkerObject && mIns[at].mAddress == ins.mAddress &&
		mIns[at - 1].mType == ASMIT_LDA && mIns[at - 1].mMode == ASMIM_IMMEDIATE)
	{
		return mIns[at - 1].mAddress;
	}
	if (at < 0 && mEntryBlocks.Size() == 1)
		return mEntryBlocks[0]->FindImmediateGlobalStore(mEntryBlocks[0]->mIns.Size(), ins);

	return -1;
}

bool NativeCodeBasicBlock::CheckPatchFailUse(void)
{
	if (mPatchStart)
		return true;

	if (mPatchChecked)
		return false;

	if (!mPatchFail)
	{
		mPatchFail = true;

		if (mTrueJump && !mTrueJump->CheckPatchFailUse())
			return false;
		if (mFalseJump && !mFalseJump->CheckPatchFailUse())
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg)
{
	if (mPatched && mEntryRequiredRegs[reg])
		return false;

	if (!mPatchFail)
	{
		mPatchFail = true;

		if (this != block)
		{
			if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
				return false;
			if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
				return false;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::CheckPatchFailRegPair(const NativeCodeBasicBlock* block, int reg)
{
	if (mPatched && (mEntryRequiredRegs[reg] || mEntryRequiredRegs[reg + 1]))
		return false;

	if (!mPatchFail)
	{
		mPatchFail = true;

		if (this != block)
		{
			if (mTrueJump && !mTrueJump->CheckPatchFailRegPair(block, reg))
				return false;
			if (mFalseJump && !mFalseJump->CheckPatchFailRegPair(block, reg))
				return false;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains, int cycles)
{
	if (!mPatched)
	{
		if (at == 0)
		{
			mPatched = true;

			if (!mEntryRequiredRegs[reg])
			{
				mPatchFail = true;

//				if (mExitRequiredRegs[reg])
				{
					if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
						return false;
					if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
						return false;
				}
				return true;
			}

			assert(mNumEntries == mEntryBlocks.Size());

			if (mNumEntries > 1)
			{
				if (mLoopHead)
					return false;

				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->IsDominatedBy(block))
						return false;
			}
		}

		if (mPatchFail)
			return false;

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ains.mFlags & ins.mFlags & NCIF_VOLATILE)
				return false;

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.UsesAddress())
				{
					if (ins.ChangesAddress())
						return false;
					if (!HasAsmInstructionMode(ins.mType, ains.mMode))
						return false;
					if (ins.mLive & LIVE_MEM)
					{
						cycles--;
						if (cycles == 0)
							return false;
					}
					else
					{
//						if (mExitRequiredRegs[reg])
						{
							if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
								return false;
							if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
								return false;
						}

						return true;
					}
				}
				else
				{
//					if (mExitRequiredRegs[reg])
					{
						if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg))
							return false;
						if (mFalseJump && !mFalseJump->CheckPatchFailReg(block, reg))
							return false;
					}

					return true;
				}
			}
			else if (ins.mType == ASMIT_JSR)
			{
				if (ains.mMode == ASMIM_ABSOLUTE_X || ains.mMode == ASMIM_ABSOLUTE_Y || ains.mMode == ASMIM_INDIRECT_Y)
					return false;
				else if (ins.mFlags & NCIF_RUNTIME)
				{
					if (ins.UsesZeroPage(reg))
						return false;
				}
				else if (ains.mFlags & NCIF_VOLATILE)
					return false;
				else if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_NO_GLOBAL_STORES) && !ins.UsesZeroPage(reg))
				{

				}
				else
					return false;
			}
			else if (ains.mMode == ASMIM_ABSOLUTE_X && ins.ChangesXReg())
				return false;
			else if (ains.mMode == ASMIM_ABSOLUTE_Y && ins.ChangesYReg())
				return false;
			else if (ains.mMode == ASMIM_INDIRECT_Y && (ins.ChangesYReg() || ins.ChangesZeroPage(ains.mAddress) || ins.ChangesZeroPage(ains.mAddress + 1)))
				return false;
			else if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress + 1 == reg))
				return false;
			else if (ins.ChangesZeroPage(reg))
				return true;
			else if (ains.MayBeChangedOnAddress(ins))
				return false;

			at++;
		}

		if (mTrueJump && !mTrueJump->CheckSingleUseGlobalLoad(block, reg, 0, ains, cycles))
			return false;
		if (mFalseJump && !mFalseJump->CheckSingleUseGlobalLoad(block, reg, 0, ains, cycles))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0 && !mEntryRequiredRegs[reg])
			return false;

		if (at == 0)
		{
			if (ains.RequiresXReg())
				mEntryRequiredRegs += CPU_REG_X;
			if (ains.RequiresYReg())
				mEntryRequiredRegs += CPU_REG_Y;
			if (ains.mMode == ASMIM_INDIRECT_Y)
			{
				mEntryRequiredRegs += ains.mAddress;
				mEntryRequiredRegs += ains.mAddress + 1;
			}
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.UsesAddress())
				{
					ins.CopyMode(ains);
					if (!(ins.mLive & LIVE_MEM))
					{
						if (ains.mMode == ASMIM_INDIRECT_Y)
							ins.mLive |= LIVE_MEM;
						return true;
					}
					changed = true;
				}
				else
					return changed;
			}

			if (ains.mMode == ASMIM_ABSOLUTE_X)
				ins.mLive |= LIVE_CPU_REG_X;
			if (ains.mMode == ASMIM_ABSOLUTE_Y || ains.mMode == ASMIM_INDIRECT_Y)
				ins.mLive |= LIVE_CPU_REG_Y;
			if (ains.mMode == ASMIM_INDIRECT_Y)
				ins.mLive |= LIVE_MEM;

			at++;
		}

		if (ains.RequiresXReg())
			mExitRequiredRegs += CPU_REG_X;
		if (ains.RequiresYReg())
			mExitRequiredRegs += CPU_REG_Y;
		if (ains.mMode == ASMIM_INDIRECT_Y)
		{
			mExitRequiredRegs += ains.mAddress;
			mExitRequiredRegs += ains.mAddress + 1;
		}

		if (mTrueJump && mTrueJump->PatchSingleUseGlobalLoad(block, reg, 0, ains))
			changed = true;
		if (mFalseJump && mFalseJump->PatchSingleUseGlobalLoad(block, reg, 0, ains))
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::CheckSingleUseGlobalLoadStruct(const NativeCodeBasicBlock* block, const NativeCodeInstruction& rins, int at, const NativeCodeInstruction& ains, bool cleared, bool poisoned)
{
	bool	ok = true;
	if (!mPatched)
	{
		if (at == 0)
			mPatched = true;

		if (this != block && !IsDominatedBy(block))
			poisoned = true;

		bool	used = false;

		for (int i = at; i < mIns.Size() && !cleared; i++)
		{
			const NativeCodeInstruction& ins(mIns[i]);

			if (ins.SameEffectiveAddress(rins))
			{
				if ((ins.mType == ASMIT_LDA || ins.mType == ASMIT_LDX || ins.mType == ASMIT_LDY) && HasAsmInstructionMode(ins.mType, ains.mMode))
				{
					if (poisoned)
						return false;
					used = true;
				}
				else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY)
				{
					cleared = true;
					poisoned = false;
				}
				else
					return false;
//					poisoned = true;
			}
			else if (poisoned && rins.MayBeSameAddress(ins))
				return false;
			else if (rins.MayBeChangedOnAddress(ins, true) || ains.MayBeChangedOnAddress(ins, true))
				poisoned = true;
			else if (ins.ChangesXReg() && ains.ReferencesXReg() || ins.ChangesYReg() && ains.ReferencesYReg())
				poisoned = true;
		}

		if (this == block && at == 0)
		{
			mPatchUsed = used;
		}
		else
		{
			mPatchUsed = used || !cleared;

			if (mTrueJump && !mTrueJump->CheckSingleUseGlobalLoadStruct(block, rins, 0, ains, cleared, poisoned))
				return false;
			if (mFalseJump && !mFalseJump->CheckSingleUseGlobalLoadStruct(block, rins, 0, ains, cleared, poisoned))
				return false;

			mPatchUsed = used || (mTrueJump && mTrueJump->mPatchUsed) || (mFalseJump && mFalseJump->mPatchUsed);
		}
	}
	else if (mPatchUsed && (poisoned || cleared))
		return false;

	return true;
}

bool NativeCodeBasicBlock::PatchSingleUseGlobalLoadStruct(const NativeCodeBasicBlock* block, const NativeCodeInstruction& rins, int at, const NativeCodeInstruction& ains)
{
	bool	changed = false;
	if (!mPatched)
	{
		if (at == 0)
			mPatched = true;

		int		finat = 0;
		bool	cleared = false;
		for (int i = at; i < mIns.Size() && !cleared; i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.SameEffectiveAddress(rins))
			{
				if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_LDX || ins.mType == ASMIT_LDY)
				{
					finat = i;
					ins.CopyMode(ains);
					changed = true;
				}
				else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY)
					cleared = true;
			}
		}

		if (!cleared)
		{
			if (mTrueJump && mTrueJump->PatchSingleUseGlobalLoadStruct(block, rins, 0, ains))
			{
				finat = mIns.Size();
				changed = true;
			}
			if (mFalseJump && mFalseJump->PatchSingleUseGlobalLoadStruct(block, rins, 0, ains))
			{
				finat = mIns.Size();
				changed = true;
			}
		}

		if (changed)
		{
			int	live = 0;
			if (ains.mMode == ASMIM_ABSOLUTE_X)
			{
				live |= LIVE_CPU_REG_X;
				if (at == 0)
					mEntryRequiredRegs += CPU_REG_X;
				if (finat == mIns.Size())
					mExitRequiredRegs += CPU_REG_X;

			}
			else if (ains.mMode == ASMIM_ABSOLUTE_Y || ains.mMode == ASMIM_INDIRECT_Y)
			{
				live |= LIVE_CPU_REG_Y;
				if (at == 0)
					mEntryRequiredRegs += CPU_REG_Y;
				if (finat == mIns.Size())
					mExitRequiredRegs += CPU_REG_Y;
			}

			if (live)
			{
				for (int i = at; i < finat; i++)
					mIns[i].mLive |= live;
			}
		}
	}

	return changed;
}


bool NativeCodeBasicBlock::CheckForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
	// Checking only current block as first optimization step

	while (at < mIns.Size())
	{
		NativeCodeInstruction& ins(mIns[at]);

		if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == yreg))
			return false;
		else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
		{
			if (yval != 0)
				return false;
			else if (!(ins.mLive & LIVE_MEM))
				return true;
		}

		if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
			yval = ins.mAddress;
		else if (ins.mType == ASMIT_INY && yval >= 0)
			yval = (yval + 1) & 255;
		else if (ins.mType == ASMIT_DEY && yval >= 0)
			yval = (yval - 1) & 255;
		else if (ins.mType == ASMIT_JSR)
		{
			if (ins.UsesZeroPage(reg) || ins.ChangesZeroPage(yreg))
				return false;
			yval = -1;
		}
		else if (ins.ChangesZeroPage(reg) || ins.ChangesZeroPage(yreg))
			return false;
		else if (ins.ChangesYReg())
			yval = -1;

		at++;
	}

	return false;
}

bool NativeCodeBasicBlock::PatchForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
	bool	changed = false;

	while (at < mIns.Size())
	{
		NativeCodeInstruction& ins(mIns[at]);

		if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
		{
			bool	done = !(ins.mLive & LIVE_MEM);

			if (ins.mLive & LIVE_CPU_REG_Y)
				mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
			mIns.Insert(at, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, yreg));
			at++;

			changed = true;

			if (done)
				return changed;
		}

		at++;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval, int ymax)
{
	if (!mPatched)
	{
		if (at == 0)
		{
			mPatched = true;

			if (!mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
			{
				mPatchFail = true;

				if (mTrueJump && !mTrueJump->CheckPatchFailRegPair(block, reg))
					return false;
				if (mFalseJump && !mFalseJump->CheckPatchFailRegPair(block, reg))
					return false;

				return true;
			}

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->IsDominatedBy(block))
						return false;
				yval = -1;
			}
		}

		if (mPatchFail)
			return false;

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1))
				return false;
			else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
			{
				if (iins.mMode == ASMIM_IMMEDIATE && yval + iins.mAddress > 255)
					return false;
				if (yval < 0) yval = RetrieveYValue(at, 2);
				if (yval < 0 || yval > ymax)
					return false;
				else if (!(ins.mLive & LIVE_MEM))
					return true;
				if (yval == 0)
				{
					if (ins.mIns)
					{
						if (ins.mIns->mCode == IC_LOAD)
							ymax = intmax(InterTypeSize[ins.mIns->mDst.mType] - 1, 255 - iins.mMaxVal);
						else if (ins.mIns->mCode == IC_STORE)
							ymax = intmax(InterTypeSize[ins.mIns->mSrc[0].mType] - 1, 255 - iins.mMaxVal);
					}
				}
			}
			if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
				yval = ins.mAddress;
			else if (ins.mType == ASMIT_INY && yval >= 0)
				yval = (yval + 1) & 255;
			else if (ins.mType == ASMIT_DEY && yval >= 0)
				yval = (yval - 1) & 255;
			else if (ins.mType == ASMIT_JSR)
			{
				if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(base) || ins.ChangesZeroPage(base + 1) || iins.MayBeChangedOnAddress(ins))
					return false;
				yval = -1;
			}
			else if (ins.mType == ASMIT_RTS)
			{
				if ((ins.mFlags & NCIF_LOWER) && (base == BC_REG_ACCU || reg == BC_REG_ACCU))
					return false;
			}
			else if (ins.ChangesZeroPage(base) || ins.ChangesZeroPage(base + 1) || iins.MayBeChangedOnAddress(ins))
				return false;
			else if (ins.ChangesYReg())
				yval = -1;

			at++;
		}

		if (mTrueJump && !mTrueJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax))
			return false;
		if (mFalseJump && !mFalseJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;
		if (at == 0 && !mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
			return false;

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1)));

			if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
			{
				assert(yval >= 0);

				bool	done = !(ins.mLive & LIVE_MEM);

				ins.mAddress = base;
				ins.mFlags &= ~NCIF_YZERO;

				const InterInstruction* inins(iins.mIns);

				if (ins.mLive & LIVE_CPU_REG_Y)
				{
					mIns.Insert(at + 1, NativeCodeInstruction(inins, ASMIT_LDY, ASMIM_IMMEDIATE, yval));
					if (mIns[at].mLive & LIVE_CPU_REG_Z)
					{
						mIns[at].mLive |= LIVE_CPU_REG_A;
						mIns.Insert(at + 2, NativeCodeInstruction(inins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
					}
				}

				mIns.Insert(at, NativeCodeInstruction(inins, ASMIT_LDY, iins));
				mIns[at].mMinVal = iins.mMinVal;
				mIns[at].mMaxVal = iins.mMaxVal;

				at++;
				for (int i = 0; i < yval; i++)
				{
					mIns.Insert(at, NativeCodeInstruction(inins, ASMIT_INY, ASMIM_IMPLIED));
					at++;
				}

				changed = true;

				if (done)
					return changed;
			}
			else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
				yval = ins.mAddress;
			else if (ins.mType == ASMIT_INY && yval >= 0)
				yval = (yval + 1) & 255;
			else if (ins.mType == ASMIT_DEY && yval >= 0)
				yval = (yval - 1) & 255;
			else if (ins.ChangesYReg())
				yval = -1;

			at++;
		}

		if (mTrueJump && mTrueJump->PatchForwardSumYPointer(block, reg, base, iins, 0, yval))
			changed = true;
		if (mFalseJump && mFalseJump->PatchForwardSumYPointer(block, reg, base, iins, 0, yval))
			changed = true;

		if (changed)
		{
			mEntryRequiredRegs += base;
			mEntryRequiredRegs += base + 1;
			if (iins.mMode == ASMIM_ZERO_PAGE)
				mEntryRequiredRegs += iins.mAddress;
		}
	}

	return changed;
}


bool NativeCodeBasicBlock::CrossBlock16BitFlood(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 3 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_MEM) && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1)
			{
				proc->ResetPatched();
				if (CheckCrossBlock16BitFlood(this, mIns[i + 0].mAddress, mIns[i + 1].mAddress, i + 4, false))
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mLive |= LIVE_MEM;

					proc->ResetPatched();
					if (PatchCrossBlock16BitFlood(this, mIns[i + 0].mAddress, mIns[i + 1].mAddress, i + 4))
					{
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->CrossBlock16BitFlood(proc))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlock16BitFlood(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at, bool rvalid)
{
	if (at == 0 && this == block)
		return false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[dreg] && !mEntryRequiredRegs[dreg + 1])
				return true;

			if (mEntryRequiredRegs[sreg] || mEntryRequiredRegs[sreg + 1])
				return false;

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->CheckCrossBlock16BitFloodExit(block, sreg, dreg, rvalid))
						return false;
			}
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.ReferencesZeroPage(sreg) || ins.ReferencesZeroPage(sreg + 1))
				return false;
			else if ((ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS) && (ins.ReferencesZeroPage(dreg) || ins.ReferencesZeroPage(dreg + 1)))
				return false;
			else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress + 1 == dreg)
				return false;

			at++;
		}

		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
			return false;

	}

	return true;
}

bool NativeCodeBasicBlock::CheckCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg, bool rvalid)
{
	if (!mPatchExit)
	{
		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlock16BitFlood(block, sreg, dreg, 0, rvalid))
			return false;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.ReferencesZeroPage(sreg) || ins.ReferencesZeroPage(sreg + 1))
				return false;
			else if ((ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS) && (ins.ReferencesZeroPage(dreg) || ins.ReferencesZeroPage(dreg + 1)))
				return false;

			at--;
		}

		mPatched = true;

		if (mEntryBlocks.Size() == 0)
			return false;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (!mEntryBlocks[i]->CheckCrossBlock16BitFloodExit(block, sreg, dreg, rvalid))
				return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[dreg] && !mEntryRequiredRegs[dreg + 1])
				return false;

			for (int i = 0; i < mEntryBlocks.Size(); i++)
				if (mEntryBlocks[i]->PatchCrossBlock16BitFloodExit(block, sreg, dreg))
					changed = true;

			mEntryRequiredRegs += sreg;
			mEntryRequiredRegs += sreg + 1;
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_INDIRECT_Y)
			{
				if (ins.mAddress == dreg)
				{
					ins.mAddress = sreg;
					changed = true;
				}
				else if (ins.mAddress == dreg + 1)
				{
					ins.mAddress = sreg + 1;
					changed = true;
				}
			}

			at++;
		}

		mPatchExit = true;

		mExitRequiredRegs += sreg;
		mExitRequiredRegs += sreg + 1;

		if (mTrueJump && mTrueJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
			changed = true;
	}

	return changed;

}

bool NativeCodeBasicBlock::PatchCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg)
{
	bool	changed = false;

	if (!mPatchExit)
	{
		mPatchExit = true;

		mExitRequiredRegs += sreg;
		mExitRequiredRegs += sreg + 1;

		if (mTrueJump && mTrueJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0))
			changed = true;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y || ins.mMode == ASMIM_INDIRECT_X || ins.mMode == ASMIM_INDIRECT_Y)
			{
				if (ins.mAddress == dreg)
				{
					ins.mAddress = sreg;
					changed = true;
				}
				else if (ins.mAddress == dreg + 1)
				{
					ins.mAddress = sreg + 1;
					changed = true;
				}
			}

			at--;
		}

		if (mEntryRequiredRegs[dreg] || mEntryRequiredRegs[dreg + 1])
		{
			mPatched = true;
			mEntryRequiredRegs += sreg;
			mEntryRequiredRegs += sreg + 1;

			for (int i = 0; i < mEntryBlocks.Size(); i++)
				if (mEntryBlocks[i]->PatchCrossBlock16BitFloodExit(block, sreg, dreg))
					changed = true;
		}

		return changed;
	}

	return false;
}

bool NativeCodeBasicBlock::CrossBlockXYFlood(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
			{
				proc->ResetPatched();
				if (mIns[i].mType != ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_X) && CheckCrossBlockXFlood(this, mIns[i].mAddress, i + 1, false))
				{
					if (mIns[i].mType == ASMIT_STX)
						mIns[i].mType = ASMIT_NOP;
					else
						mIns[i].mType = ASMIT_TAX;
					mIns[i].mMode = ASMIM_IMPLIED;
					mIns[i].mLive |= LIVE_CPU_REG_X;

					proc->ResetPatched();
					if (PatchCrossBlockXFlood(this, mIns[i].mAddress, i + 1))
					{
						changed = true;
					}
				}
				else
				{
#if 1
					proc->ResetPatched();
					if (mIns[i].mType == ASMIT_STX && CheckCrossBlockXFlood(this, mIns[i].mAddress, i + 1, true))
					{
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						mIns[i].mLive |= LIVE_CPU_REG_X;

						proc->ResetPatched();
						if (PatchCrossBlockXFlood(this, mIns[i].mAddress, i + 1))
						{
							changed = true;
						}
					}
					else
#endif
					{
						proc->ResetPatched();
						if (mIns[i].mType != ASMIT_STX && !(mIns[i].mLive & LIVE_CPU_REG_Y) && CheckCrossBlockYFlood(this, mIns[i].mAddress, i + 1, false))
						{
							if (mIns[i].mType == ASMIT_STY)
								mIns[i].mType = ASMIT_NOP;
							else
								mIns[i].mType = ASMIT_TAY;
							mIns[i].mMode = ASMIM_IMPLIED;
							mIns[i].mLive |= LIVE_CPU_REG_Y;

							proc->ResetPatched();
							if (PatchCrossBlockYFlood(this, mIns[i].mAddress, i + 1))
							{
								changed = true;
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockXYFlood(proc))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockXYFlood(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid)
{
	if (at == 0 && this == block)
		return false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[reg])
				return true;

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg, rvalid))
						return false;
			}
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
				return false;
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					if (!(ins.mLive & LIVE_MEM))
						return true;
				}
				else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
				{
					if (rvalid) return false;
				}
				else if (ins.mType == ASMIT_LDX)
				{
					return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z));
				}
				else
					return false;
			}
			else if (ins.ChangesXReg() || (!rvalid && ins.RequiresXReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
				return false;

			at++;
		}

		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
			return false;

	}

	return true;
}

bool NativeCodeBasicBlock::CheckCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg, bool rvalid)
{
	if (!mPatchExit)
	{
		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0, rvalid))
			return false;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
				return false;
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
				}
				else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
				{
					if (rvalid) return false;
				}
				else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX)
				{
					return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_X));
				}
				else
					return false;
			}
			else if (ins.ChangesXReg() || (!rvalid && ins.RequiresXReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
				return false;

			at--;
		}

		mPatched = true;

		if (mEntryBlocks.Size() == 0)
			return false;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg, rvalid))
				return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg)
{
	bool	changed = false;

	if (!mPatchExit)
	{
		mPatchExit = true;

		mExitRequiredRegs += CPU_REG_X;

		if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0))
			changed = true;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			ins.mLive |= LIVE_CPU_REG_X;

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					ins.mType = ASMIT_TXA;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_INC)
				{
					ins.mType = ASMIT_INX;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_DEC)
				{
					ins.mType = ASMIT_DEX;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_STA)
				{
					ins.mType = ASMIT_TAX;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
				else if (ins.mType == ASMIT_STX)
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
			}

			at--;
		}

		mPatched = true;
		mEntryRequiredRegs += CPU_REG_X;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg))
				changed = true;

		return changed;
	}

	return false;
}

bool NativeCodeBasicBlock::PatchCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[reg])
				return false;
			for (int i = 0; i < mEntryBlocks.Size(); i++)
				if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg))
					changed = true;
			mEntryRequiredRegs += CPU_REG_X;
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					ins.mType = ASMIT_TXA;
					ins.mMode = ASMIM_IMPLIED;
					if (!(ins.mLive & LIVE_MEM))
						return true;
					changed = true;
				}
				else if (ins.mType == ASMIT_INC)
				{
					ins.mType = ASMIT_INX;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_DEC)
				{
					ins.mType = ASMIT_DEX;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_LDX)
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
			}

			ins.mLive |= LIVE_CPU_REG_X;

			at++;
		}

		mPatchExit = true;

		mExitRequiredRegs |= CPU_REG_X;

		if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0))
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::CheckCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid)
{
	if (at == 0 && this == block)
		return false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[reg])
				return true;

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg, false))
						return false;
}
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
				return false;
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					if (!(ins.mLive & LIVE_MEM))
						return true;
				}
				else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
				{
					rvalid = false;
				}
				else if (ins.mType == ASMIT_LDY)
				{
					return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z));
				}
				else
					return false;
			}
			else if (ins.ChangesYReg() || (!rvalid && ins.RequiresYReg()) || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
				return false;

			at++;
		}

		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0, rvalid))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0, rvalid))
			return false;

	}

	return true;
}

bool NativeCodeBasicBlock::CheckCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg, bool rvalid)
{
	if (!mPatchExit)
	{
		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0, false))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0, false))
			return false;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1))
				return false;
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
				}
				else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
				{
				}
				else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STY)
				{
					return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_Y));
				}
				else
					return false;
			}
			else if (ins.ChangesYReg() || ins.RequiresYReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg))
				return false;

			at--;
		}

		mPatched = true;

		if (mEntryBlocks.Size() == 0)
			return false;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg, false))
				return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg)
{
	bool	changed = false;

	if (!mPatchExit)
	{
		mPatchExit = true;

		mExitRequiredRegs += CPU_REG_Y;

		if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0))
			changed = true;

		int at = mIns.Size() - 1;
		while (at >= 0)
		{
			NativeCodeInstruction& ins(mIns[at]);

			ins.mLive |= LIVE_CPU_REG_Y;

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					ins.mType = ASMIT_TYA;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_INC)
				{
					ins.mType = ASMIT_INY;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_DEC)
				{
					ins.mType = ASMIT_DEY;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_STA)
				{
					ins.mType = ASMIT_TAY;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
				else if (ins.mType == ASMIT_STY)
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
			}

			at--;
		}

		mPatched = true;
		mEntryRequiredRegs += CPU_REG_Y;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg))
				changed = true;

		return changed;
	}

	return false;
}

bool NativeCodeBasicBlock::PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[reg])
				return false;
			for (int i = 0; i < mEntryBlocks.Size(); i++)
				if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg))
					changed = true;
			mEntryRequiredRegs += CPU_REG_Y;
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg)
			{
				if (ins.mType == ASMIT_LDA)
				{
					ins.mType = ASMIT_TYA;
					ins.mMode = ASMIM_IMPLIED;
					if (!(ins.mLive & LIVE_MEM))
						return true;
					changed = true;
				}
				else if (ins.mType == ASMIT_INC)
				{
					ins.mType = ASMIT_INY;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_DEC)
				{
					ins.mType = ASMIT_DEY;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (ins.mType == ASMIT_LDY)
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					return true;
				}
			}

			ins.mLive |= LIVE_CPU_REG_Y;

			at++;
		}

		mPatchExit = true;

		mExitRequiredRegs |= CPU_REG_Y;

		if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0))
			changed = true;
		if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockY2XFlood(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_X))
			{
				proc->ResetPatched();
				if (CheckCrossBlockY2XFlood(this, i + 1))
				{
					mIns[i].mType = ASMIT_LDX;
					mIns[i].mLive |= LIVE_CPU_REG_X;

					proc->ResetPatched();
					if (PatchCrossBlockY2XFlood(this, i + 1))
					{
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->CrossBlockY2XFlood(proc))
			changed = true;
		if (mFalseJump && mFalseJump->CrossBlockY2XFlood(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at)
{
	if (at == 0 && this == block)
		return false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0)
		{
			if (!mEntryRequiredRegs[CPU_REG_Y])
				return true;

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->CheckCrossBlockY2XFloodExit(block))
						return false;
			}
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (ins.mMode == ASMIM_INDIRECT_Y || ins.ReferencesXReg())
				return false;
			else if (!(ins.mLive & LIVE_CPU_REG_Y))
				return true;

			at++;
		}

		mPatchExit = true;

		if (mTrueJump && !mTrueJump->CheckCrossBlockY2XFlood(block, 0))
			return false;
		if (mFalseJump && !mFalseJump->CheckCrossBlockY2XFlood(block, 0))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CheckCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block)
{
	if (!mPatchExit)
	{
		mPatchExit = true;

		if (mExitRequiredRegs[CPU_REG_X]) return false;

		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::CanSwapAccuZP(int reg, int size)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			const NativeCodeInstruction& ins(mIns[i]);
			if (ins.mType == ASMIT_JSR)
				return false;
			if (ins.mMode == ASMIM_INDIRECT_Y)
			{
				if (reg == ins.mAddress + 1) return false;
				if (reg == ins.mAddress && size < 2) return false;
				if (ins.mAddress > reg && ins.mAddress < reg + size) return false;
			}
			else if (ins.mMode == ASMIM_ZERO_PAGE_X || ins.mMode == ASMIM_ZERO_PAGE_Y)
				return false;
		}

		if (mTrueJump && !mTrueJump->CanSwapAccuZP(reg, size)) return false;
		if (mFalseJump && !mFalseJump->CanSwapAccuZP(reg, size)) return false;
	}

	return true;
}

void NativeCodeBasicBlock::SwapAccuZP(int reg, int size)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.mMode == ASMIM_INDIRECT_Y)
			{
				if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + size)
					ins.mAddress += reg - BC_REG_ACCU;
				else if (ins.mAddress >= reg && ins.mAddress < reg + size)
					ins.mAddress += BC_REG_ACCU - reg;
			}
			else if (ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + size)
					ins.mAddress += reg - BC_REG_ACCU;
				else if (ins.mAddress >= reg && ins.mAddress < reg + size)
					ins.mAddress += BC_REG_ACCU - reg;
			}
		}

		if (mTrueJump) mTrueJump->SwapAccuZP(reg, size);
		if (mFalseJump) mFalseJump->SwapAccuZP(reg, size);
	}
}


bool NativeCodeBasicBlock::CheckNonAliasedLocalStore(int at, const NativeCodeInstruction& sins)
{
	if (mPatched)
		return true;

	if (!at)
		mPatched = true;

	while (at < mIns.Size())
	{
		NativeCodeInstruction& ins(mIns[at]);

		if (ins.mMode == ASMIM_ABSOLUTE && ins.mAddress == sins.mAddress && ins.mLinkerObject == sins.mLinkerObject)
		{
			if (ins.UsesAddress())
				return false;
			if (ins.ChangesAddress())
				break;
		}
		else if ((ins.mMode == ASMIM_ABSOLUTE_X || ins.mMode == ASMIM_ABSOLUTE_Y) && ins.mLinkerObject == sins.mLinkerObject)
			return false;

		at++;
	}

	if (mTrueJump && !mTrueJump->CheckNonAliasedLocalStore(0, sins))
		return false;
	if (mFalseJump && !mFalseJump->CheckNonAliasedLocalStore(0, sins))
		return false;

	return true;
}

bool NativeCodeBasicBlock::EliminateNonAliasedLocalStores(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if ((ins.mType == ASMIT_STA || ins.mType == ASMIT_STX || ins.mType == ASMIT_STY) && ins.mMode == ASMIM_ABSOLUTE && ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_LOCAL_VAR) && ins.mLinkerObject->mVariable && !ins.mLinkerObject->mVariable->mAliased)
			{
				mProc->ResetPatched();
				if (CheckNonAliasedLocalStore(i + 1, ins))
				{
					ins.mType = ASMIT_NOP;
					ins.mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->EliminateNonAliasedLocalStores())
			changed = true;
		if (mFalseJump && mFalseJump->EliminateNonAliasedLocalStores())
			changed = true;

	}

	return changed;
}

void NativeCodeBasicBlock::PropagateAddGlobalCarry(void)
{
	if (!mVisited)
	{
		mVisited = true;

		// Accessing memory outside of a global array is undefined behaviour, so
		// if we find an indirect memory access and the pointer arithmetic for the
		// upper byte included an immediate address without an offset, the carry
		// must be clear

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				int j = i - 1;
				while (j > 0 && !(mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[i].mAddress + 1 && mIns[j].ChangesAddress()))
					j--;
				if (j > 0 && 
					mIns[j].mType == ASMIT_STA && 
					mIns[j - 1].mType == ASMIT_ADC && 
					mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
					(mIns[j - 1].mFlags & NCIF_UPPER) && 
					mIns[j - 1].mAddress == 0)
				{
					while (j < mIns.Size() && !mIns[j].ChangesCarry())
						j++;
					if (j < mIns.Size() && mIns[j].mType == ASMIT_CLC)
						mIns[j].mType = ASMIT_NOP;
				}
			}
		}

		if (mTrueJump) mTrueJump->PropagateAddGlobalCarry();
		if (mFalseJump) mFalseJump->PropagateAddGlobalCarry();
	}
}

bool NativeCodeBasicBlock::FindSelfModSource(NativeCodeBasicBlock* block, int reg, NativeCodeBasicBlock*& sblock, int& sat)
{
	for (;;)
	{
		for (int i = block->mIns.Size() - 1; i >= 0; i--)
		{
			if (block->mIns[i].ReferencesZeroPage(reg))
			{
				if (block->mIns[i].IsStore() || block->mIns[i].IsLoad())
				{
					sat = i;
					sblock = block;
					return true;
				}
				return false;
			}
		}
		if (block->mEntryBlocks.Size() == 1)
		{
			block = block->mEntryBlocks[0];
			if (block->mFalseJump)
				return false;
		}
		else if (block->mEntryBlocks.Size() == 2)
		{
			if (!block->mEntryBlocks[0]->mFalseJump &&
				block->mEntryBlocks[1]->mTrueJump == block && block->mEntryBlocks[1]->mFalseJump == block->mEntryBlocks[0] &&
				!block->mEntryBlocks[0]->ReferencesZeroPage(reg))
			{
				block = block->mEntryBlocks[1];
			}
			else if (!block->mEntryBlocks[1]->mFalseJump &&
				block->mEntryBlocks[0]->mTrueJump == block && block->mEntryBlocks[0]->mFalseJump == block->mEntryBlocks[1] &&
				!block->mEntryBlocks[1]->ReferencesZeroPage(reg))
			{
				block = block->mEntryBlocks[0];
			}
			else
				return false;
		}
		else
			return false;
	}
}

int NativeCodeBasicBlock::CalcBlockDiffY(void) const
{
	int diff = 0;
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesYReg())
		{
			if (mIns[i].mType == ASMIT_INY)
				diff++;
			else if (mIns[i].mType == ASMIT_DEY)
				diff--;
			else
				return 256;
		}
	}
	return diff;
}

int NativeCodeBasicBlock::CalcBlockDiffX(void) const
{
	int diff = 0;
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].ChangesXReg())
		{
			if (mIns[i].mType == ASMIT_INX)
				diff++;
			else if (mIns[i].mType == ASMIT_DEX)
				diff--;
			else
				return 256;
		}
	}
	return diff;
}

int NativeCodeBasicBlock::SimpleLoopNumIterations(void)
{
	if (mLoopHead && mFalseJump && mTrueJump == this && mNumEntries == 2)
	{
		NativeCodeBasicBlock* eblock = mEntryBlocks[0];
		if (eblock == this)
			eblock = mEntryBlocks[1];

		int sz = mIns.Size();
		int k = sz - 1;
		if (mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI)
		{
			while (k >= 0 && !mIns[k].ChangesZFlag())
				k--;
		}
		else if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		{
			while (k >= 0 && !mIns[k].ChangesZFlag())
				k--;
		}
		else
			return -1;

		if (k >= 0)
		{
			switch (mIns[k].mType)
			{
			case ASMIT_CPY:
				if (mIns[k].mMode == ASMIM_IMMEDIATE)
				{
					int start = eblock->RetrieveYValue();
					if (start >= 0)
					{
						int diff = CalcBlockDiffY();
						if (diff != 256)
						{
							if (diff > 0 && start < mIns[k].mAddress && (mBranch == ASMIT_BCC || mBranch == ASMIT_BNE))
								return (mIns[k].mAddress - start) / diff;
							else if (diff < 0 && start > mIns[k].mAddress && (mBranch == ASMIT_BCS || mBranch == ASMIT_BNE))
								return (start - mIns[k].mAddress) / -diff;
						}
					}
				}
				break;
			case ASMIT_CPX:
				if (mIns[k].mMode == ASMIM_IMMEDIATE)
				{
					int start = eblock->RetrieveXValue();
					if (start >= 0)
					{
						int diff = CalcBlockDiffX();
						if (diff != 256)
						{
							if (diff > 0 && start < mIns[k].mAddress && (mBranch == ASMIT_BCC || mBranch == ASMIT_BNE))
								return (mIns[k].mAddress - start) / diff;
							else if (diff < 0 && start > mIns[k].mAddress && (mBranch == ASMIT_BCS || mBranch == ASMIT_BNE))
								return (start - mIns[k].mAddress) / -diff;
						}
					}
				}
				break;
			case ASMIT_INY:
			case ASMIT_DEY:
			case ASMIT_TYA:
			{
				int start = eblock->RetrieveYValue();
				if (start >= 0)
				{
					int diff = CalcBlockDiffY();
					if (diff != 256)
					{
						if (diff > 0 && mBranch == ASMIT_BNE)
							return (256 - start) / diff;
						else if (diff < 0 && mBranch == ASMIT_BNE)
							return start / -diff;
						else if (diff < 0 && start < 128 && mBranch == ASMIT_BPL)
							return (start + 1) / -diff;
						else if (diff > 0 && start < 128 && mBranch == ASMIT_BPL)
							return (128 - start) / diff;
					}
				}
			}	break;
			case ASMIT_INX:
			case ASMIT_DEX:
			case ASMIT_TXA:
			{
				int start = eblock->RetrieveXValue();
				if (start >= 0)
				{
					int diff = CalcBlockDiffX();
					if (diff != 256)
					{
						if (diff > 0 && mBranch == ASMIT_BNE)
							return (256 - start) / diff;
						else if (diff < 0 && mBranch == ASMIT_BNE)
							return start / -diff;
						else if (diff < 0 && start < 128 && mBranch == ASMIT_BPL)
							return (start + 1) / -diff;
						else if (diff > 0 && start < 128 && mBranch == ASMIT_BPL)
							return (128 - start) / diff;
					}
				}
			}	break;
			}
		}
	}


	return -1;
}

bool NativeCodeBasicBlock::CollectSelfModTargets(void)
{
	bool	changed = false;

	assert(mEntryRequiredRegs.Size() > 0);

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mFalseJump && mTrueJump == this && mNumEntries == 2)
		{

			bool simple = true;
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].mType == ASMIT_JSR)
					simple = false;
			}

			bool	useA = false, useX = false, useY = false;
			if (!mEntryRequiredRegs[CPU_REG_A])
				useA = true;
			else if (!mEntryRequiredRegs[CPU_REG_X])
				useX = true;
			else if (!mEntryRequiredRegs[CPU_REG_Y])
				useY = true;

			if (simple && (useA || useX || useY))
			{
				NativeCodeBasicBlock* eblock = mEntryBlocks[0];
				if (eblock == this)
					eblock = mEntryBlocks[1];

				int nloops = SimpleLoopNumIterations();

				if (nloops > 2)
				{				
					for (int i = 0; i < mIns.Size(); i++)
					{
						if (mIns[i].mMode == ASMIM_INDIRECT_Y && HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
						{
							int		uses = 0, addr = mIns[i].mAddress;
							bool	fail = false;
							int		cost = 0;

							if (mFalseJump->mEntryRequiredRegs[addr])
								cost -= 3;
							if (mFalseJump->mEntryRequiredRegs[addr + 1])
								cost -= 3;

							for (int j = 0; j < mIns.Size(); j++)
							{
								if (mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == addr || mIns[j].mAddress == addr + 1))
								{
									if (mIns[j].ChangesAddress())
									{
										fail = true;
										break;
									}
									cost -= 3;
								}
								else if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == addr)
								{
									if (HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_Y))
										uses++;
									else
									{
										fail = true;
										break;
									}
								}
							}

							cost -= 8 * uses;
							cost += uses * nloops;

							if (!fail && uses <= 2 && cost > 4)
							{
								for (int j = 0; j < mIns.Size(); j++)
								{
									if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == addr)
									{
										int	modID = mProc->mSelfModSources.Size();
										mProc->mSelfModSources.Push(SelfModReference{ nullptr, 0 });

										mIns[j].mMode = ASMIM_ABSOLUTE_Y;
										mIns[j].mLinkerObject = mProc->mLinkerObject;
										mIns[j].mAddress = modID;
										mIns[j].mFlags |= NCIF_SELFMOD;

										NativeCodeBasicBlock* sblock;
										int							sat;

										if (FindSelfModSource(eblock, addr, sblock, sat))
										{
											switch (sblock->mIns[sat].mType)
											{
											case ASMIT_LDA:
											case ASMIT_STA:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_A;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
												break;
											case ASMIT_LDX:
											case ASMIT_STX:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_X;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
												break;
											case ASMIT_LDY:
											case ASMIT_STY:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_Y;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
												break;
											}
										}
										else if (useA)
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
										}
										else if (useX)
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, addr));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
										}
										else
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ABSOLUTE, 2 * modID + 0, mProc->mLinkerObject));
										}
										if (FindSelfModSource(eblock, addr + 1, sblock, sat))
										{
											switch (sblock->mIns[sat].mType)
											{
											case ASMIT_LDA:
											case ASMIT_STA:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_A;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
												break;
											case ASMIT_LDX:
											case ASMIT_STX:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_X;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
												break;
											case ASMIT_LDY:
											case ASMIT_STY:
												sblock->mIns[sat].mLive |= LIVE_CPU_REG_Y;
												sblock->mIns.Insert(sat + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
												break;
											}
										}
										else if (useA)
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr + 1));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
										}
										else if (useX)
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, addr + 1));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
										}
										else
										{
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr + 1));
											eblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ABSOLUTE, 2 * modID + 1, mProc->mLinkerObject));
										}
									}
								}

								changed = true;
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->CollectSelfModTargets()) changed = true;
		if (mFalseJump && mFalseJump->CollectSelfModTargets()) changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::PropagateZPAbsolute(const NativeRegisterDataSet& data)
{
	if (!mVisited)
	{
		mDataSet = data;

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (mLoopHead)
		{
			if (mNumEntries == 2 && (mTrueJump == this || mFalseJump == this))
			{
				ResetModifiedDataSet(mDataSet);
			}
			else
				mDataSet.Reset();
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
				mDataSet.Intersect(mNDataSet);

			mNumEntered++;

			if (mNumEntered < mNumEntries)
			{
				mNDataSet = mDataSet;
				return;
			}
		}

		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.Set(CPU_REG_A, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.Set(CPU_REG_X, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.Set(CPU_REG_Y, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
				mDataSet.Set(CPU_REG_A, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
				mDataSet.Set(CPU_REG_X, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
			{
				mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
				mDataSet.Set(CPU_REG_Y, NRDM_ABSOLUTE, mIns[i].mAddress, mIns[i].mLinkerObject, mIns[i].mFlags);
			}
			else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
				mDataSet.Set(mIns[i].mAddress, mDataSet[CPU_REG_A]);
			else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE)
				mDataSet.Set(mIns[i].mAddress, mDataSet[CPU_REG_X]);
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE)
				mDataSet.Set(mIns[i].mAddress, mDataSet[CPU_REG_Y]);
			else if (mIns[i].mType == ASMIT_JSR)
			{
				mDataSet.ResetCall(mIns[i], mProc->mFastCallBase);
				//				mDataSet.Reset();
			}
			else
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					int r = mIns[i].mAddress;

					if (mIns[i].ChangesAddress())
						mDataSet.ResetZeroPage(r);
					else if (mDataSet[r].mMode == NRDM_ABSOLUTE)
					{
						mIns[i].mMode = ASMIM_ABSOLUTE;
						mIns[i].mLinkerObject = mDataSet[r].mLinkerObject;
						mIns[i].mAddress = mDataSet[r].mValue;
					}
				}
				else if (mIns[i].mMode == ASMIM_ABSOLUTE)
				{
					if (mIns[i].ChangesAddress())
						mDataSet.ResetAbsolute(mIns[i].mLinkerObject, mIns[i].mAddress);
				}
				else if (mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_ABSOLUTE_Y)
				{
					if (mIns[i].ChangesAddress())
						mDataSet.ResetAbsoluteXY(mIns[i].mLinkerObject, mIns[i].mAddress);
				}
				else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
				{
					int r = mIns[i].mAddress;

					if (mDataSet[r].mMode == NRDM_ABSOLUTE && mDataSet[r + 1].mMode == NRDM_ABSOLUTE &&
						mDataSet[r].mLinkerObject == mDataSet[r + 1].mLinkerObject &&
						mDataSet[r].mValue + 1 == mDataSet[r + 1].mValue)
					{
						mIns[i].mLinkerObject = mDataSet[r].mLinkerObject;
						mIns[i].mAddress = mDataSet[r].mValue;
					}
				}

				if (mIns[i].ChangesAccu())
					mDataSet.Reset(CPU_REG_A);
				if (mIns[i].ChangesXReg())
					mDataSet.Reset(CPU_REG_X);
				if (mIns[i].ChangesYReg())
					mDataSet.Reset(CPU_REG_Y);
			}
		}

		if (mTrueJump) mTrueJump->PropagateZPAbsolute(mDataSet);
		if (mFalseJump) mFalseJump->PropagateZPAbsolute(mDataSet);
	}
}

void NativeCodeBasicBlock::RegisterFunctionCalls(void)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
				mProc->mGenerator->RegisterFunctionCall(this, i);
		}

		if (mTrueJump) mTrueJump->RegisterFunctionCalls();
		if (mFalseJump) mFalseJump->RegisterFunctionCalls();
	}
}

bool NativeCodeBasicBlock::MergeFunctionCalls(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject)
			{
				if (mProc->mGenerator->MergeFunctionCall(this, i))
					changed = true;
			}
		}

		if (changed)
			RemoveNops();

		if (mTrueJump && mTrueJump->MergeFunctionCalls())
			changed = true;
		if (mFalseJump && mFalseJump->MergeFunctionCalls())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const
{
	if (this == block)
		return true;
#if 0
	if (mEntryBlocks.Size())
	{
		if (mLoopHead)
			return false;

		for (int i = 0; i < mEntryBlocks.Size(); i++)
			if (!mEntryBlocks[i]->IsDominatedBy(block))
				return false;
		return true;
	}

	return false;
#else
	else
	{
		NativeCodeBasicBlock* dom = mDominator;
		while (dom)
		{
			if (dom == block)
				return true;
			dom = dom->mDominator;
		}

		return false;
	}
#endif
}

bool NativeCodeBasicBlock::JoinSameBranch(NativeCodeBasicBlock* block)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (this != block)
		{
			if (mBranch == block->mBranch && mTrueJump == block->mTrueJump && mFalseJump == block->mFalseJump)
			{
				mTrueJump->mNumEntries--;
				mFalseJump->mNumEntries--;
				block->mNumEntries++;
				mBranch = ASMIT_JMP;
				mTrueJump = block;
				mFalseJump = nullptr;
				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->JoinSameBranch(block))
			changed = true;
		if (mFalseJump && mFalseJump->JoinSameBranch(block))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::FinalCheckedSizeReduction(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		int i = 0;
		int j = 0;

		while (i < mIns.Size())
		{
			if (mIns[i].mType == ASMIT_NOP)
			{
				i++;
			}
			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;
				changed = true;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_INX &&
				mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_INC;

				j++;
				if (mIns[i + 2].mLive & LIVE_CPU_REG_X)
				{
					mIns[j + 0] = mIns[i + 2];
					mIns[j + 0].mType = ASMIT_LDX;
					j++;
				}

				i += 3;
				changed = true;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_DEX &&
				mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_DEC;

				j++;
				if (mIns[i + 2].mLive & LIVE_CPU_REG_X)
				{
					mIns[j + 0] = mIns[i + 2];
					mIns[j + 0].mType = ASMIT_LDX;
					j++;
				}
				i += 3;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_INC;
				j += 1;
				i += 4;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_DEC;
				j += 1;
				i += 4;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_DEC;
				j += 1;
				i += 4;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_INC;
				j += 1;
				i += 4;
				changed = true;
			}

			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;
				changed = true;
			}
			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;
				changed = true;
			}

			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;
				changed = true;
			}
			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;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
				changed = true;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
				changed = true;
			}

			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;
				changed = true;
			}
			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;
				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 + 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;
				changed = true;
			}
			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;
				changed = true;
			}

			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;
				changed = true;
			}
			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;
				changed = true;
			}

			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;
				changed = true;
			}
			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;
				changed = true;
			}
			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;
				changed = true;
			}
			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;
				changed = true;
			}
#if 1
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_CLC &&
				mIns[i + 3].mType == ASMIT_ADC)
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_SEC);
				mIns[j + 1] = mIns[i + 3];
				j += 2;
				i += 4;
				changed = true;
			}
			else if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA &&
				mIns[i + 2].mType == ASMIT_SBC &&
				mIns[i + 3].mType == ASMIT_SEC &&
				mIns[i + 4].mType == ASMIT_SBC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01)
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_CLC);
				j += 3;
				i += 5;
				changed = true;
			}
#endif
			else if (i + 3 < mIns.Size() &&
				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 && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
				mIns[i + 3].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z | LIVE_MEM)))
			{
				mIns[j + 0] = mIns[i + 2];
				mIns[j + 1] = mIns[i + 1]; mIns[j + 1].mType = ASMIT_LDY;
				mIns[j + 2] = mIns[i + 3];
				j += 3;
				i += 4;
				changed = true;
			}
			else if (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_X))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX);
				i++;
				j++;
				changed = true;
			}
			else if (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY);
				i++;
				j++;
				changed = true;
			}
			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[i + 0].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				mIns[j++] = mIns[i++];
				i++;
				changed = true;
			}
			else if (mIns[i].mType == ASMIT_CMP && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x80 && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_ASL);
				i++;
				j++;
				changed = true;
			}
			else if (mIns[i].mType == ASMIT_CPY && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0 && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TYA);
				i++;
				j++;
				changed = true;
			}
			else if (mIns[i].mType == ASMIT_CPX && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0 && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TXA);
				i++;
				j++;
				changed = true;
			}
			else
				mIns[j++] = mIns[i++];
		}

		mIns.SetSize(j);

		if (mTrueJump && mTrueJump->FinalCheckedSizeReduction())
			changed = true;
		if (mFalseJump && mFalseJump->FinalCheckedSizeReduction())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::MergeSameBranch(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		if (mIns.Size() == 0 && mFalseJump)
		{
			mProc->ResetPatched();
			if (mProc->mEntryBlock->JoinSameBranch(this))
				changed = true;
		}

		if (mTrueJump && mTrueJump->MergeSameBranch())
			changed = true;
		if (mFalseJump && mFalseJump->MergeSameBranch())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckPatchFailLoop(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg, bool changed)
{
	if (!mPatchLoop || (changed && !mPatchLoopChanged))
	{
		mPatchLoop = true;
		mPatchLoopChanged = changed;

		if (this == block)
			return true;

		if (!changed)
		{
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].ChangesZeroPage(reg))
					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::CheckPatchFailLoopPair(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg, bool changed)
{
	if (!mPatchLoop || (changed && !mPatchLoopChanged))
	{
		mPatchLoop = true;
		mPatchLoopChanged = changed;

		if (this == block)
			return true;

		if (!changed)
		{
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].ChangesZeroPage(reg) || mIns[i].ChangesZeroPage(reg + 1))
					changed = true;
			}
		}

		if (mTrueJump)
		{
			if (mTrueJump == head)
			{
				if (changed)
					return false;
			}
			else if (!mTrueJump->CheckPatchFailLoopPair(block, head, reg, changed))
				return false;
		}

		if (mFalseJump)
		{
			if (mFalseJump == head)
			{
				if (changed)
					return false;
			}
			else if (!mFalseJump->CheckPatchFailLoopPair(block, head, reg, changed))
				return false;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::CheckBoolBitPropagation(const NativeCodeBasicBlock* block, int at, int reg)
{
	if (!mPatched)
	{
		if (at == 0)
		{
			mPatched = true;

			if (!mEntryRequiredRegs[reg])
				return CheckPatchFailUse();

			if (mPatchFail)
				return false;

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

		}
		else
		{
			mPatchStart = true;
		}

		while (at < mIns.Size())
		{
			if (mIns[at].UsesZeroPage(reg))
			{
				if (at + 1 == mIns.Size() && (mIns[at].mType == ASMIT_LDA) && !(mIns[at].mLive & LIVE_CPU_REG_A))
				{
					mPatchChecked = true;
					if ((mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
						;
					else if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
					{
						if (mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							if (mTrueJump->mIns.Size() > 0 || mTrueJump->mExitRequiredRegs[CPU_REG_Z] ||
								!(mTrueJump->mBranch == ASMIT_BEQ || mTrueJump->mBranch == ASMIT_BNE))
								return false;
						}
						if (mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							if (mFalseJump->mIns.Size() > 0 || mFalseJump->mExitRequiredRegs[CPU_REG_Z] ||
								!(mFalseJump->mBranch == ASMIT_BEQ || mFalseJump->mBranch == ASMIT_BNE))
								return false;
						}
					}
				}
				else
					return false;
			}
			if (mIns[at].ChangesZeroPage(reg))
			{
				if (mTrueJump && !mTrueJump->CheckPatchFailUse() || mFalseJump && !mFalseJump->CheckPatchFailUse())
					return false;
				return true;
			}

			at++;
		}

		if (mTrueJump && !mTrueJump->CheckBoolBitPropagation(block, 0, reg))
			return false;
		if (mFalseJump && !mFalseJump->CheckBoolBitPropagation(block, 0, reg))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchBoolBitPropagation(const NativeCodeBasicBlock* block, int at, int reg, bool inverse)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		if (at == 0 && !mEntryRequiredRegs[reg])
			return false;

		while (at < mIns.Size())
		{
			if (mIns[at].UsesZeroPage(reg))
			{
				if (at + 1 == mIns.Size() && (mIns[at].mType == ASMIT_LDA) && !(mIns[at].mLive & LIVE_CPU_REG_A))
				{
					if (mBranch == ASMIT_BEQ)
					{
						if (inverse)
							mBranch = ASMIT_BMI;
						else
							mBranch = ASMIT_BPL;
						changed = true;
					}
					else if (mBranch == ASMIT_BNE)
					{
						if (inverse)
							mBranch = ASMIT_BPL;
						else
							mBranch = ASMIT_BMI;
						changed = true;
					}
					else if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
					{
						if (mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							if (mTrueJump->mIns.Size() == 0)
							{
								if (mTrueJump->mBranch == ASMIT_BEQ)
								{
									if (inverse)
										mBranch = ASMIT_BMI;
									else
										mBranch = ASMIT_BPL;
									changed = true;
								}
								else if (mTrueJump->mBranch == ASMIT_BNE)
								{
									if (inverse)
										mBranch = ASMIT_BPL;
									else
										mBranch = ASMIT_BMI;
									changed = true;
								}
							}
						}
						if (mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
						{
							if (mFalseJump->mIns.Size() == 0)
							{
								if (mFalseJump->mBranch == ASMIT_BEQ)
								{
									if (inverse)
										mBranch = ASMIT_BMI;
									else
										mBranch = ASMIT_BPL;
									changed = true;
								}
								else if (mFalseJump->mBranch == ASMIT_BNE)
								{
									if (inverse)
										mBranch = ASMIT_BPL;
									else
										mBranch = ASMIT_BMI;
									changed = true;
								}
							}
						}
					}
				}
			}
			if (mIns[at].ChangesZeroPage(reg))
				return false;

			at++;
		}

		if (mTrueJump && mTrueJump->PatchBoolBitPropagation(block, 0, reg, inverse))
			changed = true;
		if (mFalseJump && mFalseJump->PatchBoolBitPropagation(block, 0, reg, inverse))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CollectRegBoolInstructionsForward(int reg, ExpandingArray<NativeCodeBasicBlock*>& cblocks, ExpandingArray<NativeCodeInstruction*>& lins)
{
	if (!mPatchStart)
	{
		mPatchStart = true;
		if (!mEntryRequiredRegs[reg])
			return true;

		int i = 0;
		while (i < mIns.Size() && !mIns[i].ReferencesZeroPage(reg))
			i++;
		if (i < mIns.Size())
		{
			if (mIns[i].UsesZeroPage(reg))
			{
				if (i == mIns.Size() - 1 &&
					(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) &&
					(mIns[i].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_A) ||
					 mIns[i].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_X) ||
					 mIns[i].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Y)))
				{
					cblocks.Push(this);
				}
				else
					return false;
			}
			else if (mIns[i].ChangesZeroPage(reg))
				return true;
		}

		for (int i = 0; i < mEntryBlocks.Size(); i++)
		{
			if (!mEntryBlocks[i]->CollectRegBoolInstructionsBackward(reg, cblocks, lins))
				return false;
		}

		if (mTrueJump && !mTrueJump->CollectRegBoolInstructionsForward(reg, cblocks, lins))
			return false;
		if (mFalseJump && !mFalseJump->CollectRegBoolInstructionsForward(reg, cblocks, lins))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::CollectRegBoolInstructionsBackward(int reg, ExpandingArray<NativeCodeBasicBlock*>& cblocks, ExpandingArray<NativeCodeInstruction*>& lins)
{
	if (!mPatchExit)
	{
		mPatchExit = true;

		int sz = mIns.Size();
		if (mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && sz > 0 && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_MEM) && mIns[sz - 1].mAddress == reg)
		{
			if (mIns[sz - 1].mType == ASMIT_LDA && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) ||
				mIns[sz - 1].mType == ASMIT_LDX && !(mIns[sz - 1].mLive & LIVE_CPU_REG_X) ||
				mIns[sz - 1].mType == ASMIT_LDY && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Y))
			{
				cblocks.Push(this);
				sz -= 1;
			}
		}

		int i = sz - 1;
		while (i >= 0 && !mIns[i].ReferencesZeroPage(reg))
			i--;

		bool found = false;
		if (i >= 0)
		{
			if (i > 0 &&
				(mIns[i].mType == ASMIT_STA && mIns[i - 1].mType == ASMIT_LDA && mIns[i - 1].mMode == ASMIM_IMMEDIATE && !(mIns[i].mLive & LIVE_CPU_REG_A) ||
				 mIns[i].mType == ASMIT_STX && mIns[i - 1].mType == ASMIT_LDX && mIns[i - 1].mMode == ASMIM_IMMEDIATE && !(mIns[i].mLive & LIVE_CPU_REG_X) ||
				 mIns[i].mType == ASMIT_STY && mIns[i - 1].mType == ASMIT_LDY && mIns[i - 1].mMode == ASMIM_IMMEDIATE && !(mIns[i].mLive & LIVE_CPU_REG_Y)))
			{
				lins.Push(&(mIns[i - 1]));
				found = true;
			}
			else if (i == 0 && mIns[0].mType == ASMIT_STA && !(mIns[0].mLive & LIVE_CPU_REG_A))
			{
				for (int k = 0; k < mEntryBlocks.Size(); k++) 
				{
					NativeCodeBasicBlock* eb = mEntryBlocks[k];
					int es = eb->mIns.Size();
					if (!eb->mFalseJump && es > 0 && eb->mIns[es - 1].mType == ASMIT_LDA && eb->mIns[es - 1].mMode == ASMIM_IMMEDIATE)
						lins.Push(&(eb->mIns[es - 1]));
					else
						return false;
				}
				found = true;
			}
			else
				return false;
		}

		if (!found)
		{
			if (!mEntryBlocks.Size())
				return false;

			for (int i = 0; i < mEntryBlocks.Size(); i++)
			{
				if (!mEntryBlocks[i]->CollectRegBoolInstructionsBackward(reg, cblocks, lins))
					return false;
			}
		}

		if (mTrueJump && !mTrueJump->CollectRegBoolInstructionsForward(reg, cblocks, lins))
			return false;
		if (mFalseJump && !mFalseJump->CollectRegBoolInstructionsForward(reg, cblocks, lins))
			return false;
	}

	return true;
}



bool NativeCodeBasicBlock::PatchBitBoolConstOrigin(void)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int sz = mIns.Size();
		if (mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && sz > 0 && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_MEM))
		{
			if (mIns[sz - 1].mType == ASMIT_LDA && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) ||
				mIns[sz - 1].mType == ASMIT_LDX && !(mIns[sz - 1].mLive & LIVE_CPU_REG_X) ||
				mIns[sz - 1].mType == ASMIT_LDY && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Y))
			{
				ExpandingArray<NativeCodeBasicBlock*>	lblocks;
				ExpandingArray<NativeCodeInstruction*>	lins;

				mProc->ResetPatched();

				if (CollectRegBoolInstructionsBackward(mIns[sz - 1].mAddress, lblocks, lins))
				{
					for (int i = 0; i < lins.Size(); i++)
					{
						if (lins[i]->mAddress != 0)
							lins[i]->mAddress = 0xff;
					}
					for (int i = 0; i < lblocks.Size(); i++)
					{
						if (!lblocks[i]->mPatched)
						{
							lblocks[i]->mPatched = true;
							int sz = lblocks[i]->mIns.Size();
							lblocks[i]->mIns[sz - 1].mType = ASMIT_BIT;
							if (lblocks[i]->mBranch == ASMIT_BNE)
								lblocks[i]->mBranch = ASMIT_BMI;
							else
								lblocks[i]->mBranch = ASMIT_BPL;
						}
					}
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->PatchBitBoolConstOrigin())
			changed = true;
		if (mFalseJump && mFalseJump->PatchBitBoolConstOrigin())
			changed = true;
	}

	return changed;
}

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 && !CheckPatchFailLoopPair(block, this, reg, false))
				return false;

			if (mNumEntries > 1)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
					if (!mEntryBlocks[i]->IsDominatedBy(block))
						return false;
				yval = -1;
			}
		}
		else
		{
			mPatchStart = true;
		}

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

			if (index && at + 6 < mIns.Size() &&
				mIns[at + 0].mType == ASMIT_CLC &&
				mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg &&
				mIns[at + 2].mMode == ASMIM_IMMEDIATE && (mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mAddress == 0) &&
				mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress != index &&
				mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
				mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
				mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress != index &&
				!(mIns[at + 6].mLive & LIVE_CPU_REG_C))
			{
				if (!(mIns[at + 1].mLive & LIVE_MEM) && !(mIns[at + 4].mLive & LIVE_MEM))
					return true;
				at += 6;
			}
			else if (ins.mType == ASMIT_INC && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg + 1)
				;
			else if (ins.mMode == ASMIM_ZERO_PAGE)
			{
				if (index && ins.mAddress == index && ins.ChangesAddress())
					return false;
				else if (ins.mAddress == reg || ins.mAddress == reg + 1)
				{
					if (ins.ChangesAddress() || reg == index)
						return false;
				}
			}
			else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
			{
				if (yval < 0)
					return false;
				else if (!(ins.mLive & LIVE_MEM))
				{
					if (mPatchFail)
						return false;
					mPatchChecked = true;
					if (mTrueJump && !mTrueJump->CheckPatchFailUse() || mFalseJump && !mFalseJump->CheckPatchFailUse())
						return false;
					return true;
				}
			}

			if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
				yval = ins.mAddress;
			else if (ins.mType == ASMIT_INY && yval >= 0)
				yval = (yval + 1) & 255;
			else if (ins.mType == ASMIT_DEY && yval >= 0)
				yval = (yval - 1) & 255;
			else if (ins.mType == ASMIT_JSR || ins.mType == ASMIT_RTS)
			{
				if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || (index && ins.ChangesZeroPage(index)))
					return false;
				yval = -1;
			}
			else if (ins.ChangesYReg())
				yval = -1;

			at++;
		}

		if (mTrueJump && !mTrueJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
			return false;
		if (mFalseJump && !mFalseJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject* lobj, int address, uint32 flags)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;
		if (at == 0 && !mEntryRequiredRegs[reg] && !mEntryRequiredRegs[reg + 1])
			return false;

		while (at < mIns.Size())
		{
			NativeCodeInstruction& ins(mIns[at]);

//			assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1) && reg == index));

			if (index && at + 6 < mIns.Size() &&
				mIns[at + 0].mType == ASMIT_CLC &&
				mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg &&
				mIns[at + 2].mMode == ASMIM_IMMEDIATE && (mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mAddress == 0) &&
				mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress != index &&
				mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
				mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
				mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress != index &&
				!(mIns[at + 6].mLive & LIVE_CPU_REG_C))
			{
				bool done = !(mIns[at + 1].mLive & LIVE_MEM) && !(mIns[at + 4].mLive & LIVE_MEM);

				mIns[at + 1].mAddress = index;

				int	naddr = address + mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;

				mIns[at + 2].mType = ASMIT_ADC;
				if (flags & NCIF_LOWER)
				{
					mIns[at + 2].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE;
					mIns[at + 2].mLinkerObject = lobj;
					mIns[at + 2].mAddress = lobj ? naddr : naddr & 0xff;
					mIns[at + 2].mFlags = NCIF_LOWER;
				}
				else
					naddr &= 0xff00;
				
				mIns[at + 4].mMode = ASMIM_IMMEDIATE;
				mIns[at + 4].mAddress = 0;

				mIns[at + 5].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE;;
				mIns[at + 5].mLinkerObject = lobj;
				mIns[at + 5].mAddress = lobj ? naddr : naddr >> 8;
				mIns[at + 5].mFlags = NCIF_UPPER;

				at += 6;

				changed = true;

				if (done)
					return changed;
			}
			else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
			{
				assert(yval >= 0);

				bool	done = !(ins.mLive & LIVE_MEM);
				
				const InterInstruction* iins = ins.mIns;

				if (index)
					ins.mMode = ASMIM_ABSOLUTE_Y;
				else if (ins.mLinkerObject || address >= 256)
					ins.mMode = ASMIM_ABSOLUTE;
				else
					ins.mMode = ASMIM_ZERO_PAGE;
				ins.mLinkerObject = lobj;
				ins.mAddress = address + yval;
				ins.mFlags = (ins.mFlags & ~(NCIF_LOWER | NCIF_UPPER)) | flags;
				if (index)
				{
					if (ins.mLive & LIVE_CPU_REG_Y)
					{
						mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, yval));
						if (mIns[at].mLive & LIVE_CPU_REG_Z)
						{
							mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
							mIns[at].mLive |= LIVE_CPU_REG_A;
						}
					}
					mIns.Insert(at, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, index));
				}
				at++;
				
				changed = true;

				if (done)
					return changed;
			}
			else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
				yval = ins.mAddress;
			else if (ins.mType == ASMIT_INY && yval >= 0)
				yval = (yval + 1) & 255;
			else if (ins.mType == ASMIT_DEY && yval >= 0)
				yval = (yval - 1) & 255;
			else if (ins.mType == ASMIT_INC && ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg + 1)
			{
				ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
				address += 256;
			}
			else if (ins.ChangesYReg())
				yval = -1;
			else if (index && at + 6 < mIns.Size() &&
				mIns[at + 0].mType == ASMIT_CLC &&
				mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg + 0 &&
				mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
				mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
				mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
			{
				int	add = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
				mIns[at + 1].mAddress = index;

				mIns[at + 2].mMode = ASMIM_IMMEDIATE_ADDRESS;
				mIns[at + 2].mLinkerObject = lobj;
				mIns[at + 2].mAddress = address + add;
				mIns[at + 2].mFlags = NCIF_LOWER;
			
				mIns[at + 4].mMode = ASMIM_IMMEDIATE;
				mIns[at + 4].mAddress = 0;

				mIns[at + 5].mMode = ASMIM_IMMEDIATE_ADDRESS;
				mIns[at + 5].mLinkerObject = lobj;
				mIns[at + 5].mAddress = address + add;
				mIns[at + 5].mFlags = NCIF_UPPER;

				changed = true;
			}


			at++;
		}

		if (mTrueJump && mTrueJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags))
			changed = true;			
		if (mFalseJump && mFalseJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address, flags))
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::FindGlobalAddressSumY(int at, int reg, bool direct, int& apos, const NativeCodeInstruction*& ains, const NativeCodeInstruction*& iins, uint32& flags, int& addr)
{
	flags = 0;

	int j = at - 7;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 1]);
			iins = &(mIns[j + 2]);
			apos = j + 0;

			int ireg = iins->mAddress;
			if (reg == ireg)
			{
				if (!direct)
					return false;

				flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].ChangesYReg())
						flags &= ~LIVE_CPU_REG_Y;
					if (mIns[k].ChangesXReg())
						flags &= ~LIVE_CPU_REG_X;
					k++;
				}

				return flags != 0;
			}
			else
			{
				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}

				return true;
			}
		}
		else if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = &(mIns[j + 1]);
			apos = j + 0;

			int ireg = iins->mAddress;
			if (reg == ireg)
			{
				if (!direct)
					return false;

				flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].ChangesYReg())
						flags &= ~LIVE_CPU_REG_Y;
					if (mIns[k].ChangesXReg())
						flags &= ~LIVE_CPU_REG_X;
					k++;
				}

				return flags != 0;
			}
			else
			{
				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}

				return true;
			}
		}
		else if (
			mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = &(mIns[j + 0]);
			apos = j + 1;

			int ireg = iins->mAddress;
			if (reg == ireg)
			{
				if (!direct)
					return false;

				flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].ChangesYReg())
						flags &= ~LIVE_CPU_REG_Y;
					if (mIns[k].ChangesXReg())
						flags &= ~LIVE_CPU_REG_X;
					k++;
				}

				return flags != 0;
			}
			else
			{
				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}

				return true;
			}
		}
		else if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ABSOLUTE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 1]);
			iins = &(mIns[j + 2]);
			apos = j + 0;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].ChangesGlobalMemory())
					return false;
				k++;
			}

			return true;
		}
#if 1
		else if (
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 2].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = nullptr;
			apos = j + 1;

			if (!direct)
				return false;

			flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

			if (mIns[j + 0].mType == ASMIT_TAX)
				flags |= LIVE_CPU_REG_X;
			if (mIns[j + 0].mType == ASMIT_TAY)
				flags |= LIVE_CPU_REG_Y;

			int	k = j + 7;
			while (k < at)
			{
				assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
				if (mIns[k].ChangesYReg())
					flags &= ~LIVE_CPU_REG_Y;
				if (mIns[k].ChangesXReg())
					flags &= ~LIVE_CPU_REG_X;
				k++;
			}

			return flags != 0;
		}
		else if (
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 5].mFlags & NCIF_UPPER) && mIns[j + 5].mLinkerObject == mIns[j + 2].mLinkerObject &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = nullptr;
			apos = j + 1;

			if (!direct)
				return false;

			flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

			if (mIns[j + 0].mType == ASMIT_TAX)
				flags |= LIVE_CPU_REG_X;
			if (mIns[j + 0].mType == ASMIT_TAY)
				flags |= LIVE_CPU_REG_Y;

			int	k = j + 7;
			while (k < at)
			{
				assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
				if (mIns[k].ChangesYReg())
					flags &= ~LIVE_CPU_REG_Y;
				if (mIns[k].ChangesXReg())
					flags &= ~LIVE_CPU_REG_X;
				k++;
			}

			return flags != 0;
		}
		else if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && 
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = &(mIns[j + 1]);
			apos = j + 0;

			addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);

			int ireg = iins->mAddress;
			if (reg == ireg)
			{
				if (!direct)
					return false;

				flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].ChangesYReg())
						flags &= ~LIVE_CPU_REG_Y;
					if (mIns[k].ChangesXReg())
						flags &= ~LIVE_CPU_REG_X;
					k++;
				}

				return flags != 0;
			}
			else
			{
				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}

				return true;
			}
		}
		else if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 1]);
			iins = &(mIns[j + 2]);
			apos = j + 0;

			addr = mIns[j + 1].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);

			int ireg = iins->mAddress;
			if (reg == ireg)
			{
				if (!direct)
					return false;

				flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].ChangesYReg())
						flags &= ~LIVE_CPU_REG_Y;
					if (mIns[k].ChangesXReg())
						flags &= ~LIVE_CPU_REG_X;
					k++;
				}

				return flags != 0;
			}
			else
			{
				int	k = j + 7;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}

				return true;
			}
		}
		else if (
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE && 
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && 
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && 
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 2]);
			iins = nullptr;
			apos = j + 1;

			addr = mIns[j + 2].mAddress + 256 * (mIns[j + 4].mAddress + mIns[j + 5].mAddress);

			if (!direct)
				return false;

			flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive;

			if (mIns[j + 0].mType == ASMIT_TAX)
				flags |= LIVE_CPU_REG_X;
			if (mIns[j + 0].mType == ASMIT_TAY)
				flags |= LIVE_CPU_REG_Y;

			int	k = j + 7;
			while (k < at)
			{
				assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
				if (mIns[k].ChangesYReg())
					flags &= ~LIVE_CPU_REG_Y;
				if (mIns[k].ChangesXReg())
					flags &= ~LIVE_CPU_REG_X;
				k++;
			}

			return flags != 0;
		}
#endif

		if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
			return false;

		j--;
	}

	if (at >= 6 &&
		mIns[0].mType == ASMIT_CLC &&
		mIns[1].mType == ASMIT_ADC && mIns[1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[1].mFlags & NCIF_LOWER) && mIns[1].mLinkerObject &&
		mIns[2].mType == ASMIT_STA && mIns[2].mMode == ASMIM_ZERO_PAGE && mIns[2].mAddress == reg &&
		mIns[3].mType == ASMIT_LDA && mIns[3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[3].mFlags & NCIF_UPPER) && mIns[3].mLinkerObject == mIns[1].mLinkerObject &&
		mIns[4].mType == ASMIT_ADC && mIns[4].mMode == ASMIM_IMMEDIATE && mIns[4].mAddress == 0 &&
		mIns[5].mType == ASMIT_STA && mIns[5].mMode == ASMIM_ZERO_PAGE && mIns[5].mAddress == reg + 1)
	{
		ains = &(mIns[1]);
		iins = nullptr;
		apos = 0;

		if (!direct)
			return false;

		flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[0].mLive;

		int	k = 6;
		while (k < at)
		{
			assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA);
			if (mIns[k].ChangesYReg())
				flags &= ~LIVE_CPU_REG_Y;
			if (mIns[k].ChangesXReg())
				flags &= ~LIVE_CPU_REG_X;
			k++;
		}

		return flags != 0;
	}

	if (mFromJump)
	{
		while (j >= -6)
		{
			if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
				return false;
			j--;
		}
		if (mFromJump->FindGlobalAddressSumY(mFromJump->mIns.Size(), reg, false, apos, ains, iins, flags, addr))
		{
			if (iins->mMode == ASMIM_ZERO_PAGE)
			{
				int ireg = iins->mAddress;
				int	k = 0;
				while (k < at)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
						return false;
					k++;
				}
			}
			else
			{
				int	k = 0;
				while (k < at)
				{
					if (mIns[k].ChangesGlobalMemory())
						return false;
					k++;
				}
			}

			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::FindSharedGlobalAddressSumY(int at, int reg, const NativeCodeInstruction*& ains, const NativeCodeInstruction*& iins)
{
	int j = at - 7;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 1].mFlags & NCIF_LOWER) && mIns[j + 1].mLinkerObject &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 4].mFlags & NCIF_UPPER) && mIns[j + 4].mLinkerObject == mIns[j + 1].mLinkerObject &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ains = &(mIns[j + 1]);
			iins = &(mIns[j + 2]);

			int ireg = iins->mAddress;
			if (reg == ireg)
				return false;

			if (ChangesZeroPage(ireg, j + 7, at))
				return false;

			return true;
		}

		if (mIns[j + 6].ChangesZeroPage(reg) || mIns[j + 6].ChangesZeroPage(reg + 1))
			return false;

		j--;
	}

	if (mLoopHead)
		return false;

	if (mEntryBlocks.Size() > 0)
	{
		while (j >= -6)
		{
			if (mIns[j + 6].ChangesZeroPage(reg) || mIns[j + 6].ChangesZeroPage(reg + 1))
				return false;
			j--;
		}

		if (mEntryBlocks[0]->FindSharedGlobalAddressSumY(mEntryBlocks[0]->mIns.Size(), reg, ains, iins))
		{
			if (ChangesZeroPage(iins->mAddress, 0, at))
				return false;

			const NativeCodeInstruction* ains0;
			const NativeCodeInstruction* iins0;

			int i = 1;
			while (i < mEntryBlocks.Size() && mEntryBlocks[i]->FindSharedGlobalAddressSumY(mEntryBlocks[i]->mIns.Size(), reg, ains0, iins0) && ains0->IsSame(*ains) && iins0->IsSame(*iins))
				i++;
			if (i == mEntryBlocks.Size())
				return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::JoinTAXARange(int from, int to)
{
	int	start = from;
	if (from >= 2)
	{
		start = from - 2;
		if (mIns[start].mType == ASMIT_LDA && mIns[start].mMode == ASMIM_ZERO_PAGE && mIns[start + 1].mType == ASMIT_AND && mIns[start + 1].mMode == ASMIM_IMMEDIATE)
		{

			for (int i = from + 1; i < to; i++)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[start].mAddress && mIns[i].ChangesAddress())
					return false;
			}

			int	live = mIns[to].mLive;
			mIns.Remove(to);
			for (int i = start; i < from; i++)
			{
				mIns.Insert(to, mIns[start]);
				mIns[to].mLive |= live;
				mIns.Remove(start);
			}
			mIns.Remove(start);

			CheckLive();

			return true;
		}
		else if (mIns[start].mType == ASMIT_TXA && mIns[start + 1].mType == ASMIT_AND && mIns[start + 1].mMode == ASMIM_IMMEDIATE && !(mIns[start + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			mIns.Insert(to + 1, NativeCodeInstruction(mIns[start + 1].mIns, ASMIT_AND, ASMIM_IMMEDIATE, mIns[start + 1].mAddress));
			mIns.Remove(start, 3);

			CheckLive();

			return true;
		}
		else if (mIns[start].mType == ASMIT_LDA && mIns[start].mMode == ASMIM_ABSOLUTE_X && mIns[start + 1].ChangesAccu() && !mIns[start + 1].ChangesAddress() && !mIns[start + 1].RequiresYReg())
		{
			for (int i = from + 1; i < to; i++)
			{
				if (mIns[start].MayBeChangedOnAddress(mIns[i]) || mIns[start + 1].MayBeChangedOnAddress(mIns[i]))
					return false;
				if (mIns[start + 1].RequiresCarry() && mIns[i].ChangesCarry())
					return false;
				if ((mIns[start + 1].mLive & LIVE_CPU_REG_C) && mIns[i].RequiresCarry())
					return false;
			}

			int	live = mIns[to].mLive;
			mIns.Remove(to);
			for (int i = start; i < from; i++)
			{
				mIns.Insert(to, mIns[start]);
				mIns[to].mLive |= live;
				mIns.Remove(start);
			}
			mIns.Remove(start);

			CheckLive();

			return true;
		}
		else if (mIns[start + 0].mType == ASMIT_LDY && mIns[start + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[start + 1].mType == ASMIT_LDA && mIns[start + 1].mMode == ASMIM_INDIRECT_Y &&
			!(mIns[start + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[to].mLive & LIVE_CPU_REG_Y))
		{

			for (int i = from + 1; i < to; i++)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[start + 1].mAddress || mIns[i].mAddress == mIns[start + 1].mAddress + 1) && mIns[i].ChangesAddress())
					return false;
				if (mIns[i].ChangesGlobalMemory())
					return false;
			}

			int	live = mIns[to].mLive;
			mIns.Remove(to);
			for (int i = start; i < from; i++)
			{
				mIns.Insert(to, mIns[start]);
				mIns[to].mLive |= live;
				mIns.Remove(start);
			}
			mIns.Remove(start);

			CheckLive();

			return true;
		}

		if (!(mIns[from].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && !(mIns[to].mLive & LIVE_CPU_REG_C))
		{
			start = from;
			while (start > 0 && 
				mIns[start - 1].mType != ASMIT_LDA &&
				mIns[start - 1].mType != ASMIT_TAY &&
				mIns[start - 1].mType != ASMIT_TAX &&
				(mIns[start - 1].mMode == ASMIM_IMMEDIATE || mIns[start - 1].mMode == ASMIM_IMPLIED))
				start--;
			if (start > 0 && mIns[start - 1].mType == ASMIT_LDA && mIns[start - 1].mMode == ASMIM_ZERO_PAGE)
			{
				for (int i = from + 1; i < to; i++)
				{
					if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[start - 1].mAddress && mIns[i].ChangesAddress())
						return false;
					if ((mIns[start - 1].mLive & LIVE_CPU_REG_C) && mIns[i].ChangesCarry())
						return false;
				}

				start--;

				int	plive = mIns[start].mLive;
				for (int i = from; i < to; i++)
					mIns[i].mLive |= plive;

				if (mIns[to].mLive & LIVE_CPU_REG_Y)
				{
					for (int i = start; i < from; i++)
						mIns[i].mLive |= LIVE_CPU_REG_Y;
				}

				int	live = mIns[to].mLive;
				mIns.Remove(to);
				for (int i = start; i < from; i++)
				{
					mIns.Insert(to, mIns[start]);
					mIns[to].mLive |= live;
					mIns.Remove(start);
				}
				mIns.Remove(start);

				CheckLive();

				return true;
			}
		}
	}

	if (from > 0 && mIns[from - 1].mType == ASMIT_LDA && mIns[from - 1].mMode == ASMIM_ABSOLUTE_X)
	{
		for (int i = from + 1; i < to; i++)
		{
			if (mIns[from - 1].MayBeChangedOnAddress(mIns[i]))
				return false;
		}

		int	live = mIns[to].mLive;
		mIns.Remove(to);
		mIns.Insert(to, mIns[from - 1]);
		mIns[to].mLive |= live;
		mIns.Remove(from - 1);

		CheckLive();

		return true;
	}

	if (to + 2 < mIns.Size() && mIns[to + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[to + 2].mMode) && !(mIns[to + 2].mLive & LIVE_CPU_REG_X) && !ReferencesXReg(from + 1, to))
	{
		if (mIns[to + 1].mType == ASMIT_ORA && mIns[to + 1].mMode == ASMIM_IMMEDIATE)
		{
			if (mIns[to + 2].mLive & LIVE_CPU_REG_A)
			{
				if (to + 3 < mIns.Size() && mIns[to + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[to + 3].mMode) && !(mIns[to + 3].mLive & LIVE_CPU_REG_A))
				{
					mIns[to + 0].mType = ASMIT_NOP; mIns[to + 0].mMode = ASMIM_IMPLIED;
					mIns[to + 1].mType = ASMIT_NOP; mIns[to + 1].mMode = ASMIM_IMPLIED;
					mIns[to + 2].mType = ASMIT_STX; mIns[to + 2].mLive |= LIVE_CPU_REG_X;
					mIns[to + 3].mType = ASMIT_STX;
					mIns.Insert(from, NativeCodeInstruction(mIns[to + 0].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, mIns[to + 1].mAddress));
					return true;
				}
			}
			else
			{
				mIns[to + 0].mType = ASMIT_NOP; mIns[to + 0].mMode = ASMIM_IMPLIED;
				mIns[to + 1].mType = ASMIT_NOP; mIns[to + 1].mMode = ASMIM_IMPLIED;
				mIns[to + 2].mType = ASMIT_STX;
				mIns.Insert(from, NativeCodeInstruction(mIns[to + 0].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, mIns[to + 1].mAddress));
				return true;
			}
		}
	}

	int i = from + 1;
	while (i < to && (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i].mMode == ASMIM_ABSOLUTE || mIns[i].mMode == ASMIM_ZERO_PAGE))
		i++;
	if (i == to)
	{
		for (int i = from + 1; i < to; i++)
		{
			if (mIns[i].mType == ASMIT_LDA)
				mIns[i].mType = ASMIT_LDX;
			else if (mIns[i].mType == ASMIT_STA)
				mIns[i].mType = ASMIT_STX;
			mIns[i].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_A;
		}
		mIns[from].mType = ASMIT_NOP; mIns[from].mMode = ASMIM_IMPLIED;
		mIns[to].mType = ASMIT_NOP; mIns[to].mMode = ASMIM_IMPLIED;

		CheckLive();

		return true;
	}

	if (!(mIns[from].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && to + 1 < mIns.Size() && mIns[to + 1].IsLogic() && !(mIns[to + 1].mLive & LIVE_CPU_REG_Z))
	{
		int k = from + 1;
		while (k < to && !mIns[to + 1].MayBeChangedOnAddress(mIns[k]))
			k++;
		if (k == to)
		{
			NativeCodeInstruction	ins(mIns[to + 1]);
			ins.mLive |= mIns[from].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y);
			mIns.Remove(to + 1);
			mIns.Insert(from, ins);

			CheckLive();

			return true;
		}
	}

	if (from > 0 && mIns[from - 1].mType == ASMIT_STA && mIns[from - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[to].mLive & LIVE_CPU_REG_X) && 
		!ChangesZeroPage(mIns[from - 1].mAddress, from, to) && !ReferencesXReg(from + 1, to))
	{
		mIns[to].mType = ASMIT_LDA; mIns[to].mMode = ASMIM_ZERO_PAGE; mIns[to].mAddress = mIns[from - 1].mAddress;
		mIns[from].mType = ASMIT_NOP;

		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;
		}
	}
#if 1
	if (to + 2 < mIns.Size() &&
		!(mIns[from].mLive & LIVE_CPU_REG_A) &&
		mIns[to + 1].mType == ASMIT_LDY &&
		mIns[to + 2].mType == ASMIT_STA && !(mIns[to + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		bool	usesX = mIns[to + 1].ReferencesXReg() || mIns[to + 2].ReferencesXReg();
		uint32	vflag = (mIns[to + 1].mFlags | mIns[to + 2].mFlags) & NCIF_VOLATILE;
		int i = to - 1;
		while (i > from && 
			!mIns[i].MayBeChangedOnAddress(mIns[to + 2]) && 
			!mIns[to + 1].MayBeChangedOnAddress(mIns[i]) && 
			!(mIns[to + 2].mMode == ASMIM_INDIRECT_Y && mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[to + 2].mAddress || mIns[i].mAddress == mIns[to + 2].mAddress + 1) && mIns[i].ChangesAddress()) &&
			!mIns[i].ReferencesYReg() &&
			!(mIns[i].mFlags & vflag) &&
			!(usesX && mIns[i].ChangesXReg()))
		{
			i--;
		}
		if (i == from)
		{
			NativeCodeInstruction	i0 = mIns[to + 1];
			NativeCodeInstruction	i1 = mIns[to + 2];

			i0.mLive |= mIns[from].mLive;
			i1.mLive |= mIns[from].mLive;

			mIns.Remove(to, 3);
			mIns.Remove(from);
			mIns.Insert(from, i0);
			mIns.Insert(from + 1, i1);
			return true;
		}
	}
#endif


	return false;
}

bool NativeCodeBasicBlock::JoinTAYARangeLive(int from, int to)
{
	int k = from + 1;
	while (k < to &&
		(mIns[k].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[k].mMode) ||
			mIns[k].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[k].mMode)))
		k++;
	if (k == to)
	{
		for (int i = from + 1; i < to; i++)
		{
			if (mIns[i].mType == ASMIT_LDA)
				mIns[i].mType = ASMIT_LDY;
			else if (mIns[i].mType == ASMIT_STA)
				mIns[i].mType = ASMIT_STY;
			mIns[i].mLive |= LIVE_CPU_REG_A;
		}
		mIns[from].mType = ASMIT_NOP;
		mIns[to].mType = ASMIT_TAY;
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::JoinTAXARangeLive(int from, int to)
{
	int k = from + 1;
	while (k < to &&
		(mIns[k].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[k].mMode) ||
			mIns[k].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[k].mMode)))
		k++;
	if (k == 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_A;
		}
		mIns[from].mType = ASMIT_NOP;
		mIns[to].mType = ASMIT_TAX;
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::ReverseReplaceTAX(int at)
{
	int	i = at;
	while (i > 0)
	{
		if (mIns[i - 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i - 1].mMode))
		{
			mIns[i - 1].mType = ASMIT_LDX;
			mIns[i - 1].mLive |= LIVE_CPU_REG_X;
			while (i < at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				if (mIns[i].mType == ASMIT_STA)
					mIns[i].mType = ASMIT_STX;

				i++;
			}
			mIns[at].mType = ASMIT_NOP;

			return true;
		}
		else if (mIns[i - 1].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i - 1].mMode))
		{

		}
		else
			return false;

		i--;
	}

	return false;
}


bool NativeCodeBasicBlock::MergeXYSameValue(int from)
{
	int	to = from;
	while (to < mIns.Size())
	{
		if (mIns[to].ChangesYReg() || mIns[to].ChangesXReg())
			return false;

		if (!(mIns[to].mLive & LIVE_CPU_REG_X))
		{
			for (int i = from; i <= to; i++)
			{
				if (mIns[i].mMode == ASMIM_INDIRECT_X)
					return false;
				else if (mIns[i].mMode == ASMIM_ABSOLUTE_X)
				{
					if (!HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
						return false;
				}
			}

			return ReplaceXRegWithYReg(from, to + 1);
		}
		else if (!(mIns[to].mLive & LIVE_CPU_REG_Y))
		{
			for (int i = from; i <= to; i++)
			{
				if (mIns[i].mMode == ASMIM_INDIRECT_Y)
					return false;
				else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
				{
					if (!HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
						return false;
				}
			}

			return ReplaceYRegWithXReg(from, to + 1);
		}

		to++;
	}

	return false;
}

int NativeCodeBasicBlock::FindFreeAccu(int at) const
{
	bool used[4] = { false, false, false, false };
	for (int i = 0; i < 4; i++)
		if (mEntryRequiredRegs[i + BC_REG_ACCU])
			used[i] = true;

	for (int i = 0; i < at; i++)
	{
		for (int j = 0; j < 4; j++)
			if (mIns[i].ReferencesZeroPage(j + BC_REG_ACCU))
				used[j] = true;
	}

	for(int j=0; j<4; j++)
		if (!used[j])
			return j + BC_REG_ACCU;

	return -1;
}

bool NativeCodeBasicBlock::IsSameZPValue(int reg1, int reg2, int depth) const
{
	if (depth < 10)
	{
		int i = mIns.Size() - 1;
		while (i >= 0 && !mIns[i].ChangesZeroPage(reg1) && !mIns[i].ChangesZeroPage(reg2))
			i--;

		if (i < 0)
		{
			for (int j = 0; j < mEntryBlocks.Size(); j++)
				if (!mEntryBlocks[j]->IsSameZPValue(reg1, reg2, depth + 1))
					return false;
			return true;
		}
		else if (i > 0)
		{
			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 + 0].mAddress == reg1 && mIns[i + 1].mAddress == reg2 || mIns[i + 0].mAddress == reg2 && mIns[i + 1].mAddress == reg1))
			{
				return true;
			}
			else if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				(mIns[i + 0].mAddress == reg1 && mIns[i + 1].mAddress == reg2 || mIns[i + 0].mAddress == reg2 && mIns[i + 1].mAddress == reg1))
			{
				return true;
			}
			else if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				(mIns[i + 0].mAddress == reg1 && mIns[i + 1].mAddress == reg2 || mIns[i + 0].mAddress == reg2 && mIns[i + 1].mAddress == reg1))
			{
				return true;
			}
		}
	}

	return false;		
}

int NativeCodeBasicBlock::RetrieveZPValue(int reg, int at, int depth) const
{
	while (at >= 0 && !mIns[at].ChangesZeroPage(reg))
		at--;

	if (at >= 0)
	{
		if (mIns[at].mType == ASMIT_STA)
			return RetrieveAValue(at);
		else if (mIns[at].mType == ASMIT_STX)
			return RetrieveXValue(at);
		else if (mIns[at].mType == ASMIT_STY)
			return RetrieveYValue(at);
		else
			return -1;
	}
	else if (mEntryBlocks.Size() == 1 && depth < 20)
		return mEntryBlocks[0]->RetrieveZPValue(reg, mEntryBlocks[0]->mIns.Size() - 1, depth + 1);
	else
		return -1;
}

int NativeCodeBasicBlock::RetrieveYValue(int at, int depth) const
{
	if (at >= mIns.Size())
		at = mIns.Size() - 1;

	int offset = 0;
	while (at >= 0)
	{
		if (mIns[at].mType == ASMIT_INY)
			offset++;
		else if (mIns[at].mType == ASMIT_DEY)
			offset--;
		else if (mIns[at].ChangesYReg())
			break;
		at--;
	}

	if (at >= 0)
	{
		if (mIns[at].mType == ASMIT_LDY && mIns[at].mMode == ASMIM_IMMEDIATE)
			return (mIns[at].mAddress + offset) & 0xff;
		else
			return -1;
	}
	else if (mEntryBlocks.Size() >= 1 && depth < 20)
	{
		int yval = mEntryBlocks[0]->RetrieveYValue(mEntryBlocks[0]->mIns.Size() - 1, depth + 1);
		if (yval >= 0)
		{
			for (int i = 1; i < mEntryBlocks.Size(); i++)
			{
				if (yval != mEntryBlocks[i]->RetrieveYValue(mEntryBlocks[i]->mIns.Size() - 1, depth + 5))
					return -1;
			}
			return (yval + offset) & 0xff;
		}
		else
			return -1;
	}
	else
		return -1;
}

int NativeCodeBasicBlock::RetrieveXValue(int at, int depth) const
{
	if (at >= mIns.Size())
		at = mIns.Size() - 1;

	int offset = 0;
	while (at >= 0)
	{
		if (mIns[at].mType == ASMIT_INX)
			offset++;
		else if (mIns[at].mType == ASMIT_DEX)
			offset--;
		else if (mIns[at].ChangesXReg())
			break;
		at--;
	}

	if (at >= 0)
	{
		if (mIns[at].mType == ASMIT_LDX && mIns[at].mMode == ASMIM_IMMEDIATE)
			return (mIns[at].mAddress + offset) & 0xff;
		else
			return -1;
	}
	else if (mEntryBlocks.Size() >= 1 && depth < 20)
	{
		int xval = mEntryBlocks[0]->RetrieveXValue(mEntryBlocks[0]->mIns.Size() - 1, depth + 1);
		if (xval >= 0)
		{
			for (int i = 1; i < mEntryBlocks.Size(); i++)
			{
				if (xval != mEntryBlocks[i]->RetrieveXValue(mEntryBlocks[i]->mIns.Size() - 1, depth + 5))
					return -1;
			}
			return (xval + offset) & 0xff;
		}
		else
			return -1;
	}
	else
		return -1;
}

int NativeCodeBasicBlock::RetrieveCValue(int at, int depth) const
{
	while (at >= 0 && !mIns[at].ChangesCarry())
		at--;
	if (at >= 0)
	{
		if (mIns[at].mType == ASMIT_CLC)
			return 0;
		else if (mIns[at].mType == ASMIT_SEC)
			return 1;
		else
			return -1;
	}
	else if (mEntryBlocks.Size() == 1 && depth < 20)
		return mEntryBlocks[0]->RetrieveCValue(mEntryBlocks[0]->mIns.Size() - 1, depth + 1);
	else if (mEntryBlocks.Size() == 2 && depth < 20)
	{
		int e0 = -1, e1 = -1;
		if (mEntryBlocks[0]->mBranch == ASMIT_BCC)
		{
			if (this == mEntryBlocks[0]->mTrueJump)
				e0 = 0;
			else
				e0 = 1;
		}
		else if (mEntryBlocks[0]->mBranch == ASMIT_BCS)
		{
			if (this == mEntryBlocks[0]->mTrueJump)
				e0 = 1;
			else
				e0 = 0;
		}
		else
			e0 = mEntryBlocks[0]->RetrieveCValue(mEntryBlocks[0]->mIns.Size() - 1, depth + 1);

		if (mEntryBlocks[1]->mBranch == ASMIT_BCC)
		{
			if (this == mEntryBlocks[1]->mTrueJump)
				e1 = 0;
			else
				e1 = 1;
		}
		else if (mEntryBlocks[1]->mBranch == ASMIT_BCS)
		{
			if (this == mEntryBlocks[1]->mTrueJump)
				e1 = 1;
			else
				e1 = 0;
		}
		else
			e1 = mEntryBlocks[1]->RetrieveCValue(mEntryBlocks[1]->mIns.Size() - 1, depth + 1);

		if (e0 >= 0 && e1 >= 0 && e0 == e1)
			return e0;
		else
			return -1;
	}
	else
		return -1;
}

int NativeCodeBasicBlock::RetrieveAValue(int at, int depth) const
{
	while (at >= 0 && !mIns[at].ChangesAccu())
		at--;
	if (at >= 0)
	{
		if (mIns[at].mType == ASMIT_LDA && mIns[at].mMode == ASMIM_IMMEDIATE)
			return mIns[at].mAddress;
		else
			return -1;
	}
	else if (mEntryBlocks.Size() == 1 && depth < 20)
	{
		if (mEntryBlocks[0]->mBranch == ASMIT_BEQ && this == mEntryBlocks[0]->mTrueJump ||
			mEntryBlocks[0]->mBranch == ASMIT_BNE && this == mEntryBlocks[0]->mFalseJump)
		{
			if (mEntryBlocks[0]->mIns.Size() > 0 && mEntryBlocks[0]->mIns.Last().ChangesAccuAndFlag())
				return 0;
		}
		return mEntryBlocks[0]->RetrieveAValue(mEntryBlocks[0]->mIns.Size() - 1, depth + 1);
	}
	else
		return -1;
}

void NativeCodeBasicBlock::RepairLoadYImmediate(int at, int val)
{
	if (mIns[at].mLive & LIVE_CPU_REG_Y)
	{
		const InterInstruction* iins = mIns[at].mIns;

		if (mIns[at].mLive & LIVE_CPU_REG_Z)
		{
			int i = at;
			while (i + 1 < mIns.Size() && !mIns[i + 1].ReferencesYReg())
			{
				if (!(mIns[i].mLive & LIVE_CPU_REG_Z))
				{
					mIns.Insert(i + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
					return;
				}
				i++;
			}

			mIns[at].mLive |= LIVE_CPU_REG_A;

			mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
			mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
		}
		else
			mIns.Insert(at + 1, NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_IMMEDIATE, val));
	}
}

bool NativeCodeBasicBlock::PatchGlobalAdressSumYByX(int at, int reg, const NativeCodeInstruction& ains, int addr)
{
	int	yindex = 0;
	int last = at;

	while (last < mIns.Size())
	{
		if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE)
			yindex = mIns[last].mAddress;
		else if (mIns[last].ChangesYReg())
			return false;
		else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
			return false;
		else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
		{
			if (!(mIns[last].mLive & LIVE_MEM))
				break;
		}
		else if (mIns[last].RequiresXReg())
			return false;
		last++;
	}

	if (last == mIns.Size())
		return false;

	yindex = 0;
	for (int i = at; i <= last; i++)
	{
		mIns[i].mLive |= LIVE_CPU_REG_X;

		if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
			yindex = mIns[i].mAddress;
		else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
		{
			mIns[i].mMode = ASMIM_ABSOLUTE_X;
			if (ains.mMode == ASMIM_IMMEDIATE)
			{
				mIns[i].mLinkerObject = nullptr;
				mIns[i].mAddress = addr + yindex;
			}
			else
			{
				mIns[i].mLinkerObject = ains.mLinkerObject;
				mIns[i].mAddress = ains.mAddress + yindex;
			}
		}
	}

	return true;
}


bool NativeCodeBasicBlock::PatchDirectAddressSumY(int at, int reg, int apos, int breg)
{
	int	yindex = 0;
	int last = at;

	while (last < mIns.Size())
	{
		if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE && (mIns[last].mAddress == yindex || mIns[last].mAddress == yindex + 1))
			yindex = mIns[last].mAddress;
		else if (mIns[last].ChangesYReg())
			return false;
		else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == breg || mIns[last].mAddress == breg + 1 || mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
			return false;
		else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
		{
			if (!(mIns[last].mLive & LIVE_MEM))
				break;
		}
		else if (mIns[last].RequiresYReg())
			return false;
		last++;
	}

	if (last == mIns.Size())
		return false;

	RepairLoadYImmediate(last, yindex);

	mIns[apos].mType = ASMIT_TAY;
	for (int i = 0; i < 5; i++)
	{
		mIns[apos + i + 1].mType = ASMIT_NOP;
		mIns[apos + i + 1].mMode = ASMIM_IMPLIED;
	}
	yindex = 0;

	for (int i = apos; i <= last; i++)
	{
		mIns[i].mLive |= LIVE_CPU_REG_Y;

		if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
		{
			if (mIns[i].mAddress == yindex)
			{
				mIns[i].mType = ASMIT_NOP;
				mIns[i].mMode = ASMIM_IMPLIED;
			}
			else
			{
				mIns[i].mType = ASMIT_INY;
				mIns[i].mMode = ASMIM_IMPLIED;
				yindex++;
			}
		}
		else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
		{
			mIns[i].mAddress = breg;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::PatchAddressSumY(int at, int reg, int apos, int breg, int ireg)
{
	int	yindex = 0;
	int last = apos + 7;

	while (last < mIns.Size())
	{
		if (mIns[last].mType == ASMIT_LDY && mIns[last].mMode == ASMIM_IMMEDIATE && (mIns[last].mAddress == yindex || mIns[last].mAddress == yindex + 1 || mIns[last].mAddress + 1 == yindex))
			yindex = mIns[last].mAddress;
		else if (mIns[last].ChangesYReg())
			return false;
		else if (mIns[last].mMode == ASMIM_ZERO_PAGE && (mIns[last].mAddress == breg || mIns[last].mAddress == breg + 1 || mIns[last].mAddress == reg || mIns[last].mAddress == reg + 1) && mIns[last].ChangesAddress())
			return false;
		else if (mIns[last].mMode == ASMIM_INDIRECT_Y && mIns[last].mAddress == reg)
		{
			if (!(mIns[last].mLive & LIVE_MEM))
				break;
		}
		else if (mIns[last].RequiresYReg())
			return false;
		last++;
	}

	if (last == mIns.Size())
		return false;

	RepairLoadYImmediate(last, yindex);

	for (int i = 0; i < 5; i++)
	{
		mIns[apos + i + 2].mType = ASMIT_NOP;
		mIns[apos + i + 2].mMode = ASMIM_IMPLIED;
	}
	mIns[apos + 1].mType = ASMIT_LDY;
	mIns[apos + 1].mMode = ASMIM_ZERO_PAGE;
	mIns[apos + 1].mAddress = ireg;
	mIns[apos + 1].mLive |= LIVE_MEM | LIVE_CPU_REG_Y;

	yindex = 0;

	for (int i = apos + 7; i <= last; i++)
	{
		mIns[i].mLive |= LIVE_CPU_REG_Y;

		if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
		{
			if (mIns[i].mAddress == yindex)
			{
				mIns[i].mType = ASMIT_NOP;
				mIns[i].mMode = ASMIM_IMPLIED;
			}
			else if (mIns[i].mAddress == yindex + 1)
			{
				mIns[i].mType = ASMIT_INY;
				mIns[i].mMode = ASMIM_IMPLIED;
				yindex++;
			}
			else
			{
				mIns[i].mType = ASMIT_DEY;
				mIns[i].mMode = ASMIM_IMPLIED;
				yindex--;
			}
		}
		else if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == reg)
		{
			mIns[i].mFlags &= ~NCIF_YZERO;
			mIns[i].mAddress = breg;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::FindAbsoluteAddressSumY(int at, int reg, int& apos, int& offset)
{
	int j = at - 6;
	while (j >= 0)
	{
		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_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 && mIns[j + 4].mAddress == 0 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_ABSOLUTE && mIns[j + 5].mAddress == mIns[j + 2].mAddress + 1 && 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)
		{
			int	k = j + 6;
			while (k < at)
			{
				if (mIns[j + 2].MayBeChangedOnAddress(mIns[k]) || mIns[j + 5].MayBeChangedOnAddress(mIns[k]))
					return false;

				k++;
			}

			offset = mIns[j + 1].mAddress;
			apos = j;

			return true;

		}

		if (mIns[j + 6].ReferencesZeroPage(reg) || mIns[j + 6].ReferencesZeroPage(reg + 1))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::PatchAbsoluteAddressSumY(int at, int reg, int apos)
{
	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 + 2].mType = ASMIT_LDA;
	mIns[apos + 4].mType = ASMIT_NOP; mIns[apos + 4].mMode = ASMIM_IMPLIED;
	mIns[apos + 5].mType = ASMIT_LDA;

	return true;
}

bool NativeCodeBasicBlock::FindBypassAddressSumY(int at, int reg, int& apos, int& breg)
{
	int j = at - 6;
	while (j >= 0)
	{
		if (
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == reg &&
			mIns[j + 3].mType == ASMIT_LDA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == mIns[j + 1].mAddress + 1 &&
			mIns[j + 4].mType == ASMIT_ADC && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
			mIns[j + 5].mType == ASMIT_STA && mIns[j + 5].mMode == ASMIM_ZERO_PAGE && mIns[j + 5].mAddress == reg + 1)
		{
			breg = mIns[j + 1].mAddress;
			int	k = j + 6;
			while (k < at)
			{
				if (mIns[k].ChangesZeroPage(breg) || mIns[k].ChangesZeroPage(breg + 1))
					return false;

				k++;
			}

			apos = j;

			return true;
		}

		if (mIns[j + 5].ReferencesZeroPage(reg) || mIns[j + 5].ReferencesZeroPage(reg + 1))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::PatchBypassAddressSumY(int at, int reg, int apos, int breg)
{
	mIns[apos + 0].mType = ASMIT_NOP; mIns[apos + 0].mMode = ASMIM_IMPLIED;
	mIns[apos + 1].mType = ASMIT_NOP; mIns[apos + 1].mMode = ASMIM_IMPLIED;
	mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
	mIns[apos + 4].mType = ASMIT_NOP; mIns[apos + 4].mMode = ASMIM_IMPLIED;
	mIns[apos + 5].mType = ASMIT_NOP; mIns[apos + 5].mMode = ASMIM_IMPLIED;

	mIns[at + 0].mMode = ASMIM_ZERO_PAGE;
	mIns[at + 0].mAddress = reg;
	mIns[at + 1].mAddress = breg;
	mIns[at + 1].mLive |= LIVE_MEM;

	return true;
}

bool NativeCodeBasicBlock::FindDirectAddressSumY(int at, int reg, int& apos, int& breg)
{
	int j = at - 6;
	while (j >= 0)
	{
		if (
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == reg &&
			mIns[j + 3].mType == ASMIT_LDA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == mIns[j + 1].mAddress + 1 &&
			mIns[j + 4].mType == ASMIT_ADC && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 &&
			mIns[j + 5].mType == ASMIT_STA && mIns[j + 5].mMode == ASMIM_ZERO_PAGE && mIns[j + 5].mAddress == reg + 1)
		{
			breg = mIns[j + 1].mAddress;
			int	k = j + 6;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1) && mIns[k].ChangesAddress())
					return false;

				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
					return false;
				if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
					return false;

				k++;
			}

			apos = j;

			return true;
		}

		if (mIns[j + 5].mMode == ASMIM_ZERO_PAGE && (mIns[j + 5].mAddress == reg || mIns[j + 5].mAddress == reg + 1) && mIns[j + 5].ChangesAddress() || mIns[j + 5].ChangesYReg() || mIns[j + 5].RequiresYReg())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::FindExternAddressSumY(int at, int reg, int& breg, int& ireg)
{
	int j = at - 7;
	while (j >= 0)
	{
		if (
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 1].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 1].mAddress;
			ireg = mIns[j + 2].mAddress;

			if (ireg == breg || reg == breg || ireg == reg)
				return false;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				k++;
			}

			return true;
		}
		else if (
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 2].mAddress;
			ireg = mIns[j + 1].mAddress;

			if (ireg == breg || reg == breg || ireg == reg)
				return false;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				k++;
			}

			return true;
		}
		else if (
			mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 2].mAddress;
			ireg = mIns[j + 0].mAddress;

			if (ireg == breg || reg == breg || ireg == reg)
				return false;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				k++;
			}

			return true;
		}

		if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
			return false;

		j--;
	}

	if (mFromJump)
	{
		while (j >= -6)
		{
			if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
				return false;
			j--;
		}

		if (mFromJump->FindExternAddressSumY(mFromJump->mIns.Size(), reg, breg, ireg))
		{
			int	k = 0;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				k++;
			}

			return true;
		}
	}


	return false;

}

bool NativeCodeBasicBlock::FindLoadAddressSumY(int at, int reg, int& apos, int& ireg)
{
	int j = at - 7;
	while (j >= 0)
	{
		if (mIns[j + 0].mType == ASMIT_LDA && mIns[j + 0].mMode != ASMIM_ZERO_PAGE &&
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == mIns[j + 0].mMode &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			ireg = mIns[j + 2].mAddress;

			if (ireg == mIns[j + 3].mAddress || ireg == mIns[j + 6].mAddress)
				return false;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg && mIns[k].ChangesAddress())
					return false;
				k++;
			}

			apos = j;
			return true;
		}

		if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1))
			return false;
		if (mIns[j + 6].mMode == ASMIM_INDIRECT_Y && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress + 1 == reg || mIns[j + 6].mAddress == reg + 1))
			return false;
		if (mIns[j + 6].mType == ASMIT_JSR)
			return false;

		j--;
	}
	return false;
}

bool NativeCodeBasicBlock::PatchLoadAddressSumY(int at, int reg, int apos, int ireg)
{
	mIns[apos + 1].mType = ASMIT_NOP; mIns[apos + 1].mMode = ASMIM_IMPLIED;
	mIns[apos + 2].mType = ASMIT_NOP; mIns[apos + 2].mMode = ASMIM_IMPLIED;
	mIns[apos + 5].mType = ASMIT_NOP; mIns[apos + 5].mMode = ASMIM_IMPLIED;
	return true;
}

bool NativeCodeBasicBlock::FindAddressSumY(int at, int reg, int & apos, int& breg, int& ireg)
{
	int j = at - 7;
	while (j >= 0)
	{
		if (
#if 1
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 1].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 1].mAddress;
			ireg = mIns[j + 2].mAddress;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				if (breg == reg || ireg == breg)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
						return false;
					if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
						return false;
				}
				else if (ireg == reg)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg)
						return false;
					if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == ireg)
						return false;
				}
				k++;
			}

			apos = j;

			return true;
		}
		else if (
#endif
			mIns[j + 0].mType == ASMIT_CLC &&
			mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 2].mAddress;
			ireg = mIns[j + 1].mAddress;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				if (breg == reg || ireg == breg)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
						return false;
					if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
						return false;
				}
				else if (ireg == reg)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == ireg)
						return false;
					if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == ireg)
						return false;
				}
				k++;
			}

			apos = j;

			return true;
		}
		else if (
			mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 1].mType == ASMIT_CLC &&
			mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg &&
			mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_ZERO_PAGE && mIns[j + 4].mAddress == mIns[j + 2].mAddress + 1 &&
			mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE && mIns[j + 5].mAddress == 0 &&
			mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1)
		{
			breg = mIns[j + 2].mAddress;
			ireg = mIns[j + 0].mAddress;

			int	k = j + 7;
			while (k < at)
			{
				if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1 || mIns[k].mAddress == ireg) && mIns[k].ChangesAddress())
					return false;
				if (breg == reg || ireg == breg)
				{
					if (mIns[k].mMode == ASMIM_ZERO_PAGE && (mIns[k].mAddress == breg || mIns[k].mAddress == breg + 1))
						return false;
					if (mIns[k].mMode == ASMIM_INDIRECT_Y && mIns[k].mAddress == breg)
						return false;
				}
				k++;
			}

			apos = j;

			return true;
		}

		if (mIns[j + 6].mMode == ASMIM_ZERO_PAGE && (mIns[j + 6].mAddress == reg || mIns[j + 6].mAddress == reg + 1) && mIns[j + 6].ChangesAddress())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveIndirectLoadStoreDown(int at)
{
	int j = at + 2;

	while (j < mIns.Size())
	{
		if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 1].mAddress)
		{
			if (!(mIns[j].mLive & LIVE_MEM) && HasAsmInstructionMode(mIns[j].mType, ASMIM_INDIRECT_Y))
			{
				mIns[j].mMode = ASMIM_INDIRECT_Y;
				mIns[j].mAddress = mIns[at].mAddress;
				mIns[j].mLive |= LIVE_MEM;
				mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
				mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;

				for (int k = at; k < j; k++)
					mIns[k].mLive |= LIVE_CPU_REG_Y;

				return true;
			}

			return false;
		}

		if (mIns[j].ChangesYReg())
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at].mAddress) || mIns[j].ChangesZeroPage(mIns[at].mAddress + 1))
			return false;
		if (mIns[j].ChangesGlobalMemory())
			return false;

		j++;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLDXBeforeZ(int at)
{
	int i = at;
	while (i > 0)
	{
		i--;
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.ReferencesXReg())
			return false;

		if (ins.ChangesZFlag())
		{
			if (ins.ChangesAccuAndFlag())
			{
				mIns[at].mLive |= mIns[i].mLive;
				if (mIns[i].ReferencesCarry()) mIns[at].mLive |= LIVE_CPU_REG_C;

				mIns.Insert(i, mIns[at]);
				mIns.Remove(at + 1);
				mIns.Remove(at + 1);
				for (int j = i; j < at + 1; j++)
					mIns[j].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
				return true;
			}
			else
				return false;
		}

		if (ins.ChangesXReg() || ins.ChangesAccu())
			return false;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLDXUp(int at)
{
	NativeCodeInstruction& lins(mIns[at]);

	int i = at;
	while (i > 0)
	{
		i--;
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mType == ASMIT_STA && ins.SameEffectiveAddress(lins))
		{
			if (ins.mLive & LIVE_CPU_REG_Z)
				return false;
			ins.mLive |= LIVE_CPU_REG_A;

			mIns.Insert(i + 1, NativeCodeInstruction(lins.mIns, ASMIT_TAX));
			mIns.Remove(at + 1);
			
			while (i <= at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}
			return true;
		}
		if (ins.ReferencesXReg() || lins.MayBeChangedOnAddress(ins))
			return false;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLDYUp(int at)
{
	NativeCodeInstruction& lins(mIns[at]);

	int i = at;
	bool	referenced = false;
	while (i > 0)
	{
		i--;
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mType == ASMIT_STA && ins.SameEffectiveAddress(lins))
		{
			if (ins.mLive & LIVE_CPU_REG_Z)
				return false;
			ins.mLive |= LIVE_CPU_REG_A;

			mIns.Insert(i + 1, NativeCodeInstruction(lins.mIns, ASMIT_TAY));
			mIns.Remove(at + 1);

			while (i <= at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i++;
			}
			return true;
		}
		else if (lins.mMode == ASMIM_ZERO_PAGE && ins.mType == ASMIT_STX && ins.SameEffectiveAddress(lins) && !referenced)
		{
			if (lins.mLive & LIVE_MEM)
				return false;
			if (ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A))
				return false;

			mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;  mIns[i].mLive |= LIVE_CPU_REG_A;
			mIns.Insert(i + 1, NativeCodeInstruction(lins.mIns, ASMIT_TAY));
			mIns.Remove(at + 1);

			while (i <= at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i++;
			}
			return true;
		}
		if (ins.ReferencesYReg() || lins.MayBeChangedOnAddress(ins))
			return false;
		if (lins.mMode == ASMIM_ZERO_PAGE && ins.ReferencesZeroPage(lins.mAddress))
			referenced = true;

	}

	return false;
}

bool NativeCodeBasicBlock::MoveIndirectLoadStoreDownY(int at)
{
	int j = at + 3;

	int	saddr = mIns[at + 1].mAddress, daddr = mIns[at + 2].mAddress;

	NativeCodeBasicBlock* block = this;

	while (block)
	{
		while (j < block->mIns.Size())
		{
			if (block->mIns[j].mMode == ASMIM_ZERO_PAGE && block->mIns[j].mAddress == daddr)
			{
				if (!(block->mIns[j].mLive & (LIVE_MEM | LIVE_CPU_REG_Y)) && HasAsmInstructionMode(block->mIns[j].mType, ASMIM_INDIRECT_Y))
				{
					block->mIns[j].mMode = ASMIM_INDIRECT_Y;
					block->mIns[j].mAddress = saddr;
					block->mIns[j].mLive |= LIVE_MEM;
					mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
					mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
					block->mIns.Insert(j, NativeCodeInstruction(mIns[at + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[at + 0].mAddress));

					while (block != this)
					{
						block->mEntryRequiredRegs += saddr;
						block->mEntryRequiredRegs += saddr + 1;
						block = block->mEntryBlocks[0];
						block->mExitRequiredRegs += saddr;
						block->mExitRequiredRegs += saddr + 1;
					}

					return true;
				}

				return false;
			}

			if (block->mIns[j].ReferencesZeroPage(daddr))
				return false;
			if (block->mIns[j].ChangesZeroPage(saddr) || block->mIns[j].ChangesZeroPage(saddr + 1))
				return false;
			if (block->mIns[j].ChangesGlobalMemory())
				return false;

			j++;
		}

		if (block->mFalseJump)
		{
			if (block->mTrueJump->mNumEntries == 1 && !block->mFalseJump->mEntryRequiredRegs[daddr])
			{
				block = block->mTrueJump;
				j = 0;
			}
			else if (block->mFalseJump->mNumEntries == 1 && !block->mTrueJump->mEntryRequiredRegs[daddr])
			{
				block = block->mFalseJump;
				j = 0;
			}
			else
				block = nullptr;
		}
		else
			block = nullptr;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadIndirectTempStoreUp(int at)
{
	// ldy #imm
	// lda (t0), y
	// sta t1

	int	j = at - 1;
	while (j >= 3)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
		{
			if (mIns[j - 3].mType == ASMIT_LDA && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 2].mType == ASMIT_STA && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 1].mType == ASMIT_LDA && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 0].mType == ASMIT_STA && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[j - 2].mAddress == mIns[at + 1].mAddress && 
					mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 && 
					mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
				{
					for (int k = j + 1; k < at; k++)
						mIns[k].mLive |= mIns[at + 2].mLive & LIVE_CPU_REG_Y;

					mIns[at + 0].mLive |= mIns[j].mLive;
					mIns[at + 1].mLive |= mIns[j].mLive;
					mIns[at + 2].mLive |= mIns[j].mLive;

					mIns[at + 1].mAddress = mIns[j - 3].mAddress;
					mIns[at + 1].mLive |= LIVE_MEM;

					mIns.Insert(j + 1, mIns[at + 2]);
					mIns.Insert(j + 1, mIns[at + 2]);
					mIns.Insert(j + 1, mIns[at + 2]);

					mIns.Remove(at + 3);
					mIns.Remove(at + 3);
					mIns.Remove(at + 3);

					return true;
				}
			}

			return false;
		}
		if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
		{
			if (mIns[j - 3].mType == ASMIT_LDX && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 2].mType == ASMIT_STX && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 1].mType == ASMIT_LDX && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 0].mType == ASMIT_STX && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
					mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
					mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
				{
					int	addr = mIns[j - 3].mAddress;

					while (mIns[j].mLive & LIVE_CPU_REG_A)
					{
						j++;
						if (mIns[j].ReferencesZeroPage(addr) || mIns[j].ReferencesZeroPage(addr + 1))
							return false;
					}

					for (int k = j + 1; k < at; k++)
						mIns[k].mLive |= mIns[at + 2].mLive & LIVE_CPU_REG_Y;

					mIns[at + 0].mLive |= mIns[j].mLive;
					mIns[at + 1].mLive |= mIns[j].mLive;
					mIns[at + 2].mLive |= mIns[j].mLive;

					mIns[at + 1].mAddress = addr;
					mIns[at + 1].mLive |= LIVE_MEM;

					mIns.Insert(j + 1, mIns[at + 2]);
					mIns.Insert(j + 1, mIns[at + 2]);
					mIns.Insert(j + 1, mIns[at + 2]);

					mIns.Remove(at + 3);
					mIns.Remove(at + 3);
					mIns.Remove(at + 3);

					return true;
				}
			}

			return false;
		}

		if (mIns[j].ReferencesYReg())
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1))
			return false;
		if (mIns[j].ReferencesZeroPage(mIns[at + 2].mAddress))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadIndirectBypassYUp(int at)
{
	// ldy #imm
	// lda (t0), y

	// move up, and keep A in Y for the interval	

	int	j = at - 1;
	while (j >= 3)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
		{
			if (mIns[j - 3].mType == ASMIT_LDA && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 2].mType == ASMIT_STA && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 1].mType == ASMIT_LDA && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 0].mType == ASMIT_STA && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
					mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
					mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
				{
					const InterInstruction* iins(mIns[at + 0].mIns);

					mIns[at + 0].mLive |= mIns[j].mLive;
					mIns[at + 1].mLive |= mIns[j].mLive;

					mIns[at + 1].mAddress = mIns[j - 3].mAddress;
					mIns[at + 1].mLive |= LIVE_MEM;

					mIns.Insert(j + 1, mIns[at + 0]);
					mIns.Remove(at + 1);
					mIns.Insert(j + 2, mIns[at + 1]);
					mIns.Remove(at + 2);

					mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_TYA));
					mIns.Insert(j + 3, NativeCodeInstruction(iins, ASMIT_TAY));

					for (int k = j + 3; k < at + 3; k++)
						mIns[k].mLive |= LIVE_CPU_REG_Y;

					return true;
				}
			}

			return false;
		}
		if (mIns[j].mType == ASMIT_STX && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 1].mAddress + 1))
		{
			if (mIns[j - 3].mType == ASMIT_LDX && mIns[j - 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 2].mType == ASMIT_STX && mIns[j - 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 1].mType == ASMIT_LDX && mIns[j - 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[j - 0].mType == ASMIT_STX && mIns[j - 0].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[j - 2].mAddress == mIns[at + 1].mAddress &&
					mIns[j - 0].mAddress == mIns[at + 1].mAddress + 1 &&
					mIns[j - 1].mAddress == mIns[j - 3].mAddress + 1)
				{
					const InterInstruction* iins(mIns[at + 0].mIns);

					int	addr = mIns[j - 3].mAddress;

					while (mIns[j].mLive & LIVE_CPU_REG_A)
					{
						j++;
						if (mIns[j].ReferencesZeroPage(addr) || mIns[j].ReferencesZeroPage(addr + 1))
							return false;
					}

					mIns[at + 0].mLive |= mIns[j].mLive;
					mIns[at + 1].mLive |= mIns[j].mLive;

					mIns[at + 1].mAddress = addr;
					mIns[at + 1].mLive |= LIVE_MEM;

					mIns.Insert(j + 1, mIns[at + 0]);
					mIns.Remove(at + 1);
					mIns.Insert(j + 2, mIns[at + 1]);
					mIns.Remove(at + 2);

					mIns.Insert(at + 2, NativeCodeInstruction(iins, ASMIT_TYA));
					mIns.Insert(j + 3, NativeCodeInstruction(iins, ASMIT_TAY));

					for (int k = j + 3; k < at + 3; k++)
						mIns[k].mLive |= LIVE_CPU_REG_Y;

					return true;
				}
			}

			return false;
		}

		if (mIns[j].ReferencesYReg())
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveIndirectLoadStoreUp(int at)
{
	int	j = at - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_Y)
				return false;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns.Insert(j + 1, mIns[at + 1]);
			mIns.Insert(j + 2, mIns[at + 3]);
			mIns[at + 4].mType = ASMIT_NOP;
			mIns[at + 4].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress)
		{
			if (j > 0 && mIns[j - 1].mType == ASMIT_LDY && mIns[j - 1].mMode == ASMIM_IMMEDIATE && mIns[j - 1].mAddress != mIns[at + 1].mAddress)
				;
			else
				return false;
		}
		else if (mIns[at + 2].MayBeSameAddress(mIns[j]))
			return false;
		else if (mIns[j].mType == ASMIT_JSR)
			return false;

		if (mIns[j].ChangesZeroPage(mIns[at].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadStoreOutOfXYRangeUp(int at)
{
	uint32 flags = mIns[at + 1].mFlags | mIns[at + 2].mFlags;

	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].MayBeChangedOnAddress(mIns[at + 2]))
			return false;
		if (mIns[j].ChangesAddress() && mIns[j].SameEffectiveAddress(mIns[at + 1]))
			return false;
		if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg())
			return false;
		if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg())
			return false;
		if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].mType == ASMIT_JSR)
			return false;
		if (mIns[j].mFlags & flags & NCIF_VOLATILE)
			return false;

		if (mIns[j].mType == ASMIT_LDA)
		{
			if (j > 0 && (mIns[j - 1].mType == ASMIT_CLC || mIns[j - 1].mType == ASMIT_SEC))
				j--;
			mIns.Insert(j, mIns[at + 2]);
			mIns.Insert(j, mIns[at + 2]);
			int live = 0;

			if (j > 0)
				live = mIns[j - 1].mLive;
			else
			{
				if (mEntryRequiredRegs[CPU_REG_X])
					live |= LIVE_CPU_REG_X;
				if (mEntryRequiredRegs[CPU_REG_Y])
					live |= LIVE_CPU_REG_Y;
			}

			mIns[j].mLive |= live;
			mIns[j + 1].mLive |= live;

			mIns.Remove(at + 3);
			mIns.Remove(at + 3);

			return true;
		}

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveGenericLoadStoreUp(int at)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].SameEffectiveAddress(mIns[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 if (mIns[j].mType == ASMIT_LDA && mIns[j].SameEffectiveAddress(mIns[at]))
		{
			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[at].MayBeChangedOnAddress(mIns[j]))
			return false;
		if (mIns[j].MayBeSameAddress(mIns[at + 1], true))
			return false;
		if ((mIns[at + 0].mMode == ASMIM_ABSOLUTE_X || mIns[at + 1].mMode == ASMIM_ABSOLUTE_X) && mIns[j].ChangesXReg())
			return false;
		if ((mIns[at + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y) && mIns[j].ChangesYReg())
			return false;
		if (mIns[at + 0].mMode == ASMIM_INDIRECT_Y && (mIns[j].ChangesYReg() || mIns[j].ChangesZeroPage(mIns[at].mAddress) || mIns[j].ChangesZeroPage(mIns[at].mAddress + 1)))
			return false;
		if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[j].ChangesYReg() || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
			return false;

		if (mIns[j].mType == ASMIT_JSR)
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveAbsoluteLoadStoreUp(int at)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			mIns[j].mLive |= LIVE_CPU_REG_A;
			mIns.Insert(j + 1, mIns[at + 1]);
			mIns[j + 1].mLive |= LIVE_CPU_REG_A;
			mIns[j + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mType = ASMIT_NOP;
			mIns[at + 2].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (mIns[j].mType == ASMIT_LDA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			while (j < at && !mIns[j + 1].ChangesAccu() && (mIns[j].mLive & LIVE_CPU_REG_A))
				j++;
			if (j < at)
			{
				mIns[j].mLive |= LIVE_CPU_REG_A;
				mIns.Insert(j + 1, mIns[at + 1]);
				mIns[j + 1].mLive |= LIVE_CPU_REG_A;
				mIns[j + 1].mLive |= mIns[j].mLive;
				mIns[at + 2].mType = ASMIT_NOP;
				mIns[at + 2].mMode = ASMIM_IMPLIED;
				return true;
			}
			else
				return false;
		}
		if (mIns[j].ChangesZeroPage(mIns[at].mAddress))
			return false;
		if (mIns[j].MayBeSameAddress(mIns[at + 1], true))
			return false;
		if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg())
			return false;
		if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg())
			return false;
		if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[j].ChangesYReg() || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1)))
			return false;

		if (mIns[j].mType == ASMIT_JSR)
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::ReplaceZeroPageDown(int at)
{
	int i = at + 2;
	while (i < mIns.Size())
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			mIns[i].mLive |= LIVE_CPU_REG_A;
			mIns[at + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 1]);
			mIns.Remove(at, 2);
			return true;
		}

		if (mIns[i].ChangesZeroPage(mIns[at].mAddress))
			return false;
		if (mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress))
			return false;

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::ReplaceZeroPageUp(int at)
{
	int i = at - 1;
	while (i >= 0)
	{
		if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			while (i < at)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
					mIns[i].mAddress = mIns[at + 1].mAddress;
				i++;
			}

			mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
			mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;

			return true;
		}

		if (mIns[i].mType == ASMIT_JSR)
			return false;

		if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[i].UsesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress == mIns[at + 1].mAddress || mIns[i].mAddress + 1 == mIns[at + 1].mAddress))
			return false;
		if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress == mIns[at].mAddress || mIns[i].mAddress + 1 == mIns[at].mAddress))
			return false;

		i--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInstruction& lins, const NativeCodeInstruction& sins)
{
	if (!mPatched)
	{
		mPatched = true;

		if (at == -2)
		{
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].ChangesZeroPage(lins.mAddress))
					return false;
				if (mIns[i].ReferencesZeroPage(sins.mAddress))
					return false;
				if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress))
					return false;
			}

			at = mIns.Size();
		}
		else
		{
			if (at == -1)
				at = mIns.Size();

			int i = at;
			while (i > 0)
			{
				i--;
				if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == lins.mAddress)
				{
					while (i < at)
					{
						if (mIns[i].mAddress == lins.mAddress)
							mIns[i].mAddress = sins.mAddress;
						i++;
					}
					return true;
				}

				if (mIns[i].ChangesZeroPage(lins.mAddress))
					return false;
				else if (mIns[i].mMode == ASMIM_ZERO_PAGE && !mIns[i].ChangesAddress() && mIns[i].mAddress == lins.mAddress)
					;
				else if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress))
					return false;
				else if (mIns[i].ReferencesZeroPage(sins.mAddress))
					return false;
				else if (mIns[i].mType == ASMIT_JSR && mIns[i].ReferencesZeroPage(lins.mAddress))
					return false;
			}
		}

		int	pat = -1;
		NativeCodeBasicBlock* eb = nullptr;

		if (mEntryBlocks.Size() == 1 || mEntryBlocks.Size() == 2 && mEntryBlocks[1] == this)
		{
			eb = mEntryBlocks[0];
			if (!eb->mFalseJump)
				;
			else if (eb->mTrueJump == eb || eb->mFalseJump == eb)
				pat = -2;
			else if (eb->mFalseJump->mPatched && eb->mTrueJump->mPatched)
				;
			else if (
				eb->mTrueJump == this && !eb->mFalseJump->mEntryRequiredRegs[lins.mAddress] && !eb->mFalseJump->mEntryRequiredRegs[sins.mAddress] ||
				eb->mFalseJump == this && !eb->mTrueJump->mEntryRequiredRegs[lins.mAddress] && !eb->mTrueJump->mEntryRequiredRegs[sins.mAddress])
				;
			else
				return false;
		}
		else if (mEntryBlocks.Size() == 2)
		{
			NativeCodeBasicBlock* eb0 = mEntryBlocks[0];
			NativeCodeBasicBlock* eb1 = mEntryBlocks[1];

			if (eb0->mEntryBlocks.Size() == 1 && eb0->mEntryBlocks[0] == eb1)
				eb = eb0;
			else if (eb1->mEntryBlocks.Size() == 1 && eb1->mEntryBlocks[0] == eb0)
				eb = eb1;
			else
				return false;

			if (!eb->mFalseJump)
				;
			else if (eb->mTrueJump == eb || eb->mFalseJump == eb)
				;
			else if (eb->mFalseJump->mPatched && eb->mTrueJump->mPatched)
				;
			else if (
				eb->mTrueJump == this && !eb->mFalseJump->mEntryRequiredRegs[lins.mAddress] && !eb->mFalseJump->mEntryRequiredRegs[sins.mAddress] ||
				eb->mFalseJump == this && !eb->mTrueJump->mEntryRequiredRegs[lins.mAddress] && !eb->mTrueJump->mEntryRequiredRegs[sins.mAddress])
				;
			else
				return false;

			pat = -2;
		}
		else
			return false;

		if (!eb->MoveZeroPageCrossBlockUp(pat, lins, sins))
			return false;

		for(int i=0; i<at; i++)
		{
			if (mIns[i].mAddress == lins.mAddress)
				mIns[i].mAddress = sins.mAddress;
		}

		mEntryRequiredRegs += lins.mAddress;

		return true;
	}
	else
		return false;
}


bool NativeCodeBasicBlock::MergeDuplicateCondition(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mTrueJump && mFalseJump)
		{
			NativeCodeBasicBlock* cblock1 = nullptr, * eblock1 = nullptr;
			NativeCodeBasicBlock* cblock2 = nullptr, * eblock2 = nullptr;

			if (mTrueJump->mNumEntries == 1 && !mTrueJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump)
			{
				cblock1 = mTrueJump;
				eblock1 = mFalseJump;
			}
			else if (mFalseJump->mNumEntries == 1 && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump)
			{
				cblock1 = mFalseJump;
				eblock1 = mTrueJump;
			}

			if (eblock1 && eblock1->mNumEntries == 2 && eblock1->mTrueJump && eblock1->mFalseJump)
			{
				if (eblock1->mTrueJump->mNumEntries == 1 && !eblock1->mTrueJump->mFalseJump && eblock1->mTrueJump->mTrueJump == eblock1->mFalseJump)
				{
					cblock2 = eblock1->mTrueJump;
					eblock2 = eblock1->mFalseJump;
				}
				else if (eblock1->mFalseJump->mNumEntries == 1 && !eblock1->mFalseJump->mFalseJump && eblock1->mFalseJump->mTrueJump == eblock1->mTrueJump)
				{
					cblock2 = eblock1->mFalseJump;
					eblock2 = eblock1->mTrueJump;
				}

				if (eblock2 && eblock2->mNumEntries == 2)
				{
					int sz1 = mIns.Size(), sz2 = eblock1->mIns.Size();
					if (sz1 > 0 && sz2 == 1)
					{
						if (mIns[sz1 - 1].mType == ASMIT_CPY && mIns[sz1 - 1].mMode == ASMIM_IMMEDIATE && mIns[sz1 - 1].mAddress == 0xff && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS || mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) &&
							eblock1->mIns[0].mType == ASMIT_INY && (eblock1->mBranch == ASMIT_BEQ || eblock1->mBranch == ASMIT_BNE) && !cblock1->ReferencesYReg())
						{
							bool	check0, check1;
							check0 = (mBranch == ASMIT_BCC || mBranch == ASMIT_BNE) == (mTrueJump == cblock1);
							check1 = (eblock1->mBranch == ASMIT_BNE) == (eblock1->mTrueJump == cblock2);

							if (check0 == check1)
							{
								for (int i = 0; i < cblock1->mIns.Size(); i++)
									cblock2->mIns.Insert(i, cblock1->mIns[i]);
								mBranch = ASMIT_JMP;
								mTrueJump = eblock1;
								mFalseJump = nullptr;
								eblock1->mNumEntries--;
								eblock1->mEntryBlocks.RemoveAll(cblock1);
								changed = true;
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->MergeDuplicateCondition())
			changed = true;
		if (mFalseJump && mFalseJump->MergeDuplicateCondition())
			changed = true;

	}

	return changed;

}

bool NativeCodeBasicBlock::ShortcutCrossBlockCondition(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int sz = mIns.Size();
		if (sz > 0 && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !mFalseJump)
		{
			if (mTrueJump->mIns.Size() == 2 && mTrueJump->mIns[0].mType == ASMIT_STA &&
				mTrueJump->mIns[1].mType == ASMIT_ORA && mTrueJump->mIns[1].mMode == ASMIM_IMMEDIATE && mTrueJump->mIns[1].mAddress == 0 &&
				(mTrueJump->mBranch == ASMIT_BEQ || mTrueJump->mBranch == ASMIT_BNE))
			{
				mIns.Push(mTrueJump->mIns[0]);
				
				mTrueJump->mNumEntries--;
				mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
				if (mTrueJump->mBranch == ASMIT_BEQ)
				{
					if (mIns[sz - 1].mAddress == 0)
						mTrueJump = mTrueJump->mTrueJump;
					else
						mTrueJump = mTrueJump->mFalseJump;
				}
				else
				{
					if (mIns[sz - 1].mAddress != 0)
						mTrueJump = mTrueJump->mTrueJump;
					else
						mTrueJump = mTrueJump->mFalseJump;
				}
				mTrueJump->mNumEntries++;
				mTrueJump->mEntryBlocks.Push(this);
				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->ShortcutCrossBlockCondition())
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutCrossBlockCondition())
			changed = true;
	}

	return changed;
}

bool  NativeCodeBasicBlock::ShortcutCrossBlockMoves(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (!mLoopHead)
		{
			int i = 0;
			while (i + 1 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					proc->ResetPatched();
					if (MoveZeroPageCrossBlockUp(i, mIns[i + 0], mIns[i + 1]))
					{
						changed = true;
						mIns.Remove(i, 2);
					}
					else
						i++;
				}
				else
					i++;
			}

			CheckLive();
		}

		if (mTrueJump && mTrueJump->ShortcutCrossBlockMoves(proc))
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutCrossBlockMoves(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::Check16BitSum(int at, NativeRegisterSum16Info& info)
{
	if (at + 6 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_CLC &&
			mIns[at + 1].mType == ASMIT_LDA &&
			(mIns[at + 2].mType == ASMIT_ADC || mIns[at + 2].mType == ASMIT_ORA && mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 2].mAddress == 0) &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 4].mType == ASMIT_LDA &&
			mIns[at + 5].mType == ASMIT_ADC &&
			mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
		{
			info.mDstL = &(mIns[at + 3]);
			info.mDstH = &(mIns[at + 6]);

			if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && (mIns[at + 5].mMode == ASMIM_ZERO_PAGE || mIns[at + 5].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mAddress == 0))
			{
				if (mIns[at + 1].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE)
				{
					info.mAddress = (mIns[at + 1].mAddress & 0xff) + (mIns[at + 4].mAddress << 8);
					info.mLinkerObject = nullptr;
					info.mSrcL = &(mIns[at + 2]);
					info.mSrcH = &(mIns[at + 5]);
					info.mAddL = &(mIns[at + 1]);
					info.mAddH = &(mIns[at + 4]);
					info.mImmediate = true;

					return true;
				}
				else if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 1].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 1].mAddress == mIns[at + 4].mAddress)
				{
					info.mAddress = mIns[at + 1].mAddress;
					info.mLinkerObject = mIns[at + 1].mLinkerObject;
					info.mSrcL = &(mIns[at + 2]);
					info.mSrcH = &(mIns[at + 5]);
					info.mAddL = &(mIns[at + 1]);
					info.mAddH = &(mIns[at + 4]);
					info.mImmediate = true;

					return true;
				}
			}
			else if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && (mIns[at + 4].mMode == ASMIM_ZERO_PAGE || mIns[at + 4].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mAddress == 0))
			{
				if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE)
				{
					info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8);
					info.mLinkerObject = nullptr;
					info.mSrcL = &(mIns[at + 1]);
					info.mSrcH = &(mIns[at + 4]);
					info.mAddL = &(mIns[at + 2]);
					info.mAddH = &(mIns[at + 5]);
					info.mImmediate = true;

					return true;
				}
				else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress)
				{
					info.mAddress = mIns[at + 2].mAddress;
					info.mLinkerObject = mIns[at + 2].mLinkerObject;
					info.mSrcL = &(mIns[at + 1]);
					info.mSrcH = &(mIns[at + 4]);
					info.mAddL = &(mIns[at + 2]);
					info.mAddH = &(mIns[at + 5]);
					info.mImmediate = true;

					return true;
				}
			}

			if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mMode == ASMIM_ZERO_PAGE)
			{
				info.mSrcL = &(mIns[at + 1]);
				info.mSrcH = &(mIns[at + 4]);
				info.mAddL = &(mIns[at + 2]);
				info.mAddH = &(mIns[at + 5]);
				info.mImmediate = false;

				return true;
			}
		}
		else if (mIns[at + 0].mType == ASMIT_LDA &&
			mIns[at + 1].mType == ASMIT_CLC &&
			mIns[at + 2].mType == ASMIT_ADC &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 4].mType == ASMIT_LDA &&
			mIns[at + 5].mType == ASMIT_ADC &&
			mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
		{
			info.mDstL = &(mIns[at + 3]);
			info.mDstH = &(mIns[at + 6]);

			if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[at + 5].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[at + 0].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE)
				{
					info.mAddress = (mIns[at + 0].mAddress & 0xff) + (mIns[at + 4].mAddress << 8);
					info.mLinkerObject = nullptr;
					info.mSrcL = &(mIns[at + 2]);
					info.mSrcH = &(mIns[at + 5]);
					info.mAddL = &(mIns[at + 0]);
					info.mAddH = &(mIns[at + 4]);
					info.mImmediate = true;

					return true;
				}
				else if (mIns[at + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 0].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 0].mAddress == mIns[at + 4].mAddress)
				{
					info.mAddress = mIns[at + 0].mAddress;
					info.mLinkerObject = mIns[at + 0].mLinkerObject;
					info.mSrcL = &(mIns[at + 2]);
					info.mSrcH = &(mIns[at + 5]);
					info.mAddL = &(mIns[at + 0]);
					info.mAddH = &(mIns[at + 4]);
					info.mImmediate = true;

					return true;
				}
			}
			else if (mIns[at + 0].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE)
				{
					info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8);
					info.mLinkerObject = nullptr;
					info.mSrcL = &(mIns[at + 0]);
					info.mSrcH = &(mIns[at + 4]);
					info.mAddL = &(mIns[at + 2]);
					info.mAddH = &(mIns[at + 5]);
					info.mImmediate = true;

					return true;
				}
				else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress)
				{
					info.mAddress = mIns[at + 2].mAddress;
					info.mLinkerObject = mIns[at + 2].mLinkerObject;
					info.mSrcL = &(mIns[at + 0]);
					info.mSrcH = &(mIns[at + 4]);
					info.mAddL = &(mIns[at + 2]);
					info.mAddH = &(mIns[at + 5]);
					info.mImmediate = true;

					return true;
				}
			}
		}
	}

	return false;
}

bool NativeCodeBasicBlock::IsFinalZeroPageUseTail(const NativeCodeBasicBlock* block, int from, int to, bool pair)
{
	if (!mPatched)
	{
		mPatched = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				if (mIns[i].mAddress == to)
					return false;
				if (pair && mIns[i].mAddress == to + 1)
					return false;
			}
			else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				if (mIns[i].mAddress == to || mIns[i].mAddress + 1 == to)
					return false;
				if (pair && mIns[i].mAddress == to + 1)
					return false;
				if (!pair && (mIns[i].mAddress == from || mIns[i].mAddress + 1 == from))
					return false;
			}
			else if (mIns[i].ReferencesZeroPage(to) || (pair && mIns[i].ReferencesZeroPage(to + 1)))
				return false;
			else if (mIns[i].mType == ASMIT_JSR)
			{
				if (mIns[i].mFlags & NCIF_USE_ZP_32_X)
				{
					if (to >= mIns[i].mParam && to < mIns[i].mParam + 4 ||
						from >= mIns[i].mParam && from < mIns[i].mParam + 4)
						return false;
				}
			}
		}

		if (mTrueJump && !mTrueJump->IsFinalZeroPageUseTail(block, from, to, pair))
			return false;
		if (mFalseJump && !mFalseJump->IsFinalZeroPageUseTail(block, from, to, pair))
			return false;
	}

	return true;
}

static bool ZeroPageMayBeChangedOnBlockPathUp(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg)
{
	ExpandingArray<const NativeCodeBasicBlock*> blocks;
	blocks.Push(block);
	int i = 0;
	while (i < blocks.Size())
	{
		block = blocks[i++];
		if (block != head)
		{
			if (block->ChangesZeroPage(reg))
				return true;

			for (int j = 0; j < block->mEntryBlocks.Size(); j++)
			{
				if (!blocks.Contains(block->mEntryBlocks[j]))
					blocks.Push(block->mEntryBlocks[j]);
			}
		}
	}

	return false;
}

bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair, bool fchanged)
{
	if (at == 0 && mVisited)
		return false;

	if (!mPatched)
	{
		if (at != 0 || (mEntryRequiredRegs[from] || mEntryRequiredRegs[to] || (pair && (mEntryRequiredRegs[from + 1] || mEntryRequiredRegs[to + 1]))))
		{
			mPatched = true;

			if (at == 0)
			{
				if (mNumEntries > 1)
				{
					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						if (mEntryBlocks[i] != block && !mEntryBlocks[i]->IsDominatedBy(block))
							return false;
						if (!fchanged && (ZeroPageMayBeChangedOnBlockPathUp(mEntryBlocks[i], block, from) || pair && ZeroPageMayBeChangedOnBlockPathUp(mEntryBlocks[i], block, from + 1)))
							fchanged = true;
					}
				}
			}

			while (at < mIns.Size())
			{
				if (mIns[at].mMode == ASMIM_ZERO_PAGE)
				{
					if (mIns[at].mAddress == to && (fchanged || mIns[at].ChangesAddress()))
						return false;
					if (pair && mIns[at].mAddress == to + 1 && (fchanged || mIns[at].ChangesAddress()))
						return false;
					if (mIns[at].mAddress == from && mIns[at].ChangesAddress())
						fchanged = true;
					if (pair && mIns[at].mAddress == from + 1 && mIns[at].ChangesAddress())
						fchanged = true;
				}
				else if (mIns[at].mMode == ASMIM_INDIRECT_Y)
				{
					if (!pair && mIns[at].mAddress == to)
						return false;
					if (mIns[at].mAddress == to && (fchanged || mIns[at].ChangesAddress()))
						return false;
					if (mIns[at].mAddress + 1 == to)
						return false;
					if (pair && mIns[at].mAddress == to + 1)
						return false;
					if (!pair && mIns[at].mAddress == from)
						return false;
					if (mIns[at].mAddress + 1 == from)
						return false;
					if (pair && mIns[at].mAddress == from + 1)
						return false;
				}
				else if (mIns[at].mType == ASMIT_JSR)
				{
					fchanged = true;

					LinkerObject* lo = mIns[at].mLinkerObject;
					if (lo)
					{
						for (int i = 0; i < lo->mNumTemporaries; i++)
						{
							if (from >= lo->mTemporaries[i] && from < lo->mTemporaries[i] + lo->mTempSizes[i] ||
								to >= lo->mTemporaries[i] && to < lo->mTemporaries[i] + lo->mTempSizes[i])
								return false;
						}
					}

					if (mIns[at].ChangesZeroPage(from) || mIns[at].ChangesZeroPage(to))
						return false;

					if (mIns[at].mFlags & NCIF_USE_ZP_32_X)
					{
						if (to >= mIns[at].mParam && to < mIns[at].mParam + 4 ||
							from >= mIns[at].mParam && from < mIns[at].mParam + 4)
							return false;
					}
				}

				at++;
			}

			if (mTrueJump && !mTrueJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged))
				return false;
			if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged))
				return false;
		}
		else
			return IsFinalZeroPageUseTail(block, from, to, pair);
	}

	return true;
}

bool NativeCodeBasicBlock::BackwardFindLiveRange(const NativeCodeBasicBlock* block, int reg, bool pair, ExpandingArray<CodeRange>& ranges)
{
	if (mVisited)
		return mPatchExit;

	if (!mPatchExit)
	{
		mPatchExit = true;

		if (mTrueJump && !mTrueJump->ForwardFindLiveRange(block, 0, reg, pair, ranges))
			return false;
		if (mFalseJump && !mFalseJump->ForwardFindLiveRange(block, 0, reg, pair, ranges))
			return false;

		CodeRange	cr;
		cr.mBlock = this;
		cr.mEnd = mIns.Size();

		for (int i = mIns.Size() - 1; i >= 0; i--)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == reg)
			{
				if (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY)
				{
					cr.mStart = i;
					ranges.Push(cr);
					return true;
				}
			}
		}

		cr.mStart = 0;
		ranges.Push(cr);

		for (int i = 0; i < mEntryBlocks.Size(); i++)
		{
			if (!mEntryBlocks[i]->BackwardFindLiveRange(block, reg, pair, ranges))
				return false;
		}
	}

	return true;
}

bool NativeCodeBasicBlock::CanReplaceRegInLiveRange(const ExpandingArray<CodeRange>& range, int reg, int with, bool pair)
{
	for (int i = 0; i < range.Size(); i++)
	{
		if (range[i].mStart == 0 && range[i].mBlock->mEntryRequiredRegs[with])
			return false;
		if (range[i].mBlock->ReferencesZeroPage(with, range[i].mStart, range[i].mEnd))
			return false;
		if (!pair)
		{
			for (int j = range[i].mStart; j < range[i].mEnd; j++)
			{
				const NativeCodeInstruction& ins(range[i].mBlock->mIns[j]);
				if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress + 1 == reg))
					return false;
			}
		}
	}
	return true;
}

bool NativeCodeBasicBlock::ReplaceRegInLiveRange(const ExpandingArray<CodeRange>& range, int reg, int with, bool pair)
{
	bool	changed = false;
	for (int i = 0; i < range.Size(); i++)
	{
		for (int j = range[i].mStart; j < range[i].mEnd; j++)
		{
			NativeCodeInstruction& ins(range[i].mBlock->mIns[j]);
			if (ins.mMode == ASMIM_ZERO_PAGE || ins.mMode == ASMIM_INDIRECT_Y)
			{
				if (ins.mAddress == reg)
				{
					ins.mAddress = with;
					changed = true;
				}
			}
		}
		if (range[i].mBlock->mEntryRequiredRegs[reg])
			range[i].mBlock->mEntryRequiredRegs += with;
	}
	return changed;
}

bool NativeCodeBasicBlock::ForwardFindLiveRange(const NativeCodeBasicBlock* block, int at, int reg, bool pair, ExpandingArray<CodeRange>& ranges)
{
	if (!mPatched)
	{
		mPatched = true;
		if (at > 0 || mEntryRequiredRegs[reg] || (pair && mEntryRequiredRegs[reg + 1]))
		{
			if (at == 0)
			{
				if (mNumEntries > 1)
				{
					for (int i = 0; i < mEntryBlocks.Size(); i++)
					{
						if (mEntryBlocks[i] != block)
						{
							if (!mEntryBlocks[i]->IsDominatedBy(block))
								return false;
							if (!mEntryBlocks[i]->BackwardFindLiveRange(block, reg, pair, ranges))
								return false;
						}
					}
				}
			}

			CodeRange	cr;
			cr.mBlock = this;
			cr.mStart = at;

			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 == reg && !(mIns[i].mLive & LIVE_MEM))
					{
						cr.mEnd = i + 1;
						ranges.Push(cr);
						return true;
					}
				}

				if (mIns[i].mType == ASMIT_JSR)
					return false;
			}

			cr.mEnd = mIns.Size();
			mPatchExit = true;
			ranges.Push(cr);

			if (mTrueJump && !mTrueJump->ForwardFindLiveRange(block, 0, reg, pair, ranges))
				return false;
			if (mFalseJump && !mFalseJump->ForwardFindLiveRange(block, 0, reg, pair, ranges))
				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, false))
				{
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false))
						changed = true;

					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
			if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
				mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END && 
				mIns[i + 1].mAddress >= BC_REG_TMP)
			{
				nproc->ResetPatched();
				if (IsFinalZeroPageUse(this, i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, false))
				{
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true))
						changed = true;
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 4, mIns[i + 3].mAddress, mIns[i + 2].mAddress, false))
						changed = true;

					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

					changed = true;
				}
			}

			if (i + 5 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_ADC && 
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress + 1 &&
				mIns[i + 4].mType == ASMIT_ADC && !mIns[i + 4].MayBeSameAddress(mIns[i + 2]) &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
				mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
				mIns[i + 2].mAddress >= BC_REG_TMP)
			{
				nproc->ResetPatched();
				if (IsFinalZeroPageUse(this, i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true, true))
				{
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true))
						changed = true;
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 6, mIns[i + 5].mAddress, mIns[i + 3].mAddress, false))
						changed = true;

					mIns[i + 2].mAddress = mIns[i + 0].mAddress;
					mIns[i + 5].mAddress = mIns[i + 3].mAddress;

					changed = true;
				}
			}

			if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
				mIns[i + 3].mType == ASMIT_ADC && !mIns[i + 3].MayBeSameAddress(mIns[i + 1]) &&
				mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
				mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
				mIns[i + 1].mAddress >= BC_REG_TMP)
			{
				nproc->ResetPatched();
				if (IsFinalZeroPageUse(this, i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, true))
				{
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true))
						changed = true;
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 5, mIns[i + 4].mAddress, mIns[i + 2].mAddress, false))
						changed = true;

					mIns[i + 1].mAddress = mIns[i + 0].mAddress;
					mIns[i + 4].mAddress = mIns[i + 2].mAddress;

					changed = true;
				}
			}

			if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				(mIns[i + 1].IsArithmetic() && mIns[i + 1].mMode == ASMIM_IMMEDIATE || 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 + 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 + 3, mIns[i + 2].mAddress, mIns[i + 0].mAddress, false, true))
				{
					nproc->ResetPatched();
					if (ForwardReplaceZeroPage(i + 3, mIns[i + 2].mAddress, mIns[i + 0].mAddress, false))
					{
						mIns[i + 2].mAddress = mIns[i + 0].mAddress;
						changed = true;
					}
				}
			}
		}

		if (!changed)
		{
			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 + 0].mLive & LIVE_MEM) &&
					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)
				{
					ExpandingArray<CodeRange>	ranges;

					nproc->ResetPatched();
					if (ForwardFindLiveRange(this, i + 2, mIns[i + 1].mAddress, false, ranges))
					{
						if (CanReplaceRegInLiveRange(ranges, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false))
						{
#if 0
							printf("Replace %s, %d, %d, %02x <- %02x)\n", mProc->mIdent->mString, mIndex, i, mIns[i + 1].mAddress, mIns[i + 0].mAddress);
							printf("LiveRange %s (%d, %d, %02x)\n", mProc->mIdent->mString, mIndex, i, mIns[i + 1].mAddress);
							for (int i = 0; i < ranges.Size(); i++)
							{
								printf(" %d, %d..%d\n", ranges[i].mBlock->mIndex, ranges[i].mStart, ranges[i].mEnd);
							}
#endif
							if (ReplaceRegInLiveRange(ranges, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false))
							{
								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 + 0].mLive & LIVE_MEM) &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 && !(mIns[i + 2].mLive & LIVE_MEM) &&
					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)
				{
					ExpandingArray<CodeRange>	ranges1, ranges2;

					nproc->ResetPatched();
					if (ForwardFindLiveRange(this, i + 2, mIns[i + 1].mAddress, true, ranges1))
					{
						nproc->ResetPatched();
						if (ForwardFindLiveRange(this, i + 4, mIns[i + 3].mAddress, true, ranges2))
						{
							if (CanReplaceRegInLiveRange(ranges1, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true) &&
								CanReplaceRegInLiveRange(ranges2, mIns[i + 3].mAddress, mIns[i + 2].mAddress, true))
							{
#if 0
								printf("ReplacePair %s, %d\n", mProc->mIdent->mString, mIndex);
								printf("LivePairRange %s (%d, %d, %02x)\n", mProc->mIdent->mString, mIndex, i, mIns[i + 1].mAddress);
								for (int i = 0; i < ranges1.Size(); i++)
								{
									printf(" L %d, %d..%d\n", ranges1[i].mBlock->mIndex, ranges1[i].mStart, ranges1[i].mEnd);
								}
								for (int i = 0; i < ranges2.Size(); i++)
								{
									printf(" H %d, %d..%d\n", ranges2[i].mBlock->mIndex, ranges2[i].mStart, ranges2[i].mEnd);
								}
#endif

								ReplaceRegInLiveRange(ranges1, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true);
								ReplaceRegInLiveRange(ranges2, mIns[i + 3].mAddress, mIns[i + 2].mAddress, 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 0
				if (i + 3 < mIns.Size() &&
					mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					int reg1 = mIns[i + 0].mAddress, reg2 = mIns[i + 1].mAddress;

					int j = i + 2;
					while (j < mIns.Size() &&
						!mIns[j].ReferencesZeroPage(reg1) && !mIns[j].ChangesZeroPage(reg1 + 1) &&
						!mIns[j].ReferencesZeroPage(reg2) && !mIns[j].ChangesZeroPage(reg2 + 1))
						j++;
					if (j + 1 < mIns.Size() &&
						mIns[j + 0].mType == ASMIT_STA && mIns[j + 0].mMode == ASMIM_ZERO_PAGE && 
						mIns[j + 1].mType == ASMIT_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE)
					{
						int j1 = -1, j2 = -1;

						if (mIns[j + 0].mAddress == reg1 + 1 && mIns[j + 1].mAddress == reg2 + 1)
						{
							j1 = j + 0; j2 = j + 1;
						}
						else if (mIns[j + 0].mAddress == reg2 + 1 && mIns[j + 1].mAddress == reg1 + 1)
						{
							j1 = j + 1; j2 = j + 0;
						}

						if (j1 >= 0)
						{
							ExpandingArray<CodeRange>	ranges1, ranges2;

							nproc->ResetPatched();
							if (ForwardFindLiveRange(this, j + 2, reg1, true, ranges1))
							{
								nproc->ResetPatched();
								if (ForwardFindLiveRange(this, j + 2, reg1 + 1, true, ranges2))
								{
									if (CanReplaceRegInLiveRange(ranges1, reg1,     reg2,     true) &&
										CanReplaceRegInLiveRange(ranges2, reg1 + 1, reg2 + 1, true))
									{
										ReplaceRegInLiveRange(ranges1, reg1,     reg2,     true);
										ReplaceRegInLiveRange(ranges2, reg1 + 1, reg2 + 1, true);
										mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
										mIns[j1   ].mType = ASMIT_NOP; mIns[j1   ].mMode = ASMIM_IMPLIED;
										changed = true;
									}
								}
							}

							if (!changed)
							{
								ExpandingArray<CodeRange>	ranges1, ranges2;

								nproc->ResetPatched();
								if (ForwardFindLiveRange(this, j + 2, reg2, true, ranges1))
								{
									nproc->ResetPatched();
									if (ForwardFindLiveRange(this, j + 2, reg2 + 1, true, ranges2))
									{
										if (CanReplaceRegInLiveRange(ranges1, reg2, reg1, true) &&
											CanReplaceRegInLiveRange(ranges2, reg2 + 1, reg1 + 1, true))
										{
											ReplaceRegInLiveRange(ranges1, reg2, reg1, true);
											ReplaceRegInLiveRange(ranges2, reg2 + 1, reg1 + 1, true);
											mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
											mIns[j2   ].mType = ASMIT_NOP; mIns[j2   ].mMode = ASMIM_IMPLIED;
											changed = true;
										}
									}
								}
							}
						}
					}
				}
#endif
			}
		}

		if (mTrueJump && mTrueJump->ReplaceFinalZeroPageUse(nproc))
			changed = true;
		if (mFalseJump && mFalseJump->ReplaceFinalZeroPageUse(nproc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::Check16BitSum(const NativeCodeBasicBlock* block, int origin, int at, int reg)
{
	if (!mEntryRequiredRegs.Size())
		return false;

	if (mPatched)
		return true;

	if (at == 0)
	{
		if (!mEntryRequiredRegs[reg])
			return true;

		mPatched = true;
	}

	for (int i = at; i < mIns.Size(); i++)
	{
		if (mIns[i].ReferencesZeroPage(reg))
		{
			if (block == this && i == origin)
				return true;
			if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject && !mIns[i].mLinkerObject->mProc)
				return false;
			if (mIns[i].UsesZeroPage(reg))
				return false;
			if (mIns[i].ChangesZeroPage(reg))
				return true;
		}
	}

	if (mTrueJump && !mTrueJump->Check16BitSum(block, origin, 0, reg))
		return false;
	if (mFalseJump && !mFalseJump->Check16BitSum(block, origin, 0, reg))
		return false;

	return true;
}

bool NativeCodeBasicBlock::Simplify16BitSum8BitRange(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 5 < 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 + 4].mType == ASMIT_LDA && 
				mIns[i + 5].mType == ASMIT_ADC &&
				mIns[i + 1].mMaxVal + mIns[i + 2].mAddress < 256)
			{
				if (mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0)
				{
					mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0)
				{					
					mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
					mIns[i + 5].mType = ASMIT_LDA;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->Simplify16BitSum8BitRange()) changed = true;
		if (mFalseJump && mFalseJump->Simplify16BitSum8BitRange()) changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::EliminateUpper16BitSum(NativeCodeProcedure* nproc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();
		
		for (int i = 0; i < mIns.Size(); i++)
		{
			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].mType == ASMIT_SBC) &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) &&
				mIns[i + 2].mAddress != BC_REG_LOCALS + 1 && mIns[i + 2].mAddress != BC_REG_STACK + 1)
			{
				nproc->ResetPatched();
				if (Check16BitSum(this, i, i + 3, mIns[i + 2].mAddress))
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
			else if ((mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				!(mIns[i + 0].mLive & LIVE_CPU_REG_Z) &&
				mIns[i + 0].mAddress != BC_REG_LOCALS + 1 && mIns[i + 0].mAddress != BC_REG_STACK + 1)
			{
				nproc->ResetPatched();
				if (Check16BitSum(this, i, i + 1, mIns[i + 0].mAddress))
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->EliminateUpper16BitSum(nproc))
			changed = true;
		if (mFalseJump && mFalseJump->EliminateUpper16BitSum(nproc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::Propagate16BitHighSum(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 5 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_CLC &&
				mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress + 1 && !(mIns[i + 3].mLive & LIVE_MEM) &&
				mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
			{
				bool	success = false;

				int taddr = mIns[i + 1].mAddress, saddr = mIns[i + 0].mAddress;

				int j = i + 6;
				while (j < mIns.Size())
				{
					if (mIns[j].mType == ASMIT_JSR)
						break;
					else if (mIns[j].ChangesZeroPage(saddr) || mIns[j].ChangesZeroPage(saddr + 1))
						break;
					else if (mIns[j].ChangesZeroPage(taddr) || mIns[j].ChangesZeroPage(taddr + 1))
						break;
					else if (mIns[j].UsesZeroPage(taddr + 1) && !(mIns[j].mLive & LIVE_MEM))
					{
						success = true;
						break;
					}
					j++;
				}

				if (success)
				{
					mIns[i + 5].mAddress = saddr + 1;
					for (int k = i + 6; k <= j; k++)
					{
						if (mIns[k].mMode == ASMIM_ZERO_PAGE)
						{
							if (mIns[k].mAddress == taddr)
								mIns[k].mAddress = saddr;
							else if (mIns[k].mAddress == taddr + 1)
								mIns[k].mAddress = saddr + 1;
						}
						else if (mIns[k].mMode == ASMIM_INDIRECT_Y)
						{
							if (mIns[k].mAddress == taddr)
								mIns[k].mAddress = saddr;
						}
					}
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->Propagate16BitHighSum())
			changed = true;
		if (mFalseJump && mFalseJump->Propagate16BitHighSum())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::ForwardReplaceZeroPage(int at, int from, int to, bool pair)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		for (int i = at; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				if (mIns[i].mAddress == from)
				{
					mIns[i].mAddress = to;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->ForwardReplaceZeroPage(0, from, to, pair))
			changed = true;
		if (mFalseJump && mFalseJump->ForwardReplaceZeroPage(0, from, to, pair))
			changed = true;

		if (mEntryRequiredRegs[from])
			mEntryRequiredRegs += to;
	}

	return changed;
}



bool NativeCodeBasicBlock::CanZeroPageCopyUp(int at, int from, int to, bool diamond)
{
	bool full = at == mIns.Size();

	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 && (mTrueJump != this && mFalseJump != this || !full))
		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] == this)
			return mEntryBlocks[1]->CanZeroPageCopyUp(mEntryBlocks[1]->mIns.Size(), from, to, false);
		else if (mEntryBlocks[1] == this)
			return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, false);
		else if (
			mEntryBlocks[0]->mTrueJump == this && mEntryBlocks[0]->mFalseJump == mEntryBlocks[1] && (!mEntryBlocks[1]->mFalseJump || mEntryBlocks[1]->mFalseJump == mEntryBlocks[1] || mEntryBlocks[1]->mTrueJump == mEntryBlocks[1]) ||
			mEntryBlocks[0]->mFalseJump == this && mEntryBlocks[0]->mTrueJump == mEntryBlocks[1] && (!mEntryBlocks[1]->mFalseJump || mEntryBlocks[1]->mFalseJump == mEntryBlocks[1] || mEntryBlocks[1]->mTrueJump == mEntryBlocks[1]))
			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[0]->mFalseJump == mEntryBlocks[0] || mEntryBlocks[0]->mTrueJump == mEntryBlocks[0]) ||
			mEntryBlocks[1]->mFalseJump == this && mEntryBlocks[1]->mTrueJump == mEntryBlocks[0] && (!mEntryBlocks[0]->mFalseJump || mEntryBlocks[0]->mFalseJump == mEntryBlocks[0] || mEntryBlocks[0]->mTrueJump == mEntryBlocks[0]))
			return mEntryBlocks[0]->CanZeroPageCopyUp(mEntryBlocks[0]->mIns.Size(), from, to, true);
	}

	return false;
}

bool NativeCodeBasicBlock::ShortcutZeroPageCopyUp(NativeCodeProcedure* nproc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				nproc->ResetPatched();
				if (CanZeroPageCopyUp(i, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false))
				{
					BackwardReplaceZeroPage(i, mIns[i + 0].mAddress, mIns[i + 1].mAddress, false);
					changed = true;

					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				}
			}
		}

		if (mTrueJump && mTrueJump->ShortcutZeroPageCopyUp(nproc))
			changed = true;
		if (mFalseJump && mFalseJump->ShortcutZeroPageCopyUp(nproc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::IsSameRegisterSource(const NativeCodeInstruction& rins, int nloops) const
{
	for (int i = mIns.Size() - 1; i >= 0; i--)
	{
		const NativeCodeInstruction& ins(mIns[i]);
		if (rins.IsSame(ins))
			return true;
#if 1
		if (rins.mType == ASMIT_LDY && ins.mType == ASMIT_STY && rins.SameEffectiveAddress(ins))
			return true;
		if (rins.mType == ASMIT_LDX && ins.mType == ASMIT_STX && rins.SameEffectiveAddress(ins))
			return true;
		if (rins.mType == ASMIT_LDA && ins.mType == ASMIT_STA && rins.SameEffectiveAddress(ins))
			return true;
#endif
		if (rins.mType == ASMIT_LDY && ins.ChangesYReg())
			return false;
		if (rins.mType == ASMIT_LDX && ins.ChangesXReg())
			return false;
		if (rins.mType == ASMIT_LDA && ins.ChangesAccu())
			return false;
		if (rins.MayBeChangedOnAddress(ins))
			return false;
	}

	if (mEntryBlocks.Size() == 0)
		return false;

	if (mLoopHead)
	{
		if (nloops)
			nloops--;
		else
			return false;
	}

	for (int i = 0; i < mEntryBlocks.Size(); i++)
		if (!mEntryBlocks[i]->IsSameRegisterSource(rins, nloops))
			return false;
	return true;
}

bool NativeCodeBasicBlock::FindInitialLoadA(NativeCodeInstruction *& ins)
{
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
		{
			if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
				mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
			{
				ins = &mIns[i];
				return true;
			}
		}
		if (mIns[i].ChangesAccu())
			return false;
	}
	return false;
}

bool NativeCodeBasicBlock::FindInitialLoadX(NativeCodeInstruction *& ins)
{
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_Z))
		{
			if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
				mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
			{
				ins = &mIns[i];
				return true;
			}
		}
		if (mIns[i].ChangesXReg())
			return false;
	}
	return false;
}

bool NativeCodeBasicBlock::FindInitialLoadY(NativeCodeInstruction *& ins)
{
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Z))
		{
			if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
				mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
			{
				ins = &mIns[i];
				return true;
			}
		}
		if (mIns[i].ChangesYReg())
			return false;
	}
	return false;
}

bool NativeCodeBasicBlock::HoistCommonLoads(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
		{
			NativeCodeInstruction	*	tins = nullptr, *	fins = nullptr;
			if (!mExitRequiredRegs[CPU_REG_A] && mTrueJump->FindInitialLoadA(tins) && mFalseJump->FindInitialLoadA(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
			{
				int i = mIns.Size();
				while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
					i--;
				if (!ReferencesAccu(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
				{
					mIns.Insert(i, *tins);
					tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
					fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
			if (!mExitRequiredRegs[CPU_REG_X] && mTrueJump->FindInitialLoadX(tins) && mFalseJump->FindInitialLoadX(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
			{
				int i = mIns.Size();
				while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
					i--;
				if (!ReferencesXReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
				{
					mIns.Insert(i, *tins);
					tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
					fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
			if (!mExitRequiredRegs[CPU_REG_Y] && mTrueJump->FindInitialLoadY(tins) && mFalseJump->FindInitialLoadY(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
			{
				int i = mIns.Size();
				while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
					i--;
				if (!ReferencesYReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
				{
					mIns.Insert(i, *tins);
					tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
					fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
					changed = true;
				}					
			}

		}

		if (mTrueJump && mTrueJump->HoistCommonLoads())
			changed = true;
		if (mFalseJump && mFalseJump->HoistCommonLoads())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::BackwardValuePropagation(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool achanged = false, xchanged = false, ychanged = false;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (i + 1 < mIns.Size())
			{
				NativeCodeInstruction& nins(mIns[i + 1]);

				if (i + 1 < mIns.Size() && (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) && ins.mMode == ASMIM_ZERO_PAGE && !xchanged && nins.mType == ASMIT_LDX && nins.SameEffectiveAddress(ins))
				{
					if (!ChangesZeroPage(ins.mAddress, 0, i))
					{

						int j = 0;
						while (j < mEntryBlocks.Size() && mEntryBlocks[j]->IsSameRegisterSource(nins, 2))
							j++;
						if (j == mEntryBlocks.Size())
						{
							if (ins.mType == ASMIT_INC)
								ins.mType = ASMIT_INX;
							else
								ins.mType = ASMIT_DEX;
							ins.mMode = ASMIM_IMPLIED;
							nins.mType = ASMIT_STX;
							changed = true;
						}
					}
				}
			}

			if (ins.ChangesYReg())
				ychanged = true;
			if (ins.ChangesXReg())
				xchanged = true;
			if (ins.ChangesAccu())
				achanged = true;
		}

		if (mTrueJump && mTrueJump->BackwardValuePropagation())
			changed = true;
		if (mFalseJump && mFalseJump->BackwardValuePropagation())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::PartialBackwardValuePropagation(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (!mLoopHead && mEntryBlocks.Size() > 1)
		{
			bool	afail = mEntryRequiredRegs[CPU_REG_A];
			bool	xfail = mEntryRequiredRegs[CPU_REG_X];
			bool	yfail = mEntryRequiredRegs[CPU_REG_Y];

			int i = 0;
			while (i < mIns.Size() && !(afail && xfail && yfail))
			{
				NativeCodeInstruction& ins(mIns[i]);

				if ((!yfail && ins.mType == ASMIT_LDY || !xfail && ins.mType == ASMIT_LDX || !afail && ins.mType == ASMIT_LDA)					
					&& (ins.mMode == ASMIM_IMMEDIATE || ins.mMode == ASMIM_IMMEDIATE_ADDRESS || ins.mMode == ASMIM_ZERO_PAGE)
					&& !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
				{
					if (ins.mMode != ASMIM_ZERO_PAGE || !ChangesZeroPage(ins.mAddress, 0, i))
					{
						int j = 0;
						while (j < mEntryBlocks.Size() && !mEntryBlocks[j]->IsSameRegisterSource(ins))
							j++;
						if (j < mEntryBlocks.Size())
						{
							NativeCodeBasicBlock* pblock = mProc->AllocateBlock();
							pblock->mEntryRequiredRegs = mEntryRequiredRegs;
							pblock->mExitRequiredRegs = mEntryRequiredRegs;
							pblock->mIns.Push(ins);
							pblock->Close(ins.mIns, this, nullptr, ASMIT_JMP);
							while (j > 0)
							{
								j--;
								NativeCodeBasicBlock* eblock = mEntryBlocks[j];
								mEntryBlocks.Remove(j);
								mNumEntries--;
								if (eblock->mTrueJump == this)
									eblock->mTrueJump = pblock;
								else if (eblock->mFalseJump == this)
									eblock->mFalseJump = pblock;
								pblock->mEntryBlocks.Push(eblock);
								pblock->mNumEntries++;
							}
							j++;
							while (j < mEntryBlocks.Size())
							{
								if (mEntryBlocks[j]->IsSameRegisterSource(ins))
									j++;
								else
								{
									NativeCodeBasicBlock* eblock = mEntryBlocks[j];
									mEntryBlocks.Remove(j);
									mNumEntries--;
									if (eblock->mTrueJump == this)
										eblock->mTrueJump = pblock;
									else if (eblock->mFalseJump == this)
										eblock->mFalseJump = pblock;
									pblock->mEntryBlocks.Push(eblock);
									pblock->mNumEntries++;
								}
							}

							if (ins.mType == ASMIT_LDA)
								afail = true;
							if (ins.mType == ASMIT_LDX)
								xfail = true;
							if (ins.mType == ASMIT_LDY)
								yfail = true;

							ins.mType = ASMIT_NOP;
							ins.mMode = ASMIM_IMPLIED;
							mEntryBlocks.Push(pblock);
							mNumEntries++;
							changed = true;
						}
					}
				}

				if (ins.ChangesYReg())
					yfail = true;
				if (ins.ChangesXReg())
					xfail = true;
				if (ins.ChangesAccu())
					afail = true;

				i++;
			}
		}
#if 1
		for (int i = 0; i < mIns.Size(); i++)
		{
			if ((mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_LDX || mIns[i].mType == ASMIT_LDY) && mIns[i].mMode == ASMIM_ABSOLUTE && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				int val = FindImmediateGlobalStore(i, mIns[i]);
				if (val >= 0)
				{
					mIns[i].mMode = ASMIM_IMMEDIATE;
					mIns[i].mAddress = val;
					changed = true;
				}
			}
		}
#endif
		if (mTrueJump && mTrueJump->PartialBackwardValuePropagation())
			changed = true;
		if (mFalseJump && mFalseJump->PartialBackwardValuePropagation())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::BackwardReplaceZeroPage(int at, int from, int to, bool diamond)
{
	bool	changed = false;

	if (!mPatched)
	{
		mPatched = true;

		assert(mPatchChecked);

		if (at == mIns.Size())
			mExitRequiredRegs += to;

		bool	done = false;
		while (at > 0)
		{
			at--;
			if (mIns[at].mMode == ASMIM_ZERO_PAGE && mIns[at].mAddress == from)
			{
				mIns[at].mAddress = to;
				changed = true;
				if (mIns[at].mType == ASMIT_STA || mIns[at].mType == ASMIT_STX || mIns[at].mType == ASMIT_STY)
				{
					done = true;
					break;
				}
			}
		}

		mEntryRequiredRegs += to;

		if (diamond)
		{
			if (mEntryRequiredRegs[from])
			{
				int i = 0;
				while (i < at && !mIns[i].ReferencesZeroPage(from))
					i++;

				if (i < at)
				{
					mIns[i].mAddress = to;
					changed = true;
				}
			}

			if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, false))
				changed = true;
		}
		else if (!done)
		{
			if (mEntryBlocks.Size() == 1)
			{
				if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, false))
					changed = true;
			}
			else if (mEntryBlocks.Size() == 2)
			{
				if (mEntryBlocks[0]->mTrueJump == this && mEntryBlocks[0]->mFalseJump == mEntryBlocks[1] && (!mEntryBlocks[1]->mFalseJump || mEntryBlocks[1]->mFalseJump == mEntryBlocks[1] || mEntryBlocks[1]->mTrueJump == mEntryBlocks[1]) ||
					mEntryBlocks[0]->mFalseJump == this && mEntryBlocks[0]->mTrueJump == mEntryBlocks[1] && (!mEntryBlocks[1]->mFalseJump || mEntryBlocks[1]->mFalseJump == mEntryBlocks[1] || mEntryBlocks[1]->mTrueJump == mEntryBlocks[1]))
				{
					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[0]->mFalseJump == mEntryBlocks[0] || mEntryBlocks[0]->mTrueJump == mEntryBlocks[0]) ||
					mEntryBlocks[1]->mFalseJump == this && mEntryBlocks[1]->mTrueJump == mEntryBlocks[0] && (!mEntryBlocks[0]->mFalseJump || mEntryBlocks[0]->mFalseJump == mEntryBlocks[0] || mEntryBlocks[0]->mTrueJump == mEntryBlocks[0]))
				{
					if (mEntryBlocks[0]->BackwardReplaceZeroPage(mEntryBlocks[0]->mIns.Size(), from, to, true))
						changed = true;
				}
			}
		}
	}

	return changed;
}

bool NativeRegisterSum16Info::operator==(const NativeRegisterSum16Info& ri) const
{
	if (mSrcL != ri.mSrcL || mSrcH != ri.mSrcH || mAddL != ri.mAddL || mAddH != ri.mAddH || mDstL != ri.mDstL || mDstH != ri.mDstH)
		return false;

	if (mImmediate)
		return mAddress == ri.mAddress && mLinkerObject == ri.mLinkerObject;
	else
		return true;
}

bool NativeRegisterSum16Info::operator!=(const NativeRegisterSum16Info& ri) const
{
	return !(*this == ri);
}

bool NativeCodeBasicBlock::Propagate16BitSum(const ExpandingArray<NativeRegisterSum16Info> & cinfo)
{
	bool	changed = false;

	if (!mVisited)
	{
		if (mLoopHead)
			mRSumInfos.SetSize(0);
		else
		{
			if (mNumEntered == 0)
				mRSumInfos = cinfo;
			else
			{
				int i = 0;
				while (i < mRSumInfos.Size())
				{
					if (cinfo.Contains(mRSumInfos[i]))
						i++;
					else
						mRSumInfos.Remove(i);
				}
			}

			mNumEntered++;
			if (mNumEntered < mNumEntries)
				return false;
		}

		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeRegisterSum16Info	info;

			if (Check16BitSum(i, info))
			{
				for (int j = 0; j < mRSumInfos.Size(); j++)
				{
					if (info.mSrcL->mAddress == mRSumInfos[j].mDstL->mAddress && info.mSrcH->mAddress == mRSumInfos[j].mDstH->mAddress)
					{
						if (info.mImmediate && mRSumInfos[j].mImmediate)
						{
							if (!info.mLinkerObject && !mRSumInfos[j].mLinkerObject)
							{
								info.mAddress += mRSumInfos[j].mAddress;
								if (info.mSrcL->mType == ASMIT_LDA)
									info.mAddL->mType = ASMIT_ADC;
								else
									info.mSrcL->mType = ASMIT_ADC;
								info.mAddL->mAddress = info.mAddress & 0xff;
								info.mAddH->mAddress = info.mAddress >> 8;
								info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
								info.mSrcL->mMinVal = mRSumInfos[j].mSrcL->mMinVal;
								info.mSrcL->mMaxVal = mRSumInfos[j].mSrcL->mMaxVal;
								info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
								info.mSrcH->mMinVal = mRSumInfos[j].mSrcH->mMinVal;
								info.mSrcH->mMaxVal = mRSumInfos[j].mSrcH->mMaxVal;
								info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
								changed = true;
							}
							else if (!mRSumInfos[j].mLinkerObject)
							{
								info.mAddress += mRSumInfos[j].mAddress;
								if (info.mSrcL->mType == ASMIT_LDA)
									info.mAddL->mType = ASMIT_ADC;
								else
									info.mSrcL->mType = ASMIT_ADC;
								info.mAddL->mAddress = info.mAddress;
								info.mAddH->mAddress = info.mAddress;
								info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
								info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
								info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
								changed = true;
							}
							else if (!info.mLinkerObject)
							{
								info.mAddress += mRSumInfos[j].mAddress;
								info.mLinkerObject = mRSumInfos[j].mLinkerObject;
								if (info.mSrcL->mType == ASMIT_LDA)
									info.mAddL->mType = ASMIT_ADC;
								else
									info.mSrcL->mType = ASMIT_ADC;
								info.mAddL->mAddress = info.mAddress;
								info.mAddL->mLinkerObject = info.mLinkerObject;
								info.mAddL->mMode = ASMIM_IMMEDIATE_ADDRESS;
								info.mAddL->mFlags = NCIF_LOWER;
								info.mAddH->mAddress = info.mAddress;
								info.mAddH->mLinkerObject = info.mLinkerObject;
								info.mAddH->mMode = ASMIM_IMMEDIATE_ADDRESS;
								info.mAddH->mFlags = NCIF_UPPER;
								info.mSrcL->mAddress = mRSumInfos[j].mSrcL->mAddress;
								info.mSrcH->mAddress = mRSumInfos[j].mSrcH->mAddress;
								info.mSrcH->mMode = mRSumInfos[j].mSrcH->mMode;
								changed = true;
							}
						}
					}
					else if (info.mSrcL->mAddress == mRSumInfos[j].mSrcL->mAddress && info.mSrcH->mAddress == mRSumInfos[j].mSrcH->mAddress)
					{
						if (info.mAddH->mMode == ASMIM_IMMEDIATE && mRSumInfos[j].mAddH->mMode == ASMIM_IMMEDIATE &&
							info.mAddL->mMode == ASMIM_ZERO_PAGE && mRSumInfos[j].mAddL->mMode == ASMIM_ZERO_PAGE && info.mAddL->mAddress == mRSumInfos[j].mAddL->mAddress)
						{
							info.mAddL->mType = ASMIT_NOP; info.mAddL->mMode = ASMIM_IMPLIED;
							info.mSrcL->mAddress = mRSumInfos[j].mDstL->mAddress;
							info.mSrcH->mAddress = mRSumInfos[j].mDstH->mAddress;
							info.mAddH->mAddress -= mRSumInfos[j].mAddH->mAddress;
							changed = true;
						}
						else if (info.mAddL->mMode == ASMIM_IMMEDIATE && info.mAddH->mMode == ASMIM_IMMEDIATE &&
							mRSumInfos[j].mAddL->mMode == ASMIM_IMMEDIATE && mRSumInfos[j].mAddH->mMode == ASMIM_IMMEDIATE)
						{
							if (info.mAddress == mRSumInfos[j].mAddress)
							{
								info.mSrcL->mAddress = mRSumInfos[j].mDstL->mAddress;
								info.mSrcL->mMode = mRSumInfos[j].mDstL->mMode;
								info.mSrcH->mAddress = mRSumInfos[j].mDstH->mAddress;
								info.mSrcH->mMode = mRSumInfos[j].mDstH->mMode;
								info.mSrcL->mType = ASMIT_LDA; 
								info.mSrcH->mType = ASMIT_LDA;
								info.mAddL->mType = ASMIT_NOP; info.mAddL->mMode = ASMIM_IMPLIED;
								info.mAddH->mType = ASMIT_NOP; info.mAddH->mMode = ASMIM_IMPLIED;
								info.mAddress = 0;
								changed = true;
							}
						}
					}
				}

				if (info.mSrcL->mAddress != info.mDstL->mAddress && (info.mSrcH->mMode == ASMIM_IMMEDIATE || info.mSrcH->mAddress != info.mDstH->mAddress))
					mRSumInfos.Push(info);
			}

			int j = 0;
			while (j < mRSumInfos.Size())
			{
				if (mRSumInfos[j].mDstL != &(mIns[i]) && mRSumInfos[j].mDstH != &(mIns[i]))
				{
					if (
						mRSumInfos[j].mSrcL->MayBeChangedOnAddress(mIns[i]) ||
						mRSumInfos[j].mSrcH->MayBeChangedOnAddress(mIns[i]) ||
						mRSumInfos[j].mAddL->MayBeChangedOnAddress(mIns[i]) ||
						mRSumInfos[j].mAddH->MayBeChangedOnAddress(mIns[i]) ||
						mRSumInfos[j].mDstL->MayBeChangedOnAddress(mIns[i]) ||
						mRSumInfos[j].mDstH->MayBeChangedOnAddress(mIns[i]))
					{
						mRSumInfos.Remove(j);
					}
					else
						j++;
				}
				else
					j++;
			}
		}

		if (mTrueJump && mTrueJump->Propagate16BitSum(mRSumInfos))
			changed = true;
		if (mFalseJump && mFalseJump->Propagate16BitSum(mRSumInfos))
			changed = true;
	}
	return changed;
}

bool NativeCodeBasicBlock::FindAccuExitValue(int& at)
{
	int i = mIns.Size() - 1;
	while (i >= 0)
	{
		if ((mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
		{
			at = i;
			i++;
			while (i < mIns.Size())
			{
				if (mIns[at].MayBeChangedOnAddress(mIns[i]))
					return false;
				i++;
			}
			return true;
		}
		else if (mIns[i].ChangesAccu())
			return false;
		i--;
	}
	return false;
}

bool NativeCodeBasicBlock::MoveLoadXAbsUpCrossBlock(int at)
{
	int	i = at - 1;
	while (i >= 0)
	{
		if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA) && mIns[i].SameEffectiveAddress(mIns[at]))
		{
			mIns[i].mLive |= LIVE_CPU_REG_A;
			i++;
			mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX));
			mIns[at + 1].mType = ASMIT_NOP;
			mIns[at + 1].mMode = ASMIM_IMPLIED;
			while (i < at + 1)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}

			return true;
		}

		if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X))
			return false;
		if (mIns[at].MayBeChangedOnAddress(mIns[i]))
			return false;
		i--;
	}

	if (mEntryBlocks.Size() == 1)
	{
		NativeCodeBasicBlock* eb = mEntryBlocks[0];
		if (eb->FindAccuExitValue(i) && eb->mIns[i].SameEffectiveAddress(mIns[at]))
		{
			while (i < eb->mIns.Size())
			{
				eb->mIns[i].mLive |= LIVE_CPU_REG_A;
				i++;
			}
			eb->mExitRequiredRegs += CPU_REG_A;
			mEntryRequiredRegs += CPU_REG_A;

			mIns.Insert(0, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX));
			mIns[at + 1].mType = ASMIT_NOP;
			mIns[at + 1].mMode = ASMIM_IMPLIED;
			i = 0;
			while (i < at + 1)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}

			return true;
		}
	}

	return false;
}


bool NativeCodeBasicBlock::MoveLoadXUp(int at)
{
	int	i = at - 1;
	while (i >= 0)
	{
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			mIns[i].mType = ASMIT_TAX;
			mIns[i].mMode = ASMIM_IMPLIED;
			mIns[at].mType = ASMIT_NOP;
			mIns[at].mMode = ASMIM_IMPLIED;
			while (i < at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}

			return true;
		}
		else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			mIns[i].mType = ASMIT_LDX;
			mIns[i].mLive |= LIVE_MEM;
			mIns[at].mType = ASMIT_INX;
			mIns[at].mMode = ASMIM_IMPLIED;
			while (i < at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}

			return true;
		}

		if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X) || mIns[i].UsesZeroPage(mIns[at].mAddress))
			return false;

		i--;
	}

	return false;
}


bool NativeCodeBasicBlock::MoveStoreXUp(int at)
{
	bool	done = false;

	int	n = 0, inc = 0;;
	int	reg = mIns[at].mAddress;

	if (mIns[at].mMode == ASMIM_ZERO_PAGE && !(mIns[at].mLive & LIVE_CPU_REG_X) && at > 0 && (mIns[at - 1].mType == ASMIT_INX || mIns[at - 1].mType == ASMIT_DEX))
	{
		bool	absa = false;
		int k = at - 2;
		while (k >= 0 && !mIns[k].ChangesXReg() && !mIns[k].ChangesZeroPage(reg))
		{
			if (mIns[k].mMode == ASMIM_ABSOLUTE_X)
				absa = true;
			k--;
		}
		if (k >= 0 && absa && mIns[k].mType == ASMIT_LDX && mIns[k].mAddress == reg)
		{
			if (mIns[at - 1].mType == ASMIT_INX)
				mIns[at].mType = ASMIT_INC;
			else
				mIns[at].mType = ASMIT_DEC;
			mIns[at - 1].mType = ASMIT_NOP;
			mIns[at - 1].mMode = ASMIM_IMPLIED;
			return true;
		}
	}

	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].MayBeSameAddress(mIns[at + n], true))
				return done;

			if (mIns[at - 1].mMode == ASMIM_ABSOLUTE_X && inc)
			{
				if (inc < 0 || !mIns[at - 1].mLinkerObject || mIns[at - 1].mLinkerObject->mSize > 255)
					return done;
			}

			if (n > 0 && mIns[at + n].mLive & LIVE_CPU_REG_Z)
			{
				if (mIns[at - 1].ChangesZFlag())
					return done;
				mIns[at - 1].mLive |= LIVE_CPU_REG_Z;
			}

			int live = mIns[at - 1].mLive;
			mIns[at + n].mLive |= LIVE_CPU_REG_X;

			NativeCodeInstruction	ins = mIns[at - 1];
			if (ins.mMode == ASMIM_ABSOLUTE_X)
				ins.mAddress -= inc;

			if (ins.RequiresCarry()) live |= LIVE_CPU_REG_C;
			if (ins.RequiresYReg()) live |= LIVE_CPU_REG_Y;
			if (ins.RequiresAccu()) live |= LIVE_CPU_REG_A;

			for (int i = 0; i <= n; i++)
			{
				mIns[at + i].mLive |= live;
				mIns[at - 1 + i] = mIns[at + i];
			}

			mIns[at + n] = ins;

			if (ins.mType != ASMIT_STY)
				done = true;
		}
		at--;
	}

	return done;
}

bool NativeCodeBasicBlock::MoveLoadYUp(int at)
{
	int	i = at - 1;
	while (i >= 0)
	{
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			mIns[i].mType = ASMIT_TAY;
			mIns[i].mMode = ASMIM_IMPLIED;
			mIns[at].mType = ASMIT_NOP;
			mIns[at].mMode = ASMIM_IMPLIED;
			while (i < at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i++;
			}

			return true;
		}
		else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
		{
			mIns[i].mType = ASMIT_LDY;
			mIns[i].mLive |= LIVE_MEM;
			mIns[at].mType = ASMIT_INY;
			mIns[at].mMode = ASMIM_IMPLIED;
			while (i < at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i++;
			}

			return true;
		}

		if (mIns[i].RequiresYReg() || mIns[i].ChangesYReg() || (mIns[i].mLive & LIVE_CPU_REG_Y) || mIns[i].UsesZeroPage(mIns[at].mAddress))
			return false;

		i--;
	}

	return false;
}


bool NativeCodeBasicBlock::MoveStoreYUp(int at)
{
	bool	done = false;

	while (at > 0)
	{
		if (mIns[at - 1].ChangesYReg() || mIns[at - 1].mType == ASMIT_STY)
			return done;
		if (mIns[at].mMode == ASMIM_ZERO_PAGE)
		{
			if ((mIns[at - 1].mMode == ASMIM_ZERO_PAGE || mIns[at - 1].mMode == ASMIM_INDIRECT_Y) && mIns[at - 1].mAddress == mIns[at].mAddress)
				return done;
			if (mIns[at - 1].mMode == ASMIM_INDIRECT_Y && mIns[at - 1].mAddress + 1 == mIns[at].mAddress)
				return done;
		}
		else if (mIns[at - 1].MayBeSameAddress(mIns[at], true))
			return done;

		mIns[at].mLive |= mIns[at - 1].mLive;
		mIns[at].mLive |= LIVE_CPU_REG_Y;

		NativeCodeInstruction	ins = mIns[at - 1];

		if (ins.RequiresXReg()) mIns[at].mLive |= LIVE_CPU_REG_X;
		if (ins.RequiresAccu()) mIns[at].mLive |= LIVE_CPU_REG_A;
		if (ins.RequiresCarry()) mIns[at].mLive |= LIVE_CPU_REG_C;

		mIns[at - 1] = mIns[at];
		mIns[at] = ins;
		at--;

		if (ins.mType != ASMIT_STX)
			done = true;
	}

	return done;
}

bool NativeCodeBasicBlock::MoveStoreHighByteDown(int at)
{
	int	i = at + 4;
	while (i + 1 < mIns.Size())
	{
		if (mIns[i].mLive & LIVE_CPU_REG_Y)
			return false;
		if (mIns[i].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 2].mAddress + 1) || mIns[i].ChangesZeroPage(mIns[at + 3].mAddress))
			return false;
		if (mIns[i].UsesZeroPage(mIns[at + 3].mAddress))
			return false;
		if (mIns[i].ChangesGlobalMemory())
			return false;

		if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			mIns.Insert(i + 1, mIns[at + 3]); mIns[i + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 2]); mIns[i + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 1]); mIns[i + 1].mLive |= mIns[i].mLive;

			mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; // LDY
			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; // LDA (x), y
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED; // STA T

			return true;
		}

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveAddHighByteDown(int at)
{
	int	i = at + 4;
	while (i + 1 < mIns.Size())
	{
		if (mIns[i].mLive & LIVE_CPU_REG_C)
			return false;
		if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 3].mAddress))
			return false;
		if (mIns[i].UsesZeroPage(mIns[at + 3].mAddress))
			return false;

		if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			for (int j = at + 4; j < i + 1; j++)
				mIns[j].mLive |= LIVE_CPU_REG_C;

			mIns.Insert(i + 1, mIns[at + 3]); mIns[i + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 2]); mIns[i + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 1]); mIns[i + 1].mLive |= mIns[i].mLive;

			mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; // LDA U
			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; // ADC #
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED; // STA T

			return true;
		}

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadImmStoreAbsoluteUp(int at)
{
	int	j = at;
	while (j > 0)
	{
		if (mIns[j - 1].mType == ASMIT_LDA && (mIns[j - 1].mMode == ASMIM_IMMEDIATE || mIns[j - 1].mMode == ASMIM_ZERO_PAGE))
		{
			if (mIns[j - 1].mMode == mIns[at + 0].mMode && mIns[j - 1].mAddress == mIns[at + 0].mAddress)
			{
				while (j < at && mIns[j].mType == ASMIT_STA)
					j++;
				mIns[j - 1].mLive |= LIVE_CPU_REG_A;

				NativeCodeInstruction	sins = mIns[at + 1];
				mIns.Remove(at + 1);
				if (!(sins.mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
					mIns.Remove(at);

				if (sins.ReferencesXReg())
					sins.mLive |= LIVE_CPU_REG_X;
				if (sins.ReferencesYReg())
					sins.mLive |= LIVE_CPU_REG_Y;
				
				mIns.Insert(j, sins);

				return true;
			}
			else if (mIns[j - 1].mMode == mIns[at + 1].mMode && mIns[j - 1].mAddress == mIns[at + 1].mAddress)
				return false;

			j--;
		}
		else if (mIns[j - 1].mType == ASMIT_STA && mIns[j - 1].mMode == mIns[at + 1].mMode && !(mIns[j - 1].mLinkerObject == mIns[at + 1].mLinkerObject && mIns[j - 1].mAddress == mIns[at + 1].mAddress))
			j--;
		else
			return false;
	}

	return false;
}


bool NativeCodeBasicBlock::MoveLoadStoreUp(int at)
{
	int	j = at;
	while (j > 0 && !((mIns[j - 1].mType == ASMIT_STA || mIns[j - 1].mType == ASMIT_LDA) && mIns[j - 1].mMode == ASMIM_ZERO_PAGE && mIns[j - 1].mAddress == mIns[at].mAddress))
	{
		j--;
		if ((mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_INDIRECT_Y) && mIns[j].mAddress == mIns[at + 1].mAddress)
			return false;
		if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress + 1 == mIns[at + 1].mAddress)
			return false;
		if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress && mIns[j].ChangesAddress())
			return false;
		if (mIns[j].mMode == ASMIM_ABSOLUTE_Y && mIns[j].mAddress <= mIns[at + 1].mAddress && mIns[j].mType == ASMIT_LDA && !mIns[j].mLinkerObject)
			return false;
		if (mIns[j].mType == ASMIT_JSR)
			return false;
	}

	if (j > 0 && j < at)
	{
		mIns.Insert(j, mIns[at + 1]);
		mIns[j - 1].mLive |= LIVE_CPU_REG_A;
		mIns[j].mLive |= LIVE_CPU_REG_A;
		mIns[j].mLive |= mIns[j - 1].mLive;
		mIns[at + 2].mType = ASMIT_NOP;	mIns[at + 2].mMode = ASMIM_IMPLIED;

		return true;
	}

	return false;
}


// [at + 0] = LSR zp1 and not needed
// [at + 1] = ROR
// [at + 2] = STA zp2 and accu not needed

bool NativeCodeBasicBlock::ReverseShiftByteOrder(int at)
{
	int start = at;

	while (start > 2 &&
		mIns[start - 2].mType == mIns[at + 0].mType && mIns[start - 2].mMode == ASMIM_ZERO_PAGE && mIns[start - 2].mAddress == mIns[at + 0].mAddress &&
		mIns[start - 1].mType == mIns[at + 1].mType && mIns[start - 1].mMode == ASMIM_IMPLIED)
		start -= 2;

	if (start >= 5 &&
		mIns[start - 5].mType == ASMIT_LDA && mIns[start - 5].mMode == ASMIM_ZERO_PAGE && !(mIns[start - 5].mLive & LIVE_MEM) &&
		mIns[start - 4].mType == mIns[at + 0].mType && mIns[start - 4].mMode == ASMIM_IMPLIED &&
		mIns[start - 3].mType == ASMIT_STA && mIns[start - 3].mMode == ASMIM_ZERO_PAGE && mIns[start - 3].mAddress == mIns[at + 0].mAddress &&
		mIns[start - 2].mType == ASMIT_LDA && mIns[start - 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[start - 1].mType == mIns[at + 1].mType && mIns[start - 1].mMode == ASMIM_IMPLIED)
	{
		int reg = mIns[start - 5].mAddress;

		mIns[start - 5].mType = mIns[at + 0].mType; mIns[start - 5].mLive |= LIVE_MEM | LIVE_CPU_REG_C;
		mIns[start - 4].mType = ASMIT_NOP; mIns[start - 4].mMode = ASMIM_IMPLIED;
		mIns[start - 3].mType = ASMIT_NOP; mIns[start - 3].mMode = ASMIM_IMPLIED;

		while (start <= at)
		{
			mIns[start + 0].mAddress = reg;
			start += 2;
		}

		return true;
	}

	return false;
}

// [at + 0] LDA zp
// [at + 1] ASL        and accu not needed, move down to carry use

bool NativeCodeBasicBlock::MoveZeroPageSignToCarryDown(int at)
{
	int i = at + 2;
	while (i < mIns.Size())
	{
		if (mIns[i].ReferencesCarry())
		{
			while (i > at + 2 && (mIns[i - 1].mLive & LIVE_CPU_REG_A))
				i--;
			if (i > at + 2)
			{
				mIns.Insert(i + 0, mIns[at + 0]); mIns[i + 0].mLive |= mIns[i - 1].mLive;
				mIns.Insert(i + 1, mIns[at + 1]); mIns[i + 1].mLive |= mIns[i - 1].mLive;
				mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
				mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
				return true;
			}
			return false;
		}
		else if (mIns[i].ChangesCarry())
			return false;
		else if (mIns[i].ChangesZeroPage(mIns[at].mAddress))
			return false;
		i++;
	}
	return false;
}

// [at + 0] ASL zp
// [at + 1] ROL zp
bool NativeCodeBasicBlock::Move16BitShiftUp(int at)
{
	int i = at - 2;
	while (i >= 0)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[at + 1].mAddress &&
			mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
		{
			int live = mIns[i + 1].mLive;
			mIns[at + 0].mLive |= live; 
			mIns[at + 1].mLive |= live;
			mIns[i + 0] = mIns[at + 0];
			mIns[i + 1] = mIns[at + 1];
			mIns.Remove(at, 2);
			return true;
		}
		if (mIns[at + 0].MayBeChangedOnAddress(mIns[i]) || mIns[at + 1].MayBeChangedOnAddress(mIns[i]))
			return false;
		i--;
	}

	return false;
}

// [at + 0] CLC
// [at + 1] LDA zp
// [at + 2] ADC #
// [at + 3] STA zp
// [at + 4] LDA zp
// [at + 5] ADC #
// [at + 6] STA zp

bool NativeCodeBasicBlock::Move16BitAddUp(int at)
{
//	printf("Move16BitAddUp, %s, %d, %d\n", mProc->mIdent->mString, mIndex, at);

	int i = at - 7;
	while (i >= 0)
	{
		if ((mIns[i + 0].mType == ASMIT_TAY || mIns[i + 0].mType == ASMIT_TAX) &&
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[at + 1].mAddress &&
			mIns[i + 4].mType == ASMIT_LDA &&
			mIns[i + 5].mType == ASMIT_ADC &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[at + 4].mAddress)
		{
			if (mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS &&
				mIns[i + 2].mLinkerObject == mIns[i + 4].mLinkerObject &&
				mIns[i + 2].mAddress == mIns[i + 4].mAddress &&
				(mIns[i + 5].mMode != ASMIM_ZERO_PAGE || mIns[i + 5].mAddress != mIns[i + 6].mAddress))
			{
				printf("Add shift found, %s, %d, %d -> %d\n", mProc->mIdent->mString, mIndex, at, i);

				const InterInstruction* iins = mIns[at].mIns;

				int addr = mIns[i + 2].mAddress + mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
				int lo = mIns[at + 3].mAddress, hi = mIns[at + 6].mAddress;

				mIns.Remove(at, 7);

				int k = i + 7;

				if (mIns[i + 0].mType == ASMIT_TAY)
					mIns.Insert(k + 0, NativeCodeInstruction(iins, ASMIT_TYA));
				else
					mIns.Insert(k + 0, NativeCodeInstruction(iins, ASMIT_TXA));

				mIns.Insert(k + 1, NativeCodeInstruction(iins, ASMIT_CLC));
				mIns.Insert(k + 2, NativeCodeInstruction(iins, ASMIT_ADC, mIns[i + 2]));
				mIns.Insert(k + 3, NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, lo));
				mIns.Insert(k + 4, NativeCodeInstruction(iins, ASMIT_LDA, mIns[i + 4]));
				mIns.Insert(k + 5, NativeCodeInstruction(iins, ASMIT_ADC, mIns[i + 5]));
				mIns.Insert(k + 6, NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, hi));

				mIns[k + 2].mAddress = addr;
				mIns[k + 4].mAddress = addr;

				return true;
			}

			return false;
		}

		if (mIns[i + 6].ChangesZeroPage(mIns[at + 1].mAddress) ||
			mIns[i + 6].ReferencesZeroPage(mIns[at + 3].mAddress) ||
			mIns[i + 6].ChangesZeroPage(mIns[at + 4].mAddress) ||
			mIns[i + 6].ReferencesZeroPage(mIns[at + 6].mAddress))
		{
			return false;
		}

		i--;
	}

	return false;
}

// [at + 0] ASL zp
// [at + 1] ROL zp
bool NativeCodeBasicBlock::Move16BitShiftDown(int at)
{
	int i = at + 2;
	while (i < mIns.Size())
	{
		if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && (mIns[i + 0].mAddress == mIns[at + 1].mAddress || mIns[i + 0].mAddress == mIns[at + 0].mAddress))
		{
			if (mIns[i + 0].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_MEM)) return false;

			int live = mIns[i + 0].mLive | LIVE_CPU_REG_A;

			mIns.Insert(i + 1, mIns[at]);
			mIns.Insert(i + 2, mIns[at + 1]);

			if (mIns[i].mAddress == mIns[at + 0].mAddress)
				mIns[i + 1].mMode = ASMIM_IMPLIED;
			else
				mIns[i + 2].mMode = ASMIM_IMPLIED;

			mIns[i + 1].mLive |= live;
			mIns[i + 2].mLive |= live;
			mIns.Remove(at, 2);
			return true;
		}

		if (mIns[i].ReferencesZeroPage(mIns[at + 0].mAddress) || mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress))
			return false;
		i++;
	}

	return false;
}


// Assume [at    ] = SHIFT
// Assume [at + 1] = ORA

bool NativeCodeBasicBlock::FoldShiftORAIntoLoadImmUp(int at)
{
	int		ora = mIns[at + 1].mAddress;
	int		i = at;

	while (i >= 0)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE)
		{
			mIns[i].mAddress |= ora;
			mIns[at + 1].mType = ASMIT_NOP;
			mIns[at + 1].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if ((mIns[i].mType == ASMIT_ROL || mIns[i].mType == ASMIT_ASL) && mIns[i].mMode == ASMIM_IMPLIED)
		{
			if ((mIns[i].mLive & LIVE_CPU_REG_C) || (ora & 0x01))
				return false;
			ora >>= 1;
		}
		else if ((mIns[i].mType == ASMIT_ROR || mIns[i].mType == ASMIT_LSR) && mIns[i].mMode == ASMIM_IMPLIED)
		{
			if ((mIns[i].mLive & LIVE_CPU_REG_C) || (ora & 0x80))
				return false;
			ora <<= 1;
		}
		else if (mIns[i].ReferencesAccu())
			return false;
		i--;
	}

	return false;
}


// LDA zp
// op  #
// TAX

bool NativeCodeBasicBlock::MoveLDAopTAXDown(int at)
{
	int addr = mIns[at + 0].mAddress;

	int i = at + 3, di = 0;
	while (i < mIns.Size())
	{
		if (mIns[i].ReferencesXReg() || mIns[i].ChangesXReg())
			break;
		if (mIns[at].MayBeChangedOnAddress(mIns[i]))
			break;
		if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			di = i + 1;
		i++;
	}

	if (di > at + 3)
	{
		if (mIns[di - 1].mType == ASMIT_TAY &&
			mIns[di - 2].mMode == ASMIM_IMMEDIATE &&
			mIns[di - 3].mType == ASMIT_LDA)
		{
			di -= 3;
		}
		else if (mIns[di - 1].mType == ASMIT_LDY || mIns[di - 1].mType == ASMIT_CLC || mIns[di - 1].mType == ASMIT_SEC)
		{
			di--;
		}
	}

	if (di > at + 3)
	{
		int live = mIns[di - 1].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C);
		mIns[at + 0].mLive |= live;
		mIns[at + 1].mLive |= live;
		mIns[at + 2].mLive |= live;
		mIns.Insert(di + 0, mIns[at + 0]);
		mIns.Insert(di + 1, mIns[at + 1]);
		mIns.Insert(di + 2, mIns[at + 2]);
		mIns.Remove(at, 3);
		return true;
	}

	return false;
}

// TAX
// CLC
// ADC #1, 2, 3
// STA
// 
// convert to INX/DEX/STX when X not needed anymore

bool NativeCodeBasicBlock::MoveTAXADCSTADown(int at)
{
	int	n = mIns[at + 2].mAddress;
	int addr = mIns[at + 3].mAddress;

	int si = at + 4;
	while (si < mIns.Size())
	{
		if (!(mIns[si].mLive & LIVE_CPU_REG_X))
		{
			if (mIns[si].mLive & LIVE_CPU_REG_Z)
				return false;

			mIns[si].mLive |= LIVE_CPU_REG_X;
			si++;

			for (int i = 0; i < n; i++)
			{
				mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_INX));
				si++;
			}
			mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr));
			return true;
		}

		if (mIns[si].ChangesXReg())
			return false;
		if (mIns[si].ReferencesZeroPage(addr))
			return false;

		si++;
	}

	return false;
}


// CLC
// LDA zp0
// ADC #1, 2, 3
// STA zp1
// ...
// LDX zp1
//
// Convert to INX/DEX

bool NativeCodeBasicBlock::MoveSimpleADCToINCDECDown(int at)
{
	if (at >= 4)
	{
		int si = at - 4;

		while (si >= 0)
		{
			if (mIns[si + 3].ReferencesZeroPage(mIns[at].mAddress))
			{
				if (mIns[si + 0].mType == ASMIT_CLC &&
					mIns[si + 1].mType == ASMIT_LDA && mIns[si + 1].mMode == ASMIM_ZERO_PAGE &&
					mIns[si + 2].mType == ASMIT_ADC && mIns[si + 2].mMode == ASMIM_IMMEDIATE && (mIns[si + 2].mAddress >= 0 && mIns[si + 2].mAddress <= 4) &&
					mIns[si + 3].mType == ASMIT_STA && !(mIns[si + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
				{
					int i = si + 4;
					while (i < at && !mIns[i].ChangesZeroPage(mIns[si + 1].mAddress))
						i++;
					if (i != at)
						return false;

					AsmInsType	t = mIns[at].mType == ASMIT_LDX ? ASMIT_INX : ASMIT_INY;

					mIns[at].mAddress = mIns[si + 1].mAddress;
					for (int i = 0; i < mIns[si + 2].mAddress; i++)
						mIns.Insert(at + 1, NativeCodeInstruction(mIns[si].mIns, t));

					mIns[si + 0].mType = ASMIT_NOP; mIns[si + 0].mMode = ASMIM_IMPLIED;
					mIns[si + 1].mType = ASMIT_NOP; mIns[si + 1].mMode = ASMIM_IMPLIED;
					mIns[si + 2].mType = ASMIT_NOP; mIns[si + 2].mMode = ASMIM_IMPLIED;
					mIns[si + 3].mType = ASMIT_NOP; mIns[si + 3].mMode = ASMIM_IMPLIED;

					return true;
				}
				else
					return false;
			}

			si--;
		}

	}

	return false;
}

bool NativeCodeBasicBlock::CombineImmediateADCUp(int at)
{
	int	addr = mIns[at].mAddress;
	int i = at;
	while (i > 3)
	{
		i--;
		if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
		{
			if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				if (mIns[i - 3].mType == ASMIT_CLC &&
					mIns[i - 2].mType == ASMIT_LDA && mIns[i - 2].mMode == ASMIM_ZERO_PAGE && mIns[i - 2].mAddress == addr &&
					mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
				{
					int val = mIns[at + 1].mAddress;
					mIns[at + 1].CopyMode(mIns[i - 1]);
					if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
						mIns[at + 1].mAddress += val * 256;
					else
						mIns[at + 1].mAddress += val;
					mIns.Remove(i - 3, 4);
					return true;
				}
				else if (mIns[i - 3].mType == ASMIT_CLC &&
					mIns[i - 2].mType == ASMIT_LDA && (mIns[i - 2].mMode == ASMIM_IMMEDIATE || mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
					mIns[i - 1].mType == ASMIT_ADC && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == addr)
				{
					int val = mIns[at + 1].mAddress;
					mIns[at + 1].CopyMode(mIns[i - 2]);
					if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
						mIns[at + 1].mAddress += val * 256;
					else
						mIns[at + 1].mAddress += val;
					mIns.Remove(i - 3, 4);
					return true;
				}
				else if
					(mIns[i - 2].mType == ASMIT_CLC &&
 					 mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
				{
					int val = mIns[at + 1].mAddress;
					mIns[at + 1].CopyMode(mIns[i - 1]);
					if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[at + 1].mFlags & NCIF_UPPER))
						mIns[at + 1].mAddress += val * 256;
					else
						mIns[at + 1].mAddress += val;
					mIns.Remove(i - 2, 2);
					return true;
				}
			}

			return false;
		}

		if (mIns[i].ReferencesZeroPage(addr))
			return false;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveTXALogicTAXDown(int at)
{
	int	i = at + 3;
	while (i < mIns.Size())
	{
		if (mIns[i].ChangesXReg())
			return false;

		if (mIns[i].mType == ASMIT_TXA)
		{
			if (mIns[i].mLive & LIVE_CPU_REG_X)
				return false;
			mIns[at + 1].mLive |= mIns[i].mLive;
			mIns.Insert(i + 1, mIns[at + 1]);
			mIns.Remove(at, 3);
			return true;
		}

		if (mIns[i].RequiresXReg())
			return false;

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveTXADCDown(int at)
{
	int	i = at + 4;
	while (i < mIns.Size())
	{
		if (mIns[i].ChangesXReg())
			return false;
		if (mIns[i].ReferencesZeroPage(mIns[at + 3].mAddress))
			return false;

		if (!(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
		{
			mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 3].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[at + 3].mAddress));

			switch (mIns[at + 2].mAddress)
			{
			case -2:
			case 254:
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_DEX));
			case -1:
			case 255:
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_DEX));
				break;
			case 2:
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_INX));
			case 1:
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[at + 2].mIns, ASMIT_INX));
				break;
			}

			while (i > at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i--;
			}
			mIns.Remove(at, 4);
			return true;
		}

		i++;
	}

	return false;
}

bool NativeCodeBasicBlock::CombineImmediateADCUpX(int at)
{
	int i = at;
	while (i > 3)
	{
		i--;
		if (mIns[i].mType == ASMIT_TAX)
		{
			if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				if (mIns[i - 3].mType == ASMIT_CLC &&
					mIns[i - 2].mType == ASMIT_LDA && 
					mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
				{
					int val = mIns[at + 1].mAddress;
					mIns[at + 1].CopyMode(mIns[i - 1]);
					if (mIns[at + 1].mFlags & NCIF_UPPER)
						mIns[at + 1].mAddress += val * 256;
					else
						mIns[at + 1].mAddress += val;
					mIns[i - 1].mType = ASMIT_NOP; mIns[i - 1].mMode = ASMIM_IMPLIED;
					mIns[i - 3].mType = ASMIT_NOP; mIns[i - 3].mMode = ASMIM_IMPLIED;
					return true;
				}
				else if
					(mIns[i - 2].mType == ASMIT_CLC &&
						mIns[i - 1].mType == ASMIT_ADC && (mIns[i - 1].mMode == ASMIM_IMMEDIATE || mIns[i - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
				{
					int val = mIns[at + 1].mAddress;
					mIns[at + 1].CopyMode(mIns[i - 1]);
					if (mIns[at + 1].mFlags & NCIF_UPPER)
						mIns[at + 1].mAddress += val * 256;
					else
						mIns[at + 1].mAddress += val;
					mIns[i - 2].mType = ASMIT_NOP; mIns[i - 2].mMode = ASMIM_IMPLIED;
					mIns[i - 1].mType = ASMIT_NOP; mIns[i - 1].mMode = ASMIM_IMPLIED;
					return true;
				}
			}

			return false;
		}

		if (mIns[i].ReferencesXReg())
			return false;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveASLMemUp(int at)
{
	int j = at;
	while (j > 0 && !mIns[j - 1].SameEffectiveAddress(mIns[at]))
	{
		if ((mIns[at].mLive & LIVE_CPU_REG_C) && mIns[j - 1].ReferencesCarry())
			return false;
		j--;
	}

	if (j > 0 && mIns[j - 1].mType == ASMIT_STA && !(mIns[j - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
	{
		if (mIns[at].mLive & LIVE_CPU_REG_C)
		{
			for (int i = j - 1; i < at; i++)
				mIns[i].mLive |= LIVE_CPU_REG_C;
		}

		mIns.Insert(j - 1, NativeCodeInstruction(mIns[at].mIns, mIns[at].mType));
		mIns.Remove(at + 1);
		return true;
	}

	return false;
}


bool NativeCodeBasicBlock::MoveLoadStoreXUp(int at)
{
	int	j = at;
	while (j > 0 && !((mIns[j - 1].mType == ASMIT_STA || mIns[j - 1].mType == ASMIT_LDA) && mIns[j - 1].mMode == ASMIM_ZERO_PAGE && mIns[j - 1].mAddress == mIns[at].mAddress))
	{
		j--;
		if ((mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_INDIRECT_Y) && mIns[j].mAddress == mIns[at + 1].mAddress)
			return false;
		if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress + 1 == mIns[at + 1].mAddress)
			return false;
		if (mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress && mIns[j].ChangesAddress())
			return false;
		if (mIns[j].mMode == ASMIM_ABSOLUTE_Y && mIns[j].mAddress <= mIns[at + 1].mAddress && mIns[j].mType == ASMIT_LDA && !mIns[j].mLinkerObject)
			return false;
		if (mIns[j].mType == ASMIT_JSR)
			return false;
	}

	if (j > 0 && j < at)
	{
		for (int i = at; i > j; i--)
		{
			mIns[i] = mIns[i - 1];
		}
		mIns[at + 1].mLive |= mIns[j - 1].mLive;
		mIns[j - 1].mLive |= LIVE_CPU_REG_A;
		mIns[j] = mIns[at + 1];
		mIns[j].mType = ASMIT_STA;
		mIns[at + 1].mType = ASMIT_NOP;	mIns[at + 1].mMode = ASMIM_IMPLIED;

		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveStaTaxLdaStaDown(int at)
{
	int	j = at + 4;

	while (j < mIns.Size())
	{
		if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
		{
			if (mIns[j].mLive & (LIVE_CPU_REG_X | LIVE_MEM))
				return false;

			if (!HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_X))
				return false;

			mIns[j].CopyMode(mIns[at + 2]);
			mIns.Insert(j, NativeCodeInstruction(mIns[at].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[at + 0].mAddress));

			mIns.Remove(at + 1);
			mIns.Remove(at + 1);
			mIns.Remove(at + 1);

			return true;
		}
		if (mIns[at + 0].MayBeChangedOnAddress(mIns[j]))
			return false;
		if (mIns[at + 2].MayBeChangedOnAddress(mIns[j]))
			return false;
		if (mIns[at + 3].MayBeChangedOnAddress(mIns[j]))
			return false;

		j++;
	}	

	return false;
}

bool NativeCodeBasicBlock::MoveLoadAddImmStoreAbsXUp(int at)
{
	int	j = at - 1, top = at;
	while (j > 0)
	{
		if (mIns[j].ChangesXReg())
			break;
		if (mIns[j].MayBeSameAddress(mIns[at + 3], true))
			break;
		if (mIns[j].MayBeSameAddress(mIns[at + 0], true) && mIns[j].ChangesAddress())
			break;

		if (!(mIns[j - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			top = j;
		j--;
	}

	while (top < at && mIns[top].mType == ASMIT_STX)
		top++;

	if (top < at)
	{
		int live = 0;
		if (top > 0)
			live = mIns[top - 1].mLive;
		else if (mIns[top].RequiresYReg())
			live |= LIVE_CPU_REG_Y;
		mIns[at + 0].mLive |= live;
		mIns[at + 1].mLive |= live;
		mIns[at + 2].mLive |= live;
		mIns[at + 3].mLive |= live;

		mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
		mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
		mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);
		mIns.Insert(top, mIns[at + 3]); mIns.Remove(at + 4);

		return true;
	}
	else
		return false;
}

bool NativeCodeBasicBlock::MoveLoadAddStoreDown(int at)
{
	// at + 0 : LDA 
	// at + 1 : CLC
	// at + 2 : ADC
	// at + 3 : STA zp

	int addr = mIns[at + 3].mAddress;
	int j = at + 4;
	while (j < mIns.Size())
	{
		if (mIns[j].mType == ASMIT_ADC && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == addr && !(mIns[j].mLive & LIVE_MEM))
		{
			if (mIns[at + 0].ReferencesXReg() || mIns[at + 2].ReferencesXReg())
			{
				for (int i = at; i < j; i++)
					mIns[i].mLive |= LIVE_CPU_REG_X;
			}
			if (mIns[at + 0].ReferencesYReg() || mIns[at + 2].ReferencesYReg())
			{
				for (int i = at; i < j; i++)
					mIns[i].mLive |= LIVE_CPU_REG_Y;
			}

			mIns.Remove(j);
			mIns.Insert(j, mIns[at + 0]); mIns[j].mType = ASMIT_ADC;
			mIns.Insert(j + 1, mIns[at + 1]);
			mIns.Insert(j + 2, mIns[at + 2]);

			mIns.Remove(at, 4);
			return true;
		}

		if (mIns[at + 0].MayBeChangedOnAddress(mIns[j]) || mIns[at + 2].MayBeChangedOnAddress(mIns[j]))
			return false;
		if (mIns[j].ReferencesZeroPage(addr))
			return false;
		if (mIns[at + 0].ReferencesXReg() && mIns[j].ChangesXReg())
			return false;
		if (mIns[at + 2].ReferencesXReg() && mIns[j].ChangesXReg())
			return false;
		if (mIns[at + 0].ReferencesYReg() && mIns[j].ChangesYReg())
			return false;
		if (mIns[at + 2].ReferencesYReg() && mIns[j].ChangesYReg())
			return false;

		j++;
	}
	
	return false;
}

bool NativeCodeBasicBlock::MoveLoadLogicStoreAbsUp(int at)
{
	// at + 0 : LDA zp
	// at + 1 : ORA zp / imm
	// at + 2 : STA abs / abs,x / abs,y

	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			while (j + 1 < mIns.Size() && mIns[j + 1].mType == ASMIT_STA)
				j++;

			if (mIns[j].mLive & LIVE_CPU_REG_A)
				return false;

			mIns[j].mLive |= LIVE_CPU_REG_A;
			for (int i = j + 1; i < at; i++)
				mIns[i].mLive |= LIVE_CPU_REG_C;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			mIns.Insert(j + 1, mIns[at + 2]);	// STA
			mIns.Insert(j + 1, mIns[at + 2]);	// ORA

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;

			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
			return false;
		if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;

		if (mIns[j].UsesMemoryOf(mIns[at + 2]))
			return false;
		if (mIns[at + 2].mMode == ASMIM_ABSOLUTE_X && mIns[j].ChangesXReg())
			return false;
		if (mIns[at + 2].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg())
			return false;

		j--;
	}

	return false;
}


bool NativeCodeBasicBlock::MoveLoadOrZPUp(int at) 
{
	// at + 0 : LDA zp
	// at + 1 : ORA zp

	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].mAddress == mIns[at + 1].mAddress))
		{
			if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
				return false;

			if (mIns[at + 1].mAddress == mIns[j].mAddress)
			{
				mIns[at + 1].mAddress = mIns[at].mAddress;
				mIns[at].mAddress = mIns[j].mAddress;
			}
			mIns[at].mLive |= mIns[at + 1].mLive & LIVE_CPU_REG_Z;
			mIns[at + 1].mLive |= mIns[j].mLive | LIVE_CPU_REG_A;
			mIns.Insert(j, mIns[at + 1]);

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ReferencesZeroPage(mIns[at].mAddress))
			return false;
		if (mIns[j].ReferencesZeroPage(mIns[at + 1].mAddress))
			return false;

		j--;
	}

	return false;

}


bool NativeCodeBasicBlock::MoveImmOpBeforeStore(int at)
{
	// at + 0 : LDA zp
	// at + 1 : AND #imm

	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
				return false;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns.Insert(j, mIns[at + 1]);

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ReferencesZeroPage(mIns[at].mAddress))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadAddImmStoreUp(int at)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 1].mAddress)
		{
			while (j + 1 < mIns.Size() && mIns[j + 1].mType == ASMIT_STA)
				j++;

			if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))
				return false;

			mIns[j].mLive |= LIVE_CPU_REG_A;
			for (int i = j + 1; i < at; i++)
				mIns[i].mLive |= LIVE_CPU_REG_C;

			mIns[at + 0].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;
			mIns[at + 3].mLive |= mIns[j].mLive;

			mIns.Insert(j + 1, mIns[at + 3]);	// STA
			mIns.Insert(j + 1, mIns[at + 3]);	// ADC
			mIns.Insert(j + 1, mIns[at + 2]);	// CLC

			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
			mIns[at + 6].mType = ASMIT_NOP; mIns[at + 6].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].UsesMemoryOf(mIns[at + 3]))
			return false;
		if (mIns[j].ChangesCarry())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadEorImmStoreUp(int at)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_A)
				return false;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			mIns.Insert(j + 1, mIns[at + 2]);	// STA
			mIns.Insert(j + 1, mIns[at + 2]);	// EOR

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (mIns[j].IsShift() && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress && mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 2].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_A)
				return false;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns[at + 0].mLive |= LIVE_CPU_REG_C;
			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			mIns[j].mMode = ASMIM_IMPLIED;

			mIns.Insert(j, mIns[at + 0]);	// LDA

			mIns.Insert(j + 2, mIns[at + 3]);	// STA
			mIns.Insert(j + 2, mIns[at + 3]);	// EOR

			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
			return false;
		if (mIns[j].UsesMemoryOf(mIns[at + 2]))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveCLCLoadAddZPStoreUp(int at)
{
	int	j = at - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && (mIns[j].mAddress == mIns[at + 1].mAddress || mIns[j].mAddress == mIns[at + 2].mAddress))
		{
			bool	flip = mIns[j].mAddress != mIns[at + 1].mAddress;

			if (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))
			{					
				int k = j;
				j++;
				while (j < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
				{
					if (mIns[j].ChangesAccu())
						return false;
					j++;
				}

				while (k < j)
					mIns[k++].mLive |= LIVE_CPU_REG_A;
			}

			if (mIns[at + 2].mLive & LIVE_CPU_REG_C)
			{
				for (int i = j + 1; i < at; i++)
					mIns[i].mLive |= LIVE_CPU_REG_C;
			}

			if (flip)
				mIns[at + 2].mAddress = mIns[at + 1].mAddress;

			mIns[at + 0].mLive |= mIns[j].mLive | LIVE_CPU_REG_A;
			mIns[at + 2].mLive |= mIns[j].mLive;
			mIns[at + 3].mLive |= mIns[j].mLive;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns.Insert(j + 1, mIns[at + 3]);	// STA
			mIns.Insert(j + 1, mIns[at + 3]);	// ADC
			mIns.Insert(j + 1, mIns[at + 2]);	// CLC

			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			mIns[at + 5].mType = ASMIT_NOP; mIns[at + 5].mMode = ASMIM_IMPLIED;
			mIns[at + 6].mType = ASMIT_LDA; 
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
			return false;
		if ((mIns[at + 2].mLive & LIVE_CPU_REG_C) && mIns[j].ChangesCarry())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::ReverseLoadCommutativeOpUp(int aload, int aop)
{
	int	j = aload - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[aop].mAddress)
		{
			mIns[aop].CopyModeAndRange(mIns[aload]);
			mIns[aop].mLive |= LIVE_MEM;

			mIns[aload].mType = ASMIT_NOP;
			mIns[aload].mMode = ASMIM_IMPLIED;

			while (j < aop)
			{
				mIns[j].mLive |= LIVE_CPU_REG_A;
				j++;
			}

			j = aload;
			while (j < aop)
			{
				mIns[j].mLive |= mIns[aload - 1].mLive;
				j++;
			}

			return true;
		}

		if (mIns[j].ChangesAccu())
			return false;
		if (mIns[j].ChangesZeroPage(mIns[aop].mAddress))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveTYADCStoreDown(int at)
{
	// [at + 0] TYA
	// [at + 1] CLC
	// [at + 2] ADC #
	// [at + 3] STA

	int	offset = mIns[at + 2].mAddress;
	int addr = mIns[at + 3].mAddress;

	for (int i = at + 4; i < mIns.Size(); i++)
	{
		NativeCodeInstruction& ins(mIns[i]);

		if (mIns[i].mType == ASMIT_INY)
			offset--;
		else if (mIns[i].mType == ASMIT_DEY)
			offset++;
		else if (mIns[i].ChangesYReg())
			return false;
		else if (mIns[i].ReferencesZeroPage(addr))
			return false;
		else if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
		{
			if (offset < -2 || offset > 2)
				return false;
			while (offset < 0)
			{
				mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_DEY));
				offset++;
				i++;
			}
			while (offset > 0)
			{
				mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_INY));
				offset--;
				i++;
			}
			mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
			while (i > at)
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i--;
			}
			mIns.Remove(at, 4);
			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLDSTXOutOfRange(int at)
{
	bool vol = mIns[at + 1].mFlags & NCIF_VOLATILE;

	int j = at + 2;
	while (j < mIns.Size())
	{
		if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE)
		{
			if (mIns[j].ReferencesZeroPage(mIns[at + 1].mAddress))
				return false;
		}
		else if (mIns[j].MayBeSameAddress(mIns[at + 1]))
			return false;
		else if (vol && mIns[j].ChangesGlobalMemory())
			return false;
		else if (mIns[at + 1].mMode == ASMIM_ABSOLUTE && (mIns[j].mFlags & NCIF_VOLATILE))
			return false;
		else if (mIns[j].ReferencesXReg())
			return false;

		if (mIns[j].mType == ASMIT_JSR || mIns[j].mType == ASMIT_RTS)
			return false;

		if (!(mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
			mIns.Insert(j + 1, NativeCodeInstruction(mIns[at].mIns, ASMIT_LDA, mIns[at]));
			mIns.Remove(at, 2);

			return true;
		}

		j++;
	}

	j = at;
	while (j > 0)
	{
		j--;
		if (!(mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1]));
			mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_LDA, mIns[at + 1]));
			mIns.Remove(at + 2, 2);

			return true;
		}

		if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE)
		{
			if (mIns[j].ReferencesZeroPage(mIns[at + 1].mAddress))
				return false;
		}
		else if (mIns[j].MayBeSameAddress(mIns[at + 1]))
			return false;
		else if (vol && mIns[j].ChangesGlobalMemory())
			return false;
		else if (mIns[at + 1].mMode == ASMIM_ABSOLUTE && (mIns[j].mFlags & NCIF_VOLATILE))
			return false;
		else if (mIns[j].ReferencesXReg())
			return false;

		if (mIns[j].mType == ASMIT_JSR)
			return false;

	}

	return false;
}

bool NativeCodeBasicBlock::MoveShiftZeroPageUp(int at)
{
	int	j = at - 1;
	while (j >= 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_A)
			{
				if (mIns[j + 1].mType == ASMIT_TAY || mIns[j + 1].mType == ASMIT_TAX)
				{
					if (mIns[j + 1].mLive & LIVE_CPU_REG_A)
						return false;
					NativeCodeInstruction	ins(mIns[j + 1]);
					ins.mLive |= LIVE_CPU_REG_A;
					mIns.Remove(j + 1);
					mIns.Insert(j, ins);
					mIns[j + 1].mLive |= ins.mLive;
					j++;
				}
				else
					return false;
			}

			NativeCodeInstruction	sins(mIns[at]);
			mIns.Remove(at);
			sins.mMode = ASMIM_IMPLIED;
			sins.mLive |= LIVE_CPU_REG_A;
			mIns.Insert(j, sins);
			mIns[j].mLive |= mIns[j + 1].mLive;
			if (sins.mLive & LIVE_CPU_REG_C)
			{
				for (int i = j; i <= at; i++)
					mIns[i].mLive |= LIVE_CPU_REG_C;
			}

			return true;
		}

		if (mIns[j].ReferencesCarry())
			return false;
		if (mIns[j].ReferencesZeroPage(mIns[at].mAddress))
			return false;
		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadShiftStoreUp(int at)
{
	int	j = at - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_C)
				return false;

			if (mIns[j].mLive & LIVE_CPU_REG_A)
			{
				if (mIns[j + 1].mType == ASMIT_STA && !(mIns[j + 1].mLive & LIVE_CPU_REG_A))
				{
					NativeCodeInstruction	ins = mIns[j + 1];
					mIns[j + 1] = mIns[j];
					mIns[j] = ins;
					mIns[j].mLive |= LIVE_CPU_REG_A;
					j++;
				}
				else
					return false;
			}

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			for (int i = j + 1; i < at; i++)
				mIns[i].mLive |= LIVE_CPU_REG_C;

			mIns.Insert(j + 1, mIns[at + 2]);	// STORE
			mIns.Insert(j + 1, mIns[at + 2]);	// SHIFT

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			return true;
		}

		if ((mIns[at + 1].RequiresCarry() || (mIns[at + 2].mLive & LIVE_CPU_REG_C) != 0) && mIns[j].ChangesCarry())
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadShiftRotateUp(int at)
{
	int	j = at - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
		{
			if (mIns[j].mLive & LIVE_CPU_REG_C)
				return false;

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			for (int i = j + 1; i < at; i++)
				mIns[i].mLive |= LIVE_CPU_REG_C;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns.Insert(j + 1, mIns[at + 2]);	// ROR ZP
			mIns.Insert(j + 1, mIns[at + 2]);	// LSR

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveLoadAddZPStoreUp(int at)
{
	int	j = at - 1;
	while (j > 0)
	{
		if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 0].mAddress)
		{
			while (j < at && (mIns[j].mLive & LIVE_CPU_REG_A))
			{
				if (mIns[j].ChangesAccu())
					return false;
				j++;
			}

			mIns[at + 1].mLive |= mIns[j].mLive;
			mIns[at + 2].mLive |= mIns[j].mLive;

			mIns[j].mLive |= LIVE_CPU_REG_A;

			mIns.Insert(j + 1, mIns[at + 2]);	// STA
			mIns.Insert(j + 1, mIns[at + 2]);	// ADC

			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			mIns[at + 4].mType = ASMIT_NOP; mIns[at + 4].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 0].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].UsesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].ChangesCarry())
			return false;

		j--;
	}

	return false;
}

bool NativeCodeBasicBlock::MoveZpImmTAYDown(int at)
{
	int reg = mIns[at].mAddress;
	int j = at + 3;
	while (j < mIns.Size())
	{
		if (mIns[j].RequiresYReg())
		{
			while (j > at + 3 && (mIns[j - 1].mLive & LIVE_CPU_REG_A))
				j--;
			if (j > at + 3)
			{
				mIns.Insert(j + 0, mIns[at + 0]);
				mIns.Insert(j + 1, mIns[at + 1]);
				mIns.Insert(j + 2, mIns[at + 2]);

				mIns[j + 0].mLive |= mIns[j - 1].mLive;
				mIns[j + 1].mLive |= mIns[j - 1].mLive;
				mIns[j + 2].mLive |= mIns[j - 1].mLive;

				mIns[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;
				return true;
			}

			return false;
		}

		if (mIns[j].ChangesYReg())
			return false;
		if (mIns[j].ChangesZeroPage(reg))
			return false;
		j++;
	}
	return false;
}

bool NativeCodeBasicBlock::MoveCLCLoadAddZPStoreDown(int at)
{
	int	j = at + 4;
	while (j < mIns.Size())
	{
		if (mIns[j].mType == ASMIT_LDA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at + 3].mAddress)
		{
			if (j == at + 4)
				return false;
			if (mIns[j].mLive & LIVE_CPU_REG_C)
				return false;

			mIns.Insert(j, mIns[at + 3]);	// STA
			mIns.Insert(j, mIns[at + 2]);	// ADC
			mIns.Insert(j, mIns[at + 1]);	// LDA
			mIns.Insert(j, mIns[at + 0]);	// CLC

			mIns[j + 0].mLive |= mIns[j - 1].mLive;
			mIns[j + 1].mLive |= mIns[j - 1].mLive;
			mIns[j + 2].mLive |= mIns[j - 1].mLive;
			mIns[j + 3].mLive |= mIns[j - 1].mLive;

			mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED;
			mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED;
			mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED;
			mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED;
			return true;
		}

		if (mIns[j].ChangesZeroPage(mIns[at + 1].mAddress))
			return false;
		if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress))
			return false;
		if (mIns[j].UsesZeroPage(mIns[at + 3].mAddress))
			return false;

		j++;
	}

	return false;
}

//static bool PeepCheck = false;
//static bool PeepCheck = false;

bool NativeCodeBasicBlock::ReverseBitfieldForwarding(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		bool	cused = mExitRequiredRegs[CPU_REG_C], zused = mExitRequiredRegs[CPU_REG_Z];

		int		aused = 0x00;
		
		if (mTrueJump && mTrueJump->mEntryRequiredRegs[CPU_REG_A])
			aused = 0xff;

		if (mFalseJump)
		{
			if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
				cused = true;
			else if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI)
				zused = true;

			if (mFalseJump->mEntryRequiredRegs[CPU_REG_A])
				aused = 0xff;
		}

		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;
				zused = false;
				break;
			case ASMIT_CLC:
			case ASMIT_SEC:
				cused = false;
				break;
			case ASMIT_SBC:
				if (!cused && !zused && ins.mMode == ASMIM_IMMEDIATE && i > 0 && mIns[i - 1].mType == ASMIT_SEC)
				{
					char um = BinMask(aused);
					if (ins.mAddress & um)
						aused = 0xff;
					else if (ins.mAddress)
					{
						ins.mAddress = 0x00;
						changed = true;
					}
				}
				else
					aused = 0xff;
				cused = true;
				zused = false;
				break;
			case ASMIT_ADC:
				if (!cused && !zused && ins.mMode == ASMIM_IMMEDIATE && i > 0 && mIns[i - 1].mType == ASMIT_CLC)
				{
					char um = BinMask(aused);
					if (ins.mAddress & um)
						aused = 0xff;
					else if (ins.mAddress)
					{
						ins.mAddress = 0x00;
						changed = true;
					}
				}
				else
					aused = 0xff;
				cused = true;
				zused = false;
				break;

			case ASMIT_JSR:
				cused = true;
				zused = false;
				aused = 0xff;
				break;
			case ASMIT_CMP:
				cused = false;
				zused = false;
				aused = 0xff;
				break;
			case ASMIT_EOR:
				if (zused)
					aused = 0xff;
				else if (ins.mMode == ASMIM_IMMEDIATE)
				{
					int naddr = ins.mAddress & aused;
					if (ins.mAddress != naddr)
					{
						ins.mAddress = naddr;
						changed = true;
					}
				}
				zused = false;
				break;

			case ASMIT_STA:
			case ASMIT_TAX:
			case ASMIT_TAY:
				aused = 0xff;
				zused = false;
				break;
			case ASMIT_LSR:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (zused)
						aused = 0xfe;
					else
						aused = (aused << 1) & 0xff;
					if (cused)
						aused |= 1;
				}
				cused = false;
				zused = false;
				break;
			case ASMIT_ASL:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (zused)
						aused = 0x7f;
					else
						aused >>= 1;
					if (cused)
						aused |= 0x80;
				}
				cused = false;
				zused = false;
				break;
			case ASMIT_ROR:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (zused)
					{
						aused = 0xfe;
						if (cused)
							aused |= 1;
						cused = true;
					}
					else 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;
						changed = true;
					}
				}
				else
					cused = true;
				zused = false;
				break;
			case ASMIT_ROL:
				if (ins.mMode == ASMIM_IMPLIED)
				{
					if (zused)
					{
						aused = 0x7f;
						if (cused)
							aused |= 0x80;
						cused = true;
					}
					else if (aused & 0x01)
					{
						aused >>= 1;
						if (cused)
							aused |= 0x80;
						cused = true;
					}
					else
					{
						ins.mType = ASMIT_ASL;
						aused >>= 1;
						if (cused)
							aused |= 0x80;
						cused = false;
						changed = true;
					}
				}
				else
					cused = true;
				zused = false;
				break;
			case ASMIT_ORA:
				if (zused)
					aused = 0xff;
				else if (ins.mMode == ASMIM_IMMEDIATE)
				{
					int naddr = ins.mAddress & aused;
					if (ins.mAddress != naddr)
					{
						ins.mAddress = naddr;
						changed = true;
					}
					aused &= ~ins.mAddress;
				}
				break;
			case ASMIT_AND:
				if (zused)
					aused = 0xff;
				else if (ins.mMode == ASMIM_IMMEDIATE)
				{
					int naddr = ins.mAddress & aused;
					if (ins.mAddress != naddr)
					{
						ins.mAddress = naddr;
						changed = true;
					}
					aused &= ins.mAddress;
				}
				zused = false;
				break;
			}
		}

		if (mTrueJump && mTrueJump->ReverseBitfieldForwarding())
			changed = true;
		if (mFalseJump && mFalseJump->ReverseBitfieldForwarding())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::RemoveLocalUnusedLinkerObjects(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;


		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_LOCAL_VAR) && !(ins.mLinkerObject->mFlags & LOBJF_LOCAL_USED))
			{
				ins.mType = ASMIT_NOP;
				ins.mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}

		if (mTrueJump && mTrueJump->RemoveLocalUnusedLinkerObjects())
			changed = true;
		if (mFalseJump && mFalseJump->RemoveLocalUnusedLinkerObjects())
			changed = true;
	}
	
	return changed;
}

void NativeCodeBasicBlock::MarkLocalUsedLinkerObjects(void)
{
	if (!mVisited)
	{
		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);
			if (ins.mLinkerObject)
			{
				if (ins.mMode == ASMIM_IMMEDIATE_ADDRESS || ins.UsesAddress())
					ins.mLinkerObject->mFlags |= LOBJF_LOCAL_USED;
			}
		}

		if (mTrueJump) mTrueJump->MarkLocalUsedLinkerObjects();
		if (mFalseJump) mFalseJump->MarkLocalUsedLinkerObjects();
	}
}

bool NativeCodeBasicBlock::AbsoluteValueForwarding(const ExpandingArray<NativeCodeLoadStorePair> & npairs)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		ExpandingArray<NativeCodeLoadStorePair>	pairs;
		if (mNumEntries == 1)
			pairs = npairs;

		int ains = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			// Check content of accu
			if (mIns[i].mType == ASMIT_LDA)
			{
				if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_ZERO_PAGE)
					ains = i;
				else if (mIns[i].mMode == ASMIM_ABSOLUTE && !(mIns[i].mFlags & NCIF_VOLATILE))
				{
					int j = 0;
					while (j < pairs.Size() && !pairs[j].mStore.SameEffectiveAddress(mIns[i]))
						j++;
					if (j < pairs.Size())
					{
						mIns[i].CopyMode(pairs[j].mLoad);
						ains = i;
						changed = true;
					}
					else
						ains = -1;
				}
				else
					ains = -1;
			}
			else if (mIns[i].ChangesAccu())
				ains = -1;
			else if (ains >= 0 && mIns[ains].MayBeChangedOnAddress(mIns[i]))
				ains = -1;

			if (ains >= 0 && mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ABSOLUTE && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				int j = 0;
				while (j < pairs.Size() && !pairs[j].mStore.SameEffectiveAddress(mIns[i]))
					j++;
				if (j < pairs.Size())
				{
					pairs[j].mLoad = mIns[ains];
					pairs[j].mStore = mIns[i];
				}
				else
				{
					NativeCodeLoadStorePair	pair;
					pair.mLoad = mIns[ains];
					pair.mStore = mIns[i];
					pairs.Push(pair);
				}
			}
			else if (mIns[i].mType == ASMIT_JSR || (mIns[i].mFlags & NCIF_MEMMAP))
			{
				pairs.SetSize(0);
				ains = -1;
			}
			else if (mIns[i].ChangesAddress())
			{
				int j = 0, k = 0;
				while (j < pairs.Size())
				{
					if (!pairs[j].mLoad.MayBeChangedOnAddress(mIns[i]) && !pairs[j].mStore.MayBeChangedOnAddress(mIns[i]))
					{
						if (k != j)
							pairs[k] = pairs[j];
						k++;
					}
					j++;
				}
				pairs.SetSize(k);
			}
		}

		if (mTrueJump && mTrueJump->AbsoluteValueForwarding(pairs))
			changed = true;
		if (mFalseJump && mFalseJump->AbsoluteValueForwarding(pairs))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CrossBlockShiftForwarding(const ValueReuseDataSet& data)
{
	bool	changed = false;

	if (!mVisited)
	{
		mNReuseDataSet = data;

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (mLoopHead)
		{
			mNReuseDataSet.Reset();
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
				mNReuseDataSet.Intersect(mReuseDataSet);

			mNumEntered++;

			if (mNumEntered < mNumEntries)
			{
				mReuseDataSet = mNReuseDataSet;
				return false;
			}
		}

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_ZERO_PAGE)
			{
				int		reg = mIns[i].mAddress;

				if (i + 1 < mIns.Size() &&
					mIns[i].mType == ASMIT_LDA && 
					mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
				{
					mNReuseDataSet.mRegs[reg].mBlock = this;
					mNReuseDataSet.mRegs[reg].mIndex = i;
				}
				else if (mNReuseDataSet.mRegs[reg].mBlock)
				{
					NativeCodeBasicBlock* block = mNReuseDataSet.mRegs[reg].mBlock;
					int	index = mNReuseDataSet.mRegs[reg].mIndex;

					if (mIns[i].mType == block->mIns[index + 1].mType && !(mIns[i].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
					{
						block->mIns[index].mType = mIns[i].mType;
						block->mIns[index + 1].mType = ASMIT_NOP;
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}

					mNReuseDataSet.mRegs[reg].mBlock = nullptr;
				}
			}
			else if (mIns[i].mType == ASMIT_JSR)
			{
				mNReuseDataSet.ResetCall(mIns[i]);
			}
			else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				int		reg = mIns[i].mAddress;
				mNReuseDataSet.mRegs[reg].mBlock = nullptr;
				mNReuseDataSet.mRegs[reg + 1].mBlock = nullptr;
			}
		}

		mVisited = true;

		mFReuseDataSet = mNReuseDataSet;

		if (this->mTrueJump && this->mTrueJump->CrossBlockShiftForwarding(mNReuseDataSet))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->CrossBlockShiftForwarding(mFReuseDataSet))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OffsetValueForwarding(const ValueNumberingDataSet& data)
{
	bool	changed = false;

	if (!mVisited)
	{
		mNNumDataSet = data;

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (mLoopHead)
		{
			mNNumDataSet.Reset();
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
				mNNumDataSet.Intersect(mNumDataSet);

			mNumEntered++;

			if (mNumEntered < mNumEntries)
			{
				mNumDataSet = mNNumDataSet;
				return false;
			}
		}

		mVisited = true;

		int carry = -1;

		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if (ins.mType == ASMIT_JSR)
			{
				mNNumDataSet.ResetCall(ins);
				carry = -1;
			}
			else if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE)
			{
				int reg = ins.mAddress;

				if (carry != -1 && i + 1 < mIns.Size() && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
					(mIns[i + 1].mType == ASMIT_ADC || mIns[i + 1].mType == ASMIT_SBC) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C) &&
					mNNumDataSet.mRegs[reg].SameBase(mNNumDataSet.mRegs[CPU_REG_A]))
				{
					ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
					if (mIns[i + 1].mType == ASMIT_ADC)
						mIns[i + 1].mAddress = (mIns[i + 1].mAddress + (mNNumDataSet.mRegs[reg].mOffset - mNNumDataSet.mRegs[CPU_REG_A].mOffset)) & 0xff;
					else
						mIns[i + 1].mAddress = (mIns[i + 1].mAddress - (mNNumDataSet.mRegs[reg].mOffset - mNNumDataSet.mRegs[CPU_REG_A].mOffset)) & 0xff;
					changed = true;
				}
				else
					mNNumDataSet.mRegs[CPU_REG_A] = mNNumDataSet.mRegs[reg];
			}
			else if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE)
			{
				int reg = ins.mAddress;

				if (mNNumDataSet.mRegs[reg].SameBase(mNNumDataSet.mRegs[CPU_REG_A]))
				{
					int d = mNNumDataSet.mRegs[CPU_REG_A].mOffset - mNNumDataSet.mRegs[reg].mOffset;
					if (d == 0)
					{
						ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else if (d == 1 && !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
					{
						ins.mType = ASMIT_INC;
						if (ins.mLive & LIVE_CPU_REG_A)
							mIns.Insert(i + 1, NativeCodeInstruction(ins.mIns, ASMIT_LDA, ins));
						changed = true;
					}
					else if (d == -1 && !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
					{
						ins.mType = ASMIT_DEC;
						if (ins.mLive & LIVE_CPU_REG_A)
							mIns.Insert(i + 1, NativeCodeInstruction(ins.mIns, ASMIT_LDA, ins));
						changed = true;
					}
				}

				mNNumDataSet.mRegs[reg] = mNNumDataSet.mRegs[CPU_REG_A];
			}
			else if (ins.mType == ASMIT_ADC && ins.mMode == ASMIM_IMMEDIATE && carry != -1)
			{
				mNNumDataSet.mRegs[CPU_REG_A].mOffset += ins.mAddress + carry;
				if (!(ins.mLive & LIVE_CPU_REG_C))
				{
					int k = mNNumDataSet.Find(mNNumDataSet.mRegs[CPU_REG_A]);
					if (k >= 0)
					{
						ins.mType = ASMIT_LDA;
						ins.mMode = ASMIM_ZERO_PAGE;
						ins.mAddress = k;
						changed = true;
					}
				}
			}
			else if (ins.mType == ASMIT_SBC && ins.mMode == ASMIM_IMMEDIATE && carry != -1)
			{
				mNNumDataSet.mRegs[CPU_REG_A].mOffset -= ins.mAddress + 1 - carry;
				if (!(ins.mLive & LIVE_CPU_REG_C))
				{
					int k = mNNumDataSet.Find(mNNumDataSet.mRegs[CPU_REG_A]);
					if (k >= 0)
					{
						ins.mType = ASMIT_LDA;
						ins.mMode = ASMIM_ZERO_PAGE;
						ins.mAddress = k;
						changed = true;
					}
				}
			}
			else if (ins.ChangesAccu())
				mNNumDataSet.mRegs[CPU_REG_A].Reset();
			else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
				mNNumDataSet.mRegs[ins.mAddress].Reset();
			
			if (ins.mType == ASMIT_CLC)
				carry = 0;
			else if (ins.mType == ASMIT_SEC)
				carry = 1;
			else if (ins.ChangesCarry())
				carry = -1;
		}

		mFNumDataSet = mNNumDataSet;

		if (this->mTrueJump && this->mTrueJump->OffsetValueForwarding(mNNumDataSet))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->OffsetValueForwarding(mFNumDataSet))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::CheckLoopIndexXRegisters(NativeCodeBasicBlock* head, int xreg)
{
	for (int i = mIns.Size() - 1; i >= 0; i--)
	{
		if ((mIns[i].mType == ASMIT_LDX || mIns[i].mType == ASMIT_STX) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == xreg)
			return true;
		else if (mIns[i].ChangesXReg() || mIns[i].ChangesZeroPage(xreg))
			return false;
	}

	if (this == head)
		return true;

	if (mLoopHead)
		return false;

	for (int i = 0; i < mEntryBlocks.Size(); i++)
	{
		if (!mEntryBlocks[i]->CheckLoopIndexXRegisters(head, xreg))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::AbsoluteLocalRegisterValueReuse(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		int ains = -1, xins = -1, yins = -1;
		
		mIns.Reserve(mIns.Size() + 10);
		for (int i = 0; i < mIns.Size(); i++)
		{
			NativeCodeInstruction& ins(mIns[i]);

			if ((ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) && i + 1 < mIns.Size() && mIns[i + 1].mType == ins.mType && mIns[i + 1].SameEffectiveAddress(ins))
			{
				if (xins >= 0 && ins.SameEffectiveAddress(mIns[xins]) && !(ins.mLive & LIVE_CPU_REG_X))
				{
					AsmInsType	itype = ins.mType == ASMIT_INC ? ASMIT_INX : ASMIT_DEX;
					ins.mType = ASMIT_STX;
					mIns.Remove(i + 1, 1);
					mIns.Insert(i, NativeCodeInstruction(ins.mIns, itype));
					mIns.Insert(i, NativeCodeInstruction(ins.mIns, itype));
					for (int j = 0; j < i; j++)
						mIns[j].mLive |= LIVE_CPU_REG_X;
					changed = true;
				}
			}

			if (ains >= 0 && mIns[ains].MayBeChangedOnAddress(ins)) ains = -1;
			if (xins >= 0 && mIns[xins].MayBeChangedOnAddress(ins)) xins = -1;
			if (yins >= 0 && mIns[yins].MayBeChangedOnAddress(ins)) yins = -1;

			if (ins.ChangesAccu())
			{
				ains = -1;
			}

			if (ins.ChangesXReg())
			{
				xins = -1;
				if (ains >= 0 && mIns[ains].RequiresXReg()) ains = -1;
				if (yins >= 0 && mIns[yins].RequiresXReg()) yins = -1;
			}

			if (ins.ChangesYReg())
			{
				yins = -1;
				if (ains >= 0 && mIns[ains].RequiresYReg()) ains = -1;
				if (xins >= 0 && mIns[xins].RequiresYReg()) xins = -1;
			}

			if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA)
				ains = i;
			else if (ins.mType == ASMIT_LDX || ins.mType == ASMIT_STX)
				xins = i;
			else if (ins.mType == ASMIT_LDY || ins.mType == ASMIT_STY)
				yins = i;
		}

		if (mTrueJump && mTrueJump->AbsoluteLocalRegisterValueReuse())
			changed = true;
		if (mFalseJump && mFalseJump->AbsoluteLocalRegisterValueReuse())
			changed = true;
	}

	return changed;
}


bool NativeCodeBasicBlock::CheckLoopIndexYRegisters(NativeCodeBasicBlock* head, int yreg)
{
	for (int i = mIns.Size() - 1; i >= 0; i--)
	{
		if ((mIns[i].mType == ASMIT_LDY || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg)
			return true;
		else if (mIns[i].ChangesYReg() || mIns[i].ChangesZeroPage(yreg))
			return false;
	}

	if (this == head)
		return true;

	if (mLoopHead)
		return false;

	for (int i = 0; i < mEntryBlocks.Size(); i++)
	{
		if (!mEntryBlocks[i]->CheckLoopIndexYRegisters(head, yreg))
			return false;
	}

	return true;
}

bool NativeCodeBasicBlock::ReduceIndexXYZeroShuffle(NativeCodeBasicBlock* from, int xreg, int yreg)
{
	bool	changed = false;

	if (!mVisited)
	{
		if (mLoopHead)
		{
			if (xreg >= 0)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					if (mEntryBlocks[i] != from && !mEntryBlocks[i]->CheckLoopIndexXRegisters(this, xreg))
					{
						xreg = -1;
						break;
					}
				}
			}
			if (yreg >= 0)
			{
				for (int i = 0; i < mEntryBlocks.Size(); i++)
				{
					if (mEntryBlocks[i] != from && !mEntryBlocks[i]->CheckLoopIndexYRegisters(this, yreg))
					{
						yreg = -1;
						break;
					}
				}
			}
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
			{
				if (xreg != mXReg)
					xreg = -1;
				if (yreg != mYReg)
					yreg = -1;
			}

			mXReg = xreg; 
			mYReg = yreg;

			mNumEntered++;

			if (mNumEntered < mNumEntries)
				return false;
		}

		mVisited = true;

		if (yreg >= 0)
		{
			int ix = 0, iy = 0;
			while (ix < mIns.Size() && !mIns[ix].ReferencesXReg())
				ix++;
			while (iy < mIns.Size() && !mIns[iy].ChangesYReg() && mIns[iy].mMode != ASMIM_INDIRECT_Y && mIns[iy].mType != ASMIT_STY)
				iy++;

			int ex = ix;
			while (ex < mIns.Size() && (mIns[ex].mLive & LIVE_CPU_REG_X))
				ex++;

			if (ix < mIns.Size() && iy == mIns.Size() && mIns[ix].mType == ASMIT_LDX && mIns[ix].mMode == ASMIM_ZERO_PAGE && mIns[ix].mAddress == yreg && 
				(ex < mIns.Size() || !mExitRequiredRegs[CPU_REG_X]) && (!ChangesXReg(ix + 1, ex) || !ReferencesYReg(ix + 1)))
			{
				for (int i = 0; i < ix; i++)
					mIns[i].mLive |= LIVE_CPU_REG_Y;

				const InterInstruction* iins = nullptr;

				mIns[ix].mType = ASMIT_NOP; mIns[ix].mMode = ASMIM_IMPLIED;
				while (ix < mIns.Size() && (mIns[ix].mLive & LIVE_CPU_REG_X))
				{
					ix++;
					mIns[ix].ReplaceXRegWithYReg();
					changed = true;
				}
			}
			else if (ix < mIns.Size() && mIns[ix].mType == ASMIT_LDX && mIns[ix].mMode == ASMIM_ZERO_PAGE && mIns[ix].mAddress == yreg && ((iy > ix) || mIns[iy].mType == ASMIT_LDY))
			{
				for (int i = 0; i < iy; i++)
				{
					if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
					{
						mIns[i].mMode = ASMIM_ABSOLUTE_X;
						changed = true;
					}
				}
				if (changed)
				{
					mIns.Insert(0, NativeCodeInstruction(mIns[ix].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, yreg));
					mIns.Remove(ix + 1);
				}
			}
		}

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (i + 1 < mIns.Size() &&
				mIns[i].mType == ASMIT_LDX && xreg >= 0 && 
				HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode) && 
				!(mIns[i].mLive & LIVE_CPU_REG_Y) &&
				mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && 
				HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_Y) &&
				!(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
			{
				int j = i + 2;
				while (j < mIns.Size() && !mIns[j].ReferencesXReg())
					j++;
				if (j < mIns.Size() && mIns[j].mType == ASMIT_LDX && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == xreg)
				{
					mIns[i].mType = ASMIT_LDY;
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
					changed = true;
				}
			}

			if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE)
				xreg = mIns[i].mAddress;
			else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE)
				yreg = mIns[i].mAddress;
			else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && xreg == -1)
			{
				xreg = mIns[i].mAddress;
				if (yreg == mIns[i].mAddress)
					yreg = -1;
			}
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && yreg == -1)
			{
				yreg = mIns[i].mAddress;
				if (xreg == mIns[i].mAddress)
					xreg = -1;
			}
			else if (xreg >=0 && xreg == yreg && mIns[i].mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
				mIns[i].mMode = ASMIM_ABSOLUTE_X;
			else
			{
				if (mIns[i].ChangesXReg())
					xreg = -1;
				if (mIns[i].ChangesYReg())
					yreg = -1;
				if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
					xreg = -1;
				if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
					yreg = -1;
			}
		}

		if (mTrueJump && mTrueJump->ReduceIndexXYZeroShuffle(this, xreg, yreg))
			changed = true;
		if (mFalseJump && mFalseJump->ReduceIndexXYZeroShuffle(this, xreg, yreg))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::IndexXYValueForwarding(int xreg, int xoffset, int xvalue, int yreg, int yoffset, int yvalue)
{
	bool	changed = false;

	if (!mVisited)
	{
		if (mLoopHead)
		{
			xreg = -1;
			yreg = -1;
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
			{
				if (xreg != mXReg || xoffset != mXOffset || xvalue != mXValue)
					xreg = -1;
				if (yreg != mYReg || yoffset != mYOffset || yvalue != mYValue)
					yreg = -1;
			}

			mXReg = xreg; mXOffset = xoffset; mXValue = xvalue;
			mYReg = yreg; mYOffset = yoffset; mYValue = yvalue;
			
			mNumEntered++;

			if (mNumEntered < mNumEntries)
				return false;
		}

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_INY)
				yoffset = (yoffset + 1) & 255;
			else if (mIns[i].mType == ASMIT_DEY)
				yoffset = (yoffset - 1) & 255;
			else if (mIns[i].mType == ASMIT_INX)
				xoffset = (xoffset + 1) & 255;
			else if (mIns[i].mType == ASMIT_DEX)
				xoffset = (xoffset - 1) & 255;
			else if (mIns[i].mType == ASMIT_LDX)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					if (mIns[i].mAddress == xreg)
					{
						if (xoffset == 0)
						{
							if (!(mIns[i].mLive & LIVE_CPU_REG_Z))
							{
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								changed = true;
							}
							else if (!(mIns[i].mLive & LIVE_CPU_REG_A))
							{
								mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;
								changed = true;
							}
						}
						else if (xoffset <= 3)
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
							for (int j = 0; j < xoffset; j++)
								mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
							changed = true;
						}
						else if (xoffset >= 253)
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
							for (int j = xoffset; j < 256; j++)
								mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
							changed = true;
						}
						else
							xoffset = 0;
					}
					else if (i + 1 < mIns.Size() && mIns[i].mAddress == yreg && yoffset == 0 &&
						mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
					{
						mIns[i] = NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDA, mIns[i + 1]);
						mIns[i].mMode = ASMIM_ABSOLUTE_Y;
						mIns[i + 1].mType = ASMIT_TAY; mIns[i + 1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
					else
					{
						xreg = mIns[i].mAddress;
						xoffset = 0;
						xvalue = GlobalValueNumber++;
					}
				}
				else
					xreg = -1;
			}
			else if (mIns[i].mType == ASMIT_LDY)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					if (mIns[i].mAddress == yreg)
					{
						if (yoffset == 0)
						{
							if (!(mIns[i].mLive & LIVE_CPU_REG_Z))
							{
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
								changed = true;
							}
							else if (!(mIns[i].mLive & LIVE_CPU_REG_A))
							{
								mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
								changed = true;
							}
						}
						else if (yoffset <= 3)
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
							for (int j = 0; j < yoffset; j++)
								mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
							changed = true;
						}
						else if (yoffset >= 253)
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
							for (int j = yoffset; j < 256; j++)
								mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
							changed = true;
						}
						else
							yoffset = 0;
					}
					else
					{
						yreg = mIns[i].mAddress;
						yoffset = 0;
						yvalue = GlobalValueNumber++;
					}
				}
				else
					yreg = -1;
			}
			else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && yreg == -1)
			{
				if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
					xreg = -1;
				yreg = mIns[i].mAddress;
				yoffset = 0;
				yvalue = GlobalValueNumber++;
			}
			else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && xreg == -1)
			{
				if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
					yreg = -1;
				xreg = mIns[i].mAddress;
				xoffset = 0;
				xvalue = GlobalValueNumber++;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
			{
				if (mIns[i + 1].mAddress == yreg)
				{
					mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mAddress = (mIns[i + 2].mAddress - yoffset) & 255;
					changed = true;
				}
				else if (i + 3 < mIns.Size() && mIns[i + 3].mType == ASMIT_TAY)
				{
					yreg = mIns[i + 1].mAddress;
					yoffset = mIns[i + 2].mAddress;
					yvalue = GlobalValueNumber++;
					i += 3;
				}
				else if (mIns[i + 1].mAddress == xreg)
				{
					mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mAddress = (mIns[i + 2].mAddress - xoffset) & 255;
					changed = true;
				}
				else if (i + 3 < mIns.Size() && mIns[i + 3].mType == ASMIT_TAX)
				{
					xreg = mIns[i + 1].mAddress;
					xoffset = mIns[i + 2].mAddress;
					xvalue = GlobalValueNumber++;
					i += 3;
				}
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_ADC, mIns[i].mMode) &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE)
			{
				if (yreg == mIns[i + 2].mAddress && yoffset == 0)
				{
					mIns[i + 2].CopyMode(mIns[i]);
					mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
				}
				else if (xreg == mIns[i + 2].mAddress && xoffset == 0)
				{
					mIns[i + 2].CopyMode(mIns[i]);
					mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED;
				}
			}
			else
			{
				if (mIns[i].ChangesXReg())
					xreg = -1;
				if (mIns[i].ChangesYReg())
					yreg = -1;
				if (xreg >= 0 && mIns[i].ChangesZeroPage(xreg))
					xreg = -1;
				if (yreg >= 0 && mIns[i].ChangesZeroPage(yreg))
					yreg = -1;
			}
		}

		mVisited = true;

		if (this->mTrueJump && this->mTrueJump->IndexXYValueForwarding(xreg, xoffset, xvalue, yreg, yoffset, yvalue))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->IndexXYValueForwarding(xreg, xoffset, xvalue, yreg, yoffset, yvalue))
			changed = true;
	}

	return changed;
}



bool NativeCodeBasicBlock::BitFieldForwarding(const NativeRegisterDataSet& data)
{
	bool	changed = false;

	if (!mVisited)
	{
		mNDataSet = data;

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (mLoopHead)
		{
			mNDataSet.ResetMask();
		}
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
				mNDataSet.IntersectMask(mDataSet);

			mNumEntered++;

			if (mNumEntered < mNumEntries)
			{
				mDataSet = mNDataSet;
				return false;
			}
		}

		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			AsmInsType	carryop = ASMIT_NOP;

#if 1
			if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
				mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress &&
				(mNDataSet[CPU_REG_A].mMask & mIns[i + 2].mAddress) == mIns[i + 2].mAddress &&
				(mNDataSet[CPU_REG_A].mValue & mIns[i + 2].mAddress) == 0)
			{

				mIns[i + 1].mType = ASMIT_EOR;
				mIns[i + 2].mAddress = mIns[i + 2].mAddress ^ 0xff;
				mIns[i + 3].mType = ASMIT_EOR;
				mIns[i + 3].mAddress = mIns[i + 1].mAddress;
				changed = true;
			}
			if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_EOR && 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_EOR && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress)
			{
				int	z0 = mNDataSet[mIns[i + 0].mAddress].mMask & ~mNDataSet[mIns[i + 0].mAddress].mValue;
				if (!((~z0 & ~mIns[i + 2].mAddress) & 0xff))
				{
					mIns[i + 3].CopyMode(mIns[i + 0]);
					mIns[i + 3].mType = ASMIT_ORA;
					mIns[i + 0].CopyMode(mIns[i + 1]);
					mIns[i + 2].mAddress = ~mIns[i + 2].mAddress & 0xff;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
			if (i + 4 < 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_CLC &&
				mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
				!(mIns[i + 4].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))
				)
			{
				uint8	zeroa = mNDataSet[CPU_REG_A].mMask & ~mNDataSet[CPU_REG_A].mValue;
				uint8	zeroi = ~mIns[i + 2].mAddress & 255;

				if (zeroi == LowBinMask(zeroi) && (zeroa & zeroi) == zeroi)
				{
					mIns[i + 0] = mIns[i + 3];
					mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
					mIns[i + 1].mType = ASMIT_ADC;
					mIns[i + 1].mLive |= LIVE_CPU_REG_C;
					mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
					mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}

			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAX)
			{
				if (mIns[i + 1].mAddress == 1 && (mNDataSet[CPU_REG_X].mMask & 1))
				{
					if (mNDataSet[CPU_REG_X].mValue & 1)
					{
						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					}
					else
					{
						mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
					}

					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
				}
				else if (mIns[i + 1].mAddress == 2 && (mNDataSet[CPU_REG_X].mMask & 2))
				{
					if (mNDataSet[CPU_REG_X].mValue & 2)
					{
						mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					}
					else
					{
						mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
						mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
					}

					mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
				}
			}

			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAX)
			{
				if (mIns[i + 1].mAddress == 1 && (mNDataSet[CPU_REG_X].mMask & 1))
				{
					if (mNDataSet[CPU_REG_X].mValue & 1)
					{
						mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
					}
					else
					{
						mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
					}

					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
				}
			}

			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAY)
			{
				if (mIns[i + 1].mAddress == 1 && (mNDataSet[CPU_REG_Y].mMask & 1))
				{
					if (mNDataSet[CPU_REG_Y].mValue & 1)
					{
						mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
					}
					else
					{
						mIns[i + 0].mType = ASMIT_INY; 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_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
				}
			}
#endif
			if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
				mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1)
			{
				if (mNDataSet[CPU_REG_X].mMask & 1)
				{
					if (mNDataSet[CPU_REG_X].mValue & 1)
					{
						mIns[i + 1].mAddress = 0;
						changed = true;
					}
					else
					{
						mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
						mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}

			}

			bool	skip = false;
			if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 2].mType == ASMIT_EOR && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
			{
#if 0
				printf("EORANEOR %s, %d, %d : A:%02x:%02x Z:%02x:%02x I:%02x\n",
					mProc->mIdent->mString, mIndex, i,
					mNDataSet[CPU_REG_A].mMask, mNDataSet[CPU_REG_A].mValue,
					mNDataSet[mIns[i + 0].mAddress].mMask, mNDataSet[mIns[i + 0].mAddress].mValue & mNDataSet[mIns[i + 0].mAddress].mMask,
					mIns[i + 1].mAddress);

				if ((mIns[i + 1].mAddress ^ 0xff) == (mNDataSet[mIns[i + 0].mAddress].mMask & ~mNDataSet[mIns[i + 0].mAddress].mValue))
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mAddress ^= 0xff;
					mIns[i + 2].mType = ASMIT_ORA;
					changed = true;
				}
				else 
#endif
				if (mNDataSet[mIns[i + 0].mAddress].mMask == 0)
				{
					mNDataSet.SetMask(CPU_REG_A, mNDataSet[CPU_REG_A].mMask & mIns[i + 1].mAddress, mNDataSet[CPU_REG_A].mValue);
					mNDataSet.ResetMask(CPU_REG_Z);
					i += 2;
					skip = true;
				}
			}

			if (!skip)
			{
				if (mIns[i].BitFieldForwarding(mNDataSet, carryop))
					changed = true;
				if (carryop != ASMIT_NOP)
					mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
			}
		}

		if (mFalseJump)
		{
			mFDataSet = mNDataSet;

			if (mIns.Size() > 0)
			{
				const NativeCodeInstruction& lins(mIns[mIns.Size() - 1]);

				if (lins.ChangesAccuAndFlag())
				{
					switch (mBranch)
					{
					case ASMIT_BEQ:
						if (mNDataSet[CPU_REG_A].mMask == 0xff)
						{
							if (mNDataSet[CPU_REG_A].mValue != 0)
							{
								mTrueJump->RemEntryBlock(this);
								mTrueJump = mFalseJump;
								mFalseJump = nullptr;
							}
							else
							{
								mFalseJump->RemEntryBlock(this);
								mFalseJump = nullptr;
							}
							mBranch = ASMIT_JMP;
							changed = true;
						}
						else
						{
							mNDataSet.SetMask(CPU_REG_A, 0xff, 0x00);

							if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
							{
								mNDataSet.SetMask(lins.mAddress, 0xff, 0x00);
							}

							if (mFDataSet[CPU_REG_A].mMask == 0xfe)
							{
								mFDataSet.SetMask(CPU_REG_A, 0xff, 0x01);
							}
						}
						break;
					case ASMIT_BNE:
						if (mNDataSet[CPU_REG_A].mMask == 0xff)
						{
							if (mNDataSet[CPU_REG_A].mValue == 0)
							{
								mTrueJump->RemEntryBlock(this);
								mTrueJump = mFalseJump;
								mFalseJump = nullptr;
							}
							else
							{
								mFalseJump->RemEntryBlock(this);
								mFalseJump = nullptr;
							}
							mBranch = ASMIT_JMP;
							changed = true;
						}
						else
						{
							mFDataSet.SetMask(CPU_REG_A, 0xff, 0x00);

							if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
							{
								mFDataSet.SetMask(lins.mAddress, 0xff, 0x00);
							}

							if (mNDataSet[CPU_REG_A].mMask == 0xfe)
							{
								mNDataSet.SetMask(CPU_REG_A, 0xff, 0x01);
							}
						}
						break;
					case ASMIT_BPL:
						if (mNDataSet[CPU_REG_A].mMask & 0x80)
						{
							if (mNDataSet[CPU_REG_A].mValue & 0x80)
							{
								mTrueJump->RemEntryBlock(this);
								mTrueJump = mFalseJump;
								mFalseJump = nullptr;
							}
							else
							{
								mFalseJump->RemEntryBlock(this);
								mFalseJump = nullptr;
							}
							mBranch = ASMIT_JMP;
							changed = true;
						}
						else
						{
							mNDataSet.SetMask(CPU_REG_A, mNDataSet[CPU_REG_A].mMask | 0x80, mNDataSet[CPU_REG_A].mValue & 0x7f);
							mFDataSet.SetMask(CPU_REG_A, mFDataSet[CPU_REG_A].mMask | 0x80, mFDataSet[CPU_REG_A].mValue | 0x80);

							if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
							{
								mNDataSet.SetMask(lins.mAddress, mNDataSet[lins.mAddress].mMask | 0x80, mNDataSet[lins.mAddress].mValue & 0x7f);
								mFDataSet.SetMask(lins.mAddress, mFDataSet[lins.mAddress].mMask | 0x80, mFDataSet[lins.mAddress].mValue | 0x80);
							}
						}
						break;
					case ASMIT_BMI:
						if (mNDataSet[CPU_REG_A].mMask & 0x80)
						{
							if (!(mNDataSet[CPU_REG_A].mValue & 0x80))
							{
								mTrueJump->RemEntryBlock(this);
								mTrueJump = mFalseJump;
								mFalseJump = nullptr;
							}
							else
							{
								mFalseJump->RemEntryBlock(this);
								mFalseJump = nullptr;
							}
							mBranch = ASMIT_JMP;
							changed = true;
						}
						else
						{
							mFDataSet.SetMask(CPU_REG_A, mNDataSet[CPU_REG_A].mMask | 0x80, mNDataSet[CPU_REG_A].mValue & 0x7f);
							mNDataSet.SetMask(CPU_REG_A, mFDataSet[CPU_REG_A].mMask | 0x80, mFDataSet[CPU_REG_A].mValue | 0x80);

							if (lins.mMode == ASMIM_ZERO_PAGE && lins.mType == ASMIT_LDA)
							{
								mFDataSet.SetMask(lins.mAddress, mNDataSet[lins.mAddress].mMask | 0x80, mNDataSet[lins.mAddress].mValue & 0x7f);
								mNDataSet.SetMask(lins.mAddress, mFDataSet[lins.mAddress].mMask | 0x80, mFDataSet[lins.mAddress].mValue | 0x80);
							}
						}
						break;
					}
				}
				else if (lins.mType == ASMIT_CMP && lins.mMode == ASMIM_IMMEDIATE)
				{
					switch (mBranch)
					{
						case ASMIT_BCS:
						{
							unsigned m = ~BinMask(lins.mAddress - 1) & 0xff;
							mFDataSet.SetMask(CPU_REG_A, mFDataSet[CPU_REG_A].mMask | m, mFDataSet[CPU_REG_A].mValue & ~m);
							m = ~BinMask(~lins.mAddress & 0xff) & 0xff;
							mNDataSet.SetMask(CPU_REG_A, mNDataSet[CPU_REG_A].mMask | m, mNDataSet[CPU_REG_A].mValue | m);
						}
							break;
						case ASMIT_BCC:
						{
							unsigned m = ~BinMask(lins.mAddress - 1) & 0xff;
							mNDataSet.SetMask(CPU_REG_A, mNDataSet[CPU_REG_A].mMask | m, mNDataSet[CPU_REG_A].mValue & ~m);
							m = ~BinMask(~lins.mAddress & 0xff) & 0xff;
							mFDataSet.SetMask(CPU_REG_A, mFDataSet[CPU_REG_A].mMask | m, mFDataSet[CPU_REG_A].mValue | m);
						}
							break;
					}
				}
			}
		}

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (this->mTrueJump && this->mTrueJump->BitFieldForwarding(mNDataSet))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->BitFieldForwarding(mFDataSet))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::GlobalValueForwarding(NativeCodeProcedure* proc, bool final)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mEntryBlocks.Size() == 0)
			mDataSet.Reset();
		else
		{
			if (this == mEntryBlocks[0]->mTrueJump)
				mDataSet = mEntryBlocks[0]->mNDataSet;
			else
				mDataSet = mEntryBlocks[0]->mFDataSet;

			for (int i = 1; i < mEntryBlocks.Size(); i++)
			{
				if (this == mEntryBlocks[i]->mTrueJump)
					mDataSet.Intersect(mEntryBlocks[i]->mNDataSet);
				else
					mDataSet.Intersect(mEntryBlocks[i]->mFDataSet);
			}
		}
			
		for (int i = 0; i < mIns.Size(); i++)
		{
			AsmInsType	carryop;
#if 1
			if (i + 1 < mIns.Size() &&
				mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i].SameEffectiveAddress(mIns[i + 1]) &&
				mDataSet[CPU_REG_A].mMode == NRDM_ABSOLUTE &&
				mDataSet[CPU_REG_A].mLinkerObject == mIns[i].mLinkerObject &&
				mDataSet[CPU_REG_A].mValue == mIns[i].mAddress)
			{
				mIns[i + 1].mType = ASMIT_STA;
				mIns[i + 0].mType = ASMIT_ADC; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 1;
				mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_CLC));
				changed = true;
			}
#endif
			if (mIns[i].ValueForwarding(mDataSet, carryop, true, final, proc->mFastCallBase))
				changed = true;
			if (carryop != ASMIT_NOP)
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
		}


		if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding(proc, final))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding(proc, final))
			changed = true;
	}

	return changed;
}


void NativeCodeBasicBlock::ResetModifiedDataSet(NativeRegisterDataSet& data)
{
	// Single block loop
	for (int i = 0; i < mIns.Size(); i++)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.ChangesAccu())
			data.Reset(CPU_REG_A);
		if (ins.ChangesXReg())
			data.Reset(CPU_REG_X);
		if (ins.ChangesYReg())
			data.Reset(CPU_REG_Y);

		if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
			data.ResetZeroPage(ins.mAddress);
		else if (ins.mMode == ASMIM_ABSOLUTE && ins.ChangesAddress())
			data.ResetAbsolute(ins.mLinkerObject, ins.mAddress);

		if (ins.mType == ASMIT_JSR)
		{
			data.ResetWorkRegs();

			if (!(ins.mFlags & NCIF_RUNTIME) && ins.mLinkerObject || (ins.mFlags & NCIF_FEXEC))
			{
				if (ins.mLinkerObject && ins.mLinkerObject->mProc)
				{
					for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++)
						data.ResetZeroPage(i);
				}
				else
				{
					for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
						data.ResetZeroPage(i);
				}

				for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
					data.ResetZeroPage(i);
			}
		}
	}
}

bool NativeCodeBasicBlock::ValueForwarding(NativeCodeProcedure* proc, const NativeRegisterDataSet& data, bool global, bool final)
{
	bool	changed = false;

	if (!mVisited)
	{
		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		mNDataSet = data;

		if (mLoopHead)
		{
#if 1
			if (mNumEntries == 2 && (mTrueJump == this || mFalseJump == this))
			{
				mNDataSet.Reset(CPU_REG_C);
				mNDataSet.Reset(CPU_REG_Z);

				if (final)
				{
					for (int i = 0; i < mIns.Size(); i++)
					{
						if ((mIns[i].mType == ASMIT_ASL || mIns[i].mType == ASMIT_LSR) && mIns[i].mMode == ASMIM_ZERO_PAGE && mNDataSet[mIns[i].mAddress].mMode == NRDM_IMMEDIATE && mNDataSet[mIns[i].mAddress].mValue == 0)
						{
							if (!ChangesZeroPage(mIns[i].mAddress, 0, i - 1) && !ChangesZeroPage(mIns[i].mAddress, i + 1))
							{
								mIns[i].mType = ASMIT_CLC; mIns[i].mMode = ASMIM_IMPLIED;
							}
						}
					}
				}

				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[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mIns[sz - 2].mAddress == mNDataSet[CPU_REG_Y].mValue ||
							mNDataSet[CPU_REG_Y].SameData(mNDataSet[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[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mIns[sz - 2].mAddress == mNDataSet[CPU_REG_X].mValue ||
							mNDataSet[CPU_REG_X].SameData(mNDataSet[mIns[sz - 2].mAddress]))
						{
							loopxa = mIns[sz - 2].mAddress;
							loopx = true;
						}
					}
				}

				ResetModifiedDataSet(mNDataSet);

				if (loopy)
				{
					mNDataSet.Set(CPU_REG_Y, NRDM_ZERO_PAGE, loopya);
				}
				if (loopx)
				{
					mNDataSet.Set(CPU_REG_X, NRDM_ZERO_PAGE, loopxa);
				}
			}
			else if (mNumEntries == 2 && global)
			{
				NativeCodeBasicBlock* lblock = nullptr;

				if (mTrueJump && mFalseJump)
				{
					if (mTrueJump->mTrueJump == this && mTrueJump->mFalseJump == mFalseJump ||
						mTrueJump->mFalseJump == this && mTrueJump->mTrueJump == mFalseJump)
					{
						lblock = mTrueJump;
					}
					else if (mFalseJump->mTrueJump == this && mFalseJump->mFalseJump == mTrueJump ||
						mFalseJump->mFalseJump == this && mFalseJump->mTrueJump == mTrueJump)
					{
						lblock = mFalseJump;
					}
				}

				if (lblock)
				{
					mNDataSet.Reset(CPU_REG_C);
					mNDataSet.Reset(CPU_REG_Z);
					ResetModifiedDataSet(mNDataSet);
					lblock->ResetModifiedDataSet(mNDataSet);
				}
#if 1
				else if (final)
				{
					ExpandingArray<NativeCodeBasicBlock*> lblocks;

					if (CollectSingleEntryGenericLoop(lblocks))
					{
						mNDataSet.Reset(CPU_REG_C);
						mNDataSet.Reset(CPU_REG_Z);
						for (int i = 0; i < lblocks.Size(); i++)
							lblocks[i]->ResetModifiedDataSet(mNDataSet);
					}
					else
						mNDataSet.Reset();
				}
#endif
				else
					mNDataSet.Reset();
			}
			else if (global && final)
			{
				ExpandingArray<NativeCodeBasicBlock*> lblocks;

				if (CollectSingleEntryGenericLoop(lblocks))
				{
					int k = 0;
					for (int i = 0; i < mEntryBlocks.Size(); i++)
						if (lblocks.Contains(mEntryBlocks[i]))
							k++;
					if (k + 1 == mEntryBlocks.Size())
					{
						mNDataSet.Reset(CPU_REG_C);
						mNDataSet.Reset(CPU_REG_Z);
						for (int i = 0; i < lblocks.Size(); i++)
							lblocks[i]->ResetModifiedDataSet(mNDataSet);
					}
					else
						mNDataSet.Reset();
				}
				else
					mNDataSet.Reset();
			}
			else
#endif
				mNDataSet.Reset();
		}
		else if (!global)
		{
			mNDataSet.Reset();
		}
#if 0
		else if (mNumEntries != 1)
		{
			ndata.Reset();
		}
#endif
		else if (mNumEntries > 0)
		{
			if (mNumEntered > 0)
				mNDataSet.Intersect(mDataSet);

			mNumEntered++;

			if (mNumEntered < mNumEntries)
			{
				mDataSet = mNDataSet;
				return false;
			}
		}

		mVisited = true;

		for (int i = 0; i < mIns.Size(); i++)
		{
			AsmInsType	carryop;

#if 1
			if (mIns[i].mMode == ASMIM_INDIRECT_Y && HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y) &&
				!(mIns[i].mType == ASMIT_CMP && (mIns[i].mLive & LIVE_CPU_REG_Y)) &&
				mNDataSet[CPU_REG_Y].mMode == NRDM_IMMEDIATE &&
				mNDataSet[mIns[i].mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && (mNDataSet[mIns[i].mAddress + 1].mFlags & NCIF_UPPER) &&
				mNDataSet[mIns[i].mAddress].mMode != NRDM_IMMEDIATE_ADDRESS)
			{
				int	reg = mIns[i].mAddress;
				mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
				mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
				mIns[i + 1].mLinkerObject = mNDataSet[reg + 1].mLinkerObject;
				mIns[i + 1].mAddress = (mNDataSet[reg + 1].mValue & 0xff00) + mNDataSet[CPU_REG_Y].mValue;
				mIns[i + 1].mFlags &= ~NCIF_LOWER;
				if (mIns[i + 1].mLive & LIVE_CPU_REG_Y)
				{
					mIns.Insert(i + 2, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mNDataSet[CPU_REG_Y].mValue));
					mIns.Insert(i + 3, NativeCodeInstruction(mIns[i].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
				}
				changed = true;
			}
#endif
			// Check load and commutative with current accu value
#if 1
			if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA &&
				mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet[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 1
			if (i + 1 < mIns.Size() && 
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
				mNDataSet[CPU_REG_A].mMode == NRDM_IMMEDIATE && mNDataSet[CPU_REG_A].mValue == mIns[i + 1].mAddress &&
				!(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[i + 1].CopyMode(mIns[i + 0]);
				mIns[i + 0].mType = ASMIT_NOP;	mIns[i + 0].mMode = ASMIM_IMPLIED;
				changed = true;
			}
#endif
#if 1
			if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
				mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
				mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
			{
				mIns[i + 0].mType = ASMIT_LSR;
				if (mNDataSet[CPU_REG_C].mValue)
					mIns[i + 1].mAddress ^= 0x80;
				changed = true;
			}
#endif

#if 1
			if (i + 1 < mIns.Size() && (mIns[i].mType == ASMIT_INC || mIns[i].mType == ASMIT_DEC) && mIns[i].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i].mAddress)
			{
				if (mIns[i + 1].mType == ASMIT_LDY && mNDataSet[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mNDataSet[CPU_REG_Y].mValue == mIns[i].mAddress)
				{
					mIns[i].mType = mIns[i].mType == ASMIT_INC ? ASMIT_INY : ASMIT_DEY; mIns[i].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_STY;
					changed = true;
				}
				else if (mIns[i + 1].mType == ASMIT_LDX && mNDataSet[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mNDataSet[CPU_REG_X].mValue == mIns[i].mAddress)
				{
					mIns[i].mType = mIns[i].mType == ASMIT_INC ? ASMIT_INX : ASMIT_DEX; mIns[i].mMode = ASMIM_IMPLIED;
					mIns[i + 1].mType = ASMIT_STX;
					changed = true;
				}
			}
#endif

#if 1
			if (final &&
				i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet[CPU_REG_Y].mMode == NRDM_ZERO_PAGE && mNDataSet[CPU_REG_Y].mValue == mIns[i + 1].mAddress)
			{
				mIns[i + 1].CopyMode(mIns[i]);
				mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
				changed = true;
			}
			if (final &&
				i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mNDataSet[CPU_REG_X].mValue == mIns[i + 1].mAddress)
			{
				mIns[i + 1].CopyMode(mIns[i]);
				mIns[i].mType = ASMIT_TXA; mIns[i].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[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet[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[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet[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[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet[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 0
			if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && 
				mNDataSet.mRegs[CPU_REG_X].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_X].mValue == mIns[i].mAddress &&
				mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_X))
			{
				mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
				changed = true;
			}
#endif
			if (mIns[i].ValueForwarding(mNDataSet, carryop, !global, final, proc->mFastCallBase))
				changed = true;
			if (carryop != ASMIT_NOP)
				mIns.Insert(i + 1, NativeCodeInstruction(mIns[i].mIns, carryop));
		}

#if 1
		if (global)
		{
			NativeCodeBasicBlock* fork = this;
			if (!mFalseJump && mTrueJump && mTrueJump->mIns.Size() == 0)
				fork = mTrueJump;

			if (fork->mFalseJump)
			{
				mFDataSet = mNDataSet;

				switch (fork->mBranch)
				{
				case ASMIT_BCS:
					if (mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mNumEntries--;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						if (!mNDataSet[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;
					}
					else if (mIns.Size() > 0)
					{
						int n = mIns.Size() - 1;
						while (n >= 0 && mIns[n].mType == ASMIT_STA)
							n--;
						if (n > 0 && mIns[n - 1].mType == ASMIT_CLC && mIns[n].mType == ASMIT_ADC && mIns[n].mMode == ASMIM_IMMEDIATE && mIns[n].mAddress == 1)
						{
							mDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
							mDataSet.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
#if 1
							if (mFalseJump->mIns.Size() == 0 && mFalseJump->mFalseJump)
							{
								if (mFalseJump->mIns.Size() == 0)
								{
									if (mFalseJump->mBranch == ASMIT_BEQ)
									{
										mFalseJump->mNumEntries--;
										mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
										mFalseJump = mFalseJump->mFalseJump;
										mFalseJump->mNumEntries++;
										mFalseJump->mEntryBlocks.Push(this);
										changed = true;
									}
									else if (mFalseJump->mBranch == ASMIT_BNE)
									{
										mFalseJump->mNumEntries--;
										mFalseJump->mEntryBlocks.Remove(mFalseJump->mEntryBlocks.IndexOf(this));
										mFalseJump = mFalseJump->mTrueJump;
										mFalseJump->mNumEntries++;
										mFalseJump->mEntryBlocks.Push(this);
										changed = true;
									}
								}
							}
#endif
						}
						else if (final)
						{
							if (fork->mTrueJump->mIns.Size() > 0 && fork->mTrueJump->mIns[0].IsShift())
								mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
							if (fork->mFalseJump->mIns.Size() > 0 && fork->mFalseJump->mIns[0].IsShift())
								mFDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
						}
					}
					break;
				case ASMIT_BCC:
					if (mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mNumEntries--;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						if (mNDataSet[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;
					}
					else if (mIns.Size() > 0)
					{
						int n = mIns.Size() - 1;
						while (n >= 0 && mIns[n].mType == ASMIT_STA)
							n--;
						if (n > 0 && mIns[n - 1].mType == ASMIT_CLC && mIns[n].mType == ASMIT_ADC && mIns[n].mMode == ASMIM_IMMEDIATE && mIns[n].mAddress == 1)
						{
							mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
							mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);

							if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump)
							{
								if (mTrueJump->mBranch == ASMIT_BEQ)
								{
									mTrueJump->mNumEntries--;
									mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
									mTrueJump = mTrueJump->mFalseJump;
									mTrueJump->mNumEntries++;
									mTrueJump->mEntryBlocks.Push(this);
									changed = true;
								}
								else if (mTrueJump->mBranch == ASMIT_BNE)
								{
									mTrueJump->mNumEntries--;
									mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
									mTrueJump = mTrueJump->mTrueJump;
									mTrueJump->mNumEntries++;
									mTrueJump->mEntryBlocks.Push(this);
									changed = true;
								}
							}
						}
						else if (final)
						{
							if (fork->mTrueJump->mIns.Size() > 0 && fork->mTrueJump->mIns[0].IsShift())
								mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
							if (fork->mFalseJump->mIns.Size() > 0 && fork->mFalseJump->mIns[0].IsShift())
								mFDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
						}
					}
					break;
				case ASMIT_BNE:
					if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mNumEntries--;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						if (!mNDataSet[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.Set(CPU_REG_Y, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
							}
						}
						else if (lins.mType == ASMIT_LDX)
						{
							mFDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
							}
						}
						else if (lins.mType == ASMIT_LDA)
						{
							mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);

							}
						}
						else if (lins.mType == ASMIT_CPY)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mFDataSet.Set(CPU_REG_Y, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mFDataSet[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
									mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mFDataSet[CPU_REG_Y].mValue);
								else
									mFDataSet.Set(CPU_REG_Y, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_CPX)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mFDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mFDataSet[CPU_REG_X].mMode == NRDM_IMMEDIATE)
									mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mFDataSet[CPU_REG_X].mValue);
								else
									mFDataSet.Set(CPU_REG_X, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_CMP)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mFDataSet[CPU_REG_A].mMode == NRDM_IMMEDIATE)
									mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mFDataSet[CPU_REG_A].mValue);
								else
									mFDataSet.Set(CPU_REG_A, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_ORA || lins.mType == ASMIT_AND || lins.mType == ASMIT_EOR || lins.mType == ASMIT_ADC || lins.mType == ASMIT_SBC)
						{
							mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
						}
						else if (lins.mType == ASMIT_TXA || lins.mType == ASMIT_TAX)
						{
							mFDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
							mFDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);
						}
						else if (final && (lins.mType == ASMIT_INX || lins.mType == ASMIT_DEX))
						{
							mFDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);
						}
						else if (final && (lins.mType == ASMIT_INY || lins.mType == ASMIT_DEY))
						{
							mFDataSet.Set(CPU_REG_Y, NRDM_IMMEDIATE, 0);
						}
						else if ((lins.mType == ASMIT_INC || lins.mType == ASMIT_DEC) && lins.mMode == ASMIM_ZERO_PAGE)
						{
							mFDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
						}
					}
					break;
				case ASMIT_BEQ:
					if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mNumEntries--;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						if (mNDataSet[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.Set(CPU_REG_Y, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
							}
						}
						else if (lins.mType == ASMIT_LDX)
						{
							mNDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
							}
						}
						else if (lins.mType == ASMIT_LDA)
						{
							mNDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);

							if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
							}
						}
						else if (lins.mType == ASMIT_CPY)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mNDataSet.Set(CPU_REG_Y, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mNDataSet[CPU_REG_Y].mMode == NRDM_IMMEDIATE)
									mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mNDataSet[CPU_REG_Y].mValue);
								else
									mNDataSet.Set(CPU_REG_Y, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_CPX)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mNDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mNDataSet[CPU_REG_X].mMode == NRDM_IMMEDIATE)
									mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mNDataSet[CPU_REG_X].mValue);
								else
									mNDataSet.Set(CPU_REG_X, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_CMP)
						{
							if (lins.mMode == ASMIM_IMMEDIATE)
								mNDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, lins.mAddress);
							else if (lins.mMode == ASMIM_ZERO_PAGE)
							{
								if (mNDataSet[CPU_REG_A].mMode == NRDM_IMMEDIATE)
									mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, mNDataSet[CPU_REG_A].mValue);
								else
									mNDataSet.Set(CPU_REG_A, NRDM_ZERO_PAGE, lins.mAddress);
							}
						}
						else if (lins.mType == ASMIT_ORA || lins.mType == ASMIT_AND || lins.mType == ASMIT_EOR || lins.mType == ASMIT_ADC || lins.mType == ASMIT_SBC)
						{
							mNDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
						}
						else if (lins.mType == ASMIT_TXA || lins.mType == ASMIT_TAX)
						{
							mNDataSet.Set(CPU_REG_A, NRDM_IMMEDIATE, 0);
							mNDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);
						}
						else if (final && (lins.mType == ASMIT_INX || lins.mType == ASMIT_DEX))
						{
							mNDataSet.Set(CPU_REG_X, NRDM_IMMEDIATE, 0);
						}
						else if (final && (lins.mType == ASMIT_INY || lins.mType == ASMIT_DEY))
						{
							mNDataSet.Set(CPU_REG_Y, NRDM_IMMEDIATE, 0);
						}
						else if ((lins.mType == ASMIT_INC || lins.mType == ASMIT_DEC) && lins.mMode == ASMIM_ZERO_PAGE)
						{
							mNDataSet.Set(lins.mAddress, NRDM_IMMEDIATE, 0);
						}
					}
					break;
				case ASMIT_BPL:
					if (mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mNumEntries--;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						if ((mNDataSet[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[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
					{
						mBranch = ASMIT_JMP;
						mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
						mTrueJump->mNumEntries--;
						if (!(mNDataSet[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[CPU_REG_Y].SameData(mNDataSet[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[CPU_REG_Y].SameData(mFDataSet[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[CPU_REG_A].mMode == NRDM_IMMEDIATE)
				{
					NativeCodeBasicBlock* target;

					if (mNDataSet[CPU_REG_A].mValue == mTrueJump->mIns[0].mAddress)
					{
						if (mTrueJump->mBranch == ASMIT_BEQ)
							target = mTrueJump->mTrueJump;
						else
							target = mTrueJump->mFalseJump;
					}
					else
					{
						if (mTrueJump->mBranch == ASMIT_BNE)
							target = mTrueJump->mTrueJump;
						else
							target = mTrueJump->mFalseJump;
					}

					if (target != mTrueJump)
					{
						mIns.Push(mTrueJump->mIns[0]);
						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mNumEntries--;
						target->mEntryBlocks.Push(this);
						target->mNumEntries++;
						mTrueJump = target;
						changed = true;
					}
				}
			}
			else if (mTrueJump->mIns[0].mType == ASMIT_ORA && mTrueJump->mIns[0].mAddress == 0)
			{
				if (mNDataSet[CPU_REG_A].mMode == NRDM_IMMEDIATE)
				{
					NativeCodeBasicBlock* target;

					if (mNDataSet[CPU_REG_A].mValue == 0)
					{
						if (mTrueJump->mBranch == ASMIT_BEQ)
							target = mTrueJump->mTrueJump;
						else
							target = mTrueJump->mFalseJump;
					}
					else
					{
						if (mTrueJump->mBranch == ASMIT_BNE)
							target = mTrueJump->mTrueJump;
						else
							target = mTrueJump->mFalseJump;
					}

					if (target != mTrueJump)
					{
						mTrueJump->mEntryBlocks.RemoveAll(this);
						mTrueJump->mNumEntries--;
						target->mEntryBlocks.Push(this);
						target->mNumEntries++;
						mTrueJump = target;
						changed = true;
					}
				}
			}
		}
#endif
		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		if (this->mTrueJump && this->mTrueJump->ValueForwarding(proc, mNDataSet, global, final))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->ValueForwarding(proc, mFDataSet, global, final))
			changed = true;



	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, bool full)
{
	NativeCodeBasicBlock* lblock = proc->AllocateBlock();
	NativeCodeBasicBlock* eblock = proc->AllocateBlock();

	NativeCodeBasicBlock* xblock = mTrueJump == this ? mFalseJump : mTrueJump;

	eblock->mBranch = ASMIT_JMP;
	eblock->mTrueJump = mFalseJump;
	eblock->mFalseJump = nullptr;

	lblock->mBranch = mBranch;
	lblock->mTrueJump = lblock;
	lblock->mFalseJump = eblock;

	lblock->mEntryRequiredRegs = mEntryRequiredRegs;
	lblock->mExitRequiredRegs = mExitRequiredRegs;

	eblock->mEntryRequiredRegs = xblock->mEntryRequiredRegs;
	eblock->mExitRequiredRegs = xblock->mEntryRequiredRegs;

	mExitRequiredRegs = mEntryRequiredRegs;

	for (int i = 0; i < mIns.Size(); i++)
		lblock->mIns.Push(mIns[i]);

	mIns.SetSize(0);

	mBranch = ASMIT_JMP;
	mTrueJump = lblock;
	mFalseJump = nullptr;

	mNumEntries -= mEntryBlocks.RemoveAll(this);

	lblock->mEntryBlocks.Push(this);
	lblock->mEntryBlocks.Push(lblock);
	lblock->mNumEntries = 2;

	eblock->mEntryBlocks.Push(this);
	eblock->mNumEntries = 1;

	return lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
}

bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mEntryBlocks.Size() > 1)
		{
			NativeCodeBasicBlock* pblock = nullptr;
			ExpandingArray<NativeCodeBasicBlock*>	 lblocks, pblocks, eblocks;

			bool	addprefix = false;
			for(int i=0; i<mEntryBlocks.Size(); i++)
			{
				NativeCodeBasicBlock* b = mEntryBlocks[i];

				if (b == this || b->IsDominatedBy(this))
					lblocks.Push(b);
				else
				{
					if (b->mFalseJump)
						addprefix = true;
					pblocks.Push(b);
				}
			}

			if (pblocks.Size() < mEntryBlocks.Size())
			{
				if (pblocks.Size() > 1 || addprefix)
				{
					pblock = mProc->AllocateBlock();
					pblock->mEntryRequiredRegs = mEntryRequiredRegs;
					pblock->mExitRequiredRegs = mEntryRequiredRegs;
					pblock->Close(pblocks[0]->mBranchIns, this, nullptr, ASMIT_JMP);
					AddEntryBlock(pblock);
					for (int i = 0; i < pblocks.Size(); i++)
					{
						NativeCodeBasicBlock* b = pblocks[i];
						if (this == b->mTrueJump)
						{
							b->mTrueJump = pblock;
							RemEntryBlock(b);
							pblock->AddEntryBlock(b);
						}
						if (this == b->mFalseJump)
						{
							b->mFalseJump = pblock;
							RemEntryBlock(b);
							pblock->AddEntryBlock(b);
						}
					}
				}
				else if (pblocks.Size() == 1)
					pblock = pblocks[0];
			}

			if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
			{
				proc->ResetPatched();
				mPatched = true;

				if (!lblocks.Contains(this))
					lblocks.Push(this);

				for (int i = 0; i < lblocks.Size(); i++)
					lblocks[i]->mPatched = true;
				pblock->mPatched = true;

				int i = 0;
				while (i < lblocks.Size())
				{
					NativeCodeBasicBlock* block = lblocks[i];
					for(int j=0; j<block->mEntryBlocks.Size(); j++)
					{
						NativeCodeBasicBlock* cblock = block->mEntryBlocks[j];
						if (!cblock->mPatched)
						{
							cblock->mPatched = true;
							lblocks.Push(cblock);
						}
					}
					i++;
				}

				i = 0;
				while (i < lblocks.Size())
				{
					NativeCodeBasicBlock* b = lblocks[i];
					// !FIXME should be &&
					if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
					{
						eblocks.Push(b);
					}
					i++;
				}

				if (eblocks.Size() > 0)
				{
					bool	aimm = false, ximm = false, yimm = false;
					NativeCodeInstruction	ains, xins, yins;

					int inserta = -1, insertx = -1, inserty = -1;
					if (!pblock->mExitRequiredRegs[CPU_REG_A])
					{
						inserta = pblock->mIns.Size();
					}
					else
					{
						int i = pblock->mIns.Size();
						while (i > 0 && (pblock->mIns[i - 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
						{
							if (pblock->mIns[i - 1].IsPure())
								i--;
							else
								i = -1;
						}
						if (i > 0)
							inserta = i;
						else if (i == 0 && !pblock->mEntryRequiredRegs[CPU_REG_A])
							inserta = 0;
					}
					if (!pblock->mExitRequiredRegs[CPU_REG_X])
					{
						insertx = pblock->mIns.Size();
					}
					if (!pblock->mExitRequiredRegs[CPU_REG_Y])
					{
						inserty = pblock->mIns.Size();
					}

					if (inserta >= 0 || insertx >= 0 || inserty >= 0)
					{
						for (int i = 0; i < mIns.Size(); i++)
						{
							if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS))
							{
								aimm = true;
								ains = mIns[i];
							}
							else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !this->ChangesZeroPage(mIns[i].mAddress))
							{
								int j = 0;
								while (j < lblocks.Size() && !lblocks[j]->ChangesZeroPage(mIns[i].mAddress))
									j++;
								if (j == lblocks.Size())
								{
									aimm = true;
									ains = mIns[i];
								}
								else
									aimm = false;
							}
							else if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS))
							{
								ximm = true;
								xins = mIns[i];
							}
							else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !this->ChangesZeroPage(mIns[i].mAddress))
							{
								int j = 0;
								while (j < lblocks.Size() && !lblocks[j]->ChangesZeroPage(mIns[i].mAddress))
									j++;
								if (j == lblocks.Size())
								{
									ximm = true;
									xins = mIns[i];
								}
								else
									ximm = false;
							}
							else if (mIns[i].mType == ASMIT_LDY && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS))
							{
								yimm = true;
								yins = mIns[i];
							}
							else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !this->ChangesZeroPage(mIns[i].mAddress))
							{
								int j = 0;
								while (j < lblocks.Size() && !lblocks[j]->ChangesZeroPage(mIns[i].mAddress))
									j++;
								if (j == lblocks.Size())
								{
									yimm = true;
									yins = mIns[i];
								}
								else
									yimm = false;
							}
							else if (
								mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm ||
								mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE && ximm ||
								mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE && yimm)
							{
								int reg = mIns[i].mAddress;
								if (!ReferencedOnPath(this, 0, i, reg) && !ChangedOnPath(this, i + 1, mIns.Size(), reg))
								{
									int k = 0;
									while (k < lblocks.Size() && !(lblocks[k] != this && lblocks[k]->ChangesZeroPage(reg)))
										k++;
									if (k == lblocks.Size())
									{
										NativeCodeInstruction	ins;
										if (mIns[i].mType == ASMIT_STA)
											ins = ains;
										else if (mIns[i].mType == ASMIT_STX)
											ins = xins;
										else if (mIns[i].mType == ASMIT_STY)
											ins = yins;

										if (inserta >= 0)
										{
											pblock->mIns.Insert(inserta++, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ins));
											pblock->mIns.Insert(inserta++, NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
										}
										else if (insertx >= 0)
										{
											pblock->mIns.Insert(insertx++, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ins));
											pblock->mIns.Insert(insertx++, NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
										}
										else if (inserty >= 0)
										{
											pblock->mIns.Insert(inserty++, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, ins));
											pblock->mIns.Insert(inserty++, NativeCodeInstruction(mIns[i].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, reg));
										}

										mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
										changed = true;

										mEntryRequiredRegs += reg;
										mExitRequiredRegs += reg;
										pblock->mExitRequiredRegs += reg;

										for (int i = 0; i < lblocks.Size(); i++)
										{
											lblocks[i]->mEntryRequiredRegs += reg;
											lblocks[i]->mExitRequiredRegs += reg;
										}

									}
								}
							}
							else
							{
								if (mIns[i].ChangesAccu())
									aimm = false;
								if (mIns[i].ChangesXReg())
									ximm = false;
								if (mIns[i].ChangesYReg())
									yimm = false;
							}
						}
					}

					if (!changed)
					{
						changed = OptimizeSingleEntryLoopInvariant(proc, pblock, eblocks, lblocks);
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->OptimizeSingleEntryLoop(proc))
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeSingleEntryLoop(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeLoopRegisterWrapAround(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump)
		{
			NativeCodeBasicBlock* hblock = nullptr;

			int sz = mIns.Size();
			if (sz > 0)
			{
				hblock = nullptr;

				if (mTrueJump->mLoopHead)
					hblock = mTrueJump;
				else if (mFalseJump->mLoopHead)
					hblock = mFalseJump;

				if (hblock && hblock->mIns.Size() > 0 && hblock->mNumEntries == 2)
				{
					NativeCodeBasicBlock* pblock;
					if (hblock->mEntryBlocks[0] == this)
						pblock = hblock->mEntryBlocks[1];
					else
						pblock = hblock->mEntryBlocks[0];

					if (!pblock->mFalseJump)
					{
						int k = pblock->mIns.Size();
						while (k > 0 && (pblock->mIns[k - 1].mLive & LIVE_CPU_REG_Z))
							k--;

						if (k > 0 && hblock->mIns[0].mType == ASMIT_TAX && mIns[sz - 1].mType == ASMIT_TXA && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z))
						{
							pblock->mIns.Insert(k, NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_TAX));
							hblock->mIns.Remove(0);

							pblock->mExitRequiredRegs += CPU_REG_X;
							hblock->mEntryRequiredRegs += CPU_REG_X;
							mExitRequiredRegs += CPU_REG_X;
							changed = true;
						}
						else if (k > 0 && hblock->mIns[0].mType == ASMIT_TAY && mIns[sz - 1].mType == ASMIT_TYA && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z))
						{
							pblock->mIns.Insert(k, NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_TAY));
							hblock->mIns.Remove(0);

							pblock->mExitRequiredRegs += CPU_REG_Y;
							hblock->mEntryRequiredRegs += CPU_REG_Y;
							mExitRequiredRegs += CPU_REG_Y;
							changed = true;
						}
						else if (k > 0 && sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA
							&& hblock->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z) && !(hblock->mIns[0].mFlags & NCIF_VOLATILE))
						{
							pblock->mIns.Insert(k, hblock->mIns[0]);
							hblock->mIns.Remove(0);

							pblock->mExitRequiredRegs += CPU_REG_A;
							hblock->mEntryRequiredRegs += CPU_REG_A;
							mExitRequiredRegs += CPU_REG_A;
							changed = true;
						}
						else
						{
							int	finalA = -1, finalX = -1, finalY = -1;
							for (int i = sz - 1; i >= 0; i--)
							{
								NativeCodeInstruction& ins(mIns[i]);

								if (finalA == -1 && (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1))
									finalA = ins.mAddress;
								else if (finalX == -1 && (ins.mType == ASMIT_LDX || ins.mType == ASMIT_STX) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1))
									finalX = ins.mAddress;
								else if (finalY == -1 && (ins.mType == ASMIT_LDY || ins.mType == ASMIT_STY) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1))
									finalY = ins.mAddress;
								else if (finalA == -1 && ins.ChangesAccu())
									finalA = -2;
								else if (finalX == -1 && ins.ChangesXReg())
									finalX = -2;
								else if (finalY == -1 && ins.ChangesYReg())
									finalY = -2;
							}

							bool	usedA = false, usedX = false, usedY = false;
							for (int i = 0; i < hblock->mIns.Size(); i++)
							{
								NativeCodeInstruction& ins(hblock->mIns[i]);
								if (!usedX && ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE)
								{
									if (ins.mAddress == finalA && !mExitRequiredRegs[CPU_REG_X])
									{
										int k = sz - 1;
										if (mIns[k].mType == ASMIT_CMP || mIns[k].mType == ASMIT_CPX || mIns[k].mType == ASMIT_CPY || mIns[k].mType == ASMIT_INC || mIns[k].mType == ASMIT_DEC || mIns[k].mType == ASMIT_INY || mIns[k].mType == ASMIT_DEY)
											k--;
										if (!(mIns[k].mLive & LIVE_CPU_REG_X))
										{
											pblock->mIns.Push(ins);
											mIns.Insert(k + 1, NativeCodeInstruction(ins.mIns, ASMIT_TAX));
											for (int j = k + 1; j < sz + 1; j++)
												mIns[j].mLive |= LIVE_CPU_REG_X;
											for (int j = 0; j < i; j++)
												hblock->mIns[j].mLive |= LIVE_CPU_REG_X;
											if (ins.mLive & LIVE_CPU_REG_Z)
											{
												ins.mType = ASMIT_CPX;
												ins.mMode = ASMIM_IMMEDIATE;
												ins.mAddress = 0;
											}
											else
											{
												ins.mType = ASMIT_NOP;
												ins.mMode = ASMIM_IMPLIED;
											}

											mExitRequiredRegs += CPU_REG_X;
											pblock->mExitRequiredRegs += CPU_REG_X;
											hblock->mEntryRequiredRegs += CPU_REG_X;
											changed = true;
										}

									}
									usedX = true;
								}

								if (!usedA && ins.ReferencesAccu())
									usedA = true;
								if (!usedX && ins.ReferencesXReg())
									usedX = true;
								if (!usedY && ins.ReferencesYReg())
									usedY = true;

								if (finalA >= 0 && ins.ChangesZeroPage(finalA))
									finalA = -1;
								if (finalX >= 0 && ins.ChangesZeroPage(finalX))
									finalX = -1;
								if (finalY >= 0 && ins.ChangesZeroPage(finalY))
									finalY = -1;
							}
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->OptimizeLoopRegisterWrapAround())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeLoopRegisterWrapAround())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump)
		{
			NativeCodeBasicBlock* hblock = nullptr;

			if (mBranch == ASMIT_BCC && mTrueJump->mLoopHead)
				hblock = mTrueJump;
			else if (mBranch == ASMIT_BCS && mFalseJump->mLoopHead)
				hblock = mFalseJump;

			if (hblock && hblock->mIns.Size() > 0 && hblock->mIns[0].mType == ASMIT_CLC && hblock->mNumEntries == 2)
			{
				NativeCodeBasicBlock* pblock;
				if (hblock->mEntryBlocks[0] == this)
					pblock = hblock->mEntryBlocks[1];
				else
					pblock = hblock->mEntryBlocks[0];

				if (!pblock->mFalseJump)
				{
					pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_CLC));
					hblock->mIns.Remove(0);

					pblock->mExitRequiredRegs += CPU_REG_C;
					hblock->mEntryRequiredRegs += CPU_REG_C;
					mExitRequiredRegs += CPU_REG_C;
					changed = true;
				}
			}
		}

#if 1
		if (!changed && mLoopHead && mEntryBlocks.Size() == 2)
		{
			int i = 0;
			while (i < mIns.Size() && !mIns[i].ReferencesCarry())
				i++;
			if (i < mIns.Size() && mIns[i].mType == ASMIT_CLC)
			{
				NativeCodeBasicBlock	*	pblock = nullptr, *	eblock = nullptr;
				if (mEntryBlocks[0]->mFalseJump && !mEntryBlocks[1]->mFalseJump)
				{
					eblock = mEntryBlocks[0];
					pblock = mEntryBlocks[1];
				}
				else if (!mEntryBlocks[0]->mFalseJump && mEntryBlocks[1]->mFalseJump)
				{
					eblock = mEntryBlocks[1];
					pblock = mEntryBlocks[0];
				}

				if (eblock && (eblock->mBranch != ASMIT_BCC && eblock->mBranch != ASMIT_BCS) && !eblock->mLoopHead)
				{
					int j = eblock->mIns.Size() - 1;
					while (j >= 0 && !eblock->mIns[j].ReferencesCarry())
						j--;
					if (j < 0)
					{
						if (eblock->mEntryBlocks.Size() == 2)
						{
							NativeCodeBasicBlock* peblock = nullptr, * deblock = nullptr;
							NativeCodeBasicBlock* eblock0 = eblock->mEntryBlocks[0], * eblock1 = eblock->mEntryBlocks[1];

							if (eblock0->mFalseJump && !eblock1->mFalseJump)
							{
								if (eblock0->mFalseJump == eblock && eblock0->mTrueJump == eblock1 && eblock0->mBranch == ASMIT_BCS ||
									eblock0->mTrueJump == eblock && eblock0->mFalseJump == eblock1 && eblock0->mBranch == ASMIT_BCC)
								{
									peblock = eblock0;
									deblock = eblock1;
								}
							}
							else if (eblock1->mFalseJump && !eblock0->mFalseJump)
							{
								if (eblock1->mFalseJump == eblock && eblock1->mTrueJump == eblock0 && eblock1->mBranch == ASMIT_BCS ||
									eblock1->mTrueJump == eblock && eblock1->mFalseJump == eblock0 && eblock1->mBranch == ASMIT_BCC)
								{
									peblock = eblock1;
									deblock = eblock0;
								}
							}

							if (peblock && deblock->mEntryBlocks.Size() == 1)
							{
								deblock->mIns.Push(mIns[i]);
								pblock->mIns.Push(mIns[i]);
								mIns.Remove(i);

								for (int k = 0; k < i; k++)
									mIns[k].mLive |= LIVE_CPU_REG_C;
								for (int k = 0; k < eblock->mIns.Size(); k++)
									eblock->mIns[k].mLive |= LIVE_CPU_REG_C;

								deblock->mExitRequiredRegs += CPU_REG_C;
								peblock->mExitRequiredRegs += CPU_REG_C;
								pblock->mExitRequiredRegs += CPU_REG_C;
								eblock->mExitRequiredRegs += CPU_REG_C;
								eblock->mEntryRequiredRegs += CPU_REG_C;
								mEntryRequiredRegs += CPU_REG_C;
								changed = true;
							}
						}

					}
				}
			}
		}
#endif
		if (mTrueJump && mTrueJump->OptimizeLoopCarryOver())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeLoopCarryOver())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::RemoveSimpleLoopUnusedIndex(void)
{
	bool	changed = false;

	assert(mEntryRequiredRegs.Size() > 0);

	if (!mVisited)
	{
		mVisited = true;

		if (mFalseJump && mTrueJump == this)
		{
			NumberSet	required(mFalseJump->mEntryRequiredRegs);

			bool	complex = false;

			int	k = mIns.Size() - 1;
			while (k >= 0)
			{
				NativeCodeInstruction	& ins(mIns[k]);

				if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && !(ins.mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && !required[ins.mAddress])
				{
					if (k > 2 && mIns[k - 1].mMode == ASMIM_IMMEDIATE && mIns[k - 2].mType == ASMIT_LDA && mIns[k - 2].mMode == ASMIM_ZERO_PAGE && mIns[k - 2].mAddress == mIns[k].mAddress)
						k -= 2;
					else
						required += ins.mAddress;
				}
				else if (ins.mMode == ASMIM_ZERO_PAGE)
					required += ins.mAddress;
				else if (ins.mMode == ASMIM_INDIRECT_Y)
				{
					required += ins.mAddress;
					required += ins.mAddress + 1;
				}
				else if (ins.mType == ASMIT_JSR)
				{
					required += BC_REG_ADDR + 0;
					required += BC_REG_ADDR + 1;
					for (int i = 0; i < 4; i++)
						required += BC_REG_ACCU + i;
					for (int i = 0; i < 8; i++)
						required += BC_REG_WORK + i;
					required += BC_REG_WORK_Y;

					if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC))
					{
#if 1
						if (ins.mLinkerObject)
						{
							LinkerObject* lo = ins.mLinkerObject;

							for (int i = 0; i < 256; i++)
							{
								if (lo->mZeroPageSet[i])
									required += i;
							}

							for (int i = 0; i < ins.mLinkerObject->mNumTemporaries; i++)
							{
								for (int j = 0; j < ins.mLinkerObject->mTempSizes[i]; j++)
									required += ins.mLinkerObject->mTemporaries[i] + j;
							}
						}

#else
						for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++)
							required += i;
						for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
							required += i;
#endif
					}

//					complex = true;

				}
				k--;
			}

			if (!complex)
			{
				for (int i = 0; i < mIns.Size(); i++)
				{
					if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && !required[mIns[i].mAddress])
					{
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->RemoveSimpleLoopUnusedIndex())
			changed = true;
		if (mFalseJump && mFalseJump->RemoveSimpleLoopUnusedIndex())
			changed = true;

	}

	return changed;
}

static bool Is16BitInc(NativeCodeBasicBlock* block, int reg, int at)
{
	if (at + 6 < block->mIns.Size())
	{
		if (block->mIns[at + 0].mType == ASMIT_CLC &&
			block->mIns[at + 1].mType == ASMIT_LDA && block->mIns[at + 1].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 1].mAddress == reg &&
			block->mIns[at + 2].mType == ASMIT_ADC && block->mIns[at + 2].mMode == ASMIM_IMMEDIATE && block->mIns[at + 2].mAddress == 1 &&
			block->mIns[at + 3].mType == ASMIT_STA && block->mIns[at + 3].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 3].mAddress == reg &&
			block->mIns[at + 4].mType == ASMIT_LDA && block->mIns[at + 4].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 4].mAddress == reg + 1 &&
			block->mIns[at + 5].mType == ASMIT_ADC && block->mIns[at + 5].mMode == ASMIM_IMMEDIATE && block->mIns[at + 5].mAddress == 0 &&
			block->mIns[at + 6].mType == ASMIT_STA && block->mIns[at + 6].mMode == ASMIM_ZERO_PAGE && block->mIns[at + 6].mAddress == reg + 1 &&
			!(block->mIns[at + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
		{
			return true;
		}
	}

	return false;
}

static bool IsPointerIncAddrs(NativeCodeBasicBlock* block, int reg)
{
	bool	changed = false;
	bool	used = false;

	int i = 0;
	while (i < block->mIns.Size())
	{
		NativeCodeInstruction	ins(block->mIns[i]);

		if (ins.mMode == ASMIM_INDIRECT_Y)
		{
			if (ins.mAddress == reg)
			{
				if (changed)
					return false;
				used = true;
				i++;
			}
			else
				return false;
		}
		else if (Is16BitInc(block, reg, i))
		{
			changed = true;
			i += 7;
		}
		else if (ins.ReferencesZeroPage(reg) || ins.ReferencesZeroPage(reg + 1) || ins.ReferencesYReg())
			return false;
		else
			i++;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeSimpleYIndexedLoop(NativeCodeBasicBlock* prevBlock, NativeCodeBasicBlock* exitBlock)
{
	char regs[256];
	for (int i = 0; i <256; i++)
		regs[i] = 0;

	// 1 used
	// 2 indexed
	// 4 16inc

	int i = 0;
	while (i < mIns.Size())
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mMode == ASMIM_INDIRECT_Y)
		{
			if ((regs[ins.mAddress] & 5) || (regs[ins.mAddress + 1] & 5))
				return false;
			regs[ins.mAddress] |= 2;
			i++;
		}
		else if (ins.mMode == ASMIM_ZERO_PAGE)
		{
			if (regs[ins.mAddress] & 1)
				i++;
			else if (i > 0 && Is16BitInc(this, ins.mAddress, i - 1))
			{
				if (exitBlock->mEntryRequiredRegs[ins.mAddress] || exitBlock->mEntryRequiredRegs[ins.mAddress + 1])
					return false;
				i += 6;
				regs[ins.mAddress] |= 4;
			}
			else if (regs[ins.mAddress] & 2)
				return false;
			else
			{
				regs[ins.mAddress] |= 1;
				i++;
			}
		}
		else if (ins.mType == ASMIT_JSR)
			return false;
		else
			i++;
	}

	// All indirect Y must be incremented
	for (int k = 0; k < 256; k++)
		if (regs[k] == 1)
			return false;

	bool	changed = false;

	for(int i=0; i<mIns.Size(); i++)
	{
		NativeCodeInstruction& ins(mIns[i]);
		if (ins.mMode == ASMIM_ZERO_PAGE)
		{
			if (regs[ins.mAddress] == 6)
			{
				for (int k = 0; k < 7; k++)
				{
					mIns[i - 1 + k].mType = ASMIT_NOP; mIns[i - 1 + k].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}
	}

	if (changed)
		mIns.Insert(mIns.Size() - 1, NativeCodeInstruction(mIns.Last().mIns, ASMIT_INY, ASMIM_IMPLIED));
	
	return changed;
}

bool NativeCodeBasicBlock::Is16BitImmSum(int at, int& val, int& reg) const
{
	if (at + 6 < mIns.Size())
	{
		if (mIns[at + 0].mType == ASMIT_CLC &&
			mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && mIns[at + 3].mAddress == mIns[at + 1].mAddress &&
			mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == mIns[at + 1].mAddress + 1 &&
			mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE && mIns[at + 6].mAddress == mIns[at + 4].mAddress)
		{
			reg = mIns[at + 1].mAddress;
			val = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
			return true;
		}
	}

	return false;
}


bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prevBlock, NativeCodeBasicBlock* exitBlock, bool full)
{
	bool changed = false;
	
	if (mBranch == ASMIT_JMP)
		return false;

	assert(mEntryRequiredRegs.Size());

	CheckLive();

	if (!exitBlock)
	{
		if (mTrueJump == this)
			exitBlock = mFalseJump;
		else
			exitBlock = mTrueJump;
	}

	NativeCodeBasicBlock* pblock = prevBlock;
	if (!pblock && mEntryBlocks.Size() == 2)
	{
		if (mEntryBlocks[0] == this)
			pblock = mEntryBlocks[1];
		else
			pblock = mEntryBlocks[0];
	}

	int	sz = mIns.Size();

	if (sz == 2 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && mIns[0].mType == ASMIT_LDA && mIns[1].mType == ASMIT_CMP && !(mIns[1].mFlags & NCIF_VOLATILE) && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);
		mIns[1].mType = ASMIT_LDA; mIns[1].mLive |= LIVE_CPU_REG_A;
		mIns[0].mType = ASMIT_CMP; mIns[0].mLive |= LIVE_CPU_REG_Z;
		prevBlock->mIns.Push(mIns[1]);
		prevBlock->mExitRequiredRegs += CPU_REG_A;
		mEntryRequiredRegs += CPU_REG_A;
		mIns.Remove(1);

		CheckLive();

		return true;
	}

	if (!mEntryRequiredRegs[CPU_REG_A])
	{
		for (int i = 0; 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].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) &&
				!ReferencesZeroPage(mIns[i + 3].mAddress, 0, i + 2) && !ChangesZeroPage(mIns[i + 1].mAddress))
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				prevBlock->mExitRequiredRegs += mIns[i + 3].mAddress;
				mEntryRequiredRegs += mIns[i + 3].mAddress;
				mExitRequiredRegs += mIns[i + 3].mAddress;

				prevBlock->mIns.Push(mIns[i + 0]);
				prevBlock->mIns.Push(mIns[i + 1]);
				prevBlock->mIns.Push(mIns[i + 2]);
				prevBlock->mIns.Push(mIns[i + 3]);
				mIns.Remove(i, 4);
				changed = true;
			}
		}
	}

	sz = mIns.Size();
	if (sz >= 3 &&
		mIns[sz - 3].mType == ASMIT_CLC &&
		mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
		!mIns[sz - 1].ChangesZFlag() && !mIns[sz - 1].ChangesCarry())
	{
		if (mBranch == ASMIT_BCC)
		{
			mBranch = ASMIT_BNE;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
		}
		else if (mBranch == ASMIT_BCS)
		{
			mBranch = ASMIT_BEQ;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
		}
	}

#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);

			if (mEntryRequiredRegs[CPU_REG_A]) mIns[i].mLive |= LIVE_CPU_REG_A;
			if (mEntryRequiredRegs[CPU_REG_X]) mIns[i].mLive |= LIVE_CPU_REG_X;
			if (mEntryRequiredRegs[CPU_REG_Y]) mIns[i].mLive |= LIVE_CPU_REG_Y;

			prevBlock->mIns.Push(mIns[i]);
			prevBlock->mExitRequiredRegs += CPU_REG_C;
			for (int j = 0; j < i; j++)
				mIns[j].mLive |= LIVE_CPU_REG_C;
			mEntryRequiredRegs += CPU_REG_C;
			mIns.Remove(i);

			CheckLive();

			return true;
		}
	}
#endif

	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
			mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
		{
			int reg = mIns[i + 1].mAddress;

			if (!ReferencesZeroPage(reg, 0, i) && !ChangesZeroPage(reg, i + 2))
			{
				if (!mEntryRequiredRegs[CPU_REG_A])
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					prevBlock->mIns.Push(mIns[i + 0]);
					prevBlock->mIns.Push(mIns[i + 1]);
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					prevBlock->mExitRequiredRegs += reg;
					mEntryRequiredRegs += reg;
					mExitRequiredRegs += reg;
					changed = true;
				}
				else if (!mEntryRequiredRegs[CPU_REG_X])
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, mIns[i + 0]));
					prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, mIns[i + 1]));
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					prevBlock->mExitRequiredRegs += reg;
					mEntryRequiredRegs += reg;
					mExitRequiredRegs += reg;
					changed = true;
				}
			}
		}
		if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
		{
			int a0 = mIns[i + 0].mAddress, a1 = mIns[i + 1].mAddress;
			if (!mEntryRequiredRegs[a0] && !ReferencesZeroPage(a0, i + 2) && !ChangesZeroPage(a1, i + 2))
			{
				if (!exitBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				if (exitBlock->mNumEntries == 1 && !exitBlock->mEntryRequiredRegs[CPU_REG_Z])
				{
					if (!exitBlock->mEntryRequiredRegs[CPU_REG_A])
					{
						mExitRequiredRegs += a1;
						exitBlock->mEntryRequiredRegs += a1;
						exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, mIns[i + 1]));
						exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, mIns[i + 0]));
						mIns.Remove(i + 0);
						sz--;
						changed = true;
					}
				}
			}
			else if (!mEntryRequiredRegs[a1] && !ReferencesZeroPage(a1, i + 2) && !ChangesZeroPage(a0, i + 2))
			{
				if (!exitBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				if (exitBlock->mNumEntries == 1 && !exitBlock->mEntryRequiredRegs[CPU_REG_Z])
				{
					if (!exitBlock->mEntryRequiredRegs[CPU_REG_A])
					{
						mExitRequiredRegs += a0;
						exitBlock->mEntryRequiredRegs += a0;
						exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDA, mIns[i + 0]));
						exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, mIns[i + 1]));
						mIns.Remove(i + 1);
						sz--;
						changed = true;
					}
				}
			}
		}

	}

	if (sz >= 3 && mIns[0].mType == ASMIT_LDA && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) && mIns[sz - 1].mType == ASMIT_CMP)
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mEntryRequiredRegs += CPU_REG_A;
		mExitRequiredRegs += CPU_REG_A;
		prevBlock->mExitRequiredRegs += CPU_REG_A;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	if (sz >= 2 && mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 1]))
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mEntryRequiredRegs += CPU_REG_A;
		mExitRequiredRegs += CPU_REG_A;
		prevBlock->mExitRequiredRegs += CPU_REG_A;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	if (sz >= 3 && mIns[0].mType == ASMIT_LDY && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) &&
		mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		mIns[sz - 2].mType = ASMIT_LDY; mIns[sz - 2].mLive |= LIVE_CPU_REG_Y;
		mIns[sz - 1].mType = ASMIT_CPY; mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mExitRequiredRegs += CPU_REG_Y;
		mEntryRequiredRegs += CPU_REG_Y;
		prevBlock->mExitRequiredRegs += CPU_REG_Y;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	if (sz >= 2 && mIns[0].mType == ASMIT_LDY && mIns[sz - 1].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 1]) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Y])
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		mIns[sz - 1].mType = ASMIT_LDY; mIns[sz - 1].mLive |= LIVE_CPU_REG_Y;

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mExitRequiredRegs += CPU_REG_Y;
		mEntryRequiredRegs += CPU_REG_Y;
		prevBlock->mExitRequiredRegs += CPU_REG_Y;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	if (sz >= 4 && mIns[0].mType == ASMIT_TAY && mIns[sz - 3].mType == ASMIT_INX && mIns[sz - 2].mType == ASMIT_TXA && mIns[sz - 1].mType == ASMIT_CPX && !ChangesYReg(1) && !ReferencesXReg(0, sz - 3))
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		for (int i = 0; i < sz; i++)
			mIns[i].mLive |= LIVE_CPU_REG_Y;

		mIns[sz - 3].mType = ASMIT_INY; 
		mIns[sz - 2].mType = ASMIT_TYA;
		mIns[sz - 1].mType = ASMIT_CPY;

		if (exitBlock->mEntryRequiredRegs[CPU_REG_X])
		{
			exitBlock->mEntryRequiredRegs += CPU_REG_A;
			exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[sz - 2].mIns, ASMIT_TAX));
		}

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mExitRequiredRegs += CPU_REG_Y;
		mEntryRequiredRegs += CPU_REG_Y;
		prevBlock->mExitRequiredRegs += CPU_REG_Y;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	if (sz >= 5 && full &&
		mIns[sz - 5].mType == ASMIT_TYA && mIns[sz - 4].mType == ASMIT_CLC && mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mType == ASMIT_TAY && 
		mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mBranch == ASMIT_BNE &&
		!ChangesYReg(0, sz - 5) && !ChangesCarry(0, sz - 5))
	{
		if (pblock)
		{
			int yend = mIns[sz - 1].mAddress;
			int ystart = pblock->RetrieveYValue(pblock->mIns.Size() - 1);
			int ystep = mIns[sz - 3].mAddress;
			if (ystart >= 0 && yend > ystart && (yend - ystart) % ystep == 0)
			{
				mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
				mBranch = ASMIT_BCC;
				changed = true;
#if 0
				prevBlock->mIns.Push(mIns[sz - 4]);
				mIns.Remove(sz - 4);
				for (int i = 0; i < sz - 4; i++)
					mIns[i].mLive |= LIVE_CPU_REG_C;

				mExitRequiredRegs += CPU_REG_C;
				mEntryRequiredRegs += CPU_REG_C;
				prevBlock->mExitRequiredRegs += CPU_REG_C;

				prevBlock->CheckLive();
				CheckLive();

				return true;
#endif
			}
		}
	}


	if (sz >= 3 && mIns[0].mType == ASMIT_LDX && mIns[sz - 2].mType == ASMIT_LDA && mIns[0].SameEffectiveAddress(mIns[sz - 2]) &&
		mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		mIns[sz - 2].mType = ASMIT_LDX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X;
		mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_X;

		prevBlock->mIns.Push(mIns[0]);
		mIns.Remove(0);

		mExitRequiredRegs += CPU_REG_X;
		mEntryRequiredRegs += CPU_REG_X;
		prevBlock->mExitRequiredRegs += CPU_REG_X;

		prevBlock->CheckLive();
		CheckLive();

		return true;
	}

	int	si = 0, ei = mIns.Size() - 1;
	while (si < mIns.Size() && !mIns[si].ReferencesYReg())
		si++;
	while (ei > si && !(mIns[ei].ChangesYReg() || mIns[ei].mType == ASMIT_STY))
		ei--;

	if (si < ei && mIns[si].mType == ASMIT_LDY && mIns[ei].mType == ASMIT_STY && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_Y;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_Y;
					i++;
				}

				if (prevBlock->mExitRequiredRegs[CPU_REG_C])
					mIns[si].mLive |= LIVE_CPU_REG_C;
				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				mEntryRequiredRegs += CPU_REG_Y;
				mExitRequiredRegs += CPU_REG_Y;

				CheckLive();
				prevBlock->CheckLive();

				return true;
			}
		}
	}
	
	if (si < ei && mIns[ei].mType == ASMIT_STY && mIns[ei].mMode == ASMIM_ZERO_PAGE)
	{
		int	j = 0;
		while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
			j++;
		if (j == mIns.Size())
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			mExitRequiredRegs += CPU_REG_Y;
			exitBlock->mEntryRequiredRegs += CPU_REG_Y;

			exitBlock->mIns.Insert(0, mIns[ei]);
			mIns.Remove(ei);

			CheckLive();

			return true;
		}
	}

	si = 0, ei = mIns.Size() - 1;
	while (si < mIns.Size() && !mIns[si].ReferencesXReg())
		si++;
	while (ei > si && !(mIns[ei].ChangesXReg() || mIns[ei].mType == ASMIT_STX))
		ei--;

	if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[ei].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_X;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_X;
					i++;
				}

				if (prevBlock->mExitRequiredRegs[CPU_REG_C])
					mIns[si].mLive |= LIVE_CPU_REG_C;
				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				prevBlock->mExitRequiredRegs += CPU_REG_X;
				mEntryRequiredRegs += CPU_REG_X;
				mExitRequiredRegs += CPU_REG_X;

				CheckLive();
				prevBlock->CheckLive();

				return true;
			}
		}
	}



	si = 0;
	ei = mIns.Size() - 1;
	while (si < mIns.Size() && !mIns[si].ReferencesXReg())
		si++;
	while (ei > si && !mIns[ei].ReferencesXReg())
		ei--;

	if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[ei].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_X;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_X;
					i++;
				}

				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				prevBlock->mExitRequiredRegs += CPU_REG_X;

				mEntryRequiredRegs += CPU_REG_X;
				mExitRequiredRegs += CPU_REG_X;

				CheckLive();
				prevBlock->CheckLive();

				return true;
			}
		}
	}

	if (si + 2 < mIns.Size() && mIns[si].mType == ASMIT_LDX && mIns[si + 2].mType == ASMIT_STX && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[si + 2].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[si + 2].mAddress && mIns[si + 1].mType == ASMIT_INX)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = si + 3;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress) && !mIns[i].ChangesXReg())
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				for(int i=0; i<mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_X;

				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				prevBlock->mExitRequiredRegs += CPU_REG_X;

				mEntryRequiredRegs += CPU_REG_X;
				mExitRequiredRegs += CPU_REG_X;

				CheckLive();
				prevBlock->CheckLive();

				return true;
			}
		}
	}

	if (si < ei && mIns[si].mType == ASMIT_LDX && mIns[si].mMode == ASMIM_ZERO_PAGE)
	{
		// Loads X once from zero page and never changes it again

		int i = si;
		while (i < ei && !mIns[i + 1].ChangesXReg())
			i++;

		if (i == ei)
		{
			i = 0;
			while (i < si && !mIns[i].ReferencesZeroPage(mIns[si].mAddress))
				i++;
			if (i == si)
			{
				i++;
				while (i < mIns.Size() && !mIns[i].ReferencesZeroPage(mIns[si].mAddress))
					i++;
				if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC) && (!(mIns[ei].mLive & LIVE_CPU_REG_Z) || mIns[ei].ChangesAccuAndFlag()))
				{
					int j = i + 1;
					while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(mIns[si].mAddress))
						j++;
					if (j == mIns.Size())
					{
						// So we have an LDX from ZP, and exactly one INC/DECof this ZP and X never changes in the loop
						if (!prevBlock)
							return OptimizeSimpleLoopInvariant(proc, full);

						bool needRecheck = mIns[ei].mLive & LIVE_CPU_REG_Z;

						prevBlock->mIns.Push(mIns[si]);
						exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[si].mIns, ASMIT_STX, mIns[si]));
						mIns[si].mType = ASMIT_NOP;
						mIns[si].mMode = ASMIM_IMPLIED;
						
						AsmInsType	t;
						if (mIns[i].mType == ASMIT_DEC)
							t = ASMIT_DEX;
						else
							t = ASMIT_INX;

						if (i < ei)
						{
							mIns[i].mType = ASMIT_NOP;
							mIns[i].mMode = ASMIM_IMPLIED;

							if (needRecheck)
							{
								mIns[ei].mLive |= LIVE_CPU_REG_A;
								mIns.Insert(ei + 1, NativeCodeInstruction(mIns[ei].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
							}

							mIns.Insert(ei + 1, NativeCodeInstruction(mIns[i].mIns, t));
						}
						else
						{
							mIns[i].mType = t;
							mIns[i].mMode = ASMIM_IMPLIED;
						}

						for (int i = 0; i < mIns.Size(); i++)
							mIns[i].mLive |= LIVE_CPU_REG_X;

						mExitRequiredRegs += CPU_REG_X;
						mEntryRequiredRegs += CPU_REG_X;
						prevBlock->mExitRequiredRegs += CPU_REG_X;
						exitBlock->mEntryRequiredRegs += CPU_REG_X;

						prevBlock->CheckLive();
						CheckLive();
						return true;
					}
				}
			}
		}
	}

	if (si < ei && mIns[ei].mType == ASMIT_STX && mIns[ei].mMode == ASMIM_ZERO_PAGE)
	{
		int	j = 0;
		while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
			j++;
		if (j == mIns.Size())
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			exitBlock->mIns.Insert(0, mIns[ei]);
			mIns.Remove(ei);

			CheckLive();

			return true;
		}
	}

	si = 0;
	ei = mIns.Size() - 1;
	while (si < mIns.Size() && !mIns[si].ReferencesAccu())
		si++;
	while (ei > si && !mIns[ei].ReferencesAccu())
		ei--;

	if (si < ei && mIns[si].mType == ASMIT_LDA && mIns[ei].mType == ASMIT_STA && mIns[si].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si].mAddress == mIns[ei].mAddress)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				mEntryRequiredRegs += CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				prevBlock->CheckLive();
				CheckLive();

				return true;
			}
		}
	}

	ei = mIns.Size() - 1;
	while (ei > si && !mIns[ei].ReferencesYReg())
		ei--;

	if (si < ei && mIns[si].mType == ASMIT_TYA && mIns[ei].mType == ASMIT_TAY)
	{
		int i = 0;
		while (i < si && !mIns[i].ChangesYReg())
			i++;
		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesAccu())
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				mEntryRequiredRegs += CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				prevBlock->CheckLive();
				CheckLive();

				return true;
			}
		}
	}

	if (si + 2 < ei && 
		mIns[si + 0].mType == ASMIT_LDA && 
		mIns[si + 1].mType == ASMIT_CLC &&
		mIns[si + 2].mType == ASMIT_ADC &&
		mIns[ei].mType == ASMIT_STA && mIns[si + 2].mMode == ASMIM_ZERO_PAGE && mIns[ei].mMode == ASMIM_ZERO_PAGE && mIns[si + 2].mAddress == mIns[ei].mAddress)
	{
		int	i = 0;
		while (i < si && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
			i++;

		if (i == si)
		{
			i = ei + 1;
			while (i < mIns.Size() && !mIns[i].ChangesZeroPage(mIns[si].mAddress))
				i++;

			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				i = 0;
				while (i < si)
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				i = ei;
				while (i < mIns.Size())
				{
					mIns[i].mLive |= LIVE_CPU_REG_A;
					i++;
				}

				mIns[si + 2].CopyMode(mIns[si + 0]);

				if (mIns[si + 2].RequiresYReg())
					mIns[si + 1].mLive |= LIVE_CPU_REG_Y;
				if (mIns[si + 2].RequiresXReg())
					mIns[si + 1].mLive |= LIVE_CPU_REG_X;

				mIns[si + 0].CopyMode(mIns[ei]);
				prevBlock->mIns.Push(mIns[si]);
				mIns.Remove(si);

				mEntryRequiredRegs += CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				prevBlock->CheckLive();
				CheckLive();

				return true;
			}
		}
	}


	if (si < ei && mIns[ei].mType == ASMIT_STA && mIns[ei].mMode == ASMIM_ZERO_PAGE)
	{
		int	j = 0;
		while (j < mIns.Size() && (j == ei || !(mIns[j].ChangesZeroPage(mIns[ei].mAddress) || mIns[j].UsesZeroPage(mIns[ei].mAddress))))
			j++;
		if (j == mIns.Size())
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			exitBlock->mIns.Insert(0, mIns[ei]);
			mIns.Remove(ei);

			CheckLive();

			return true;
		}
	}



	if (sz >= 2 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
	{
		int	i = mIns.Size() - 1;
		while (i > 0 && !mIns[i].ChangesYReg() && !mIns[i].ChangesZeroPage(mIns[0].mAddress))
			i--;

		if (i > 0 &&
			(mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[0].mAddress) ||
			(mIns[i].mType == ASMIT_TAY && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_STA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == mIns[0].mAddress))
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			while (i < mIns.Size())
			{
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				i++;
			}

			prevBlock->mIns.Push(mIns[0]);
			mIns.Remove(0);

			mEntryRequiredRegs += CPU_REG_Y;
			mExitRequiredRegs += CPU_REG_Y;

			prevBlock->CheckLive();
			CheckLive();

			return true;
		}
	}

	if (sz >= 2 &&
		mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ABSOLUTE &&
		mIns[1].mType == ASMIT_INC && mIns[0].SameEffectiveAddress(mIns[1]))
	{
		int i = 2;
		while (i < mIns.Size() && !mIns[i].ChangesXReg() && !mIns[0].MayBeChangedOnAddress(mIns[i]))
			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;
			mIns[1].mType = ASMIT_INX; mIns[1].mMode = ASMIM_IMPLIED;
			prevBlock->mIns.Push(mIns[0]);
			exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STX, mIns[0]));
			mIns.Remove(0);
			prevBlock->mExitRequiredRegs += CPU_REG_X;
			mEntryRequiredRegs += CPU_REG_X;
			mExitRequiredRegs += CPU_REG_X;
			exitBlock->mEntryRequiredRegs += CPU_REG_X;
			changed = true;
		}
	}

	if (sz >= 2 && mIns[0].mType == ASMIT_LDX && mIns[0].mMode == ASMIM_ZERO_PAGE)
	{
		int	i = mIns.Size() - 1;
		while (i > 0 && !mIns[i].ChangesXReg() && !mIns[i].ChangesZeroPage(mIns[0].mAddress))
			i--;

		if (i > 0 &&
			(mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[0].mAddress) ||
			(mIns[i].mType == ASMIT_TAX && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_STA) && mIns[i - 1].mMode == ASMIM_ZERO_PAGE && mIns[i - 1].mAddress == mIns[0].mAddress))
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			while (i < mIns.Size())
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				i++;
			}

			prevBlock->mIns.Push(mIns[0]);
			mIns.Remove(0);

			mEntryRequiredRegs += CPU_REG_X;
			mExitRequiredRegs += CPU_REG_X;
			prevBlock->mExitRequiredRegs += CPU_REG_X;

			prevBlock->CheckLive();
			CheckLive();

			return true;
		}
	}

	if (sz >= 2 && 
		mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && 
		mIns[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].ChangesZeroPage(mIns[1].mAddress) && !mIns[i].ReferencesZeroPage(mIns[0].mAddress))
			i--;

		if (i > 1)
		{
			i--;

			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[1].mAddress &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[0].mAddress && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				if ((!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && (!mExitRequiredRegs[CPU_REG_A] || !mExitRequiredRegs[CPU_REG_X]) && !mExitRequiredRegs[CPU_REG_Z])
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					bool	live = mIns[0].mLive & LIVE_MEM;

					prevBlock->mIns.Push(mIns[0]);
					prevBlock->mIns.Push(mIns[1]);

					if (mEntryRequiredRegs[CPU_REG_A])
					{
						prevBlock->mIns[prevBlock->mIns.Size() - 2].mType = ASMIT_LDX;
						prevBlock->mIns[prevBlock->mIns.Size() - 2].mLive |= LIVE_CPU_REG_X;
						prevBlock->mIns[prevBlock->mIns.Size() - 1].mType = ASMIT_STX;
					}

					if (!live)
					{
						exitBlock->mIns.Insert(0, mIns[i + 0]);
						exitBlock->mIns.Insert(1, mIns[i + 1]);

						if (mExitRequiredRegs[CPU_REG_A])
						{
							exitBlock->mIns[0].mType = ASMIT_LDX;
							exitBlock->mIns[0].mLive |= LIVE_CPU_REG_X;
							exitBlock->mIns[1].mType = ASMIT_STX;
						}
						mIns.Remove(i + 1);
					}

					mIns.Remove(0); mIns.Remove(0);

					prevBlock->CheckLive();
					CheckLive();

					return true;
				}
			}
		}
	}


	int	ai = 0;
	while (ai < mIns.Size() && !mIns[ai].ChangesAccu())
		ai++;

	if (ai < mIns.Size() && !(mIns[ai].mLive & LIVE_CPU_REG_Z) && !mEntryRequiredRegs[CPU_REG_A])
	{
		if (mIns[ai].mType == ASMIT_LDA && mIns[ai].mMode == ASMIM_IMMEDIATE)
		{
			int i = ai + 1;
			while (i < mIns.Size() && !mIns[i].ChangesAccu())
				i++;
			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				mEntryRequiredRegs += CPU_REG_A;
				for(int i=0; i<mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				if (mEntryRequiredRegs[CPU_REG_X])
					mIns[ai].mLive |= LIVE_CPU_REG_X;
				if (mEntryRequiredRegs[CPU_REG_Y])
					mIns[ai].mLive |= LIVE_CPU_REG_Y;
				prevBlock->mIns.Push(mIns[ai]);
				mIns.Remove(ai);

				changed = true;
			}
		}
		else if (mIns[ai].mType == ASMIT_LDA && mIns[ai].mMode == ASMIM_ZERO_PAGE)
		{
			int i = 0;
			while (i < mIns.Size() && (i <= ai || !mIns[i].ChangesAccu()) && !mIns[i].ChangesZeroPage(mIns[ai].mAddress))
				i++;
			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				prevBlock->mIns.Push(mIns[ai]);
				mIns.Remove(ai);

				mEntryRequiredRegs += CPU_REG_A;
				for (int i = 0; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				changed = true;
			}

			i = mIns.Size() - 1;
			while (i >= 0 && !mIns[i].ChangesAccu() && mIns[i].mType != ASMIT_STA)
				i--;
			if (i >= 0 && mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[ai].mAddress)
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				prevBlock->mIns.Push(mIns[ai]);
				mIns.Remove(ai);

				mEntryRequiredRegs += CPU_REG_A;
				for (int i = 0; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;

				changed = true;
			}
		}
	}

	ai = 0;
	while (ai < mIns.Size() && !mIns[ai].ChangesYReg())
		ai++;

	if (ai < mIns.Size())
	{
		if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_IMMEDIATE)
		{
			int i = ai + 1;
			while (i < mIns.Size() && !mIns[i].ChangesYReg())
				i++;
			if (i == mIns.Size())
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				for (int i = 0; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_Y;

				if (mEntryRequiredRegs[CPU_REG_X])
					mIns[ai].mLive |= LIVE_CPU_REG_X;
				if (mEntryRequiredRegs[CPU_REG_C])
					mIns[ai].mLive |= LIVE_CPU_REG_C;

				prevBlock->mIns.Push(mIns[ai]);
				mIns.Remove(ai);

				mEntryRequiredRegs += CPU_REG_Y;
				prevBlock->mExitRequiredRegs += CPU_REG_Y;

				changed = true;
			}
		}
		else if (mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_ZERO_PAGE && !(mIns[ai].mLive & LIVE_CPU_REG_Z))
		{
			int i = 0;
			while (i < mIns.Size() && (i == ai || !mIns[i].ChangesYReg()))
				i++;
			if (i == mIns.Size())
			{
				int addr = mIns[ai].mAddress;
				bool	fail = false, changey = false, changev = false;
				
				for (int i = 0; i < mIns.Size(); i++)
				{
					if (mIns[i].mType == ASMIT_LDY)
						changey = false;
					else if (mIns[i].ReferencesYReg() && changey)
					{
						fail = true;
						break;
					}
					else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
					{
						if (mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_INC || mIns[i].mType == ASMIT_DEC)
						{
							changey = true;
							changev = true;
						}
						else if (mIns[i].mType != ASMIT_LDA)
						{
							fail = true;
							break;
						}
					}
				}

				if (!fail)
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					changed = true;

					prevBlock->mExitRequiredRegs += CPU_REG_Y;
					mEntryRequiredRegs += CPU_REG_Y;
					mExitRequiredRegs += CPU_REG_Y;
					exitBlock->mEntryRequiredRegs += CPU_REG_Y;

					prevBlock->mIns.Push(NativeCodeInstruction(mIns[ai].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
					if (changev)
						exitBlock->mIns.Push(NativeCodeInstruction(mIns[ai].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
					for (int i = 0; i < mIns.Size(); i++)
					{
						mIns[i].mLive |= LIVE_CPU_REG_Y;

						if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
						{
							if (mIns[i].mType == ASMIT_LDA)
							{
								mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (mIns[i].mType == ASMIT_STA)
							{
								mIns[i].mType = ASMIT_TAY; mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (mIns[i].mType == ASMIT_LDY)
							{
								mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (mIns[i].mType == ASMIT_INC)
							{
								mIns[i].mType = ASMIT_INY; mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (mIns[i].mType == ASMIT_DEC)
							{
								mIns[i].mType = ASMIT_DEY; mIns[i].mMode = ASMIM_IMPLIED;
							}
						}
					}
				}
			}
		}
	}
	else
	{
		int i = 0;
		while (i < mIns.Size() && !mIns[i].ReferencesYReg())
			i++;
		if (i < mIns.Size() && mIns[i].mMode == ASMIM_INDIRECT_Y && IsPointerIncAddrs(this, mIns[i].mAddress))
		{
			NativeCodeBasicBlock* oblock = mTrueJump == this ? mFalseJump : mTrueJump;

			int	reg = mIns[i].mAddress;

			if (!oblock->mEntryRequiredRegs[CPU_REG_Y] &&
				!oblock->mEntryRequiredRegs[reg] &&
				!oblock->mEntryRequiredRegs[reg + 1])
			{
				for (int i = 0; i < mIns.Size(); i++)
				{
					if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == reg)
					{
						if (mIns[i].mType == ASMIT_LDA)
						{
							mIns[i].mType = ASMIT_TYA;
							mIns[i].mMode = ASMIM_IMPLIED;
						}
						else if (mIns[i].mType == ASMIT_STA)
						{
							mIns[i].mType = ASMIT_TAY;
							mIns[i].mMode = ASMIM_IMPLIED;
						}
					}
				}
				changed = true;
			}
		}
		else if (pblock && mIns.Last().mType == ASMIT_DEX && !ChangesXReg(0, mIns.Size() - 1))
		{
			NativeCodeBasicBlock* oblock = mTrueJump == this ? mFalseJump : mTrueJump;
			int ystart = pblock->RetrieveYValue();
			if (ystart == 0 && !oblock->mEntryRequiredRegs[CPU_REG_Y])
			{
				changed = OptimizeSimpleYIndexedLoop(pblock, oblock);
			}
		}
	}

	sz = mIns.Size();
	ai = 0;
	while (ai < sz && !mIns[ai].ReferencesYReg())
		ai++;

	if (ai < sz && mIns[ai].mType == ASMIT_LDY && mIns[ai].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[ai].mAddress, 0, ai) && 
		sz >= 2 && 
		mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)) &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[ai].mAddress)
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		prevBlock->mIns.Push(mIns[ai]);
		mIns[ai].mType = ASMIT_NOP; mIns[ai].mMode = ASMIM_IMPLIED;
		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;

		for (int i = 0; i < ai; i++)
			mIns[i].mLive |= LIVE_CPU_REG_Y;
		mExitRequiredRegs += CPU_REG_Y;
		mEntryRequiredRegs += CPU_REG_Y;
		prevBlock->mExitRequiredRegs += CPU_REG_Y;

		changed = true;
	}

#if 1
	if (mEntryRequiredRegs.Size() && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && (!mExitRequiredRegs[CPU_REG_A] || !mExitRequiredRegs[CPU_REG_X]) && !mExitRequiredRegs[CPU_REG_Z])
	{
		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
			{
				int j = 0;
				while (j < mIns.Size() &&
					(j == i + 0 || !mIns[j].ChangesZeroPage(mIns[i + 0].mAddress)) &&
					(j == i + 1 || !mIns[j].ChangesZeroPage(mIns[i + 1].mAddress)))
					j++;
				if (j == mIns.Size())
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);
					if (!mEntryRequiredRegs[CPU_REG_A])
					{
						assert(mIns[0].mType != ASMIT_STA);
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
					}
					else
					{
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
					}
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				}
				else if (j > i && !(mIns[i + 0].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[mIns[i + 1].mAddress] && !ReferencesZeroPage(mIns[i + 0].mAddress, 0, i))
				{
					int j = mIns.Size() - 1;

					while (j >= i + 2 && !mIns[j].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[j].ReferencesZeroPage(mIns[i + 1].mAddress))
						j--;

					if (j >= i + 2 && mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[i + 0].mAddress)
					{
						if (!prevBlock)
							return OptimizeSimpleLoopInvariant(proc, full);

						mIns[j].mAddress = mIns[i + 1].mAddress;

						if (!mEntryRequiredRegs[CPU_REG_A])
						{
							assert(mIns[0].mType != ASMIT_STA);
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
						}
						else
						{
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
						}

						prevBlock->mExitRequiredRegs += mIns[i + 1].mAddress;
						mEntryRequiredRegs += mIns[i + 1].mAddress;
						mExitRequiredRegs += mIns[i + 1].mAddress;
						if (!mExitRequiredRegs[CPU_REG_A])
						{
							exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
							exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						}
						else
						{
							exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
							exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						}
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
						changed = true;
					}
				}
			}
			else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					int j = 0;
					while (j < mIns.Size() &&
						(j == i + 1 || !mIns[j].ChangesZeroPage(mIns[i + 1].mAddress)))
						j++;
					if (j == mIns.Size())
					{
						if (!prevBlock)
							return OptimizeSimpleLoopInvariant(proc, full);

						int k = prevBlock->mIns.Size();
						while (k > 0 && (prevBlock->mIns[k - 1].mLive & LIVE_CPU_REG_A))
							k--;

						if (!mEntryRequiredRegs[CPU_REG_A])
						{
							assert(mIns[0].mType != ASMIT_STA);
							prevBlock->mIns.Insert(k, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 0].mAddress));
							prevBlock->mIns.Insert(k + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
						}
						else
						{
							prevBlock->mIns.Insert(k, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, mIns[i + 0].mAddress));
							prevBlock->mIns.Insert(k + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
						}
						mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					}
			}
		}
	}
#endif

#if 1
	if (mEntryRequiredRegs.Size() && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]) && (!mExitRequiredRegs[CPU_REG_A] || !mExitRequiredRegs[CPU_REG_X]))
	{
		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 &&
				!ChangesZeroPage(mIns[i + 1].mAddress, 0, i) && !ChangesZeroPage(mIns[i + 0].mAddress, 0, i))
			{
				int j = mIns.Size() - 1;
				while (j >= 0 && !mIns[j].ReferencesZeroPage(mIns[i + 1].mAddress))
					j--;
				if (j >= 0 && j + 1 < mIns.Size() &&
					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_STA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 1].mAddress == mIns[i + 0].mAddress)
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					if (!mEntryRequiredRegs[CPU_REG_A])
					{
						assert(mIns[0].mType != ASMIT_STA);
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
					}
					else
					{
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress));
					}
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}
	}
#endif

#if 1
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1)
		{
			int	treg = mIns[i + 3].mAddress;
			int	sreg = mIns[i + 1].mAddress;
			int areg = mIns[i + 2].mAddress;

			if (sreg != treg && areg != treg &&
				!mExitRequiredRegs[treg] && !mExitRequiredRegs[treg + 1] &&
				!ReferencesZeroPage(treg, 0, i) && !ReferencesZeroPage(treg + 1, 0, i) &&
				!ChangesZeroPage(treg, i + 7) && !ChangesZeroPage(treg + 1, i + 7) &&
				!ChangesZeroPage(sreg) && !ChangesZeroPage(sreg + 1))
			{
				int j = i + 7;
				while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(treg) && !mIns[j].ReferencesZeroPage(treg + 1) && !mIns[j].ChangesZeroPage(areg))
					j++;

				if (j < mIns.Size() && mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == treg)
				{
					if (mIns[j - 1].mType == ASMIT_LDY && mIns[j - 1].mMode == ASMIM_IMMEDIATE && !(mIns[j].mLive & LIVE_CPU_REG_Y) && !ReferencesZeroPage(treg, j + 1) && !ReferencesZeroPage(treg + 1, j + 1))
					{
						if (!prevBlock)
							return OptimizeSimpleLoopInvariant(proc, full);

						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_CLC));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_ADC, ASMIM_IMMEDIATE, mIns[j - 1].mAddress));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, treg));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 1));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
						prevBlock->mIns.Push(NativeCodeInstruction(mIns[j - 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1));
						prevBlock->mExitRequiredRegs += treg;
						prevBlock->mExitRequiredRegs += treg + 1;
						
						mIns[j - 1].mMode = ASMIM_ZERO_PAGE;
						mIns[j - 1].mAddress = areg;

						mEntryRequiredRegs += treg;
						mEntryRequiredRegs += treg + 1;
						mExitRequiredRegs += treg;
						mExitRequiredRegs += treg + 1;

						mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
						mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

						changed = true;
					}
				}
			}
		}
	}
#endif

#if 1
	sz = mIns.Size();
	if (sz >= 2 && mIns[sz - 2].mType == ASMIT_INX && mIns[sz - 1].mType == ASMIT_CPX && !mEntryRequiredRegs[CPU_REG_Y] && !mExitRequiredRegs[CPU_REG_Y])
	{
		int xtoy = -1;

		for (int i = 0; i < sz - 2; i++)
		{
			if (mIns[i].ChangesXReg())
			{
				xtoy = -1;
				break;
			}

			if (mIns[i].ChangesYReg())
			{
				if (xtoy >= 0)
				{
					xtoy = -1;
					break;
				}

				if (i >= 3 &&
					mIns[i - 0].mType == ASMIT_TAY &&
					mIns[i - 1].mType == ASMIT_ADC &&
					mIns[i - 2].mType == ASMIT_TXA &&
					mIns[i - 3].mType == ASMIT_CLC &&
					!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
					xtoy = i - 3;
				else
				{
					xtoy = -1;
					break;
				}
			}


		}

		if (xtoy >= 0)
		{
			int i = 0;
			while (i < sz && !mIns[xtoy + 1].MayBeChangedOnAddress(mIns[i]))
				i++;
			if (i == sz)
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				prevBlock->mIns.Push(mIns[xtoy + 0]);
				prevBlock->mIns.Push(mIns[xtoy + 1]);
				prevBlock->mIns.Push(mIns[xtoy + 2]);
				prevBlock->mIns.Push(mIns[xtoy + 3]);

				mIns.Insert(sz - 2, NativeCodeInstruction(mIns[xtoy].mIns, ASMIT_INY));

				mIns.Remove(xtoy, 4);
				for (int i = 0; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_Y;
				mEntryRequiredRegs += CPU_REG_Y;
				mExitRequiredRegs += CPU_REG_Y;
			}
		}
	}
#endif

#if 1
	sz = mIns.Size();
	if (sz >= 2 && (mBranch == ASMIT_BEQ && mFalseJump == this || mBranch == ASMIT_BNE && mTrueJump == this) &&
		((mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && !mEntryRequiredRegs[CPU_REG_A]) ||
		 (mIns[sz - 2].mType == ASMIT_LDX && mIns[sz - 1].mType == ASMIT_CPX && !mEntryRequiredRegs[CPU_REG_X]) ||
		 (mIns[sz - 2].mType == ASMIT_LDY && mIns[sz - 1].mType == ASMIT_CPY && !mEntryRequiredRegs[CPU_REG_Y])) &&
		mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE)
	{
		if (ChangesZeroPage(mIns[sz - 1].mAddress) && !ChangesZeroPage(mIns[sz - 2].mAddress))
		{
			int a = mIns[sz - 1].mAddress;
			mIns[sz - 1].mAddress = mIns[sz - 2].mAddress;
			mIns[sz - 2].mAddress = a;
			changed = true;
		}
	}
#endif

	CheckLive();

	// Special case of 16 bit shift with unused upper byte result
	if (mIns.Size() == 3 && mBranch == ASMIT_BNE && mTrueJump == this && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] &&
		mIns[0].mType == ASMIT_ASL && mIns[0].mMode == ASMIM_ZERO_PAGE &&
		mIns[1].mType == ASMIT_ROL && mIns[1].mMode == ASMIM_IMPLIED && !(mIns[1].mLive & LIVE_CPU_REG_C) &&
		mIns[2].mType == ASMIT_DEX)
	{
		if (!prevBlock)
			return OptimizeSimpleLoopInvariant(proc, full);

		prevBlock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDA, mIns[0]));
		prevBlock->mExitRequiredRegs += CPU_REG_A;

		exitBlock->mEntryRequiredRegs += CPU_REG_A;
		exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));

		mIns[0].mMode = ASMIM_IMPLIED;
		mIns[1].mType = ASMIT_NOP;


		changed = true;
	}

	CheckLive();

	if (sz >= 2 && (mIns[0].mType == ASMIT_ASL || mIns[0].mType == ASMIT_LSR) && mIns[0].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mIns[0]))
	{
		if (!ChangesZeroPage(mIns[0].mAddress, 1, sz - 1) && !ReferencesZeroPage(mIns[0].mAddress, 1, sz - 1) && !ReferencesAccu(0, sz - 1))
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);

			prevBlock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDA, mIns[0]));
			prevBlock->mExitRequiredRegs += CPU_REG_A;

			exitBlock->mEntryRequiredRegs += CPU_REG_A;
			exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STA, mIns[0]));

			mEntryRequiredRegs += CPU_REG_A;
			mExitRequiredRegs += CPU_REG_A;
			mIns[0].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = 0;

			for (int i = 0; i < sz; i++)
				mIns[i].mLive |= LIVE_CPU_REG_A;
			changed = true;
		}
	}

	CheckLive();

	if (sz >= 2 && (mIns[0].mType == ASMIT_DEC || mIns[0].mType == ASMIT_INC) && mIns[0].mMode == ASMIM_ZERO_PAGE && 
		mIns[1].mType == ASMIT_LDY && mIns[1].SameEffectiveAddress(mIns[0]))
	{
		int i = 2;
		int inc = 0;
		while (i < mIns.Size())
		{
			if (mIns[i].ChangesYReg())
			{
				if (mIns[i].mType == ASMIT_INY)
					inc++;
				else if (mIns[i].mType == ASMIT_DEY)
					inc--;
				else if (mIns[i].mType == ASMIT_LDY && mIns[i].SameEffectiveAddress(mIns[0]))
					inc = 0;
				else
					break;
			}
			else if (mIns[i].ChangesZeroPage(mIns[0].mAddress))
				break;
			i++;
		}

		if (i == mIns.Size() && inc == 0)
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			prevBlock->mIns.Push(NativeCodeInstruction(mIns[1].mIns, ASMIT_LDY, mIns[1]));
			prevBlock->mExitRequiredRegs += CPU_REG_Y;
			mEntryRequiredRegs += CPU_REG_Y;
			mExitRequiredRegs += CPU_REG_Y;
			mIns[1].mType = ASMIT_STY;
			mIns[0].mLive |= LIVE_CPU_REG_Y;
			if (mIns[0].mType == ASMIT_DEC)
				mIns[0].mType = ASMIT_DEY;
			else
				mIns[0].mType = ASMIT_INY;
			mIns[0].mMode = ASMIM_IMPLIED;
			changed = true;
		}
	}

	CheckLive();

	if (mIns.Size() > 0 && (mIns.Last().mType == ASMIT_DEX || mIns.Last().mType == ASMIT_DEC || mIns.Last().mType == ASMIT_CPX))
	{
		bool	yzero = false;

		if (prevBlock)
			yzero = prevBlock->RetrieveYValue(prevBlock->mIns.Size() - 1) == 0;

		int		nregs = 0;
		int		iregs[32];

		for (int i = 0; i + 3 < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
				yzero = true;
			else if (mIns[i].ChangesYReg())
			{
				nregs = 0;
				break;
			}

			if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				if (!yzero)
				{
					nregs = 0;
					break;
				}

				int reg = mIns[i].mAddress;

				if (ReferencesZeroPage(mIns[i].mAddress, 0, i) ||
					ReferencesZeroPage(mIns[i].mAddress + 1, 0, i))
				{
					nregs = 0;
					break;
				}
				if (exitBlock->mEntryRequiredRegs[reg] || exitBlock->mEntryRequiredRegs[reg + 1] || exitBlock->mEntryRequiredRegs[CPU_REG_Y])
				{
					nregs = 0;
					break;
				}

				int j = i + 1;
				while (j < mIns.Size() && (
					mIns[j].mMode == ASMIM_INDIRECT ||
					!(mIns[j].ReferencesZeroPage(reg) || mIns[j].ReferencesZeroPage(reg + 1))))
					j++;

				if (j == mIns.Size())
				{
					nregs = 0;
					break;
				}

				int sreg, dreg, offset;
				if (Is16BitAddSubImmediate(j - 1, sreg, dreg, offset) && sreg == reg && dreg == sreg && offset == 1)
				{
					if (ReferencesZeroPage(reg, j + 6) || ReferencesZeroPage(reg + 1, j + 6))
					{
						nregs = 0;
						break;
					}
					iregs[nregs++] = sreg;
				}
				else
				{
					nregs = 0;
					break;
				}
			}
		}

		if (nregs)
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);

			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE)
				{
					int j = 0;
					while (j < nregs && iregs[j] != mIns[i].mAddress && iregs[j] + 1 != mIns[i].mAddress)
						j++;
					if (j < nregs)
					{
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
				}
				else if (mIns[i].mType == ASMIT_LDY)
				{
					mIns[i].mType = ASMIT_NOP;
					mIns[i].mMode = ASMIM_IMPLIED;
				}

				mIns[i].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_A;
			}
			int j = mIns.Size();
			while (j > 0 && (mIns[j - 1].mLive & LIVE_CPU_REG_Z))
				j--;
			mIns.Insert(j, NativeCodeInstruction(mIns[0].mIns, ASMIT_INY));
			prevBlock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));

			changed = true;
		}
	}

	CheckLive();

	sz = mIns.Size();
	if (sz >= 3 && 
		mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
		!mIns[0].SameEffectiveAddress(mIns[sz - 2]) && mIns[sz - 1].mType == ASMIT_CMP && 
		!exitBlock->mEntryRequiredRegs[mIns[0].mAddress] && !exitBlock->mEntryRequiredRegs[mIns[sz - 2].mAddress] &&
		!ChangesZeroPage(mIns[0].mAddress, 1))
	{
		int ai = mIns[sz - 2].mAddress;
		int aj = mIns[0].mAddress;

		int i = 1;
		while (i < sz - 2 && (mIns[i].mMode == ASMIM_ZERO_PAGE || !mIns[i].ReferencesZeroPage(ai)))
			i++;
		if (i == sz - 2)
		{
			int i = 0;
			while (i < sz - 2 && !mIns[i].ChangesZeroPage(ai))
				i++;
			if (!ReferencesZeroPage(aj, i + 1, sz - 2))
			{
				int index;
				NativeCodeBasicBlock* block = this;

				if (IsExitARegZP(ai, index, block))
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					for (int i = 1; i < sz; i++)
					{
						if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == ai)
							mIns[i].mAddress = aj;
					}

					prevBlock->mIns.Push(mIns[0]);
					mIns.Remove(0);

					mExitRequiredRegs += aj;
					mEntryRequiredRegs += aj;

					CheckLive();

					return true;
				}
			}
		}

	}

	CheckLive();

	if (sz >= 3 && 
		mIns[0].mType == ASMIT_TAY && 
		mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 2].mType == ASMIT_TXA && mIns[sz - 3].mType == ASMIT_INX &&
		!mExitRequiredRegs[CPU_REG_Y] &&
		!ChangesXReg(0, sz - 3) && !ChangesYReg(1, sz - 3))
	{
		bool	canX = true, canY = false;

		for (int i = 0; i < sz - 3; i++)
		{
			if (mIns[i].mMode == ASMIM_ABSOLUTE_X && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y))
				canY = false;
			else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y && !HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_X))
				canX = false;
			else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
				canX = false;
			else if (mIns[i].mMode == ASMIM_INDIRECT_X)
				canY = false;
		}

		if (canX)
		{
			for (int i = 0; i < sz - 3; i++)
			{
				mIns[i].mLive |= LIVE_CPU_REG_X;
				if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
					mIns[i].mMode = ASMIM_ABSOLUTE_X;
			}
			return true;
		}
	}

	CheckLive();

#if 1
	// Exchange Y against low byte of pointer
	if (!ChangesYReg() && !mEntryRequiredRegs[CPU_REG_A] && !mExitRequiredRegs[CPU_REG_A])
	{
		int rind = -1;
		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_INDIRECT_Y)
			{
				if (rind == -1)
					rind = mIns[i].mAddress;
				else if (rind != mIns[i].mAddress)
				{
					rind = -2;
					break;
				}
			}
			else if (mIns[i].ReferencesYReg())
			{
				rind = -2;
				break;
			}
		}

		if (rind >= 0)
		{
			bool	found = false, ptruse = false;
			for (int i = 0; i < mIns.Size(); i++)
			{
				if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == rind)
				{
					if (i + 2 < mIns.Size() &&
						mIns[i].mType == ASMIT_LDA &&
						mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
						mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == rind && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
					{
						found = true;
						i += 2;
					}
					else if (mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA)
					{
						found = true;
						ptruse = true;
					}
					else
					{
						rind = -2;
						break;
					}
				}
				else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
					;
				else if (mIns[i].ReferencesZeroPage(rind))
				{
					rind = -2;
					break;
				}
			}

			if (rind >= 0 && found)
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				int yentry = pblock->RetrieveYValue(pblock->mIns.Size() - 1);

				// Need to have actual value if needed after loop, otherwise just keep counting from zero
				if (ptruse || exitBlock->mEntryRequiredRegs[rind] || exitBlock->mEntryRequiredRegs[rind + 1] || yentry < 0 && exitBlock->mEntryRequiredRegs[CPU_REG_Y])
				{
					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, rind));
					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, rind));
					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TAY));

					exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, rind));
					exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, rind));
					exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TAY));
				}
				else if (exitBlock->mEntryRequiredRegs[CPU_REG_Y])
					exitBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, yentry));

				for (int i = 0; i < mIns.Size(); i++)
				{
					mIns[i].mLive |= LIVE_CPU_REG_Y;
					if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == rind)
					{
						if (mIns[i].mType == ASMIT_LDA)
						{
							mIns[i].mType = ASMIT_TYA;
							mIns[i].mMode = ASMIM_IMPLIED;
						}
						else if (mIns[i].mType == ASMIT_STA)
						{
							mIns[i].mType = ASMIT_TAY;
							mIns[i].mMode = ASMIM_IMPLIED;
						}
					}
				}

				prevBlock->mExitRequiredRegs += CPU_REG_Y;
				mEntryRequiredRegs += CPU_REG_Y;
				mExitRequiredRegs += CPU_REG_Y;
				exitBlock->mEntryRequiredRegs += CPU_REG_Y;
				changed = true;
			}
		}
	}
#endif

	if (!changed && !mEntryRequiredRegs[CPU_REG_Y] && !mExitRequiredRegs[CPU_REG_Y] && !mEntryRequiredRegs[CPU_REG_A])
	{
		int firsty = 0;
		while (firsty + 2 < mIns.Size() && !mIns[firsty].ReferencesYReg())
			firsty++;
		if (firsty + 2 < mIns.Size() && mIns[firsty].mType == ASMIT_LDY && mIns[firsty].mMode == ASMIM_IMMEDIATE && mIns[firsty].mAddress == 0 && mIns[firsty + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[firsty + 1].mLive & LIVE_CPU_REG_Y))
		{
			int reg = mIns[firsty + 1].mAddress;
			int lastz = mIns.Size() - 1;
			while (lastz > firsty && !mIns[lastz].ReferencesZeroPage(reg))
				lastz--;
			if (lastz > firsty && mIns[lastz].mType == ASMIT_STA && mIns[lastz].mMode == ASMIM_ZERO_PAGE && !ReferencesYReg(lastz))
			{
				int i = firsty + 2;
				while (i < lastz && !((mIns[i].ReferencesZeroPage(reg) || mIns[i].ChangesYReg()) && (mIns[i].mType != ASMIT_LDY || mIns[i].mMode != ASMIM_ZERO_PAGE || mIns[i].mAddress != reg)))
					i++;

				if (i == lastz)
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));

					mIns[firsty].mType = ASMIT_NOP; mIns[firsty].mMode = ASMIM_IMPLIED;
					for (int i = firsty + 2; i < lastz; i++)
					{
						if (mIns[i].mType == ASMIT_LDY)
						{
							mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
						}
					}
					mIns[lastz].mType = ASMIT_TAY; mIns[lastz].mMode = ASMIM_IMPLIED;
					for (int i = 0; i < mIns.Size(); i++)
						mIns[i].mLive |= LIVE_CPU_REG_Y;
					mEntryRequiredRegs += CPU_REG_Y;
					mExitRequiredRegs += CPU_REG_Y;
					exitBlock->mEntryRequiredRegs += CPU_REG_Y;
					exitBlock->mIns.Insert(0, NativeCodeInstruction(mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, reg));
					changed = true;
				}
			}
		}
	}

	if (!changed && mIns.Size() >= 3)
	{
		int sz = mIns.Size();
		if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz - 2].mType == ASMIT_LDX && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 3].mAddress &&
			mIns[sz - 1].mType == ASMIT_CPX)
		{
			int reg = mIns[sz - 3].mAddress;
			int index;
			NativeCodeBasicBlock* xblock = mEntryBlocks[0] == this ? mEntryBlocks[1] : mEntryBlocks[0];
			if (!ReferencesZeroPage(reg, 0, sz - 3) && !ChangesXReg(0, sz - 3) && xblock->IsExitXRegZP(reg, index, xblock))
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				exitBlock->mIns.Insert(0, NativeCodeInstruction(mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
				mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
				mIns[sz - 2].mType = ASMIT_INX; mIns[sz - 2].mMode = ASMIM_IMPLIED;

				for (int i = 0; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_X;
				mEntryRequiredRegs += CPU_REG_X;
				mExitRequiredRegs += CPU_REG_X;
				exitBlock->mEntryRequiredRegs += CPU_REG_X;
				changed = true;
			}
		}
	}

	sz = mIns.Size();
	if (sz >= 5 && mIns[0].mType == ASMIT_TXA && mIns[1].mType == ASMIT_TAY && mIns[sz - 2].mType == ASMIT_INX && mIns[sz - 1].mType == ASMIT_CPX && !exitBlock->mEntryRequiredRegs[CPU_REG_X])
	{
		int i = 2;
		while (i < sz - 2 && !mIns[i].ChangesXReg() && !mIns[i].ChangesYReg() && 
			(mIns[i].mMode != ASMIM_ABSOLUTE_X || HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y)))
			i++;

		if (i == sz - 2)
		{
			if (!prevBlock)
				return OptimizeSimpleLoopInvariant(proc, full);
			prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TXA));
			prevBlock->mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_TAY));
			mIns[0].mType = ASMIT_NOP;
			mIns[1].mType = ASMIT_TYA;
			for (int i = 0; i < sz; i++)
			{
				mIns[i].ReplaceXRegWithYReg();
				mIns[i].mLive |= LIVE_CPU_REG_Y;
			}
			mEntryRequiredRegs += CPU_REG_Y;
			mExitRequiredRegs += CPU_REG_Y;
			changed = true;
		}
	}

	sz = mIns.Size();
	if (pblock && sz >= 2 && mIns[sz - 2].mType == ASMIT_INY && mIns[sz - 1].mType == ASMIT_DEX && 
		mBranch == ASMIT_BNE && mTrueJump == this && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] &&
		!ReferencesXReg(0, mIns.Size() - 1) && !ChangesYReg(0, mIns.Size() - 2))
	{
		int xval = pblock->RetrieveXValue(), yval = pblock->RetrieveYValue();
		if (xval > 0 && yval >= 0)
		{
			mIns[sz - 1].mType = ASMIT_CPY;
			mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
			mIns[sz - 1].mAddress = yval + xval;
			changed = true;
		}
	}

	// Optimize for single inc/dec zero page variables

	for (int i = 0; i < mIns.Size(); i++)
	{
		if ((mIns[i].mType == ASMIT_INC || mIns[i].mType == ASMIT_DEC) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
		{
			int reg = mIns[i].mAddress;
			if (!ChangesZeroPage(reg, 0, i) && !ReferencesZeroPage(reg, i + 1) && !exitBlock->mEntryRequiredRegs[reg])
			{
				int k = 0;
				while (k < i && !mIns[k].ReferencesZeroPage(reg))
					k++;
				if (k > 0 && k < i && !ReferencesZeroPage(reg, k + 1, i))
				{
					if (mIns[k - 1].mType == ASMIT_CLC && mIns[k].mType == ASMIT_LDA && mIns[k + 1].mType == ASMIT_ADC && !(mIns[k + 1].mLive & LIVE_CPU_REG_C))
					{
						if (mIns[k + 1].mMode == ASMIM_IMMEDIATE ||
							mIns[k + 1].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[k + 1].mAddress))
						{
							if (!prevBlock)
								return OptimizeSimpleLoopInvariant(proc, full);
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_CLC));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_ADC, mIns[k + 1]));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
							mIns[k + 1].mType = ASMIT_NOP;
							mIns[k + 1].mMode = ASMIM_IMPLIED;
							changed = true;
						}
					}
					else if (k > 1 && mIns[k - 2].mType == ASMIT_CLC && mIns[k - 1].mType == ASMIT_LDA && mIns[k].mType == ASMIT_ADC && !(mIns[k].mLive & LIVE_CPU_REG_C))
					{
						if (mIns[k - 1].mMode == ASMIM_IMMEDIATE ||
							mIns[k - 1].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[k - 1].mAddress))
						{
							if (!prevBlock)
								return OptimizeSimpleLoopInvariant(proc, full);
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_CLC));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_ADC, mIns[k - 1]));
							prevBlock->mIns.Push(NativeCodeInstruction(mIns[k].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
							mIns[k - 1].mType = ASMIT_NOP;
							mIns[k - 1].mMode = ASMIM_IMPLIED;
							mIns[k].mType = ASMIT_LDA;
							changed = true;
						}
					}
				}
			}
		}
	}

	ai = mIns.Size() - 1;
	while (ai >= 0 && !(mIns[ai].ChangesAccu() || mIns[ai].mType == ASMIT_STA && mIns[ai].mMode == ASMIM_ZERO_PAGE))
		ai--;
	if (ai >= 0 && mIns[ai].mType == ASMIT_STA && !ChangesZeroPage(mIns[ai].mAddress, ai + 1))
	{
		int reg = mIns[ai].mAddress;
		int zi = 0;
		while (zi < mIns.Size() && !(mIns[zi].ChangesAccu() || mIns[zi].ReferencesZeroPage(reg)))
			zi++;
		if (zi < mIns.Size())
		{
			if (mIns[zi].IsShift() && mIns[zi].mMode == ASMIM_ZERO_PAGE && !(mIns[zi].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
			{
				if (!prevBlock)
					return OptimizeSimpleLoopInvariant(proc, full);

				prevBlock->mIns.Push(NativeCodeInstruction(mIns[zi].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, reg));
				mIns[zi].mMode = ASMIM_IMPLIED;
				for (int i = 0; i < zi; i++)
					mIns[i].mLive |= LIVE_CPU_REG_A;
				for (int i = ai; i < mIns.Size(); i++)
					mIns[i].mLive |= LIVE_CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
				mEntryRequiredRegs += CPU_REG_A;
				prevBlock->mExitRequiredRegs += CPU_REG_A;
				changed = true;
			}
		}
	}

	sz = mIns.Size();
	if (sz >= 4)
	{
		if (mIns[sz - 1].mType == ASMIT_CMP &&
			mIns[sz - 2].mType == ASMIT_LDA && (mIns[sz - 2].mMode == ASMIM_ZERO_PAGE || mIns[sz - 2].mMode == ASMIM_ABSOLUTE) &&
			(mIns[sz - 3].mType == ASMIT_INC || mIns[sz - 3].mType == ASMIT_DEC) && mIns[sz - 3].SameEffectiveAddress(mIns[sz - 2]) &&
			!(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			if (HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_X))
			{
				int k = sz - 4;
				while (k >= 0 && !mIns[k].ChangesXReg())
					k--;

				if (k >= 0 && mIns[k].mType == ASMIT_LDX && mIns[k].SameEffectiveAddress(mIns[sz - 3]))
				{
					mIns[sz - 1].mType = ASMIT_CPX;
					mIns[sz - 2].mType = ASMIT_STX;
					mIns[sz - 3].mType = mIns[sz - 3].mType == ASMIT_DEC ? ASMIT_DEX : ASMIT_INX;
					mIns[sz - 3].mMode = ASMIM_IMPLIED;
					while (k < sz - 1)
					{
						mIns[k].mLive |= LIVE_CPU_REG_X;
						k++;
					}
					changed = true;
				}
			}
		}
	}

	sz = mIns.Size();
	if (sz >= 5)
	{
		if (mIns[0].mType == ASMIT_STA && mIns[0].mMode == ASMIM_ZERO_PAGE &&
			mIns[sz - 4].mType == ASMIT_CLC &&
			mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[0].mAddress &&
			mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
			mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mBranch == ASMIT_BNE &&
			!ReferencesZeroPage(mIns[0].mAddress, 1, sz - 4) && !mFalseJump->mEntryRequiredRegs[mIns[0].mAddress] && pblock)
		{
			int aexit = mIns[sz - 1].mAddress;
			int aimm = pblock->RetrieveAValue(pblock->mIns.Size() - 1, 2);
			if (aimm >= 0)
			{
				if (mIns[1].mType == ASMIT_CLC &&
					mIns[2].mType == ASMIT_ADC && (mIns[2].mMode == ASMIM_IMMEDIATE || mIns[2].mMode == ASMIM_IMMEDIATE_ADDRESS))
				{
					if (!prevBlock)
						return OptimizeSimpleLoopInvariant(proc, full);

					prevBlock->mIns.Push(NativeCodeInstruction(mIns[2].mIns, ASMIT_LDA, mIns[2]));
					int pz = prevBlock->mIns.Size();
					prevBlock->mIns[pz-1].mAddress += aimm;
					mIns[sz - 1].CopyMode(mIns[2]);
					mIns[sz - 1].mAddress += aexit;
					mIns[2].mMode = ASMIM_IMMEDIATE;
					mIns[2].mAddress = 0;
					changed = true;
				}
			}
		}

	}


	sz = mIns.Size();
	if (full && pblock && mBranch == ASMIT_BCC && mTrueJump == this && sz >= 2 && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mIns[sz - 2].mType == ASMIT_INX && mIns[sz - 1].mType == ASMIT_CPX && !ChangesXReg(0, sz - 2) &&
			(mIns[sz - 1].mMode == ASMIM_IMMEDIATE || mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[sz - 1].mAddress)) && pblock->RetrieveXValue() == 0)
		{
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			mBranch = ASMIT_BNE;
			changed = true;
		}
		else if (mIns[sz - 2].mType == ASMIT_INY && mIns[sz - 1].mType == ASMIT_CPY && !ChangesYReg(0, sz - 2) &&
			(mIns[sz - 1].mMode == ASMIM_IMMEDIATE || mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[sz - 1].mAddress)) && pblock->RetrieveYValue() == 0)
		{
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			mBranch = ASMIT_BNE;
			changed = true;
		}
	}

#if 1
	// Check X and Y same increment
	if (sz >= 6)
	{
		int xi = 0;
		while (xi < mIns.Size() && mIns[xi].mType != ASMIT_TXA)
			xi++;
		int yi = 0;
		while (yi < mIns.Size() && mIns[yi].mType != ASMIT_TYA)
			yi++;
		if (xi + 3 < mIns.Size() && yi + 3 < mIns.Size())
		{
			if (mIns[xi + 1].mType == ASMIT_CLC && mIns[xi + 2].mType == ASMIT_ADC && mIns[xi + 2].mMode == ASMIM_IMMEDIATE && mIns[xi + 3].mType == ASMIT_TAX &&
				mIns[yi + 1].mType == ASMIT_CLC && mIns[yi + 2].mType == ASMIT_ADC && mIns[yi + 2].mMode == ASMIM_IMMEDIATE && mIns[yi + 3].mType == ASMIT_TAY &&
				mIns[xi + 2].mAddress == mIns[yi + 2].mAddress)
			{
				if (!ChangesXReg(0, xi) && !ChangesXReg(xi + 4) && !ChangesYReg(0, yi) && !ChangesYReg(yi + 4))
				{
					if (pblock)
					{
						int ystart = pblock->RetrieveYValue(pblock->mIns.Size() - 1);
						int xstart = pblock->RetrieveXValue(pblock->mIns.Size() - 1);

						if (ystart >= 0 && xstart >= 0)
						{
							if (!prevBlock)
								return OptimizeSimpleLoopInvariant(proc, full);

							if (xi < yi)
							{
								mIns[xi + 0].mType = ASMIT_TYA;
								if (!ReferencesXReg(0, xi) && !ReferencesXReg(xi + 4) && !exitBlock->mEntryRequiredRegs[CPU_REG_A])
								{
									exitBlock->mEntryRequiredRegs += CPU_REG_Y;
									mIns[xi + 3].mType = ASMIT_NOP;
									exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[xi + 0].mIns, ASMIT_TYA));
									exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[xi + 0].mIns, ASMIT_TAX));
								}
							}
							else
							{
								mIns[yi + 0].mType = ASMIT_TXA;
								if (!ReferencesYReg(0, yi) && !ReferencesYReg(yi + 4) && !exitBlock->mEntryRequiredRegs[CPU_REG_A])
								{
									exitBlock->mEntryRequiredRegs += CPU_REG_X;
									mIns[yi + 3].mType = ASMIT_NOP;
									exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[yi + 0].mIns, ASMIT_TXA));
									exitBlock->mIns.Insert(1, NativeCodeInstruction(mIns[yi + 0].mIns, ASMIT_TAY));
								}
							}
							changed = true;
						}
					}
				}
			}
		}
	}
#endif
	return changed;
}

bool NativeCodeBasicBlock::SimpleLoopReversal(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();


		if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 1 &&
			mTrueJump->mBranch == ASMIT_BNE)
		{
			NativeCodeBasicBlock* lb = mTrueJump;
			int	lbs = lb->mIns.Size();

			if ((lb->mIns[lbs - 2].mType == ASMIT_ROL || lb->mIns[lbs - 2].mType == ASMIT_ROR) && lb->mIns[lbs - 2].mMode == ASMIM_ZERO_PAGE &&
				lb->mIns[lbs - 1].mType == ASMIT_DEC && lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE && !(lb->mIns[lbs - 1].mLive & LIVE_CPU_REG_C))
			{
				if (!lb->ReferencesZeroPage(lb->mIns[lbs - 1].mAddress, 0, lbs - 1) && !lb->ReferencesZeroPage(lb->mIns[lbs - 2].mAddress, 0, lbs - 2) &&
					!lb->mFalseJump->mEntryRequiredRegs[lb->mIns[lbs - 1].mAddress])
				{
					int	lcount = RetrieveZPValue(lb->mIns[lbs - 1].mAddress, mIns.Size() - 1);
					int lshift = RetrieveZPValue(lb->mIns[lbs - 2].mAddress, mIns.Size() - 1);

					if (lcount <= 8 && lshift == 0)
					{
						if (!mExitRequiredRegs[CPU_REG_A])
						{
							if (lb->mIns[lbs - 2].mType == ASMIT_ROR)
								mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (lcount - 1)));
							else
								mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (8 - lcount)));

							mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, lb->mIns[lbs - 2].mAddress));
							lb->mBranch = ASMIT_BCC;
							lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
							lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_C;
							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 1 && 
			mTrueJump->mBranch == ASMIT_BCC && !mExitRequiredRegs[CPU_REG_C])
		{
			NativeCodeBasicBlock* lb = mTrueJump;
			NativeCodeBasicBlock* eb = mTrueJump->mFalseJump;

			int	lbs = lb->mIns.Size();

			if (lb->mIns[lbs-1].mType == ASMIT_CPX)
			{
				int li = mIns.Size() - 1;
				while (li >= 0 && !mIns[li].ChangesXReg())
					li--;

				if (li >= 0 && lb->mIns[lbs-2].mType == ASMIT_INX && mIns[li].mType == ASMIT_LDX && mIns[li].mMode == ASMIM_IMMEDIATE)
				{
					if (lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE && mIns[li].mAddress == 0)
					{
						int	a = lb->mIns[lbs - 1].mAddress;

						int	i = 0;
						while (i + 2 < lbs && !(lb->mIns[i].RequiresXReg() || lb->mIns[i].ChangesZeroPage(a)))
							i++;
						if (i + 2 == lbs)
						{
							mIns[li].mMode = ASMIM_ZERO_PAGE;
							mIns[li].mAddress = a;
							lb->mIns[lbs - 2].mType = ASMIT_DEX; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
							lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
							lb->mBranch = ASMIT_BNE;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, mIns[li]));
							changed = true;

							CheckLive();

						}
					}
					else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
					{
						int finalx = lb->mIns[lbs - 1].mAddress;
						int	a = lb->mIns[lbs - 1].mAddress - mIns[li].mAddress;
						if (a <= 0)
						{
							finalx = mIns[li].mAddress + 1;
							a = 1;
						}

						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].mLinkerObject && !(lb->mIns[0].mFlags & NCIF_VOLATILE) && a <= 40)))
						{
							lb->mIns[0].mAddress += mIns[li].mAddress;
							mIns[li].mAddress = a - 1;
							lb->mIns[1].mType = ASMIT_DEX; lb->mIns[1].mLive |= LIVE_CPU_REG_Z;
							lb->mIns[2].mType = ASMIT_NOP; lb->mIns[2].mMode = ASMIM_IMPLIED;
							lb->mBranch = ASMIT_BPL;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, finalx));
							changed = true;
						}
						else
						{
							int	i = 0;
							while (i + 2 < lbs && !lb->mIns[i].RequiresXReg())
								i++;
							if (i + 2 == lbs)
							{
								mIns[li].mAddress = a;
								lb->mIns[lbs - 2].mType = ASMIT_DEX; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
								lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
								lb->mBranch = ASMIT_BNE;
								eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, finalx));
								changed = true;

								CheckLive();

							}
						}

						if (a == 1 && changed)
						{
							lb->mBranch = ASMIT_JMP;
							lb->mTrueJump->mEntryBlocks.RemoveAll(lb);
							lb->mTrueJump->mNumEntries--;
							lb->mTrueJump = lb->mFalseJump;
							lb->mFalseJump = nullptr;
						}
					}
				}

			}
			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)
				{
					if (lb->mIns[lbs - 1].mMode == ASMIM_ZERO_PAGE)
					{
						int	a = lb->mIns[lbs - 1].mAddress - mIns[li].mAddress;

						int	i = 0;
						while (i + 2 < lbs && !(lb->mIns[i].RequiresYReg() || lb->mIns[i].ChangesZeroPage(a)))
							i++;
						if (i + 2 == lbs)
						{
							mIns[li].mMode = ASMIM_ZERO_PAGE;
							mIns[li].mAddress = a;
							lb->mIns[lbs - 2].mType = ASMIT_DEY; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
							lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
							lb->mBranch = ASMIT_BNE;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, mIns[li]));
							changed = true;

							CheckLive();
						}
					}
					else if (lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
					{
						int finaly = lb->mIns[lbs - 1].mAddress;
						int	a = lb->mIns[lbs - 1].mAddress - mIns[li].mAddress;

						if (a <= 0)
						{
							finaly = mIns[li].mAddress + 1;
							a = 1;
						}

						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].mLinkerObject && !(lb->mIns[0].mFlags & NCIF_VOLATILE) && a <= 40)))
						{
							lb->mIns[0].mAddress += mIns[li].mAddress;
							mIns[li].mAddress = a - 1;
							lb->mIns[1].mType = ASMIT_DEY; lb->mIns[1].mLive |= LIVE_CPU_REG_Z;
							lb->mIns[2].mType = ASMIT_NOP; lb->mIns[2].mMode = ASMIM_IMPLIED;
							lb->mBranch = ASMIT_BPL;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
							changed = true;

							CheckLive();
							
						}
						else if (lbs == 3 && lb->mIns[0].mType == ASMIT_STA && lb->mIns[0].mMode == ASMIM_INDIRECT_Y && !(lb->mIns[0].mFlags & NCIF_VOLATILE) && a <= 40 && mIns[li].mAddress == 0)
						{
							mIns[li].mAddress = a - 1;
							lb->mIns[1].mType = ASMIT_DEY; lb->mIns[1].mLive |= LIVE_CPU_REG_Z;
							lb->mIns[2].mType = ASMIT_NOP; lb->mIns[2].mMode = ASMIM_IMPLIED;
							lb->mBranch = ASMIT_BPL;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
							changed = true;

							CheckLive();
						}
						else if (lbs == 3 && lb->mIns[0].mType == ASMIT_STA && lb->mIns[0].mMode == ASMIM_INDIRECT_Y && !(lb->mIns[0].mFlags & NCIF_VOLATILE) && a <= 40 && mIns[li].mAddress == 1)
						{
							mIns[li].mAddress = a;
							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_BNE;
							eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
							changed = true;

							CheckLive();
						}
						else
						{
							int	i = 0;
							while (i + 2 < lbs && !lb->mIns[i].RequiresYReg())
								i++;
							if (i + 2 == lbs)
							{
								mIns[li].mAddress = a;
								lb->mIns[lbs - 2].mType = ASMIT_DEY; lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_Z;
								lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
								lb->mBranch = ASMIT_BNE;
								eb->mIns.Insert(0, NativeCodeInstruction(lb->mIns[lbs - 1].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, finaly));
								changed = true;

								CheckLive();

							}
						}

						if (a == 1 && changed)
						{
							lb->mBranch = ASMIT_JMP;
							lb->mTrueJump->mEntryBlocks.RemoveAll(lb);
							lb->mTrueJump->mNumEntries--;
							lb->mTrueJump = lb->mFalseJump;
							lb->mFalseJump = nullptr;
						}
					}
				}
			}
		}

		if (mTrueJump && !mFalseJump && mTrueJump->mTrueJump == mTrueJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 2 &&
			mTrueJump->mBranch == ASMIT_BCC)
		{
			NativeCodeBasicBlock* lb = mTrueJump;
			int	lbs = lb->mIns.Size();

			if ((lb->mIns[lbs - 3].mType == ASMIT_ROL || lb->mIns[lbs - 3].mType == ASMIT_ROR) && lb->mIns[lbs - 3].mMode == ASMIM_ZERO_PAGE &&
				lb->mIns[lbs - 2].mType == ASMIT_INY && 
				lb->mIns[lbs - 1].mType == ASMIT_CPY && lb->mIns[lbs - 1].mMode == ASMIM_IMMEDIATE)
			{
				if (!lb->ReferencesZeroPage(lb->mIns[lbs - 3].mAddress, 0, lbs - 3))
				{
					int ystart = RetrieveYValue(mIns.Size() - 1);
					int	lcount = lb->mIns[lbs - 1].mAddress - ystart;
					int lshift = RetrieveZPValue(lb->mIns[lbs - 3].mAddress, mIns.Size() - 1);

					if (ystart >= 0 && lcount <= 8 && lshift == 0)
					{
						if (!mExitRequiredRegs[CPU_REG_A])
						{
							if (lb->mIns[lbs - 2].mType == ASMIT_ROR)
								mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (lcount - 1)));
							else
								mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 1LL << (8 - lcount)));

							mIns.Push(NativeCodeInstruction(lb->mIns[lbs - 2].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, lb->mIns[lbs - 3].mAddress));
							lb->mBranch = ASMIT_BCC;
							lb->mIns[lbs - 1].mType = ASMIT_NOP; lb->mIns[lbs - 1].mMode = ASMIM_IMPLIED;
							lb->mIns[lbs - 2].mLive |= LIVE_CPU_REG_C;
							lb->mIns[lbs - 3].mLive |= LIVE_CPU_REG_C;
							changed = true;
						}
					}
				}
			}
		}


		if (mTrueJump && mTrueJump->SimpleLoopReversal(proc))
			changed = true;
		if (mFalseJump && mFalseJump->SimpleLoopReversal(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeXYSpilling(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && (mTrueJump == this || mFalseJump == this) && mEntryBlocks.Size() == 2)
		{
			NativeCodeBasicBlock* pblock = mEntryBlocks[0];
			if (pblock == this)
				pblock = mEntryBlocks[1];
			NativeCodeBasicBlock* nblock = mTrueJump;
			if (nblock == this)
				nblock = mFalseJump;

			if (nblock)
			{
				int ps = pblock->mIns.Size();
				if (nblock->mEntryBlocks.Size() == 1 && !pblock->mFalseJump && ps > 0)
				{
					if (!ReferencesAccu())
					{
						if (!ReferencesXReg() && pblock->mIns.Size() > 0 && pblock->mIns[ps - 1].mType == ASMIT_TAX)
						{
							nblock->mIns.Insert(0, NativeCodeInstruction(pblock->mIns[ps - 1].mIns, ASMIT_TAX));
							pblock->mIns.Remove(ps - 1);
							ps--;
							pblock->mExitRequiredRegs += CPU_REG_A;
							nblock->mEntryRequiredRegs += CPU_REG_A;
							mEntryRequiredRegs += CPU_REG_A;
							mExitRequiredRegs += CPU_REG_A;
							for (int i = 0; i < mIns.Size(); i++)
								mIns[i].mLive |= LIVE_CPU_REG_A;
							changed = true;
						}

						if (!ReferencesYReg() && pblock->mIns.Size() > 0 && pblock->mIns[ps - 1].mType == ASMIT_TAY)
						{
							nblock->mIns.Insert(0, NativeCodeInstruction(pblock->mIns[ps - 1].mIns, ASMIT_TAY));
							pblock->mIns.Remove(ps - 1);
							ps--;
							pblock->mExitRequiredRegs += CPU_REG_A;
							nblock->mEntryRequiredRegs += CPU_REG_A;
							mEntryRequiredRegs += CPU_REG_A;
							mExitRequiredRegs += CPU_REG_A;
							for (int i = 0; i < mIns.Size(); i++)
								mIns[i].mLive |= LIVE_CPU_REG_A;
							changed = true;
						}
					}
				}
			}
		}

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (i + 2 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_TAX &&
					mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
					mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
					mIns.Insert(i + 3, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
					mIns.Remove(i);
					changed = true;
				}
				else if (mIns[i + 0].mType == ASMIT_TAY &&
					mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Y;
					mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
					mIns.Insert(i + 3, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY));
					mIns.Remove(i);
					changed = true;
				}
			}
			
			if (i + 1 < mIns.Size())
			{
				if (mIns[i + 0].mType == ASMIT_TAX && !mIns[i + 1].ChangesAccu() && !mIns[i + 1].ReferencesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
				{
					mIns[i + 1].mLive |= LIVE_CPU_REG_A;
					mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
					mIns.Remove(i);
					changed = true;
				}
				else if (mIns[i + 0].mType == ASMIT_TAY && !mIns[i + 1].ChangesAccu() && !mIns[i + 1].ReferencesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
				{
					mIns[i + 1].mLive |= LIVE_CPU_REG_A;
					mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY));
					mIns.Remove(i);
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->OptimizeXYSpilling())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeXYSpilling())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeXYSimpleLoop(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mTrueJump && mFalseJump && mEntryBlocks.Size() == 2)
		{
			NativeCodeBasicBlock	* pblock, * eblock;
			if (mTrueJump == this)
				eblock = mFalseJump;
			else
				eblock = mTrueJump;

			if (mEntryBlocks[0] == this)
				pblock = mEntryBlocks[1];
			else
				pblock = mEntryBlocks[0];

			int	sz = mIns.Size();

			if (sz > 2 && mIns[sz - 2].mType == ASMIT_STY && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mType == ASMIT_CPY)
			{
				int addr = mIns[sz - 2].mAddress;
				int psz = pblock->mIns.Size();
				if (psz > 0 && pblock->mIns[psz - 1].mType == ASMIT_STY && pblock->mIns[psz - 1].mMode == ASMIM_ZERO_PAGE && pblock->mIns[psz - 1].mAddress == addr)
				{
					int i = 0;
					while (i + 2 < sz && !mIns[i].ChangesYReg() && !mIns[i].ChangesZeroPage(addr) && (mIns[i].mLive & LIVE_CPU_REG_Y))
					{
						if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
						{
							mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
							changed = true;
						}
						else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == addr)
						{
							mIns[i + 1].CopyMode(mIns[i]);
							mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED;
							changed = true;
						}

						i++;
					}
				}
			}

#if 1
			if (sz > 2 && mIns[sz - 2].mType == ASMIT_INY && mIns[sz - 1].mType == ASMIT_CPY)
			{
				int i = 0;
				while (i < sz - 2 && !mIns[i].ChangesYReg())
					i++;

				// y register is simple loop increment
				if (i == sz - 2)
				{
					i = 0;
					while (i < sz && !mIns[i].ReferencesXReg())
						i++;
					if (i < sz && i >= 3 && mIns[i].mType == ASMIT_TAX && mIns[i - 3].mType == ASMIT_TYA && mIns[i - 2].mType == ASMIT_CLC && mIns[i - 1].mType == ASMIT_ADC)
					{
						int j = i + 4;
						while (j < sz && !mIns[j].ChangesXReg())
							j++;
						if (j == sz)
						{
							j = 0;
							while (j < sz && !mIns[i - 1].MayBeChangedOnAddress(mIns[j]))
								j++;
							if (j == sz)
							{
								for (int j = 0; j < 4; j++)
								{
									pblock->mIns.Push(mIns[i - 3 + j]);
									mIns[i - 3 + j].mType = ASMIT_NOP; mIns[i - 3 + j].mMode = ASMIM_IMPLIED;
								}

								for (int j = 0; j < sz; j++)
									mIns[j].mLive |= LIVE_CPU_REG_X;

								mIns.Insert(sz - 2, NativeCodeInstruction(mIns[i - 3].mIns, ASMIT_INX));
								sz++;
								changed = true;
								mEntryRequiredRegs += CPU_REG_X;
								mExitRequiredRegs += CPU_REG_X;
								pblock->mExitRequiredRegs += CPU_REG_X;
							}
						}
					}
				}
				else if (sz > 5 &&
					mIns[0].mType == ASMIT_STY && mIns[0].mMode == ASMIM_ZERO_PAGE &&
					mIns[sz - 3].mType == ASMIT_LDY && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && mIns[0].mAddress == mIns[sz - 3].mAddress &&
					!ChangesZeroPage(mIns[0].mAddress, 1, sz - 3) && !(mIns[sz - 3].mLive & LIVE_CPU_REG_X))
				{
					int j = 0;
					while (j < sz - 3 && !(mIns[j].ChangesYReg() || mIns[j].mType == ASMIT_LDX && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[0].mAddress))
						j++;
					if (mIns[j].mType == ASMIT_LDX && !ChangesXReg(j + 1, sz - 3))
					{
						int k = j + 1;
						while (k < sz - 3 && mIns[k].CanSwapXYReg())
							k++;
						if (k == sz - 3)
						{
							for (k = j + 1; k < sz - 3; k++)
								mIns[k].SwapXYReg();

							for (k = 0; k < sz; k++)
								mIns[k].mLive |= LIVE_CPU_REG_Y;

							mIns[j].mType = ASMIT_NOP; mIns[j].mMode = ASMIM_IMPLIED;
							mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
							changed = true;
						}
					}
				}
			}
#endif
		}

		if (mTrueJump && mTrueJump->OptimizeXYSimpleLoop())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeXYSimpleLoop())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeSimpleFixLoop(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mFalseJump && mNumEntries == 2)
		{
			NativeCodeBasicBlock* lbody = nullptr, * eblock = nullptr, * pblock = nullptr;
			AsmInsType	bins = mBranch;

			if (mTrueJump == this)
				eblock = mFalseJump;
			else if (mFalseJump == this)
			{
				eblock = mTrueJump;
				bins = InvertBranchCondition(bins);
			}

			if (eblock)
			{
				if (mEntryBlocks[0] == this)
					pblock = mEntryBlocks[1];
				else
					pblock = mEntryBlocks[0];

				int nloop = -1;
				int sz = mIns.Size();

				if (sz > 1 && mIns[sz - 1].mType == ASMIT_DEX && bins == ASMIT_BNE && !ChangesXReg(0, sz - 1))
				{
					int xval = pblock->RetrieveXValue(pblock->mIns.Size() - 1);
					if (xval == 0)
						nloop = 256;
					else
						nloop = xval;
					sz -= 1;
				}
				else if (sz > 2 && bins == ASMIT_BNE &&
					mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
					mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE_ADDRESS && 
					mIns[sz - 1].mLinkerObject && (mIns[sz - 1].mFlags & NCIF_LOWER))
				{
					int reg = mIns[sz - 2].mAddress;
					int k = 0;
					while (k < mIns.Size() && !mIns[k].ChangesZeroPage(reg))
						k++;
					if (k < mIns.Size() && k >= 3 && !ChangesZeroPage(reg, k + 1))
					{
						if (mIns[k - 3].mType == ASMIT_CLC &&
							mIns[k - 2].mType == ASMIT_LDA && mIns[k - 2].mMode == ASMIM_ZERO_PAGE && mIns[k - 2].mAddress == reg &&
							mIns[k - 1].mType == ASMIT_ADC && mIns[k - 1].mMode == ASMIM_IMMEDIATE)
						{
							int j = pblock->mIns.Size() - 1;
							while (j >= 0 && !pblock->mIns[j].ChangesZeroPage(reg))
								j--;
							if (j > 0 && pblock->mIns[j].mType == ASMIT_STA && pblock->mIns[j - 1].mType == ASMIT_LDA &&
								pblock->mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
								pblock->mIns[j - 1].mLinkerObject == mIns[sz - 1].mLinkerObject)
							{
								int ni = mIns[sz - 1].mAddress - pblock->mIns[j - 1].mAddress;
								if (ni < 256 && ni % mIns[k - 1].mAddress == 0)
								{
									nloop = ni / mIns[k - 1].mAddress;
									sz -= 2;
								}
							}
						}
					}
				}

				if (nloop > 0)
				{
					const InterInstruction* ihead = nullptr;

					signed char zpinc[256];

					// -1 unused
					// -2 used low byte
					// -3 used high byte
					// -4 used

					for (int i = 0; i < 256; i++)
						zpinc[i] = -1;

					int ypred = -1, ystart = -1, ymax = -1;
					int i = 0;
					while (i < sz)
					{
						if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
						{
							if (ypred == -1)
							{
								ystart = ypred = mIns[i].mAddress;
								ihead = mIns[i].mIns;
							}
							else if (mIns[i].mAddress == ypred || mIns[i].mAddress == ((ypred + 1) & 255) || mIns[i].mAddress == ((ypred - 1) & 255))
								ypred = mIns[i].mAddress;
							else
								break;
						}
						else if (mIns[i].mType == ASMIT_LDY || mIns[i].mType == ASMIT_STY || mIns[i].mMode == ASMIM_ABSOLUTE_Y)
							break;
						else if (mIns[i].mType == ASMIT_INY)
						{
							if (ypred == -1)
								break;
							ypred = (ypred + 1) & 255;
						}
						else if (mIns[i].mType == ASMIT_DEY)
						{
							if (ypred == -1)
								break;
							ypred = (ypred - 1) & 255;
						}
						else if (mIns[i].mMode == ASMIM_INDIRECT_Y)
						{
							if ((zpinc[mIns[i].mAddress + 0] == -1 || zpinc[mIns[i].mAddress + 0] == -2) &&
								(zpinc[mIns[i].mAddress + 1] == -1 || zpinc[mIns[i].mAddress + 1] == -3))
							{
								zpinc[mIns[i].mAddress + 0] = -2;
								zpinc[mIns[i].mAddress + 1] = -3;
							}
							else
								break;
						}
						else if (mIns[i].mType == ASMIT_CLC && i + 6 < mIns.Size())
						{
							if (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 + 1].mAddress == mIns[i + 3].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 + 4].mAddress == mIns[i + 6].mAddress &&
								!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
							{
//								printf("Add %d, %d, %d\n", i, zpinc[mIns[i + 1].mAddress + 0], mIns[i + 2].mAddress);

								if (zpinc[mIns[i + 1].mAddress + 0] == -1)
									;
								else if (zpinc[mIns[i + 1].mAddress + 0] == -2)
								{
									zpinc[mIns[i + 1].mAddress + 0] = mIns[i + 2].mAddress;
									i += 6;
								}
								else
									break;
							}
						}
						else if (mIns[i].mMode == ASMIM_ZERO_PAGE)
						{
							if (zpinc[mIns[i].mAddress + 0] == -1 || zpinc[mIns[i].mAddress + 0] == -4)
								zpinc[mIns[i].mAddress + 0] = -4;
							else
								break;
						}

						if (ypred > ymax)
							ymax = ypred;

						if (ypred >= 128)
							break;

						i++;
					}

					if (ystart >= 0 && i == sz)
					{
						int yinc = -1;
						int i = 0;
						while (i < 256)
						{
							if (zpinc[i] >= 0)
							{
								if (yinc == -1 || yinc == zpinc[i])
									yinc = zpinc[i];
								else
									break;
							}
							else if (zpinc[i] == -2)
								break;
							i++;
						}

						if (i == 256 && yinc > 0 && ymax + (nloop - 1) * yinc < 256)
						{
							if (eblock->mNumEntries > 1)
							{
								if (eblock == mTrueJump)
									mTrueJump = eblock = BuildSingleEntry(mProc, eblock);
								else
									mFalseJump = eblock = BuildSingleEntry(mProc, eblock);
							}

							pblock->mIns.Push(NativeCodeInstruction(ihead, ASMIT_LDY, ASMIM_IMMEDIATE, ystart));
							ypred = ystart;

							int ei = 0;
							i = 0;
							while (i < mIns.Size())
							{
								if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
								{
									if (mIns[i].mAddress == ypred)
									{
										mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
									}
									else if (mIns[i].mAddress == ((ypred + 1) & 255))
									{
										ypred = mIns[i].mAddress;
										mIns[i].mType = ASMIT_INY; mIns[i].mMode = ASMIM_IMPLIED;
									}
									else if (mIns[i].mAddress == ((ypred - 1) & 255))
									{
										ypred = mIns[i].mAddress;
										mIns[i].mType = ASMIT_DEY; mIns[i].mMode = ASMIM_IMPLIED;
									}
									i++;
								}
								else if (mIns[i].mType == ASMIT_INY)
								{
									ypred = (ypred + 1) & 255;
									i++;
								}
								else if (mIns[i].mType == ASMIT_DEY)
								{
									ypred = (ypred - 1) & 255;
									i++;
								}
								else if (mIns[i].mType == ASMIT_CLC && i + 6 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && zpinc[mIns[i + 1].mAddress] >= 0)
								{
									mIns[i + 2].mAddress = yinc * nloop;
									for (int k = 0; k < 7; k++)
										eblock->mIns.Insert(ei++, mIns[i + k]);
									mIns.Remove(i, 7);
								}
								else
								{
									mIns[i].mLive |= LIVE_CPU_REG_Y;
									i++;
								}
							}

							pblock->mExitRequiredRegs += CPU_REG_Y;
							mEntryRequiredRegs += CPU_REG_Y;
							mExitRequiredRegs += CPU_REG_Y;

							sz = mIns.Size();
							mIns[sz - 1] = NativeCodeInstruction(mIns[sz - 1].mIns, ASMIT_CPY, ASMIM_IMMEDIATE, (ystart + yinc * nloop) & 255);
							if (ypred != yinc)
							{
								mIns.Insert(sz - 1, NativeCodeInstruction(ihead, ASMIT_CLC));
								mIns.Insert(sz - 0, NativeCodeInstruction(ihead, ASMIT_TYA));
								mIns.Insert(sz + 1, NativeCodeInstruction(ihead, ASMIT_ADC, ASMIM_IMMEDIATE, (yinc + ystart - ypred) & 255));
								mIns.Insert(sz + 2, NativeCodeInstruction(ihead, ASMIT_TAY));
							}

							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->OptimizeSimpleFixLoop())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeSimpleFixLoop())
			changed = true;
	}

	return changed;

}



bool NativeCodeBasicBlock::OptimizeSimpleForLoop(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		if (mLoopHead && mFalseJump && mNumEntries == 2)
		{
			NativeCodeBasicBlock* lbody = nullptr, * eblock = nullptr, *pblock = nullptr;

			if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump == this)
			{
				lbody = mTrueJump;
				eblock = mFalseJump;
			}
			else if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump == this)
			{
				lbody = mFalseJump;
				eblock = mTrueJump;
			}

			if (lbody)
			{
				if (mEntryBlocks[0] == lbody)
					pblock = mEntryBlocks[1];
				else
					pblock = mEntryBlocks[0];

				if (!pblock->mFalseJump && eblock->mNumEntries == 1)
				{
					if (mIns.Size() == 2 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mIns[1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[1].mMode) && !(mIns[0].mLive & LIVE_CPU_REG_Y) && !lbody->ReferencesYReg())
					{
						int		reg = mIns[0].mAddress;
						bool	fail = false;

						for (int i = 0; !fail && i < lbody->mIns.Size(); i++)
						{
							const NativeCodeInstruction& ins(lbody->mIns[i]);
							if (ins.ReferencesZeroPage(reg))
							{
								if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
									;
								else if (ins.mType == ASMIT_LDX)
								{
									if (i + 1 < lbody->mIns.Size())
									{
										if (lbody->mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(lbody->mIns[i + 1].mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(lbody->mIns[i + 1].mType, ASMIM_ABSOLUTE_Y))
											;
										else
											fail = true;
									}
									else
										fail = true;
								}
								else
									fail = true;
							}
						}

						if (!fail)
						{
							mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
							mIns[1].mType = ASMIT_CPY; mIns[1].mLive |= LIVE_CPU_REG_Y;
							mEntryRequiredRegs += CPU_REG_Y;
							mExitRequiredRegs += CPU_REG_Y;

							lbody->mEntryRequiredRegs += CPU_REG_Y;
							lbody->mExitRequiredRegs += CPU_REG_Y;

							for (int i = 0; i < lbody->mIns.Size(); i++)
							{
								NativeCodeInstruction& ins(lbody->mIns[i]);
								ins.mLive |= LIVE_CPU_REG_Y;

								if (ins.ReferencesZeroPage(reg))
								{
									if (ins.mType == ASMIT_LDA)
									{
										ins.mType = ASMIT_TYA;
										ins.mMode = ASMIM_IMPLIED;
									}
									else if (ins.mType == ASMIT_INC)
									{
										ins.mType = ASMIT_INY;
										ins.mMode = ASMIM_IMPLIED;
									}
									else if (ins.mType == ASMIT_DEC)
									{
										ins.mType = ASMIT_DEY;
										ins.mMode = ASMIM_IMPLIED;
									}
									else if (ins.mType == ASMIT_LDX)
									{
										ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED;
										lbody->mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
									}
								}
							}

							eblock->mEntryRequiredRegs += CPU_REG_Y;
							pblock->mExitRequiredRegs += CPU_REG_Y;

							pblock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
							eblock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, reg));

							changed = true;

						}
					}
					else if (mIns.Size() >= 2 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
					{
						int reg = mIns[0].mAddress;

						int lz = lbody->mIns.Size();

						int	yoffset = 0;
						if (lbody->ChangesYReg())
						{
							for (int i = 0; i < lbody->mIns.Size(); i++)
							{
								if (lbody->mIns[i].mType == ASMIT_INY)
									yoffset++;
								else if (lbody->mIns[i].mType == ASMIT_DEY)
									yoffset--;
								else if (lbody->mIns[i].ChangesYReg())
								{
									yoffset = 1000;
									break;
								}
							}
						}

						if (lz > 0 && lbody->mIns[lz - 1].mType == ASMIT_INC && lbody->mIns[lz - 1].mMode == ASMIM_ZERO_PAGE &&
							lbody->mIns[lz - 1].mAddress == reg && !ReferencesZeroPage(reg, 1) && 
							!lbody->ReferencesZeroPage(reg, 0, lz - 1) && yoffset >= 0 && yoffset <= 1)
						{
							pblock->mIns.Push(NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
							eblock->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, reg));

							mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
							if (yoffset == 0)
							{
								lbody->mIns[lz - 1].mType = ASMIT_INY; lbody->mIns[lz - 1].mMode = ASMIM_IMPLIED;
							}
							else
							{
								lbody->mIns[lz - 1].mType = ASMIT_NOP; lbody->mIns[lz - 1].mMode = ASMIM_IMPLIED;
							}
							for (int i = 0; i < mIns.Size(); i++)
								mIns[i].mLive |= LIVE_CPU_REG_Y;
							for (int i = 0; i < lbody->mIns.Size(); i++)
								lbody->mIns[i].mLive |= LIVE_CPU_REG_Y;
							mExitRequiredRegs += CPU_REG_Y;
							mEntryRequiredRegs += CPU_REG_Y;
							eblock->mEntryRequiredRegs += CPU_REG_Y;
							pblock->mExitRequiredRegs += CPU_REG_Y;
							changed = true;
						}
					}
				}
			}
		}

		if (mTrueJump && mTrueJump->OptimizeSimpleForLoop())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeSimpleForLoop())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::SimplifyLoopExitCondition(void)
{
	bool	changed = false;
	if (!mVisited)
	{
		mVisited = true;

		int	sz = mIns.Size();

		if (mLoopHead && mTrueJump == this && mEntryBlocks.Size() == 2)
		{
			NativeCodeBasicBlock* pblock = mEntryBlocks[0];
			if (pblock == this)
				pblock = mEntryBlocks[1];

			if (sz > 1 &&
				mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE &&
				mIns[sz - 2].mType == ASMIT_INY && mBranch == ASMIT_BCC &&
				!ChangesYReg(0, sz - 2))
			{
				int yval = pblock->RetrieveYValue();
				if (yval >= 0 && yval < mIns[sz - 1].mAddress)
				{
					mBranch = ASMIT_BNE;
					mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
			}
			if (sz > 1 &&
				mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE &&
				mIns[sz - 2].mType == ASMIT_INX && mBranch == ASMIT_BCC &&
				!ChangesXReg(0, sz - 2))
			{
				int xval = pblock->RetrieveXValue();
				if (xval >= 0 && xval < mIns[sz - 1].mAddress)
				{
					mBranch = ASMIT_BNE;
					mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
					changed = true;
				}
			}
		}

		if (mTrueJump && mTrueJump->SimplifyLoopExitCondition())
			changed = true;
		if (mFalseJump && mFalseJump->SimplifyLoopExitCondition())
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool full)
{
	if (!mVisited)
	{
		mVisited = true;

		assert(mLocked || mNumEntries == mEntryBlocks.Size());
		assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);

		bool	changed = false;
		int	sz = mIns.Size();
		
		assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);

		CheckLive();
		if (mTrueJump)
			mTrueJump->CheckLive();
		if (mFalseJump)
			mFalseJump->CheckLive();

#if 1
		if (sz > 3 &&
			mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
			mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			if (mBranch == ASMIT_BCS && mIns[sz - 2].mAddress < 0xff && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z))
			{
				int	val = mIns[sz - 2].mAddress + 1;
				mBranch = ASMIT_BCC;
				mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
				mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
			}
			else if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z))
			{
				int	val = mIns[sz - 2].mAddress + 1;
				mBranch = ASMIT_BCS;
				mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
				mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
			}
			else if ((mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
			{
				int	val = mIns[sz - 2].mAddress;
				mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val;
				mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM;
			}
		}
#endif
		if (mFalseJump == this)
		{
			mBranch = InvertBranchCondition(mBranch);
			mFalseJump = mTrueJump;
			mTrueJump = this;
		}

		if (sz <= 3 && mTrueJump == this)
		{
			changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr, full);

			CheckLive();
		}
		else if (sz > 3 && sz < 200 && mNumEntries >= 2 && mTrueJump == this)
		{
			bool		simple = true;

			for(int i=0; i<mIns.Size(); i++)				
			{ 
				if (mIns[i].mType == ASMIT_JSR)
					simple = false;
			}

			if (simple)
			{
				if ((mIns[sz - 3].mType == ASMIT_INC || mIns[sz - 3].mType == ASMIT_DEC) && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
					mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
					mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
					(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS || mBranch == ASMIT_BNE))
				{
					// check for usage of Y register

					bool	yother = false, yindex = false, xother = false, xindex = false;
					int		zreg = mIns[sz - 3].mAddress;
					int		limit = mIns[sz - 1].mAddress;
					int		yinc = 0, xinc = 0;

					if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
						xother = true;
					if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
						yother = true;

					for (int i = 0; i < sz - 3; i++)
					{
						if (mIns[i].mType == ASMIT_TAY)
							yother = true;
						else if (mIns[i].mType == ASMIT_INY)
							yinc++;
						else if (mIns[i].mType == ASMIT_DEY)
							yinc--;
						else if (mIns[i].mType == ASMIT_LDY)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && yinc >= -1 && yinc <= 1)
							{
								yinc = 0;
								yindex = true;
							}
							else
								yother = true;
						}
						else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
							yother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							yother = true;

						if (mIns[i].mType == ASMIT_TAX)
							xother = true;
						else if (mIns[i].mType == ASMIT_INX)
							xinc++;
						else if (mIns[i].mType == ASMIT_DEX)
							xinc--;
						else if (mIns[i].mType == ASMIT_LDX)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && xinc >= -1 && xinc <= 1)
								xindex = true;
							else
								xother = true;
						}
						else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
							xother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							xother = true;
					}
					if (yindex && yother)
					{
						for (int i = 0; i < sz - 3; i++)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								;
							else if (mIns[i].mType == ASMIT_TAY && !(mIns[i].mLive & LIVE_CPU_REG_X) && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_X) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
							{
								mIns[i].mType = ASMIT_TAX; mIns[i].mLive |= LIVE_CPU_REG_X; mIns[i].mLive &= ~LIVE_CPU_REG_Y;
								mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
								changed = true;
							}
							else if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_X))
							{
								int j = i + 1;
								while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesGlobalMemory())
									j++;
								if (j < mIns.Size() && mIns[j].mMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_X) && !(mIns[j].mLive & LIVE_CPU_REG_Y))
								{
									mIns[i].mType = ASMIT_LDX;
									mIns[j].mMode = ASMIM_ABSOLUTE_X;
									while (j > i)
									{
										j--;
										mIns[j].mLive |= LIVE_CPU_REG_X; mIns[j].mLive &= ~LIVE_CPU_REG_Y;
									}
									changed = true;
								}
							}
						}
					}
					else if (xindex && xother)
					{
						bool	xswap = true;
						for (int i = 0; i < sz - 3; i++)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								;
							else if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & LIVE_CPU_REG_Y) && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_Y) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
								;
							else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_Y))
							{
								int j = i + 1;
								while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesGlobalMemory())
									j++;
								if (j < mIns.Size() && mIns[j].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_Y) && !(mIns[j].mLive & LIVE_CPU_REG_X))
									;
								else
									xswap = false;
							}
							else if (mIns[i].ChangesXReg())
								xswap = false;
						}

						if (xswap)
						{
							for (int i = 0; i < sz - 3; i++)
							{
								if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
									;
								else if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & LIVE_CPU_REG_Y) && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_Y) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
								{
									mIns[i].mType = ASMIT_TAY; mIns[i].mLive |= LIVE_CPU_REG_Y; mIns[i].mLive &= ~LIVE_CPU_REG_X;
									mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
									changed = true;
								}
								else if (mIns[i].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_LDY, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_Y))
								{
									int j = i + 1;
									while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesGlobalMemory())
										j++;
									if (j < mIns.Size() && mIns[j].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_Y) && !(mIns[j].mLive & LIVE_CPU_REG_X))
									{
										mIns[i].mType = ASMIT_LDY;
										mIns[j].mMode = ASMIM_ABSOLUTE_Y;
										while (j > i)
										{
											j--;
											mIns[j].mLive |= LIVE_CPU_REG_Y; mIns[j].mLive &= ~LIVE_CPU_REG_X;
										}
										changed = true;
									}
								}
							}
						}
					}

					if (!yother)
					{
						int	linc = yinc;
						if (mIns[sz - 3].mType == ASMIT_INC)
							linc--;
						else
							linc++;

						const InterInstruction* iins(mIns[sz - 3].mIns);

						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();

						yinc = 0;
						for (int i = 0; i + 3 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_Y;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
							else if (mIns[i].mType == ASMIT_LDY)
							{
								if (yinc > 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
								else if (yinc < 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
								yinc = 0;
							}
							else
							{
								lblock->mIns.Push(mIns[i]);
								if (mIns[i].mType == ASMIT_INY)
									yinc++;
								else if (mIns[i].mType == ASMIT_DEY)
									yinc--;
							}
						}

						while (linc < 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
							linc++;
						}
						while (linc > 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY, ASMIM_IMPLIED));
							linc--;
						}

						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, limit));
						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_Y;
						lblock->mEntryRequiredRegs += CPU_REG_Y;
						lblock->mExitRequiredRegs += CPU_REG_Y;
						eblock->mEntryRequiredRegs += CPU_REG_Y;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
					else if (!xother)
					{
						int	linc = xinc;
						if (mIns[sz - 3].mType == ASMIT_INC)
							linc--;
						else
							linc++;

						const InterInstruction* iins(mIns[sz - 3].mIns);

						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();

						xinc = 0;
						for (int i = 0; i + 3 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_X;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
							else if (mIns[i].mType == ASMIT_LDX)
							{
								if (xinc > 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
								else if (xinc < 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
								xinc = 0;
							}
							else
							{
								lblock->mIns.Push(mIns[i]);
								if (mIns[i].mType == ASMIT_INX)
									xinc++;
								else if (mIns[i].mType == ASMIT_DEX)
									xinc--;
							}
						}

						while (linc < 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
							linc++;
						}
						while (linc > 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX, ASMIM_IMPLIED));
							linc--;
						}

						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, limit));
						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_X;
						lblock->mEntryRequiredRegs += CPU_REG_X;
						lblock->mExitRequiredRegs += CPU_REG_X;
						eblock->mEntryRequiredRegs += CPU_REG_X;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->CheckLive();

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
				}
				else if (mIns[sz - 1].mType == ASMIT_DEC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && (mBranch == ASMIT_BNE || mBranch == ASMIT_BPL))
				{
					// check for usage of Y register

					bool	yother = false, yindex = false, xother = false, xindex = false;
					int		zreg = mIns[sz - 1].mAddress;
					int		yinc = 0, xinc = 0;

					const InterInstruction* iins(mIns[sz - 1].mIns);

					if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
						yother = true;
					if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
						xother = true;

					for (int i = 0; i < sz - 1; i++)
					{
						if (mIns[i].mType == ASMIT_TAY)
							yother = true;
						else if (mIns[i].mType == ASMIT_INY)
							yinc++;
						else if (mIns[i].mType == ASMIT_DEY)
							yinc--;
						else if (mIns[i].mType == ASMIT_LDY)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && yinc >= -1 && yinc <= 1)
							{
								yinc = 0;
								yindex = true;
							}
							else
								yother = true;
						}
						else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
							yother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							yother = true;

						if (mIns[i].mType == ASMIT_TAX)
							xother = true;
						else if (mIns[i].mType == ASMIT_INX)
							xinc++;
						else if (mIns[i].mType == ASMIT_DEX)
							xinc--;
						else if (mIns[i].mType == ASMIT_LDX)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && xinc >= -1 && xinc <= 1)
							{
								xinc = 0;
								xindex = true;
							}
							else
								xother = true;
						}
						else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X))
							xother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							xother = true;
					}

					if (!yother)
					{
						int	linc = yinc + 1;

						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();

						yinc = 0;
						for (int i = 0; i + 1 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_Y;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
							else if (mIns[i].mType == ASMIT_LDY)
							{
								if (yinc > 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEY));
								else if (yinc < 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INY));
								yinc = 0;
							}
							else
							{
								lblock->mIns.Push(mIns[i]);
								if (mIns[i].mType == ASMIT_INY)
									yinc++;
								else if (mIns[i].mType == ASMIT_DEY)
									yinc--;
							}
						}

						if (linc == 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, 0));
						}
						else						
						{
							while (linc < 0)
							{
								lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
								linc++;
							}
							while (linc > 0)
							{
								lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEY, ASMIM_IMPLIED));
								linc--;
							}
						}

						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_Y;
						lblock->mEntryRequiredRegs += CPU_REG_Y;
						lblock->mExitRequiredRegs += CPU_REG_Y;
						eblock->mEntryRequiredRegs += CPU_REG_Y;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
					else if (!xother)
					{
						int	linc = xinc + 1;

						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();

						yinc = 0;
						for (int i = 0; i + 1 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_X;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
							else if (mIns[i].mType == ASMIT_LDX)
							{
								if (yinc > 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX));
								else if (yinc < 0)
									lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX));
								yinc = 0;
							}
							else
							{
								lblock->mIns.Push(mIns[i]);
								if (mIns[i].mType == ASMIT_INX)
									yinc++;
								else if (mIns[i].mType == ASMIT_DEX)
									yinc--;
							}
						}

						if (linc == 0)
						{
							lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, 0));
						}
						else
						{
							while (linc < 0)
							{
								lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
								linc++;
							}
							while (linc > 0)
							{
								lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX, ASMIM_IMPLIED));
								linc--;
							}
						}

						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_X;
						lblock->mEntryRequiredRegs += CPU_REG_X;
						lblock->mExitRequiredRegs += CPU_REG_X;
						eblock->mEntryRequiredRegs += CPU_REG_X;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
				}
				else if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
					mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
					mIns[sz - 1].mType == ASMIT_CMP && (mIns[sz - 1].mMode == ASMIM_ZERO_PAGE || mIns[sz - 1].mMode == ASMIM_ABSOLUTE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
					mBranch == ASMIT_BCC)
				{
					// check for usage of Y register

					bool	yother = false, yindex = false, lchanged = false, xother = false, xindex = false;
					NativeCodeInstruction	lins = mIns[sz - 1];
					
					const InterInstruction* iins(mIns[sz - 1].mIns);

					int		zreg = mIns[sz - 3].mAddress;

					if (mIns[sz - 1].mLive & LIVE_CPU_REG_X)
						xother = true;
					if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y)
						yother = true;

					for (int i = 0; i < sz - 3; i++)
					{
						if (mIns[i].SameEffectiveAddress(lins) && mIns[i].ChangesAddress())
							lchanged = true;

						if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
							yother = true;
						else if (mIns[i].mType == ASMIT_LDY)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								yindex = true;
							else
								yother = true;
						}
						else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
							yother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							yother = true;

						if (mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX || mIns[i].mType == ASMIT_TAX)
							xother = true;
						else if (mIns[i].mType == ASMIT_LDX)
						{
							if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								xindex = true;
							else
								xother = true;
						}
						else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							xother = true;
						else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
							xother = true;
						else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
							xother = true;
					}

					if (!yother && !lchanged)
					{
						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();
						for (int i = 0; i + 3 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_Y;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
							else if (mIns[i].mType != ASMIT_LDY)
								lblock->mIns.Push(mIns[i]);
						}
						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, lins));
						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_Y;
						lblock->mEntryRequiredRegs += CPU_REG_Y;
						lblock->mExitRequiredRegs += CPU_REG_Y;
						eblock->mEntryRequiredRegs += CPU_REG_Y;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
					else if (!xother && !lchanged)
					{
						NativeCodeBasicBlock* lblock = proc->AllocateBlock();
						NativeCodeBasicBlock* eblock = proc->AllocateBlock();
						for (int i = 0; i + 3 < sz; i++)
						{
							mIns[i].mLive |= LIVE_CPU_REG_X;

							if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
							else if (mIns[i].mType != ASMIT_LDX)
								lblock->mIns.Push(mIns[i]);
						}
						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
						lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, lins));
						lblock->mBranch = mBranch;
						lblock->mTrueJump = lblock;
						lblock->mFalseJump = eblock;

						eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
						eblock->mBranch = ASMIT_JMP;
						eblock->mTrueJump = mFalseJump;
						eblock->mFalseJump = nullptr;

						mIns.SetSize(0);
						mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
						mBranch = ASMIT_JMP;
						mTrueJump = lblock;
						mFalseJump = nullptr;

						lblock->mEntryRequiredRegs = mEntryRequiredRegs;
						lblock->mExitRequiredRegs = mExitRequiredRegs;
						eblock->mEntryRequiredRegs = mExitRequiredRegs;
						eblock->mExitRequiredRegs = mExitRequiredRegs;
						mExitRequiredRegs = mEntryRequiredRegs;
						mExitRequiredRegs += CPU_REG_X;
						lblock->mEntryRequiredRegs += CPU_REG_X;
						lblock->mExitRequiredRegs += CPU_REG_X;
						eblock->mEntryRequiredRegs += CPU_REG_X;

						lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);

						lblock->CheckLive();

						changed = true;

						assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);
					}
				}
			}

#if 1
			assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
			if (!changed)
			{
				CheckLive();
				changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr, full);
				CheckLive();
			}
			assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
#endif
		}

		assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);

		CheckLive();

		if (mTrueJump && mTrueJump->OptimizeSimpleLoop(proc, full))
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeSimpleLoop(proc, full))
			changed = true;

		assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);

		return changed;
	}

	return false;
}

static bool NativeBlocksArrayEntryRequiresReg(const ExpandingArray<NativeCodeBasicBlock*>& blocks, int reg)
{
	for (int i = 0; i < blocks.Size(); i++)
		if (blocks[i]->mEntryRequiredRegs[reg])
			return true;
	return false;
}

bool NativeCodeBasicBlock::OptimizeSingleEntryLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prev, const ExpandingArray<NativeCodeBasicBlock*>& tails, const ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
	bool	changed = false;

	for (int bi = 0; bi < lblocks.Size(); bi++)
	{
		NativeCodeBasicBlock* block = lblocks[bi];
		for (int i = 0; i + 1 < block->mIns.Size(); i++)
		{
			if (block->mIns[i].mType == ASMIT_LDA && (block->mIns[i].mMode == ASMIM_IMMEDIATE || block->mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
				block->mIns[i + 1].mType == ASMIT_STA && block->mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
			{
				int addr = block->mIns[i + 1].mAddress;
				if (!mEntryRequiredRegs[addr] && !NativeBlocksArrayEntryRequiresReg(tails, addr) && !ReferencesZeroPage(addr) &&
					!block->ReferencesZeroPage(addr, 0, i) && !block->ChangesZeroPage(addr, i + 2) && !prev->mExitRequiredRegs[CPU_REG_Z])
				{
					int j = 0;
					while (j < lblocks.Size() && (j == bi || !lblocks[j]->ReferencesZeroPage(addr)))
						j++;
					if (j == lblocks.Size())
					{
						bool	ok = true;
						if (!prev->mExitRequiredRegs[CPU_REG_A])
						{
							prev->mIns.Push(block->mIns[i]);
							prev->mIns.Push(block->mIns[i + 1]);
						}
						else if (!prev->mExitRequiredRegs[CPU_REG_X])
						{
							prev->mIns.Push(NativeCodeInstruction(block->mIns[i].mIns, ASMIT_LDX, block->mIns[i]));
							prev->mIns.Push(NativeCodeInstruction(block->mIns[i + 1].mIns, ASMIT_STX, block->mIns[i + 1]));
						}
						else if (!prev->mExitRequiredRegs[CPU_REG_Y])
						{
							prev->mIns.Push(NativeCodeInstruction(block->mIns[i].mIns, ASMIT_LDY, block->mIns[i]));
							prev->mIns.Push(NativeCodeInstruction(block->mIns[i + 1].mIns, ASMIT_STY, block->mIns[i + 1]));
						}
						else
							ok = false;

						if (ok)
						{
							block->mIns.Remove(i + 1);
							changed = true;

							prev->mExitRequiredRegs += addr;
							mEntryRequiredRegs += addr;
							mExitRequiredRegs += addr;

							for (int i = 0; i < lblocks.Size(); i++)
							{
								lblocks[i]->mEntryRequiredRegs += addr;
								lblocks[i]->mExitRequiredRegs += addr;
							}
						}
					}
				}
			}
		}
	}

	if (!changed)
	{
		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)
			{
				if (!ReferencesZeroPage(mIns[i + 1].mAddress, 0, i) && !ChangesZeroPage(mIns[i].mAddress) && !ChangesZeroPage(mIns[i + 1].mAddress, i + 2))
				{
					int j = 0;
					while (j < lblocks.Size() && !lblocks[j]->ChangesZeroPage(mIns[i].mAddress) && !lblocks[j]->ChangesZeroPage(mIns[i + 1].mAddress))
						j++;
					if (j == lblocks.Size())
					{
						int addr = mIns[i + 1].mAddress;

						bool	ok = true;
						if (!prev->mExitRequiredRegs[CPU_REG_A])
						{
							prev->mIns.Push(mIns[i]);
							prev->mIns.Push(mIns[i + 1]);
						}
						else if (!prev->mExitRequiredRegs[CPU_REG_X])
						{
							prev->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i]));
							prev->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, mIns[i + 1]));
						}
						else if (!prev->mExitRequiredRegs[CPU_REG_Y])
						{
							prev->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, mIns[i]));
							prev->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STY, mIns[i + 1]));
						}
						else
							ok = false;

						if (ok)
						{
							mIns[i + 1].mType = ASMIT_LDA;
							mIns.Remove(i);

							prev->mExitRequiredRegs += addr;
							mEntryRequiredRegs += addr;
							mExitRequiredRegs += addr;

							for (int i = 0; i < lblocks.Size(); i++)
							{
								lblocks[i]->mEntryRequiredRegs += addr;
								lblocks[i]->mExitRequiredRegs += addr;
							}
							changed = true;
						}
					}
				}
			}

			if (!changed && 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 (!ReferencesZeroPage(mIns[i + 1].mAddress, 0, i) && !ChangesZeroPage(mIns[i].mAddress, 0, i))
				{
					int		reg0 = mIns[i].mAddress, reg1 = mIns[i + 1].mAddress;
					bool	same = true;

					for (int j = 0; j < mEntryBlocks.Size(); j++)
					{
						NativeCodeBasicBlock* eb = mEntryBlocks[j];
						if (eb != prev)
						{
							if (!eb->IsSameZPValue(reg0, reg1))
							{
								same = false;
								break;
							}
						}
					}

					if (same)
					{
						prev->mIns.Push(mIns[i]);
						prev->mIns.Push(mIns[i + 1]);
						prev->mExitRequiredRegs += reg1;
						mEntryRequiredRegs += reg1;
						mIns.Remove(i + 1);
						changed = true;
					}
				}
			}

			if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS) && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
			{
				int addr = mIns[i + 1].mAddress;

				if (tails.Size() == 1 && !ReferencesZeroPage(addr, 0, i) && !ChangesZeroPage(addr, i + 2))
				{
					int j = 0;
					while (j < lblocks.Size() && (lblocks[j] == tails[0] || lblocks[j] == this || !lblocks[j]->ChangesZeroPage(addr)))
						j++;
					if (j == lblocks.Size())
					{
						NativeCodeBasicBlock* tail = tails[0];

						int tz = tail->mIns.Size() - 1;
						while (tz >= 0 && !tail->mIns[tz].ReferencesZeroPage(addr))
							tz--;

						if (tz >= 0 && !tail->ChangesZeroPage(addr, 0, tz - 1))
						{
							if (tail->mIns[tz].mType == ASMIT_STA && !tail->ChangesAccu(tz + 1) ||
								tail->mIns[tz].mType == ASMIT_STY && !tail->ChangesYReg(tz + 1) ||
								tail->mIns[tz].mType == ASMIT_STX && !tail->ChangesXReg(tz + 1))
							{
								bool	ok = true;
								if (!prev->mExitRequiredRegs[CPU_REG_A])
								{
									prev->mIns.Push(mIns[i]);
									prev->mIns.Push(mIns[i + 1]);
								}
								else if (!prev->mExitRequiredRegs[CPU_REG_X])
								{
									prev->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, mIns[i]));
									prev->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STX, mIns[i + 1]));
								}
								else if (!prev->mExitRequiredRegs[CPU_REG_Y])
								{
									prev->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDY, mIns[i]));
									prev->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STY, mIns[i + 1]));
								}
								else
									ok = false;

								if (ok)
								{
									NativeCodeBasicBlock* exitBlock;
									if (lblocks.Contains(tail->mTrueJump))
										exitBlock = tail->mFalseJump;
									else
										exitBlock = tail->mTrueJump;

									if (exitBlock->mEntryBlocks.Size() > 1)
									{
										NativeCodeBasicBlock* eb = mProc->AllocateBlock();
										eb->mEntryRequiredRegs = exitBlock->mEntryRequiredRegs;
										eb->mExitRequiredRegs = exitBlock->mEntryRequiredRegs;
										eb->Close(exitBlock->mBranchIns, exitBlock, nullptr, ASMIT_JMP);
										eb->AddEntryBlock(tail);
										exitBlock->AddEntryBlock(eb);
										exitBlock->RemEntryBlock(tail);
										if (tail->mFalseJump == exitBlock)
											tail->mFalseJump = eb;
										else
											tail->mTrueJump = eb;
										exitBlock = eb;
									}

									mIns.Remove(i + 1);

									prev->mExitRequiredRegs += addr;
									mEntryRequiredRegs += addr;
									mExitRequiredRegs += addr;

									for (int i = 0; i < lblocks.Size(); i++)
									{
										lblocks[i]->mEntryRequiredRegs += addr;
										lblocks[i]->mExitRequiredRegs += addr;
									}

									int live = 0;
									if (tail->mIns[tz].mType == ASMIT_STA)
									{
										live |= LIVE_CPU_REG_A;
										tail->mExitRequiredRegs += CPU_REG_A;
										exitBlock->mEntryRequiredRegs += CPU_REG_A;
									}
									else if (tail->mIns[tz].mType == ASMIT_STX)
									{
										live |= LIVE_CPU_REG_X;
										tail->mExitRequiredRegs += CPU_REG_X;
										exitBlock->mEntryRequiredRegs += CPU_REG_X;
									}
									else if (tail->mIns[tz].mType == ASMIT_STY)
									{
										live |= LIVE_CPU_REG_A;
										tail->mExitRequiredRegs += CPU_REG_Y;
										exitBlock->mEntryRequiredRegs += CPU_REG_Y;
									}

									exitBlock->mIns.Insert(0, tail->mIns[tz]);
									tail->mIns.Remove(tz);

									changed = true;
								}
							}
						}
					}
				}
			}
		}

	}

	if (!changed)
	{
		if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_IMMEDIATE)
		{
			if (!ChangesAccu(1))
			{
				int i = 0;
				while (i < lblocks.Size() && !lblocks[i]->ChangesAccu())
					i++;
				if (i == lblocks.Size())
				{
					prev->mIns.Push(mIns[0]);
					mIns.Remove(0);
					prev->mExitRequiredRegs += CPU_REG_A;
					mEntryRequiredRegs += CPU_REG_A;
					mExitRequiredRegs += CPU_REG_A;

					for (int i = 0; i < lblocks.Size(); i++)
					{
						lblocks[i]->mEntryRequiredRegs += CPU_REG_A;
						lblocks[i]->mExitRequiredRegs += CPU_REG_A;
					}
					changed = true;
				}
			}
		}
		if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_IMMEDIATE)
		{
			if (!ChangesYReg(1))
			{
				int i = 0;
				while (i < lblocks.Size() && !lblocks[i]->ChangesYReg())
					i++;
				if (i == lblocks.Size())
				{
					prev->mIns.Push(mIns[0]);
					mIns.Remove(0);
					prev->mExitRequiredRegs += CPU_REG_Y;
					mEntryRequiredRegs += CPU_REG_Y;
					mExitRequiredRegs += CPU_REG_Y;

					for (int i = 0; i < lblocks.Size(); i++)
					{
						lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
						lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
					}
					changed = true;
				}
			}
		}

		if (tails.Size() == 1)
		{
			NativeCodeBasicBlock* tail = tails[0];
			int tz = tail->mIns.Size();
			if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE &&
				tz > 0 && (tail->mIns[tz - 1].mType == ASMIT_INC || tail->mIns[tz - 1].mType == ASMIT_DEC) && tail->mIns[tz - 1].SameEffectiveAddress(mIns[0]))
			{
				if (!ChangesYReg(1) && !ReferencesZeroPage(mIns[0].mAddress, 1) &&
					!tail->ChangesYReg() && !tail->ReferencesZeroPage(mIns[0].mAddress, 0, tz - 1))
				{
					int i = 0;
					while (i < lblocks.Size() && (lblocks[i] == tail || (!lblocks[i]->ChangesYReg() && !lblocks[i]->ReferencesZeroPage(mIns[0].mAddress))))
						i++;
					if (i == lblocks.Size())
					{
						if (lblocks.Contains(tail->mTrueJump))
						{
							tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
							tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
						}
						else
						{
							tail->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
							tail->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
						}

						if (tail->mIns[tz - 1].mType == ASMIT_INC)
							tail->mIns[tz - 1].mType = ASMIT_INY;
						else
							tail->mIns[tz - 1].mType = ASMIT_DEY;
						tail->mIns[tz - 1].mMode = ASMIM_IMPLIED;

						prev->mIns.Push(mIns[0]);
						mIns.Remove(0);
						mEntryRequiredRegs += CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;
						prev->mExitRequiredRegs += CPU_REG_Y;
						for (int i = 0; i < lblocks.Size(); i++)
						{
							lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
							lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
						}
						changed = true;
					}
				}
			}
		}

		if (!changed)
		{
			if (mIns.Size() > 0 && mIns[0].mType == ASMIT_TXA)
			{
				if (!ChangesAccu(1) && !ChangesXReg(1))
				{
					int i = 0;
					while (i < lblocks.Size() && (lblocks[i] == this || (!lblocks[i]->ChangesXReg() && !lblocks[i]->ChangesAccu())))
						i++;
					if (i == lblocks.Size())
					{
						prev->mIns.Push(mIns[0]);
						mIns.Remove(0);
						prev->mExitRequiredRegs += CPU_REG_A;
						mEntryRequiredRegs += CPU_REG_A;
						mExitRequiredRegs += CPU_REG_A;

						for (int i = 0; i < lblocks.Size(); i++)
						{
							lblocks[i]->mEntryRequiredRegs += CPU_REG_A;
							lblocks[i]->mExitRequiredRegs += CPU_REG_A;
						}
						changed = true;
					}
				}
			}
		}

		if (!changed)
		{
			if (tails.Size() == 1 && mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
			{
				NativeCodeBasicBlock* tail = tails[0];
				int k = 1;
				while (k < mIns.Size() && !(mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == mIns[0].mAddress))
					k++;

				if (k < mIns.Size() && !ChangesYReg(1) &&
					!ReferencesZeroPage(mIns[0].mAddress, 1, k) &&
					!ReferencesZeroPage(mIns[0].mAddress, k + 1) &&
					(mIns[k].mType == ASMIT_INC || mIns[k].mType == ASMIT_DEC))
				{
					int i = 0;
					while (i < lblocks.Size() && (lblocks[i] == this || (!lblocks[i]->ChangesYReg() && !lblocks[i]->ReferencesZeroPage(mIns[0].mAddress))))
						i++;
					if (i == lblocks.Size())
					{
						AsmInsType	it, nit;
						
						if (mIns[k].mType == ASMIT_INC)
						{
							it = ASMIT_INY;
							nit = ASMIT_DEY;
						}
						else
						{
							it = ASMIT_DEY;
							nit = ASMIT_INY;
						}

						if (lblocks.Contains(tail->mTrueJump))
						{
							tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
							tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
							tail->mFalseJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
						}
						else
						{
							tail->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
							tail->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
							tail->mTrueJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
						}

						prev->mIns.Push(mIns[0]);
						prev->mIns.Push(NativeCodeInstruction(mIns[0].mIns, nit));

						mIns[0].mType = it;
						mIns[0].mMode = ASMIM_IMPLIED;
						mIns.Remove(k);

						mEntryRequiredRegs += CPU_REG_Y;
						mExitRequiredRegs += CPU_REG_Y;
						prev->mExitRequiredRegs += CPU_REG_Y;
						for (int i = 0; i < lblocks.Size(); i++)
						{
							lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
							lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
						}
						changed = true;
					}
				}
			}
		}
	}

	if (mEntryBlocks.Size() == 2 && tails.Size() == 1)
	{
		NativeCodeBasicBlock* tail = tails[0];
		if (tail->mExitRequiredRegs.Size() && !tail->mExitRequiredRegs[CPU_REG_X] && !mEntryRequiredRegs[CPU_REG_X])
		{
			int ei = tail->mIns.Size() - 1;
			while (ei >= 0 && !tail->mIns[ei].ReferencesXReg())
				ei--;
			if (ei >= 0 && tail->mIns[ei].mType == ASMIT_STX && tail->mIns[ei].mMode == ASMIM_ZERO_PAGE)
			{
				int reg = tail->mIns[ei].mAddress;

				int si = 0;
				while (si < mIns.Size() && !mIns[si].ChangesXReg())
					si++;
				if (si < mIns.Size() && mIns[si].mType == ASMIT_LDX && mIns[si].SameEffectiveAddress(tail->mIns[ei]))
				{
					if (!tail->ReferencesZeroPage(reg, ei + 1) && !ReferencesZeroPage(reg, 0, si) && !ReferencesZeroPage(reg, si + 1))
						tail->mIns.Remove(ei);

					prev->mIns.Push(mIns[si]);
					mIns.Remove(si);

					for (int i = 0; i < si; i++)
						mIns[i].mLive |= LIVE_CPU_REG_X;
					for (int i = ei; i < tail->mIns.Size(); i++)
						tail->mIns[i].mLive |= LIVE_CPU_REG_X;
					mEntryRequiredRegs += CPU_REG_X;
					tail->mExitRequiredRegs += CPU_REG_X;
					changed = true;
				}
			}
		}
	}

	if (!changed)
	{
		if (tails.Size() == 1)
		{
			NativeCodeBasicBlock* tail = tails[0];
			int iy = 0;
			while (iy < mIns.Size() && !mIns[iy].ReferencesYReg())
				iy++;

			if (iy < mIns.Size() && mIns[iy].mType == ASMIT_LDY && mIns[iy].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[iy].mAddress, 0, iy))
			{
				int addr = mIns[iy].mAddress;
				if (!ChangesAccu(0, iy))
				{
					int tz = tail->mIns.Size();
					if (tz >= 2 &&
						tail->mIns[tz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, tail->mIns[tz - 1].mMode) && !(tail->mIns[tz - 1].mLive & LIVE_CPU_REG_A) &&
						tail->mIns[tz - 2].mType == ASMIT_LDA && tail->mIns[tz - 2].mMode == ASMIM_ZERO_PAGE && tail->mIns[tz - 2].mAddress == addr)
					{
						prev->mIns.Push(mIns[iy]);
						tail->mIns[tz - 1].mType = ASMIT_CPY; tail->mIns[tz - 1].mLive |= LIVE_CPU_REG_Y;
						tail->mIns[tz - 2].mType = ASMIT_LDY; tail->mIns[tz - 2].mLive |= LIVE_CPU_REG_Y;
						tail->mExitRequiredRegs += CPU_REG_Y;
						mEntryRequiredRegs += CPU_REG_Y;
						prev->mExitRequiredRegs += CPU_REG_Y;
						for (int i = 0; i < iy; i++)
							mIns[i].mLive |= LIVE_CPU_REG_Y;
						mIns.Remove(iy);
						changed = true;
					}
				}
				if (!changed)
				{
					int tz = tail->mIns.Size() - 1;
					while (tz >= 0 && tail->mIns[tz].mType != ASMIT_STY)
						tz--;
					if (tz >= 0 && tail->mIns[tz].mMode == ASMIM_ZERO_PAGE && tail->mIns[tz].mAddress == addr && !tail->ChangesZeroPage(addr, tz + 1) && !tail->ChangesYReg(tz + 1))
					{
						prev->mIns.Push(mIns[iy]);
						tail->mExitRequiredRegs += CPU_REG_Y;
						mEntryRequiredRegs += CPU_REG_Y;
						prev->mExitRequiredRegs += CPU_REG_Y;
						for (int i = 0; i < iy; i++)
							mIns[i].mLive |= LIVE_CPU_REG_Y;
						for (int i = tz; i < tail->mIns.Size(); i++)
							tail->mIns[i].mLive |= LIVE_CPU_REG_Y;
						mIns.Remove(iy);
						changed = true;
					}

				}
			}

		}
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeInnerLoop(NativeCodeProcedure* proc, NativeCodeBasicBlock* head, NativeCodeBasicBlock* tail, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
	bool		simple = true;

	for (int j = 0; j < lblocks.Size(); j++)
	{
		NativeCodeBasicBlock* block = lblocks[j];
		for (int i = 0; i < block->mIns.Size(); i++)
		{
			if (block->mIns[i].mType == ASMIT_JSR)
				simple = false;

		}

		block->CheckLive();
	}

	int sz = tail->mIns.Size();
	if (simple && sz >= 3)
	{
		if (tail->mIns[sz - 3].mType == ASMIT_INC && tail->mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
			tail->mIns[sz - 2].mType == ASMIT_LDA && tail->mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && tail->mIns[sz - 3].mAddress == tail->mIns[sz - 2].mAddress &&
			tail->mIns[sz - 1].mType == ASMIT_CMP && tail->mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(tail->mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
			tail->mBranch == ASMIT_BCC && tail->mTrueJump == head)
		{
			// check for usage of Y register

			bool	yother = false, yindex = false, xother = false, xindex = false;
			int		zreg = tail->mIns[sz - 3].mAddress;
			int		limit = tail->mIns[sz - 1].mAddress;

			for (int j = 0; j < lblocks.Size(); j++)
			{
				NativeCodeBasicBlock* block = lblocks[j];

				int bz = block == tail ? block->mIns.Size() - 3 : block->mIns.Size();

				for (int i = 0; i < bz; i++)
				{
					if (block->mIns[i].mType == ASMIT_INY || block->mIns[i].mType == ASMIT_DEY || block->mIns[i].mType == ASMIT_TAY)
						yother = true;
					else if (block->mIns[i].mType == ASMIT_LDY)
					{
						if (block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
							yindex = true;
						else
							yother = true;
					}
					else if (!yindex && (block->mIns[i].mType == ASMIT_STY || block->mIns[i].mType == ASMIT_TYA || block->mIns[i].mMode == ASMIM_ABSOLUTE_Y || block->mIns[i].mMode == ASMIM_INDIRECT_Y))
						yother = true;
					else if (block->mIns[i].mType == ASMIT_LDX && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg && xother && !yother && !(block->mIns[i].mLive & LIVE_CPU_REG_Y))
					{
						if (i + 1 < bz && !(block->mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) && block->mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(block->mIns[i + 1].mType, ASMIM_ABSOLUTE_Y))
						{
							block->mIns[i].mType = ASMIT_LDY; block->mIns[i].mLive |= LIVE_CPU_REG_Y;
							block->mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
							yindex = true;
						}
						else
							yother = true;
					}
					else if (block->mIns[i].mType != ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
						yother = true;

					if (block->mIns[i].mType == ASMIT_INX || block->mIns[i].mType == ASMIT_DEX || block->mIns[i].mType == ASMIT_TAX)
						xother = true;
					else if (block->mIns[i].mType == ASMIT_LDX)
					{
						if (block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
							xindex = true;
						else
							xother = true;
					}
					else if (!xindex && (block->mIns[i].mType == ASMIT_STX || block->mIns[i].mType == ASMIT_TXA || block->mIns[i].mMode == ASMIM_ABSOLUTE_X || block->mIns[i].mMode == ASMIM_INDIRECT_X))
						xother = true;
					else if (block->mIns[i].mType != ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
						xother = true;

				}
			}
#if 1
			if (!yother)
			{
				NativeCodeBasicBlock* lblock = proc->AllocateBlock();
				NativeCodeBasicBlock* eblock = proc->AllocateBlock();

				const InterInstruction* iins(tail->mIns[sz - 1].mIns);

				tail->mIns.Remove(sz - 3);
				tail->mIns.Remove(sz - 3);
				tail->mIns.Remove(sz - 3);

				for (int j = 0; j < lblocks.Size(); j++)
				{
					NativeCodeBasicBlock* block = lblocks[j];

					int bz = block->mIns.Size();

					if (block == head)
					{
						for (int i = 0; i < bz; i++)
						{
							if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TYA, ASMIM_IMPLIED));
							else if (block->mIns[i].mType != ASMIT_LDY)
								lblock->mIns.Push(block->mIns[i]);
						}

						for (int i = 0; i < lblock->mIns.Size(); i++)
							lblock->mIns[i].mLive |= LIVE_CPU_REG_Y;
					}
					else
					{
						for (int i = 0; i < bz; i++)
						{
							if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
							{
								block->mIns[i].mType = ASMIT_TYA;
								block->mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (block->mIns[i].mType == ASMIT_LDY)
							{
								block->mIns[i].mType = ASMIT_NOP; block->mIns[i].mMode = ASMIM_IMPLIED;
							}
							block->mIns[i].mLive |= LIVE_CPU_REG_Y;
						}
					}

					block->mEntryRequiredRegs += CPU_REG_Y;
					block->mExitRequiredRegs += CPU_REG_Y;
				}

				tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_INY, ASMIM_IMPLIED));
				tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPY, ASMIM_IMMEDIATE, limit));

				lblock->mBranch = head->mBranch;
				lblock->mTrueJump = head->mTrueJump;
				lblock->mFalseJump = head->mFalseJump;

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
				eblock->mBranch = ASMIT_JMP;
				eblock->mTrueJump = tail->mFalseJump;
				eblock->mFalseJump = nullptr;

				tail->mTrueJump = lblock;
				tail->mFalseJump = eblock;

				head->mIns.SetSize(0);
				head->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
				head->mBranch = ASMIT_JMP;
				head->mTrueJump = lblock;
				head->mFalseJump = nullptr;

				tail->mEntryRequiredRegs += CPU_REG_Y;
				tail->mExitRequiredRegs += CPU_REG_Y;
				head->mExitRequiredRegs += CPU_REG_Y;
				eblock->mEntryRequiredRegs = tail->mExitRequiredRegs;
				eblock->mEntryRequiredRegs += CPU_REG_Y;

				lblock->CheckLive();

				return true;
			}
			else 
#endif				
			if (!xother)
			{
				NativeCodeBasicBlock* lblock = proc->AllocateBlock();
				NativeCodeBasicBlock* eblock = proc->AllocateBlock();

				const InterInstruction* iins(tail->mIns[sz - 1].mIns);

				tail->mIns.Remove(sz - 3);
				tail->mIns.Remove(sz - 3);
				tail->mIns.Remove(sz - 3);

				for (int j = 0; j < lblocks.Size(); j++)
				{
					NativeCodeBasicBlock* block = lblocks[j];

					int bz = block->mIns.Size();

					if (block == head)
					{
						for (int i = 0; i < bz; i++)
						{
							if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
								lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED));
							else if (block->mIns[i].mType != ASMIT_LDX)
								lblock->mIns.Push(block->mIns[i]);
						}

						for (int i = 0; i < lblock->mIns.Size(); i++)
							lblock->mIns[i].mLive |= LIVE_CPU_REG_X;
					}
					else
					{
						for (int i = 0; i < bz; i++)
						{
							if (block->mIns[i].mType == ASMIT_LDA && block->mIns[i].mMode == ASMIM_ZERO_PAGE && block->mIns[i].mAddress == zreg)
							{
								block->mIns[i].mType = ASMIT_TXA;
								block->mIns[i].mMode = ASMIM_IMPLIED;
							}
							else if (block->mIns[i].mType == ASMIT_LDX)
							{
								block->mIns[i].mType = ASMIT_NOP; block->mIns[i].mMode = ASMIM_IMPLIED;
							}
							block->mIns[i].mLive |= LIVE_CPU_REG_X;
						}
					}

					block->mEntryRequiredRegs += CPU_REG_X;
					block->mExitRequiredRegs += CPU_REG_X;
				}

				tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED));
				tail->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, limit));

				lblock->mBranch = head->mBranch;
				lblock->mTrueJump = head->mTrueJump;
				lblock->mFalseJump = head->mFalseJump;
				lblock->mEntryRequiredRegs = tail->mTrueJump->mEntryRequiredRegs;

				eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
				eblock->mBranch = ASMIT_JMP;
				eblock->mTrueJump = tail->mFalseJump;
				eblock->mFalseJump = nullptr;
				eblock->mEntryRequiredRegs = tail->mFalseJump->mEntryRequiredRegs;

				tail->mTrueJump = lblock;
				tail->mFalseJump = eblock;

				head->mIns.SetSize(0);
				head->mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
				head->mBranch = ASMIT_JMP;
				head->mTrueJump = lblock;
				head->mFalseJump = nullptr;

				eblock->mEntryRequiredRegs += CPU_REG_X;
				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;
			}
		}
	}
#if 1
	else if (head->mEntryBlocks.Size() == 2)
	{
		bool	changed = false;

		NativeCodeBasicBlock* exitBlock, * prefixBlock;

		if (tail->mTrueJump == this)
			exitBlock = tail->mFalseJump;
		else
			exitBlock = tail->mTrueJump;

		if (head->mEntryBlocks[0] == this)
			prefixBlock = head->mEntryBlocks[1];
		else
			prefixBlock = head->mEntryBlocks[0];
		
		if (!prefixBlock->mExitRequiredRegs[CPU_REG_A])
		{
			for (int i = 0; i + 1 < head->mIns.Size(); i++)
			{
				if (head->mIns[i + 0].mType == ASMIT_LDA && head->mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					head->mIns[i + 1].mType == ASMIT_STA && head->mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(head->mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				{
					if (!head->ChangesZeroPage(mIns[i + 0].mAddress, 0, i) && !head->ReferencesZeroPage(mIns[i + 1].mAddress, 0, i) && 
						tail->IsSameZPValue(mIns[i + 0].mAddress, mIns[i + 1].mAddress))
					{
						if (prefixBlock->mFalseJump)
							prefixBlock = PrefixLoopBlock(prefixBlock);

						prefixBlock->mIns.Push(head->mIns[i + 0]);
						prefixBlock->mIns.Push(head->mIns[i + 1]);
						prefixBlock->mExitRequiredRegs += head->mIns[i + 1].mAddress;
						for (int i = 0; i < lblocks.Size(); i++)
						{
							lblocks[i]->mExitRequiredRegs += head->mIns[i + 1].mAddress;
							lblocks[i]->mEntryRequiredRegs += head->mIns[i + 1].mAddress;
							lblocks[i]->mEntryProvidedRegs += head->mIns[i + 1].mAddress;
							lblocks[i]->mExitRequiredRegs += head->mIns[i + 0].mAddress;
							lblocks[i]->mEntryProvidedRegs += head->mIns[i + 0].mAddress;
						}

						head->mIns[i + 0].mType = ASMIT_NOP; head->mIns[i + 0].mMode = ASMIM_IMPLIED;
						head->mIns[i + 1].mType = ASMIT_NOP; head->mIns[i + 1].mMode = ASMIM_IMPLIED;

						changed = true;
					}
				}
			}
		}

		return changed;
	}
#endif
	return false;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::CollectInnerLoop(NativeCodeBasicBlock* head, ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
	if (mLoopHeadBlock != head)
	{
		mLoopHeadBlock = head;
		lblocks.Push(this);

		if (mTrueJump != head && mFalseJump != head)
		{
			if (mFalseJump && mTrueJump == this && mEntryBlocks.Size() == 2 && mIns.Size() == 1 && (mIns[0].mType == ASMIT_BIT || mIns[0].mType == ASMIT_LDA && !(mIns[0].mLive & LIVE_CPU_REG_A)))
			{
				mLoopTailBlock = mFalseJump->CollectInnerLoop(head, lblocks);
			}
			else
			{
				if (mTrueJump)
					mLoopTailBlock = mTrueJump->CollectInnerLoop(head, lblocks);

				if (mLoopTailBlock && mFalseJump)
				{
					NativeCodeBasicBlock* tail = mFalseJump->CollectInnerLoop(head, lblocks);
					if (tail != mLoopTailBlock)
						mLoopTailBlock = nullptr;
				}
			}
		}
		else
			mLoopTailBlock = this;
	}

	return mLoopTailBlock;
}

bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc)
{
	bool changed = false;

	if (!mVisited)
	{
		CheckLive();

		if (mLoopHead)
		{
			ExpandingArray<NativeCodeBasicBlock*>	 lblocks;

			NativeCodeBasicBlock* tail = CollectInnerLoop(this, lblocks);

			if (tail && this != tail)
				changed = OptimizeInnerLoop(proc, this, tail, lblocks);
		}

		CheckLive();

		mVisited = true;

		if (mTrueJump && mTrueJump->OptimizeInnerLoops(proc))
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeInnerLoops(proc))
			changed = true;
	}

	return changed;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleEntry(NativeCodeProcedure* proc, NativeCodeBasicBlock* block)
{
	if (block->mNumEntries > 1)
	{
		NativeCodeBasicBlock* nblock = proc->AllocateBlock();
		nblock->mTrueJump = block;
		nblock->mEntryRequiredRegs = block->mEntryRequiredRegs;
		nblock->mExitRequiredRegs = block->mEntryRequiredRegs;
		int k = block->mEntryBlocks.IndexOf(this);
		block->mEntryBlocks[k] = nblock;
		nblock->mEntryBlocks.Push(this);
		nblock->mNumEntries = 1;
		return nblock;
	}
	else
		return block;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleExit(NativeCodeProcedure* proc, NativeCodeBasicBlock* block)
{
	if (block->mFalseJump)
	{
		NativeCodeBasicBlock* nblock = proc->AllocateBlock();
		if (block->mFalseJump == this)
			block->mFalseJump = nblock;
		if (block->mTrueJump == this)
			block->mTrueJump = nblock;
		nblock->mTrueJump = this;

		nblock->mEntryRequiredRegs = this->mEntryRequiredRegs;
		nblock->mExitRequiredRegs = this->mEntryRequiredRegs;

		int k = mEntryBlocks.IndexOf(block);
		mEntryBlocks[k] = nblock;
		nblock->mEntryBlocks.Push(block);
		nblock->mNumEntries = 1;
		return nblock;
	}
	else
		return block;
}

int NativeCodeBasicBlock::CorrectXOffset(const InterInstruction * ins, int xoffset, int at)
{
	while (xoffset > 0)
	{
		mIns.Insert(at, NativeCodeInstruction(ins, ASMIT_DEX));
		at++;
		xoffset--;
	}

	while (xoffset < 0)
	{
		mIns.Insert(at, NativeCodeInstruction(ins, ASMIT_INX));
		at++;
		xoffset++;
	}

	return at;
}

int NativeCodeBasicBlock::CorrectYOffset(const InterInstruction * ins, int yoffset, int at)
{
	while (yoffset > 0)
	{
		mIns.Insert(at, NativeCodeInstruction(ins, ASMIT_DEY));
		at++;
		yoffset--;
	}

	while (yoffset < 0)
	{
		mIns.Insert(at, NativeCodeInstruction(ins, ASMIT_INY));
		at++;
		yoffset++;
	}

	return at;
}


bool NativeCodeBasicBlock::OptimizeGenericLoop(void)
{
	bool	changed = false;

	if (!mVisited)
	{
		if (mLoopHead)
		{
			ExpandingArray<NativeCodeBasicBlock*>	 lblocks;

			mProc->ResetPatched();
			if (CollectSingleEntryGenericLoop(lblocks))
			{
				int		yreg = -1, xreg = -1, areg = -1;
				int		zyreg[NUM_REGS], zxreg[NUM_REGS], zareg[NUM_REGS];
				for (int i = 0; i < NUM_REGS; i++)
				{
					zyreg[i] = 0;
					zxreg[i] = 0;
					zareg[i] = 0;
				}

				if (mEntryRequiredRegs[CPU_REG_Y])
					yreg = -2;
				if (mEntryRequiredRegs[CPU_REG_X])
					xreg = -2;
				if (mEntryRequiredRegs[CPU_REG_A])
					areg = -2;

				for (int i = 0; i < lblocks.Size(); i++)
				{
					NativeCodeBasicBlock* block = lblocks[i];

					int	yoffset = 0, xoffset = 0, aoffset = 0;
					int yskew = 0, xskew = 0;

					for (int j = 0; j < block->mIns.Size(); j++)
					{
						const NativeCodeInstruction& ins(block->mIns[j]);

						switch (ins.mType)
						{
						case ASMIT_LDY:
							if (ins.mMode == ASMIM_ZERO_PAGE && (yreg == -1 || yreg == ins.mAddress))
								yreg = ins.mAddress;
							else
								yreg = -2;
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zxreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							yoffset = 0;
							yskew = 0;
							zareg[CPU_REG_Y] = -1;
							break;
						case ASMIT_LDX:
							if (ins.mMode == ASMIM_ZERO_PAGE && (xreg == -1 || xreg == ins.mAddress))
								xreg = ins.mAddress;
							else
								xreg = -2;
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zyreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							xoffset = 0;
							xskew = 0;
							zareg[CPU_REG_X] = -1;
							break;
						case ASMIT_STY:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zxreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							break;
						case ASMIT_STX:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zyreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							break;
						case ASMIT_INY:
							yoffset++;
							zareg[CPU_REG_Y] = -1;
							break;
						case ASMIT_DEY:
							yoffset--;
							zareg[CPU_REG_Y] = -1;
							break;
						case ASMIT_INX:
							xoffset++;
							zareg[CPU_REG_X] = -1;
							break;
						case ASMIT_DEX:
							xoffset--;
							zareg[CPU_REG_X] = -1;
							break;
						case ASMIT_INC:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								if (zxreg[ins.mAddress] >= 0)
								{
									if (ins.mLive & LIVE_CPU_REG_X)
										zxreg[ins.mAddress] = -1;
									else
									{
										zxreg[ins.mAddress] += 3;
										xskew++;
									}
								}
								if (zyreg[ins.mAddress] >= 0)
								{
									if (ins.mLive & LIVE_CPU_REG_Y)
										zyreg[ins.mAddress] = -1;
									else
									{
										zyreg[ins.mAddress] += 3;
										yskew++;
									}
								}

								zareg[ins.mAddress] = -1;
							}
							break;
						case ASMIT_DEC:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								if (zxreg[ins.mAddress] >= 0)
								{
									if (ins.mLive & LIVE_CPU_REG_X)
										zxreg[ins.mAddress] = -1;
									else
									{
										zxreg[ins.mAddress] += 3;
										xskew--;
									}
								}
								if (zyreg[ins.mAddress] >= 0)
								{
									if (ins.mLive & LIVE_CPU_REG_Y)
										zyreg[ins.mAddress] = -1;
									else
									{
										zyreg[ins.mAddress] += 3;
										yskew--;
									}
								}

								zareg[ins.mAddress] = -1;
							}
							break;

						case ASMIT_ASL:
						case ASMIT_LSR:
						case ASMIT_ROL:
						case ASMIT_ROR:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								if (zareg[ins.mAddress] >= 0)
								{
									if (ins.mLive & LIVE_CPU_REG_A)
										zareg[ins.mAddress] = -1;
									else
										zareg[ins.mAddress] += 3;
								}

								zxreg[ins.mAddress] = -1;
								zyreg[ins.mAddress] = -1;
							}
							else if (ins.mMode == ASMIM_IMPLIED)
								aoffset = 1;
							break;

						case ASMIT_LDA:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								if ((areg == -1 || areg == ins.mAddress && aoffset == 0) && !(ins.mLive & LIVE_CPU_REG_Z))
									areg = ins.mAddress;
								else
									areg = -2;

								if (ins.mAddress == yreg && yoffset != 0)
									yreg = -2;
								if (ins.mAddress == xreg && xoffset != 0)
									xreg = -2;

								if (zxreg[ins.mAddress] >= 0)
									zxreg[ins.mAddress]++;
								if (zyreg[ins.mAddress] >= 0)
									zyreg[ins.mAddress]++;
							}
							else
								areg = -2;
							break;
						case ASMIT_STA:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								if (areg == ins.mAddress)
									aoffset = 0;

								if (ins.mAddress == yreg && (yoffset != 0 || (ins.mLive & LIVE_CPU_REG_Y)))
									yreg = -2;
								if (ins.mAddress == xreg && (xoffset != 0 || (ins.mLive & LIVE_CPU_REG_X)))
									xreg = -2;
								
								if (zxreg[ins.mAddress] >= 0)
									zxreg[ins.mAddress]++;
								if (zyreg[ins.mAddress] >= 0)
									zyreg[ins.mAddress]++;
							}
							break;
						case ASMIT_TYA:
							if (yoffset)
							{
								yreg = -2;
								areg = -2;
							}
							else if ((areg == -1 || areg == CPU_REG_Y) && !(ins.mLive & LIVE_CPU_REG_Z))
								areg = CPU_REG_Y;
							else
								areg = -2;
							break;
						case ASMIT_TXA:
							if (xoffset)
							{
								xreg = -2;
								areg = -2;
							}
							else if ((areg == -1 || areg == CPU_REG_X) && !(ins.mLive & LIVE_CPU_REG_Z))
								areg = CPU_REG_X;
							else
								areg = -2;
							break;
						case ASMIT_TAY:
							yreg = -2;
							zareg[CPU_REG_Y] = -1;
							break;
						case ASMIT_TAX:
							xreg = -2;
							zareg[CPU_REG_X] = -1;
							break;
						case ASMIT_JSR:
							yreg = -2;
							xreg = -2;
							areg = -2;
							zareg[CPU_REG_X] = -1;
							zareg[CPU_REG_Y] = -1;
							break;
						case ASMIT_CMP:
							if (ins.mMode == ASMIM_INDIRECT_Y && yoffset != 0 && yreg >= 0)
							{
								yreg = -2;
							}
							else if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zxreg[ins.mAddress] = -1;
								zyreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							break;
						default:
							if (ins.mMode == ASMIM_ZERO_PAGE)
							{
								zxreg[ins.mAddress] = -1;
								zyreg[ins.mAddress] = -1;
								zareg[ins.mAddress] = -1;
							}
							if (ins.ChangesAccu())
								aoffset = 1;
							break;
						}

						if (xreg >= 0 && ins.mMode == ASMIM_ABSOLUTE_X && xskew != xoffset)
							zxreg[xreg] = -1;
						if (yreg >= 0 && (ins.mMode == ASMIM_ABSOLUTE_Y || ins.mMode == ASMIM_INDIRECT_Y) && yskew != yoffset)
							zyreg[yreg] = -1;

						if (!(ins.mLive & LIVE_CPU_REG_Y))
							yoffset = 0;
						if (!(ins.mLive & LIVE_CPU_REG_X))
							xoffset = 0;
//						if (!(ins.mLive & LIVE_CPU_REG_A))
//							aoffset = 0;

						if (ins.mMode == ASMIM_INDIRECT_Y)
						{
							zxreg[ins.mAddress] = -1;
							zyreg[ins.mAddress] = -1;
							zareg[ins.mAddress] = -1;
							zxreg[ins.mAddress + 1] = -1;
							zyreg[ins.mAddress + 1] = -1;
							zareg[ins.mAddress + 1] = -1;
						}
					}
#if 1
					if (yoffset && block->mExitRequiredRegs[CPU_REG_Y])
						yreg = -2;
					if (xoffset && block->mExitRequiredRegs[CPU_REG_X])
						xreg = -2;
					if (aoffset) // && block->mExitRequiredRegs[CPU_REG_A])
						areg = -2;
#endif
				}

				if (areg >= 0)
				{
					if (zareg[areg] < 0)
						areg = -2;
					else
					{
						zxreg[areg] = -1;
						zyreg[areg] = -1;
					}
				}

				if (xreg != -2)
				{
					if (xreg == -1)
					{
						int	nx = 0;
						for (int i = 0; i < 256; i++)
						{
							if (i != yreg && zxreg[i] > nx)
							{
								nx = zxreg[i];
								xreg = i;
							}
						}
					}
					else if (zxreg[xreg] < 0)
						xreg = -1;
				}

				if (yreg != -2)
				{
					if (yreg == -1)
					{
						int	nx = 0;
						for (int i = 0; i < 256; i++)
						{
							if (i != xreg && zyreg[i] > nx)
							{
								nx = zyreg[i];
								yreg = i;
							}
						}
					}
					else if (zyreg[yreg] < 0)
						yreg = -1;
				}

				if (yreg >= 0 || xreg >= 0 || areg >= 0)
				{
					ExpandingArray<NativeCodeBasicBlock*>	 entries;
					ExpandingArray<NativeCodeBasicBlock*>	 exits;

					for (int i = 0; i < lblocks.Size(); i++)
					{
						NativeCodeBasicBlock* block = lblocks[i];

						if (yreg >= 0)
						{
							block->mEntryRequiredRegs += CPU_REG_Y;
							block->mExitRequiredRegs += CPU_REG_Y;
						}
						if (xreg >= 0)
						{
							block->mEntryRequiredRegs += CPU_REG_X;
							block->mExitRequiredRegs += CPU_REG_X;
						}
						if (areg >= 0)
						{
							block->mEntryRequiredRegs += CPU_REG_A;
							block->mExitRequiredRegs += CPU_REG_A;
						}

						for (int j = 0; j < block->mEntryBlocks.Size(); j++)
						{
							if (!lblocks.Contains(block->mEntryBlocks[j]))
							{
								block->mEntryBlocks[j] = block->BuildSingleExit(mProc, block->mEntryBlocks[j]);
								if (areg >= 0 && mEntryRequiredRegs[areg])
								{
									if (areg == CPU_REG_X)
										block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_TXA));
									else if (areg == CPU_REG_Y)
										block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_TYA));
									else
										block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, areg));
									block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_A;
								}
								if (yreg >= 0 && mEntryRequiredRegs[yreg])
								{
									block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDY, ASMIM_ZERO_PAGE, yreg));
									block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_Y;
								}
								if (xreg >= 0 && mEntryRequiredRegs[xreg])
								{
									block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(block->mEntryBlocks[j]->mBranchIns, ASMIT_LDX, ASMIM_ZERO_PAGE, xreg));
									block->mEntryBlocks[j]->mExitRequiredRegs += CPU_REG_X;
								}
							}
						}

						int yoffset = 0, xoffset = 0, xskew = 0, yskew = 0;

						for (int j = 0; j < block->mIns.Size(); j++)
						{
							NativeCodeInstruction& ins(block->mIns[j]);

							switch (ins.mType)
							{
							case ASMIT_LDY:
							case ASMIT_STY:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
								{
									ins.mType = ASMIT_NOP;
									ins.mMode = ASMIM_IMPLIED;
									yoffset = 0;
									yskew = 0;
								}
								break;
							case ASMIT_LDX:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									if (ins.mLive & LIVE_CPU_REG_Z)
									{
										if (!(ins.mLive & LIVE_CPU_REG_A))
										{
											ins.mType = ASMIT_TXA;
											ins.mMode = ASMIM_IMPLIED;
										}
										else
										{
											ins.mType = ASMIT_CPX;
											ins.mMode = ASMIM_IMMEDIATE;
											ins.mAddress = 0;
										}
									}
									else
									{
										ins.mType = ASMIT_NOP;
										ins.mMode = ASMIM_IMPLIED;
									}
									xoffset = 0;
									xskew = 0;
								}
								break;
							case ASMIT_STX:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									ins.mType = ASMIT_NOP;
									ins.mMode = ASMIM_IMPLIED;
									xoffset = 0;
									xskew = 0;
								}
								break;
							case ASMIT_ASL:
							case ASMIT_LSR:
							case ASMIT_ROL:
							case ASMIT_ROR:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
									ins.mMode = ASMIM_IMPLIED;
								break;

							case ASMIT_INC:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
								{
									ins.mType = ASMIT_INY;
									ins.mMode = ASMIM_IMPLIED;
									yskew += 1;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									ins.mType = ASMIT_INX;
									ins.mMode = ASMIM_IMPLIED;
									xskew += 1;
								}
								break;
							case ASMIT_DEC:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
								{
									ins.mType = ASMIT_DEY;
									ins.mMode = ASMIM_IMPLIED;
									yskew -= 1;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									ins.mType = ASMIT_DEX;
									ins.mMode = ASMIM_IMPLIED;
									xskew -= 1;
								}
								break;

							case ASMIT_LDA:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
								{
									ins.mType = ASMIT_NOP;
									ins.mMode = ASMIM_IMPLIED;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
								{
									ins.mType = ASMIT_TYA;
									ins.mMode = ASMIM_IMPLIED;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									ins.mType = ASMIT_TXA;
									ins.mMode = ASMIM_IMPLIED;
								}
								break;
							case ASMIT_STA:
								if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == areg)
								{
									ins.mType = ASMIT_NOP;
									ins.mMode = ASMIM_IMPLIED;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg)
								{
									ins.mType = ASMIT_TAY;
									ins.mMode = ASMIM_IMPLIED;
								}
								else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg)
								{
									ins.mType = ASMIT_TAX;
									ins.mMode = ASMIM_IMPLIED;
								}
								break;

							case ASMIT_INY:
								yoffset++;
								break;
							case ASMIT_DEY:
								yoffset--;
								break;
							case ASMIT_INX:
								xoffset++;
								break;
							case ASMIT_DEX:
								xoffset--;
								break;

							case ASMIT_TXA:
								if (areg == CPU_REG_X)
									ins.mType = ASMIT_NOP;
								break;
							case ASMIT_TYA:
								if (areg == CPU_REG_Y)
									ins.mType = ASMIT_NOP;
								break;
							}

							if (yoffset && yreg >= 0 && !(ins.mLive & LIVE_CPU_REG_Y))
							{
								if (j + 1 == block->mIns.Size() && !block->mExitRequiredRegs[yreg])
									yoffset = 0;
								else
								{
									if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.mType == ASMIT_CMP)
									{
										printf("oopsie Y\n");
									}
									else
									{
										j = block->CorrectYOffset(ins.mIns, yoffset, j + 1) - 1;
										yoffset = 0;

										if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag())
										{
											ins.mLive |= LIVE_CPU_REG_A;
											block->mIns.Push(NativeCodeInstruction(ins.mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
										}
									}
								}
							}

							if (xoffset && xreg >= 0 && !(ins.mLive & LIVE_CPU_REG_X))
							{
								if (j + 1 == block->mIns.Size() && !block->mExitRequiredRegs[xreg])
									xoffset = 0;
								else
								{
									if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.mType == ASMIT_CMP)
									{
										printf("oopsie X\n");
									}
									else
									{
										j = block->CorrectXOffset(ins.mIns, xoffset, j + 1) - 1;
										xoffset = 0;

										if (j + 1 == block->mIns.Size() && (ins.mLive & LIVE_CPU_REG_Z) && ins.ChangesAccuAndFlag())
										{
											ins.mLive |= LIVE_CPU_REG_A;
											block->mIns.Push(NativeCodeInstruction(ins.mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0));
										}
									}
								}
							}

							if (yreg >= 0)
								ins.mLive |= LIVE_CPU_REG_Y;
							if (xreg >= 0)
								ins.mLive |= LIVE_CPU_REG_X;
							if (areg >= 0)
								ins.mLive |= LIVE_CPU_REG_A;

						}

						if (block->mTrueJump)
						{
							if (!lblocks.Contains(block->mTrueJump))
							{
								block->mTrueJump = block->BuildSingleEntry(mProc, block->mTrueJump);
								if (areg >= 0 && block->mTrueJump->mEntryRequiredRegs[areg])
								{
									if (areg < 256)
										block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg));
										block->mExitRequiredRegs += CPU_REG_A;
										block->mTrueJump->mEntryRequiredRegs += CPU_REG_A;
								}
								if (yreg >= 0 && block->mTrueJump->mEntryRequiredRegs[yreg])
								{
									int j = block->mTrueJump->CorrectYOffset(block->mBranchIns, yoffset, 0);
									block->mTrueJump->mIns.Insert(j, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));

									block->mExitRequiredRegs += CPU_REG_Y;
									block->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
								}
								if (xreg >= 0 && block->mTrueJump->mEntryRequiredRegs[xreg])
								{
									int j = block->mTrueJump->CorrectXOffset(block->mBranchIns, xoffset, 0);

									block->mTrueJump->mIns.Insert(j, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg));
									block->mExitRequiredRegs += CPU_REG_X;
									block->mTrueJump->mEntryRequiredRegs += CPU_REG_X;
								}
							}
							else
							{
								if (yreg >= 0 && yoffset != 0 && block->mFalseJump->mEntryRequiredRegs[yreg])
									block->mTrueJump->CorrectYOffset(block->mBranchIns, yoffset, 0);
								if (xreg >= 0 && xoffset != 0 && block->mFalseJump->mEntryRequiredRegs[xreg])
									block->mTrueJump->CorrectXOffset(block->mBranchIns, xoffset, 0);
							}
						}
						if (block->mFalseJump)
						{
							if (!lblocks.Contains(block->mFalseJump))
							{
								block->mFalseJump = block->BuildSingleEntry(mProc, block->mFalseJump);
								if (areg >= 0 && block->mFalseJump->mEntryRequiredRegs[areg])
								{
									if (areg < 256)
										block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg));
									block->mExitRequiredRegs += CPU_REG_A;
									block->mFalseJump->mEntryRequiredRegs += CPU_REG_A;
								}
								if (yreg >= 0 && block->mFalseJump->mEntryRequiredRegs[yreg])
								{
									int j = block->mTrueJump->CorrectYOffset(block->mBranchIns, yoffset, 0);
									block->mFalseJump->mIns.Insert(j, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg));
									block->mExitRequiredRegs += CPU_REG_Y;
									block->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
								}
								if (xreg >= 0 && block->mFalseJump->mEntryRequiredRegs[xreg])
								{
									int j = block->mTrueJump->CorrectXOffset(block->mBranchIns, xoffset, 0);
									block->mFalseJump->mIns.Insert(j, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg));
									block->mExitRequiredRegs += CPU_REG_X;
									block->mFalseJump->mEntryRequiredRegs += CPU_REG_X;
								}
							}
							else
							{
								if (yreg >= 0 && yoffset != 0 && block->mFalseJump->mEntryRequiredRegs[yreg])
									block->mFalseJump->CorrectYOffset(block->mBranchIns, yoffset, 0);
								if (xreg >= 0 && xoffset != 0 && block->mFalseJump->mEntryRequiredRegs[xreg])
									block->mFalseJump->CorrectXOffset(block->mBranchIns, xoffset, 0);
							}
						}

						block->CheckLive();
					}

					CheckLive();

					changed = true;
				}
			}
		}

		mVisited = true;

		if (mTrueJump && mTrueJump->OptimizeGenericLoop())
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeGenericLoop())
			changed = true;
	}

	return changed;
}

void NativeCodeBasicBlock::CollectReachable(ExpandingArray<NativeCodeBasicBlock*>& lblock)
{
	if (!mVisited && !mPatched)
	{
		lblock.Push(this);
		mPatched = true;

		if (mTrueJump) mTrueJump->CollectReachable(lblock);
		if (mFalseJump) mFalseJump->CollectReachable(lblock);
	}
}

bool NativeCodeBasicBlock::CollectGenericLoop(ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
	ExpandingArray<NativeCodeBasicBlock*>	 rblocks;
	
	mProc->ResetPatched();
	CollectReachable(rblocks);
	
	mProc->ResetPatched();
	
	bool	changed;
	do
	{
		changed = false;

		for (int i = 0; i < rblocks.Size(); i++)
		{
			NativeCodeBasicBlock* block(rblocks[i]);

			if (!block->mPatched &&
				(block->mTrueJump && (block->mTrueJump->mPatched || block->mTrueJump == this) ||
					block->mFalseJump && (block->mFalseJump->mPatched || block->mFalseJump == this)))
			{
				lblocks.Push(block);
				block->mPatched = true;
				changed = true;
			}
		}

	} while (changed);

	return lblocks.Size() > 0;
}

bool NativeCodeBasicBlock::CollectSingleEntryGenericLoop(ExpandingArray<NativeCodeBasicBlock*>& lblocks)
{
	if (CollectGenericLoop(lblocks))
	{
		for (int i = 0; i < lblocks.Size(); i++)
		{
			NativeCodeBasicBlock* block = lblocks[i];

			if (block != this)
			{
				for (int j = 0; j < block->mEntryBlocks.Size(); j++)
					if (!lblocks.Contains(block->mEntryBlocks[j]))
						return false;
			}
		}

		return true;
	}
	else
		return false;
}


bool NativeCodeBasicBlock::OptimizeFindLoop(NativeCodeProcedure* proc)
{
	bool changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		if (mLoopHead && mNumEntries == 2)
		{
			if (mTrueJump && mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 1)
			{
				NativeCodeBasicBlock* succ = nullptr, * body = nullptr;

				if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump == this)
				{
					succ = mTrueJump;
					body = mFalseJump;
				}
				else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump == this)
				{
					succ = mFalseJump;
					body = mTrueJump;
				}

				if (succ)
				{
					NativeCodeBasicBlock* pred = mEntryBlocks[0];
					if (pred == body)
						pred = mEntryBlocks[1];

					if (!pred->mFalseJump)
					{
						if (mIns.Size() > 0 && body->mIns.Size() > 0)
						{
							int	fsz = body->mIns.Size();

							if (mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE &&
								body->mIns[fsz - 1].mType == ASMIT_INC && body->mIns[fsz - 1].SameEffectiveAddress(mIns[0]))
							{
								int i = 1;
								while (i < mIns.Size() && !mIns[i].ChangesYReg() && !mIns[i].ReferencesZeroPage(mIns[0].mAddress))
									i++;
								if (i == mIns.Size())
								{
									i = 0;
									while (i + 1 < fsz && !body->mIns[i].ChangesYReg() && !body->mIns[i].ReferencesZeroPage(mIns[0].mAddress))
										i++;
									if (i + 1 == fsz)
									{
										pred->mIns.Push(mIns[0]);
										succ->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
										body->mIns[fsz - 1].mType = ASMIT_INY;
										body->mIns[fsz - 1].mMode = ASMIM_IMPLIED;
										mIns.Remove(0);

										body->mEntryRequiredRegs += CPU_REG_Y;
										body->mExitRequiredRegs += CPU_REG_Y;
										mEntryRequiredRegs += CPU_REG_Y;
										mExitRequiredRegs += CPU_REG_Y;
										succ->mEntryRequiredRegs += CPU_REG_Y;

										for (int i = 0; i < mIns.Size(); i++)
											mIns[i].mLive |= LIVE_CPU_REG_Y;
										for (int i = 0; i < fsz; i++)
											body->mIns[i].mLive |= LIVE_CPU_REG_Y;

										changed = true;
									}
								}
							}
						}

						if (!ReferencesYReg() && body->mIns.Size() > 0 && body->mIns[0].mType == ASMIT_LDY && body->mIns[0].mMode == ASMIM_ZERO_PAGE && !mExitRequiredRegs[CPU_REG_Y])
						{
							int		incdec = 0;
							bool	fail = false;
							int		addr = body->mIns[0].mAddress;
							if (!ReferencesZeroPage(addr))
							{
								for (int i = 1; i < body->mIns.Size(); i++)
								{
									const NativeCodeInstruction& bins(body->mIns[i]);
									if (bins.mMode == ASMIM_ZERO_PAGE && bins.mAddress == addr)
									{
										if (bins.mType == ASMIT_INC)
											incdec++;
										else if (bins.mType == ASMIT_DEC)
											incdec--;
										else
										{
											fail = true;
											break;
										}
									}
									else if (bins.ReferencesZeroPage(addr))
										fail = true;
									else if (bins.ChangesYReg())
										fail = true;
								}

								if (!fail)
								{
									if (pred->mIns.Size() > 0 && (pred->mIns.Last().mLive & LIVE_CPU_REG_Z))
										pred->mIns.Insert(pred->mIns.Size() - 1, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
									else
										pred->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, addr));
									body->mIns.Remove(0);
									while (incdec > 0)
									{
										if (body->mIns.Size() > 0 && (body->mIns.Last().mLive & LIVE_CPU_REG_Z))
											body->mIns.Insert(body->mIns.Size() - 1, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_INY));
										else
											body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_INY));
										incdec--;
									}
									while (incdec < 0)
									{
										if (body->mIns.Size() > 0 && (body->mIns.Last().mLive & LIVE_CPU_REG_Z))
											body->mIns.Insert(body->mIns.Size() - 1, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_DEY));
										else
											body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_DEY));
										incdec++;
									}
									for (int i = 0; i < body->mIns.Size(); i++)
									{
										if (body->mIns[i].mMode == ASMIM_ZERO_PAGE && body->mIns[i].mAddress == addr)
										{
											body->mIns[i].mType = ASMIT_NOP; body->mIns[i].mMode = ASMIM_IMPLIED;
										}
									}
									succ->mIns.Insert(0, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));

									body->mEntryRequiredRegs += CPU_REG_Y;
									body->mExitRequiredRegs += CPU_REG_Y;
									mEntryRequiredRegs += CPU_REG_Y;
									mExitRequiredRegs += CPU_REG_Y;
									succ->mEntryRequiredRegs += CPU_REG_Y;

									for (int i = 0; i < mIns.Size(); i++)
										mIns[i].mLive |= LIVE_CPU_REG_Y;
									for (int i = 0; i < body->mIns.Size(); i++)
										body->mIns[i].mLive |= LIVE_CPU_REG_Y;

									changed = true;
								}
							}
						}
						else if (!ReferencesXReg() && body->mIns.Size() > 0 && body->mIns[0].mType == ASMIT_LDX && body->mIns[0].mMode == ASMIM_ZERO_PAGE && !mExitRequiredRegs[CPU_REG_X])
						{
							int		incdec = 0;
							bool	fail = false;
							int		addr = body->mIns[0].mAddress;
							if (!ChangesZeroPage(addr))
							{
								bool	references = ReferencesZeroPage(addr);

								for (int i = 1; i < body->mIns.Size(); i++)
								{
									const NativeCodeInstruction& bins(body->mIns[i]);
									if (bins.mMode == ASMIM_ZERO_PAGE && bins.mAddress == addr)
									{
										if (bins.mType == ASMIT_INC)
											incdec++;
										else if (bins.mType == ASMIT_DEC)
											incdec--;
										else
										{
											fail = true;
											break;
										}
									}
									else if (bins.ReferencesZeroPage(addr))
										fail = true;
									else if (bins.ChangesXReg())
										fail = true;
								}

								if (!fail)
								{
									pred->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, addr));
									body->mIns.Remove(0);
									while (incdec > 0)
									{
										body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_INX));
										incdec--;
									}
									while (incdec < 0)
									{
										body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_DEX));
										incdec++;
									
									}

									for (int i = 0; i < body->mIns.Size(); i++)
									{
										if (body->mIns[i].mMode == ASMIM_ZERO_PAGE && body->mIns[i].mAddress == addr)
										{
											body->mIns[i].mType = ASMIT_NOP; body->mIns[i].mMode = ASMIM_IMPLIED;
										}
									}

									if (references)
										body->mIns.Push(NativeCodeInstruction(body->mIns[0].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr));
									else
										succ->mIns.Insert(0, NativeCodeInstruction(body->mIns[0].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr));

									body->mEntryRequiredRegs += CPU_REG_X;
									body->mExitRequiredRegs += CPU_REG_X;
									mEntryRequiredRegs += CPU_REG_X;
									mExitRequiredRegs += CPU_REG_X;
									succ->mEntryRequiredRegs += CPU_REG_X;

									for (int i = 0; i < mIns.Size(); i++)
										mIns[i].mLive |= LIVE_CPU_REG_X;
									for (int i = 0; i < body->mIns.Size(); i++)
										body->mIns[i].mLive |= LIVE_CPU_REG_X;

									changed = true;
								}
							}
						}
					}
				}
			}
		}

		CheckLive();

		if (mTrueJump && mTrueJump->OptimizeFindLoop(proc))
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeFindLoop(proc))
			changed = true;
	}

	return changed;
}

bool NativeCodeBasicBlock::OptimizeSelect(NativeCodeProcedure* proc)
{
	bool	changed = false;

	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);

		if (mFalseJump && mIns.Size() > 0 && mIns.Last().ChangesAccuAndFlag() &&
			mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
			!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump &&
			mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
			mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
		{
			if (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ)
			{
				uint8	vt = mTrueJump->mIns[0].mAddress, vf = mFalseJump->mIns[0].mAddress;
				mTrueJump = mTrueJump->mTrueJump;
				mFalseJump = nullptr;

				if (mBranch == ASMIT_BEQ)
				{
					char t = vt; vt = vf; vf = t;
				}

				mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_A;

				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_CMP, ASMIM_IMMEDIATE, 1));
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, 0xff));
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_AND, ASMIM_IMMEDIATE, vt ^ vf));
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, vt));
				changed = true;

				mBranch = ASMIT_JMP;
			}
		}

		CheckLive();

		assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);

		if (mTrueJump && mTrueJump->OptimizeSelect(proc))
			changed = true;
		if (mFalseJump && mFalseJump->OptimizeSelect(proc))
			changed = true;
	}

	return changed;
}

static bool CheckBlockCopySequence(const ExpandingArray<NativeCodeInstruction>& ins, int si, int n)
{
	if (si + 2 * n <= ins.Size() &&
		ins[si + 0].mType == ASMIT_LDA && (ins[si + 0].mMode == ASMIM_ZERO_PAGE || ins[si + 0].mMode == ASMIM_ABSOLUTE) &&
		ins[si + 1].mType == ASMIT_STA && (ins[si + 1].mMode == ASMIM_ZERO_PAGE || ins[si + 1].mMode == ASMIM_ABSOLUTE))
	{
		for (int i = 1; i < n; i++)
		{
			if (!(ins[si + 2 * i + 0].mType == ASMIT_LDA && ins[si + 2 * i + 0].mMode == ins[si + 0].mMode && ins[si + 2 * i + 0].mAddress == ins[si + 0].mAddress + i &&
				  ins[si + 2 * i + 1].mType == ASMIT_STA && ins[si + 2 * i + 1].mMode == ins[si + 1].mMode && ins[si + 2 * i + 1].mAddress == ins[si + 1].mAddress + i))
				return false;
		}
		if (ins[si + 2 * n - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
			return false;

		return true;
	}
	else
		return false;
}

void NativeCodeBasicBlock::BranchAccuAlternativeElimination(void)
{
	if (!mVisited)
	{
		mVisited = true;
		if (mTrueJump && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) &&
			mTrueJump->mEntryBlocks.Size() == 1 && mFalseJump->mEntryBlocks.Size() == 1 && 
			mIns.Size() > 0 && mIns[mIns.Size() - 1].ChangesAccuAndFlag() &&
			!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)
		{
			NativeCodeBasicBlock* eblock = mTrueJump->mTrueJump;
			if (eblock->mEntryBlocks.Size() == 2)
			{
				if (mBranch == ASMIT_BEQ)
				{
					mTrueJump->mIns[0].mType = ASMIT_EOR;
					mFalseJump->mIns[0].mAddress ^= mTrueJump->mIns[0].mAddress;
					eblock->mEntryBlocks.RemoveAll(mFalseJump);
					eblock->mNumEntries--;
					mFalseJump->mTrueJump = mTrueJump;
					mTrueJump->mNumEntries++;
					mTrueJump->mEntryBlocks.Push(mFalseJump);
					mTrueJump->mEntryRequiredRegs += CPU_REG_A;
				}
				else
				{
					mFalseJump->mIns[0].mType = ASMIT_EOR;
					mTrueJump->mIns[0].mAddress ^= mFalseJump->mIns[0].mAddress;
					eblock->mEntryBlocks.RemoveAll(mTrueJump);
					eblock->mNumEntries--;
					mTrueJump->mTrueJump = mFalseJump;
					mFalseJump->mNumEntries++;
					mFalseJump->mEntryBlocks.Push(mTrueJump);
					mFalseJump->mEntryRequiredRegs += CPU_REG_A;
				}

				mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_A;
				mExitRequiredRegs += CPU_REG_A;
			}
		}

		if (mTrueJump) mTrueJump->BranchAccuAlternativeElimination();
		if (mFalseJump) mFalseJump->BranchAccuAlternativeElimination();
	}
}

bool NativeCodeBasicBlock::BlockSizeCopyReduction(NativeCodeProcedure* proc, int& si, int& di) 
{
	if ((proc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
	{
		if (si + 1 < mIns.Size() &&
			mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE))
		{
			int i = 1;
			while (si + 2 * i + 1 < mIns.Size() &&
				mIns[si + 2 * i + 0].mType == ASMIT_LDA && mIns[si + 2 * i + 0].mMode == mIns[si + 0].mMode && mIns[si + 2 * i + 0].mAddress == mIns[si + 0].mAddress + i &&
				mIns[si + 2 * i + 1].mType == ASMIT_STA && mIns[si + 2 * i + 1].mMode == mIns[si + 1].mMode && mIns[si + 2 * i + 1].mAddress == mIns[si + 1].mAddress + i &&
				!(mIns[si + 2 * i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				i++;
			}

			if (i > 2)
			{
				if (!(mIns[si + 0].mLive & LIVE_CPU_REG_X))
				{
					int	k = 1;
					while (CheckBlockCopySequence(mIns, si + 2 * k * i, i))
						k++;

					if (k == 1 && i == 4 && mIns[si + 0].mMode == ASMIM_ZERO_PAGE && mIns[si + 1].mMode == ASMIM_ZERO_PAGE)
					{
						if (mIns[si + 0].mAddress == BC_REG_ACCU)
						{
							NativeCodeGenerator::Runtime& frt(mProc->mGenerator->ResolveRuntime(Ident::Unique("store32")));
							mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, mIns[si + 1].mAddress);
							si += 8;
							return true;
						}
						else if (mIns[si + 1].mAddress == BC_REG_ACCU)
						{
							NativeCodeGenerator::Runtime& frt(mProc->mGenerator->ResolveRuntime(Ident::Unique("load32")));
							mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER | NCIF_USE_ZP_32_X, mIns[si + 0].mAddress);
							si += 8;
							return true;
						}
					}

					int	sz = 3 + 4 * k;
					for (int j = 0; j < k; j++)
					{
						NativeCodeInstruction	lins = mIns[si + 2 * i * j + 0];
						NativeCodeInstruction	sins = mIns[si + 2 * i * j + 1];

						if (lins.mMode == ASMIM_ZERO_PAGE || (lins.mLinkerObject && (lins.mLinkerObject->mFlags & LOBJF_ZEROPAGE)))
							lins.mMode = ASMIM_ZERO_PAGE_X;
						else
						{
							lins.mMode = ASMIM_ABSOLUTE_X;
							sz++;
						}
						if (sins.mMode == ASMIM_ZERO_PAGE || (sins.mLinkerObject && (sins.mLinkerObject->mFlags & LOBJF_ZEROPAGE)))
							sins.mMode = ASMIM_ZERO_PAGE_X;
						else
						{
							sins.mMode = ASMIM_ABSOLUTE_X;
							sz++;
						}

						if (j == 0)
							mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_LDX, ASMIM_IMMEDIATE, i - 1);

						mIns[di++] = lins;
						mIns[di++] = sins;
					}

					mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_DEX, ASMIM_IMPLIED);
					mIns[di++] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_BPL, ASMIM_RELATIVE, -sz);

					si += 2 * i * k;

					return true;
				}					
			}

		}
		if (si + 2 < mIns.Size() &&
			mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE) &&
			mIns[si + 1].mType == ASMIT_STA && (mIns[si + 1].mMode == ASMIM_ZERO_PAGE || mIns[si + 1].mMode == ASMIM_ABSOLUTE))
		{
			int i = 1;
			while (si + 3 * i + 2 < mIns.Size() &&
				mIns[si + 3 * i + 0].mType == ASMIT_LDA && mIns[si + 3 * i + 0].mMode == mIns[si + 0].mMode && mIns[si + 3 * i + 0].mAddress == mIns[si + 0].mAddress + i &&
				mIns[si + 3 * i + 1].mType == ASMIT_STA && mIns[si + 3 * i + 1].mMode == mIns[si + 1].mMode && mIns[si + 3 * i + 1].mAddress == mIns[si + 1].mAddress + i &&
				mIns[si + 3 * i + 2].mType == ASMIT_STA && mIns[si + 3 * i + 2].mMode == mIns[si + 2].mMode && mIns[si + 3 * i + 2].mAddress == mIns[si + 2].mAddress + i &&
				!(mIns[si + 3 * i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				i++;
			}

			if (i > 2)
			{
				if (!(mIns[si + 0].mLive & LIVE_CPU_REG_X))
				{
					NativeCodeInstruction	lins = mIns[si + 0];
					NativeCodeInstruction	sins0 = mIns[si + 1];
					NativeCodeInstruction	sins1 = mIns[si + 2];

					int	sz = 9;
					if (lins.mMode == ASMIM_ZERO_PAGE)
						lins.mMode = ASMIM_ZERO_PAGE_X;
					else
					{
						lins.mMode = ASMIM_ABSOLUTE_X;
						sz++;
					}
					if (sins0.mMode == ASMIM_ZERO_PAGE)
						sins0.mMode = ASMIM_ZERO_PAGE_X;
					else
					{
						sins0.mMode = ASMIM_ABSOLUTE_X;
						sz++;
					}
					if (sins1.mMode == ASMIM_ZERO_PAGE)
						sins1.mMode = ASMIM_ZERO_PAGE_X;
					else
					{
						sins1.mMode = ASMIM_ABSOLUTE_X;
						sz++;
					}

					mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_LDX, ASMIM_IMMEDIATE, i - 1);
					mIns[di++] = lins;
					mIns[di++] = sins0;
					mIns[di++] = sins1;
					mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_DEX, ASMIM_IMPLIED);
					mIns[di++] = NativeCodeInstruction(lins.mIns, ASMIT_BPL, ASMIM_RELATIVE, -sz);

					si += 3 * i;

					return true;
				}
			}

		}

#if 1
		if (si + 5 < mIns.Size() &&
			mIns[si + 0].mType == ASMIT_LDY && mIns[si + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[si + 1].mType == ASMIT_STA && mIns[si + 1].mMode == ASMIM_INDIRECT_Y &&
			!(mIns[si + 1].mLive & LIVE_CPU_REG_C))
		{
			int i = 1;
			while (si + 2 * i + 1 < mIns.Size() &&
				mIns[si + 2 * i + 0].mType == ASMIT_LDY &&
				mIns[si + 2 * i + 0].mMode == ASMIM_IMMEDIATE &&
				mIns[si + 2 * i + 0].mAddress == mIns[si + 0].mAddress + i &&
				mIns[si + 2 * i + 1].mType == ASMIT_STA &&
				mIns[si + 2 * i + 1].mMode == ASMIM_INDIRECT_Y &&
				mIns[si + 2 * i + 1].mAddress == mIns[si + 1].mAddress)
			{
				i++;
			}

			if (i > 2)
			{
				int k = mIns[si + 0].mAddress + i - 1;
				mIns[di + 0] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[si + 0].mAddress - 1);
				mIns[di + 2] = mIns[si + 1];
				mIns[di + 1] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_INY);
				mIns[di + 3] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_CPY, ASMIM_IMMEDIATE, k);
				mIns[di + 4] = NativeCodeInstruction(mIns[si + 0].mIns, ASMIT_BNE, ASMIM_RELATIVE, -7);
				di += 5;
				si += 2 * i;
				if (si == mIns.Size())
				{
					mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 1);
					mNDataSet.Set(CPU_REG_Z, NRDM_IMMEDIATE, 0);
				}
				return true;
			}
		}
#endif
	}

	return false;
}

// Size reduction violating various assumptions such as no branches in basic blocks
// must be last step before actual assembly

void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc, int xenter, int yenter, int center)
{
	if (!mVisited)
	{
		mVisited = true;

		CheckLive();

		int i = 0;
		int j = 0;

		if (mEntryBlocks.Size() == 1 && 
			mEntryBlocks[0]->mIns.Size() > 0 && mIns.Size() > 0 && 
			mIns[0].mType == ASMIT_CMP && mIns[0].mMode == ASMIM_IMMEDIATE &&
			mEntryBlocks[0]->mIns.Last().mType == ASMIT_CMP && mEntryBlocks[0]->mIns.Last().mMode == ASMIM_IMMEDIATE &&
			mIns[0].mAddress == mEntryBlocks[0]->mIns.Last().mAddress)
		{
			// Skip initial compare if same as last of entry block
			i++;
		}

		while (i < mIns.Size())
		{
			if (mIns[i].mType == ASMIT_NOP)
			{
				i++;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;  mIns[j + 1].mAddress = 2;
				mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
				j += 3;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;  mIns[j + 1].mAddress = 2;
				mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
				mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ZERO_PAGE; mIns[j + 3].mAddress = mIns[j + 0].mAddress;
				j += 4;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_TXA &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_TAX &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 4].mAddress &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_TXA; mIns[j + 0].mMode = ASMIM_IMPLIED;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;  mIns[j + 1].mAddress = 2;
				mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 4].mAddress;
				mIns[j + 3].mType = ASMIT_DEX; mIns[j + 3].mMode = ASMIM_IMPLIED;
				j += 4;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 1].mLinkerObject;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;  
				if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 1].mAddress = 2;
				else
					mIns[j + 1].mAddress = 3;
				mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
				j += 3;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 1].mLinkerObject;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE; 
				if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 1].mAddress = 2;
				else
					mIns[j + 1].mAddress = 3;
				mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
				mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ABSOLUTE; mIns[j + 3].mAddress = mIns[j + 0].mAddress; mIns[j + 3].mLinkerObject = mIns[j + 0].mLinkerObject;
				j += 4;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 0].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 0].mLinkerObject;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE; 
				if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 1].mAddress = 2;
				else
					mIns[j + 1].mAddress = 3;
				mIns[j + 2].mType = ASMIT_INC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
				j += 3;
				i += 7;
			}
			else if (i + 6 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0xff &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ABSOLUTE && mIns[i + 6].SameEffectiveAddress(mIns[i + 4]) &&
				!(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_LDA; mIns[j + 0].mMode = ASMIM_ABSOLUTE; mIns[j + 0].mAddress = mIns[i + 0].mAddress; mIns[j + 0].mLinkerObject = mIns[i + 0].mLinkerObject;
				mIns[j + 1].mType = ASMIT_BNE; mIns[j + 1].mMode = ASMIM_RELATIVE;
				if (mIns[i + 4].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 1].mAddress = 2;
				else
					mIns[j + 1].mAddress = 3;
				mIns[j + 2].mType = ASMIT_DEC; mIns[j + 2].mMode = ASMIM_ABSOLUTE; mIns[j + 2].mAddress = mIns[i + 4].mAddress; mIns[j + 2].mLinkerObject = mIns[i + 4].mLinkerObject;
				mIns[j + 3].mType = ASMIT_DEC; mIns[j + 3].mMode = ASMIM_ABSOLUTE; mIns[j + 3].mAddress = mIns[j + 0].mAddress; mIns[j + 2].mLinkerObject = mIns[j + 0].mLinkerObject;
				j += 4;
				i += 7;
			}
			else if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && 
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 &&
				mIns[i + 3].mType == ASMIT_CLC &&
				mIns[i + 4].mType == ASMIT_ADC && !(mIns[i + 4].mLive & LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
			{
				mIns[j + 0] = mIns[i + 0]; mIns[j + 0].mType = ASMIT_SEC;
				mIns[j + 1] = mIns[i + 1];
				mIns[j + 2] = mIns[i + 4];
				j += 3;
				i += 5;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_INX &&
				mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
				!(mIns[i + 2].mLive & LIVE_CPU_REG_X))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_INC; 
				j += 1;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDX && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_DEX &&
				mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
				!(mIns[i + 2].mLive & LIVE_CPU_REG_X))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_DEC; 
				j += 1;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 2;
				mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 2].mAddress;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE; 
				if (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 0].mAddress = 2;
				else
					mIns[j + 0].mAddress = 3;
				mIns[j + 1] = mIns[i + 2];
				mIns[j + 1].mType = ASMIT_INC;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAX &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCC; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 1;
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 2;
				mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 2].mAddress;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE; 
				if (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE)
					mIns[j + 0].mAddress = 2;
				else
					mIns[j + 0].mAddress = 3;
				mIns[j + 1] = mIns[i + 2];
				mIns[j + 1].mType = ASMIT_DEC;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_TXA &&
				mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_TAX &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_BCS; mIns[j + 0].mMode = ASMIM_RELATIVE; mIns[j + 0].mAddress = 1;
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				j += 2;
				i += 3;
			}
#if 1
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
				!(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_AND; mIns[j + 0].mMode = ASMIM_IMMEDIATE; mIns[j + 0].mAddress = 0x80;
				mIns[j + 1].mType = ASMIT_BPL; mIns[j + 1].mMode = ASMIM_RELATIVE;  mIns[j + 1].mAddress = 2;   
				mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = 0xff;
				j += 3;
				i += 4;
			}
#endif
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_INC;
				j += 1;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_DEC;
				j += 1;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_DEC;
				j += 1;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 1]) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_INC;
				j += 1;
				i += 4;
			}

			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}

			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_SEC &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_LDX; 
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 1];
				mIns[j + 0].mType = ASMIT_LDX; 
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].CopyMode(mIns[i + 3]);
				j += 3;
				i += 4;
			}

			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_INX; mIns[j + 2].mMode = ASMIM_IMPLIED;
				mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].CopyMode(mIns[i + 3]);
				j += 4;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
				mIns[i + 1].mType == ASMIT_SEC &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 0].mType = ASMIT_LDX; 
				mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
				mIns[j + 2].mType = ASMIT_DEX; mIns[j + 2].mMode = ASMIM_IMPLIED;
				mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].CopyMode(mIns[i + 3]);
				j += 4;
				i += 4;
			}

			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = nullptr;
				mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 3].mAddress; mIns[j + 1].mLinkerObject = nullptr;
				j += 2;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_DEC; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0].mLinkerObject = nullptr;
				mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].mMode = ASMIM_ZERO_PAGE; mIns[j + 1].mAddress = mIns[i + 3].mAddress; mIns[j + 1].mLinkerObject = nullptr;
				j += 2;
				i += 4;
			}

			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 1].mType == ASMIT_CLC &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_INC; mIns[j + 0].CopyMode(mIns[i + 0]);
				mIns[j + 1].mType = ASMIT_INC; mIns[j + 1].CopyMode(mIns[i + 0]);
				j += 2;
				i += 4;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
				!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
			{
				mIns[j + 0].mType = ASMIT_DEC; mIns[j + 0].CopyMode(mIns[i + 0]);
				mIns[j + 1].mType = ASMIT_DEC; mIns[j + 1].CopyMode(mIns[i + 0]);
				j += 2;
				i += 4;
			}

			else if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
				mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
			{
				mIns[j] = mIns[i];
				mIns[j].mType = ASMIT_LDY;
				mIns[j].mLive |= LIVE_CPU_REG_Y;
				j++;
				i += 2;
			}
			else if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
				mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
			{
				mIns[j] = mIns[i];
				mIns[j].mType = ASMIT_LDX;
				mIns[j].mLive |= LIVE_CPU_REG_Y;
				j++;
				i += 2;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDY && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
				mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 1] = mIns[i + 1];

				mIns[j + 0].mType = ASMIT_LDX;
				mIns[j + 0].mLive |= LIVE_CPU_REG_X;
				mIns[j + 1].mType = ASMIT_LDY;
				mIns[j + 1].mMode = ASMIM_ABSOLUTE_X;
				mIns[j + 1].mLive |= LIVE_CPU_REG_Y;
				j += 2;
				i += 3;
			}
			else if (i + 2 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDX && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
				mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 1] = mIns[i + 1];

				mIns[j + 0].mType = ASMIT_LDY;
				mIns[j + 0].mLive |= LIVE_CPU_REG_Y;
				mIns[j + 1].mType = ASMIT_LDX;
				mIns[j + 1].mMode = ASMIM_ABSOLUTE_Y;
				mIns[j + 1].mLive |= LIVE_CPU_REG_X;
				j += 2;
				i += 3;
			}
			else if (i + 5 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
				mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 5].mType == ASMIT_EOR && mIns[i + 5].mMode == ASMIM_IMMEDIATE)
			{
				char veq = mIns[i + 4].mAddress ^ mIns[i + 5].mAddress, vne = mIns[i + 5].mAddress;

				mIns[j + 0] = mIns[i + 0];
				mIns[j + 1].mType = ASMIT_BEQ; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = veq != 0 ? 4 : 2;
				mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = vne; mIns[j + 2].mFlags = 0;
				j += 3;
				if (veq != 0)
				{
					if (vne)
						mIns[j + 0].mType = ASMIT_BNE;
					else
						mIns[j + 0].mType = ASMIT_BEQ;
					mIns[j + 0].mMode = ASMIM_RELATIVE;
					mIns[j + 0].mAddress = 2;
					mIns[j + 1].mType = ASMIT_LDA; mIns[j + 1].mMode = ASMIM_IMMEDIATE; mIns[j + 1].mAddress = veq; mIns[j + 1].mFlags = 0;
					j += 2;
				}
				i += 6;
			}
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].ChangesAccuAndFlag() &&
				mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x00 &&
				mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED)
			{
				mIns[j + 0] = mIns[i + 0];
				mIns[j + 1].mType = ASMIT_BEQ; mIns[j + 1].mMode = ASMIM_RELATIVE; mIns[j + 1].mAddress = 2;
				mIns[j + 2].mType = ASMIT_LDA; mIns[j + 2].mMode = ASMIM_IMMEDIATE; mIns[j + 2].mAddress = 1;
				j += 3;
				i += 4;
			}
#if 1
			else if (i + 3 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 &&
				mIns[i + 2].mType == ASMIT_CLC &&
				mIns[i + 3].mType == ASMIT_ADC)
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_SEC);
				mIns[j + 1] = mIns[i + 3];
				j += 2;
				i += 4;
			}
			else if (i + 4 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_SEC &&
				mIns[i + 1].mType == ASMIT_LDA &&
				mIns[i + 2].mType == ASMIT_SBC &&
				mIns[i + 3].mType == ASMIT_SEC &&
				mIns[i + 4].mType == ASMIT_SBC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01)
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_CLC);
				j += 3;
				i += 5;
			}
#endif
			else if (i + 3 < mIns.Size() &&
				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 && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
				mIns[i + 3].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z | LIVE_MEM)))
			{
				mIns[j + 0] = mIns[i + 2];
				mIns[j + 1] = mIns[i + 1]; mIns[j + 1].mType = ASMIT_LDY;
				mIns[j + 2] = mIns[i + 3];
				j += 3;
				i += 4;			
			}
			else if (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_X))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX);
				i++;
				j++;
			}
			else if (mIns[i + 0].mType == ASMIT_ORA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y))
			{
				mIns[j + 0] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY);
				i++;
				j++;
			}
			else if (i + 1 < mIns.Size() &&
				mIns[i + 0].ChangesZFlag() && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_A) &&
				!(mIns[i + 0].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				mIns[j++] = mIns[i++];
				i++;
			}
			else if (BlockSizeCopyReduction(proc, i, j))
			{
				
			}
			else
				mIns[j++] = mIns[i++];
		}
		mIns.SetSize(j);

#if 1
		bool	yimm = false, ximm = false, aimm = false, afail = false;
		int		yval = 0, xval = 0, aval = 0;

		if (mNumEntries == 1)
		{
			if (yenter >= 0)
			{
				yval = yenter;
				yimm = true;
			}
			if (xenter >= 0)
			{
				xval = xenter;
				ximm = true;
			}
		}

		for(int i = 0; i < mIns.Size(); i++)
		{
			if (afail)
				aimm = false;

			if (mIns[i].mType == ASMIT_LDA)
			{
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					if (yimm && mIns[i].mAddress == yval)
					{
						mIns[i].mType = ASMIT_TYA;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (ximm && mIns[i].mAddress == xval)
					{
						mIns[i].mType = ASMIT_TXA;
						mIns[i].mMode = ASMIM_IMPLIED;
					}

					aimm = true;
					aval = mIns[i].mAddress;
				}
				else
					aimm = false;
			}
			else if (mIns[i].mType == ASMIT_TYA)
			{
				if (yimm)
				{
					aimm = true;
					aval = yval;
				}
				else
					aimm = false;
			}
			else if (mIns[i].mType == ASMIT_TXA)
			{
				if (ximm)
				{
					aimm = true;
					aval = xval;
				}
				else
					aimm = false;
			}
			else if (mIns[i].mType == ASMIT_LDY)
			{
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					if (yimm && mIns[i].mAddress == yval)
					{
						mIns[i].mType = ASMIT_NOP;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (yimm && mIns[i].mAddress == ((yval + 1) & 0xff))
					{
						yval = mIns[i].mAddress;
						mIns[i].mType = ASMIT_INY;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (yimm && mIns[i].mAddress == ((yval - 1) & 0xff))
					{
						yval = mIns[i].mAddress;
						mIns[i].mType = ASMIT_DEY;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (aimm && mIns[i].mAddress == aval)
					{
						mIns[i].mType = ASMIT_TAY;
						mIns[i].mMode = ASMIM_IMPLIED;
						yimm = true;
						yval = aval;
					}
					else
					{
						yimm = true;
						yval = mIns[i].mAddress;
					}

				}
				else
					yimm = false;
			}
			else if (yimm && mIns[i].mType == ASMIT_INY)
			{
				yval = (yval + 1) & 0xff;
			}
			else if (yimm && mIns[i].mType == ASMIT_DEY)
			{
				yval = (yval - 1) & 0xff;
			}
			else if (mIns[i].mType == ASMIT_TAY)
			{
				if (aimm)
				{
					yimm = true;
					yval = aval;
				}
				else
					yimm = false;
			}
			else if (mIns[i].mType == ASMIT_LDX)
			{
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					if (ximm && mIns[i].mAddress == ((xval + 1) & 0xff))
					{
						xval = mIns[i].mAddress;
						mIns[i].mType = ASMIT_INX;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (ximm && mIns[i].mAddress == ((xval - 1) & 0xff))
					{
						xval = mIns[i].mAddress;
						mIns[i].mType = ASMIT_DEX;
						mIns[i].mMode = ASMIM_IMPLIED;
					}
					else if (aimm && mIns[i].mAddress == aval)
					{
						mIns[i].mType = ASMIT_TAX;
						mIns[i].mMode = ASMIM_IMPLIED;
						ximm = true;
						xval = aval;
					}
					else
					{
						ximm = true;
						xval = mIns[i].mAddress;
					}

				}
				else
					ximm = false;
			}
			else if (ximm && mIns[i].mType == ASMIT_INX)
			{
				xval = (xval + 1) & 0xff;
			}
			else if (ximm && mIns[i].mType == ASMIT_DEX)
			{
				xval = (xval - 1) & 0xff;
			}
			else if (mIns[i].mType == ASMIT_TAX)
			{
				if (aimm)
				{
					ximm = true;
					xval = aval;
				}
				else
					ximm = false;
			}
			else if (mIns[i].mType == ASMIT_JSR)
				yimm = ximm = aimm = false;
			else if (mIns[i].mMode == ASMIM_RELATIVE)
			{
				if (mIns[i].mAddress < 0)
					yimm = ximm = aimm = false;
				else
					afail = true;
			}
			else if (mIns[i].ChangesAccu())
				aimm = false;
		}
#endif

		// Check for small condition block
		if (mFalseJump)
		{
			NativeCodeBasicBlock* cblock = nullptr, * eblock = nullptr;

			if (mTrueJump == mFalseJump->mTrueJump && !mFalseJump->mFalseJump && mTrueJump->mNumEntries == 2 && mFalseJump->mNumEntries == 1)
			{
				cblock = mFalseJump;
				eblock = mTrueJump;
			}
			else if (mFalseJump == mTrueJump->mTrueJump && !mTrueJump->mFalseJump && mFalseJump->mNumEntries == 2 && mTrueJump->mNumEntries == 1)
			{
				cblock = mTrueJump;
				eblock = mFalseJump;
			}

			if (eblock && cblock->mIns.Size() == 1 && (cblock->mIns[0].mType == ASMIT_INC || cblock->mIns[0].mType == ASMIT_INX || cblock->mIns[0].mType == ASMIT_INY))
			{
				int i = 0;
				while (i < eblock->mIns.Size() && !eblock->mIns[i].ReferencesCarry())
					i++;
				if (i < eblock->mIns.Size() && eblock->mIns[i].mType == ASMIT_CLC)
				{
					if (mBranch == ASMIT_BCC && eblock == mTrueJump || mBranch == ASMIT_BCS && eblock == mFalseJump)
					{
						cblock->mIns.Push(NativeCodeInstruction(eblock->mIns[i].mIns, ASMIT_CLC));
						eblock->mIns.Remove(i);
						mExitRequiredRegs += CPU_REG_C;
						cblock->mExitRequiredRegs += CPU_REG_C;
						eblock->mEntryRequiredRegs += CPU_REG_C;
						for (int j = 0; j < i; j++)
							eblock->mIns[j].mLive |= LIVE_CPU_REG_C;
						cblock->mNDataSet.Set(CPU_REG_C, NRDM_IMMEDIATE, 0);
					}
				}
			}
		}

		bool	carrySet = false, carryClear = false;
		if (mEntryBlocks.Size() == 1 && center >= 0)
		{
			if (center)
				carrySet = true;
			else
				carryClear = true;
		}
		else
		{
			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 if (mEntryBlocks[i]->mBranch == ASMIT_BEQ && mEntryBlocks[i]->mTrueJump == this && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_CMP)
					carryClear = false;
				else if (mEntryBlocks[i]->mBranch == ASMIT_BNE && mEntryBlocks[i]->mFalseJump == this && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().mType == ASMIT_CMP)
					carryClear = false;
				else
					carryClear = carrySet = false;
			}
		}

#if 1

		i = 0;
		j = 0;
		int	accuVal = 0, accuMask = 0, xregVal = 0, xregMask = 0, yregVal = 0, yregMask = 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 if (carrySet && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress > 0)
				{
					// convert CLC before const add into SEC and reduce immediate
					skip = true;
					mIns[i + 1].mAddress--;
				}
				else
				{
					carryClear = true;
					carrySet = false;
				}
				break;
			case ASMIT_SEC:
				if (carrySet)
					skip = true;
				else if (carryClear && i + 1 < mIns.Size() && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress > 0)
				{
					// convert SEC before const sub into CLC and reduce immediate
					skip = true;
					mIns[i + 1].mAddress--;
				}
				else
				{
					carryClear = false;
					carrySet = true;
				}
				break;
			case ASMIT_ADC:
			{
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					if (carryClear && mIns[i].mAddress == 0 && !(mIns[i].mLive & LIVE_CPU_REG_Z))
					{
						skip = true;
					}
					else if (carryClear && accuMask == 0xff && accuVal == 0x00 && j > 0 && mIns[j - 1].mType == ASMIT_LDA && mIns[j - 1].mMode == ASMIM_IMMEDIATE)
					{
						mIns[j - 1].mAddress = mIns[i].mAddress;
						skip = true;
					}
					else
					{
						int	amax = ((accuVal & accuMask) | (~accuMask & 255)) + mIns[i].mAddress;
						if (!carryClear)
							amax++;
						if (amax < 256)
						{
							carryClear = true;
							carrySet = false;
							accuMask = ~BinMask(amax) & 255;
							accuVal = 0;
						}
						else
						{
							accuMask = 0;
							accuFlags = true;
							carryClear = false;
							carrySet = false;
						}
					}
				}
				else if (mIns[i].mMaxVal < 255)
				{
					int	amax = ((accuVal & accuMask) | (~accuMask & 255)) + mIns[i].mMaxVal;
					if (!carryClear)
						amax++;
					if (amax < 256)
					{
						carryClear = true;
						carrySet = false;
						accuMask = ~BinMask(amax) & 255;
						accuVal = 0;
					}
					else
					{
						accuMask = 0;
						accuFlags = true;
						carryClear = false;
						carrySet = false;
					}
				}
				else
				{
					accuMask = 0;
					accuFlags = true;
					carryClear = false;
					carrySet = false;
				}
			}	break;
			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_LDX:
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					xregVal = mIns[i].mAddress;
					xregMask = 0xff;
				}
				else
					xregMask = 0;
				accuFlags = false;
				break;
			case ASMIT_LDY:
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					yregVal = mIns[i].mAddress;
					yregMask = 0xff;
				}
				else
					yregMask = 0;
				accuFlags = false;
				break;

			case ASMIT_LDA:
				if (mIns[i].mMode == ASMIM_IMMEDIATE)
				{
					accuVal = mIns[i].mAddress;
					accuMask = 0xff;
				}
				else if (mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_CONST) && mIns[i].mLinkerObject->mReferences.Size() == 0)
				{
					accuVal = mIns[i].mLinkerObject->mData[mIns[i].mAddress];
					accuMask = 0xff;
				}
#if 1
				else if ((mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_ABSOLUTE_Y) && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_CONST) && mIns[i].mLinkerObject->mReferences.Size() == 0)
				{
					int mor = 0;
					int mand = 0xff;
					int ior = 0;
					int iand = 0xff;

					if (mIns[i].mMode == ASMIM_ABSOLUTE_X)
					{
						ior = xregMask & xregVal;
						iand = (~xregMask | xregVal) & 0xff;
					}
					else if (mIns[i].mMode == ASMIM_ABSOLUTE_Y)
					{
						ior = yregMask & yregVal;
						iand = (~yregMask | yregVal) & 0xff;
					}

					int size = mIns[i].mLinkerObject->mSize - mIns[i].mAddress;
					if (mIns[i].mLinkerObject->mStripe > 1)
						size = mIns[i].mLinkerObject->mStripe - mIns[i].mAddress % mIns[i].mLinkerObject->mStripe;
					if (size > 256)
						size = 256;

					for (int j = 0; j < size; j++)
					{
						if ((j & ~iand) == 0 && (j & ior) == ior)
						{
							mor |= mIns[i].mLinkerObject->mData[mIns[i].mAddress + j];
							mand &= mIns[i].mLinkerObject->mData[mIns[i].mAddress + j];
						}
					}

					accuMask = (mand | ~mor) & 0xff;
					accuVal = mand;
				}
#endif
				else
				{
					accuVal = 0;
					accuMask = ~ BinMask(mIns[i].mMaxVal) & 255;
				}
				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:
				xregMask = accuMask;
				xregVal = accuVal;
				accuFlags = true;
				break;
			case ASMIT_TAY:
				yregMask = accuMask;
				yregVal = accuVal;
				accuFlags = true;
				break;
			case ASMIT_TXA:
				accuMask = xregMask;
				accuVal = xregVal;
				accuFlags = true;
				break;
			case ASMIT_TYA:
				accuMask = yregMask;
				accuVal = yregVal;
				accuFlags = true;
				break;
			default:
				if (mIns[i].ChangesCarry())
				{
					carryClear = false;
					carrySet = false;
				}
				if (mIns[i].ChangesXReg())
					xregMask = 0;
				if (mIns[i].ChangesYReg())
					yregMask = 0;

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

		int cval = -1;
		if (carrySet)
			cval = 1;
		else if (carryClear)
			cval = 0;

#endif
		int tcval = cval, fcval = cval;

		if (mBranch == ASMIT_BCC)
		{
			tcval = 0; fcval = 1;
		}
		else if (mBranch == ASMIT_BCS)
		{
			tcval = 1; fcval = 0;
		}

		int xtrue = ximm ? xval : -1, xfalse = xtrue;
		int ytrue = yimm ? yval : -1, yfalse = ytrue;

		if (mIns.Size() > 0)
		{
			const NativeCodeInstruction& ins(mIns.Last());

			if (ins.mMode == ASMIM_IMMEDIATE)
			{
				if (ins.mType == ASMIT_CPY)
				{
					if (mBranch == ASMIT_BEQ)
						ytrue = ins.mAddress;
					else if (mBranch == ASMIT_BNE)
						yfalse = ins.mAddress;
				}
				if (ins.mType == ASMIT_CPX)
				{
					if (mBranch == ASMIT_BEQ)
						xtrue = ins.mAddress;
					else if (mBranch == ASMIT_BNE)
						xfalse = ins.mAddress;
				}
			}
		}


		if (mTrueJump)
			mTrueJump->BlockSizeReduction(proc, xtrue, ytrue, tcval);
		if (mFalseJump)
			mFalseJump->BlockSizeReduction(proc, xfalse, yfalse, fcval);
	}
}

bool NativeCodeBasicBlock::ReferencesAccu(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ReferencesAccu())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ReferencesYReg(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ReferencesYReg())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ReferencesXReg(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ReferencesXReg())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesAccu(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ChangesAccu())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesYReg(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ChangesYReg())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesXReg(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ChangesXReg())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesCarry(int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ChangesCarry())
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesZeroPage(int address, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ChangesZeroPage(address))
			return true;
	return false;
}

bool NativeCodeBasicBlock::UsesZeroPage(int address, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].UsesZeroPage(address))
			return true;
	return false;
}

bool NativeCodeBasicBlock::LoadsZeroPage(int address, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].LoadsZeroPage(address))
			return true;
	return false;
}

bool NativeCodeBasicBlock::ReferencesZeroPage(int address, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].ReferencesZeroPage(address))
			return true;
	return false;
}

bool NativeCodeBasicBlock::ChangesMemory(const NativeCodeInstruction& ins, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (ins.MayBeChangedOnAddress(mIns[i]))
			return true;
	return false;
}

bool NativeCodeBasicBlock::ReferencesMemory(const NativeCodeInstruction& ins, int from, int to) const
{
	if (to > mIns.Size()) to = mIns.Size();
	for (int i = from; i < to; i++)
		if (mIns[i].MayReference(ins))
		return true;
	return false;
}



bool NativeCodeBasicBlock::RemoveNops(void)
{
	bool changed = false;

	assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);

	int i = 0;
	int j = 0;
	while (i < mIns.Size())
	{
		if (mIns[i].mType == ASMIT_NOP)
			;
		else
		{
			if (i != j)
				mIns[j] = mIns[i];
			j++;
		}
		i++;
	}
	if (j != i)
		changed = true;
	mIns.SetSize(j);
	mIns.Reserve(2 * j);

	return changed;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerShuffle(int pass)
{
	bool	changed = false;

#if 1
#if 1
	// move load store pairs up to initial store

	for (int i = 2; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
		{
			if (MoveLoadStoreUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	// replace zero page up

	for (int i = 1; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !(mIns[i + 0].mLive & LIVE_MEM))
		{
			if (ReplaceZeroPageUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

	// Move LDX/LDY up to STA of same address
#if 1
	if (pass >= 9)
	{
		for (int i = 2; i < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				if (MoveLDXUp(i))
					changed = true;
			}
			else if (mIns[i].mType == ASMIT_LDY && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				if (MoveLDYUp(i))
					changed = true;
			}
		}
		CheckLive();
	}
#endif

#if 1
	// move ORA #imm up a shift chain to an LDA #imm

	for (int i = 1; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].IsShift() && mIns[i].mMode == ASMIM_IMPLIED && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
		{
			if (FoldShiftORAIntoLoadImmUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 1].IsLogic() && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
		{
			if (MoveLDAopTAXDown(i))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	// move ORA #imm up a shift chain to an LDA #imm

	for (int i = 1; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
		{
			if (MoveLDXBeforeZ(i))
				changed = true;
		}
	}
	CheckLive();

#endif


#if 1
	// Combine ADC with immediate

	for (int i = 4; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_MEM) &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
		{
			if (CombineImmediateADCUp(i))
				changed = true;
		}
		else if (mIns[i].mType == ASMIT_TXA && !(mIns[i].mLive & LIVE_CPU_REG_X) &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
		{
			if (CombineImmediateADCUpX(i))
				changed = true;
		}
	}

	CheckLive();
#endif

#if 1
	// Move mask after load up

	for (int i = 2; 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_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))

		{
			if (MoveImmOpBeforeStore(i))
				changed = true;
		}
	}

	CheckLive();
#endif

#if 1
	// Move load or zp up

	for (int i = 2; 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_ORA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & LIVE_MEM))

		{
			if (MoveLoadOrZPUp(i))
				changed = true;
		}
	}

	CheckLive();
#endif

#if 1
	// move load store pairs up to initial store

	for (int i = 2; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
		{
			if (MoveLoadStoreXUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	// move load - store (),y up to initial store
	// 

	for (int i = 2; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y)
		{
			if (MoveIndirectLoadStoreUp(i))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	// move load (),y store zp down to potential user
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mFlags & NICT_ZPFLIPPED) &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			if (MoveLoadIndirectTempStoreUp(i))
				changed = true;
		}
		else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			if (MoveIndirectLoadStoreDown(i))
				changed = true;
		}
#if 1
		if (pass > 0 &&
			mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			if (MoveIndirectLoadStoreDownY(i))
				changed = true;
		}
#endif
	}
	CheckLive();


#endif

#if 1
	// move load (),y store zp up to potential user
	for (int i = 4; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y)))
		{
			if (MoveLoadIndirectBypassYUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
		{
			if (MoveTYADCStoreDown(i))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	// move load - store abs up to initial store
	// 

	for (int i = 2; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA &&
			(mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_INDIRECT_Y))
		{
			if (MoveAbsoluteLoadStoreUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	// move load - store abs up to initial store
	// 

	if (pass == 4)
	{
		for (int i = 2; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA &&
				(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].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_INDIRECT_Y) &&
				!(mIns[i + 0].mFlags & NCIF_VOLATILE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				if (MoveGenericLoadStoreUp(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_MEMMAP))
		{
			if (MoveLDSTXOutOfRange(i))
				changed = true;
		}
	}
	CheckLive();

#endif


#if 1
	// move load - add # - store up to initial store
	// 

	for (int i = 2; i + 3 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
			(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
		{
			if (MoveLoadAddImmStoreUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif


#if 1
	// move load - add # - store up to initial store
	// 

	for (int i = 1; i + 2 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].IsLogic() && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) &&
			mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE || mIns[i + 2].mMode == ASMIM_ABSOLUTE_X || mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y) &&
			(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
		{
			if (MoveLoadLogicStoreAbsUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1

	// move load - add - store down to usage

	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_LDA && 
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC &&
			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)))
		{
			if (MoveLoadAddStoreDown(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	// move load - ora/and/eor # - store up to initial store
	// 

	for (int i = 2; i + 2 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			(mIns[i + 1].mType == ASMIT_ORA || mIns[i + 1].mType == ASMIT_AND || mIns[i + 1].mType == ASMIT_EOR) && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
			(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
		{
			if (MoveLoadEorImmStoreUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif


#if 1
	// move load - add # - store with absolute,x up as far possible
	// 

	for (int i = 9; i + 3 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
		{
			if (MoveLoadAddImmStoreAbsXUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	// move load - add ZP - store up to initial store
	// 

	for (int i = 2; i + 3 < mIns.Size(); i++)
	{
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE)
		{
			if (MoveCLCLoadAddZPStoreUp(i))
				changed = true;
		}
#if 1
		else if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
		{
			if (MoveLoadAddZPStoreUp(i))
				changed = true;
		}
#endif
#if 1
		else if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
		{
			if (MoveLoadShiftStoreUp(i))
				changed = true;
		}
#endif
#if 1
		else if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			(mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL) && mIns[i + 1].mMode == ASMIM_IMPLIED &&
			(mIns[i + 2].mType == ASMIT_ROL || mIns[i + 2].mType == ASMIT_ROR) && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
		{
			if (MoveLoadShiftRotateUp(i))
				changed = true;
		}
#endif
	}
	CheckLive();

#endif
#if 1
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].IsShift() && mIns[i].mMode == ASMIM_ZERO_PAGE)
		{
			if (MoveShiftZeroPageUp(i))
			{
				CheckLive();
				changed = true;
			}
		}
	}

	CheckLive();
#endif
#if 1
	// move simple add down to consumer

	if (!changed)
	{
		for (int i = 0; i + 4 < mIns.Size(); i++)
		{
			if (
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && (mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)) == 0)
			{
				if (MoveCLCLoadAddZPStoreDown(i))
					changed = true;
			}
		}
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i + 3 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))

		{
			if (MoveTAXADCSTADown(i))
				changed = true;
		}
	}

	CheckLive();
#endif

	// Combine and shift
	for (int i = 1; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x01 &&
			mIns[i + 1].mType == ASMIT_ORA && 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 + 2].mLive & LIVE_CPU_REG_C))
		{
			int j = i - 1;
			while (j >= 0 && !mIns[j].ReferencesZeroPage(mIns[i + 1].mAddress))
				j--;
			if (j >= 0 && mIns[j].IsShift() && !(mIns[j].mLive & LIVE_CPU_REG_C))
			{
				if (mIns[j].mType == ASMIT_ASL)
				{
					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_ROL;
					mIns[i + 2].mType = ASMIT_LDA;
					mIns[j + 0].mType = ASMIT_NOP; mIns[j + 0].mMode = ASMIM_IMPLIED;
					changed = true;
				}
				else if (mIns[j].mType == ASMIT_LSR)
				{
					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_ROR;
					mIns[i + 2].mType = ASMIT_LDA;
					mIns[j + 0].mType = ASMIT_NOP; mIns[j + 0].mMode = ASMIM_IMPLIED;
					changed = true;
				}
			}
		}
	}

	CheckLive();

	int shifti = -1, shiftr = -1;
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
			mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			!(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
		{
			shifti = i;
			shiftr = mIns[i + 1].mAddress;
			i++;
		}
		else if (shiftr >= 0)
		{
			if (shiftr >= 0 && mIns[i].ReferencesZeroPage(shiftr))
				shiftr = -1;
			else if (
				mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 1 &&
				mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == shiftr &&
				!(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
			{
				mIns[shifti].mType = ASMIT_NOP; mIns[shifti].mMode = ASMIM_IMPLIED;
				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_LDA; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
				mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_ROL));
				shiftr = -1;
				changed = true;
			}
		}
	}

	CheckLive();

#if 1
	for (int i = 0; i < mIns.Size(); i++)
	{
		if ((mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_LDY) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM))
		{
			if (MoveSimpleADCToINCDECDown(i))
				changed = true;
		}
	}

#endif

	// 
	// shorten x/y register lifetime

	CheckLive();
#if 1
		//
		// move ldx/y down

	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
#if 1
		if (mIns[i].mType == ASMIT_LDY)
		{
			if (!mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				if (mIns[i].mMode != ASMIM_ABSOLUTE_X || !mIns[i + 1].ChangesXReg())
				{
					if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
					{
						if (mIns[i + 1].SameEffectiveAddress(mIns[i]))
							mIns[i + 1].mLive |= LIVE_MEM;

						NativeCodeInstruction	ins = mIns[i];
						mIns[i] = mIns[i + 1];
						mIns[i].mLive &= ~LIVE_CPU_REG_Y;
						mIns[i + 1] = ins;
						mIns[i + 1].mLive |= mIns[i].mLive;
						if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X)
							mIns[i].mLive |= LIVE_CPU_REG_X;
					}
				}
			}
		}
		else if (mIns[i].mType == ASMIT_LDX)
		{
			if (!mIns[i + 1].RequiresXReg() && !mIns[i + 1].ChangesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
			{
				if (mIns[i].mMode != ASMIM_ABSOLUTE_Y || !mIns[i + 1].ChangesYReg())
				{
					if (!mIns[i].MayBeChangedOnAddress(mIns[i + 1]))
					{
						if (mIns[i + 1].SameEffectiveAddress(mIns[i]))
							mIns[i + 1].mLive |= LIVE_MEM;

						NativeCodeInstruction	ins = mIns[i];
						mIns[i] = mIns[i + 1];
						mIns[i].mLive &= ~LIVE_CPU_REG_X;
						mIns[i + 1] = ins;
						mIns[i + 1].mLive |= mIns[i].mLive;
						if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y)
							mIns[i].mLive |= LIVE_CPU_REG_Y;
					}
				}
			}
		}
#endif			
	}
	CheckLive();

#endif

#if 1
	// move stx up

	for (int i = 1; i < mIns.Size(); i++)
	{
		if (!(mIns[i].mFlags & NCIF_VOLATILE))
		{
			if (mIns[i].mType == ASMIT_STX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
			{
				if (MoveStoreXUp(i))
					changed = true;
			}
			else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
			{
				if (MoveLoadXUp(i))
					changed = true;
			}
			else if (mIns[i].mType == ASMIT_STY && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE))
			{
				if (i > 1 || mIns[0].mType != ASMIT_STX)
				{
					if (MoveStoreYUp(i))
						changed = true;
				}
			}
			else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
			{
				if (MoveLoadYUp(i))
					changed = true;
			}
		}
	}
	CheckLive();

#endif

#if 1
	if (pass > 10)
	{
		for (int i = 0; i < mIns.Size(); i++)
		{
			if (!(mIns[i].mFlags & NCIF_VOLATILE))
			{
				if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z))
				{
					if (MoveLoadXAbsUpCrossBlock(i))
						changed = true;
				}
			}
		}
		CheckLive();
	}
#endif
#if 1
	// move ldy, sty down if live

	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
			(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
		{
			int j = i;
			while (j + 2 < mIns.Size() &&
				!mIns[j + 2].ReferencesYReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z))
			{
				mIns[j + 0].mLive |= mIns[j + 2].mLive;
				mIns[j + 1].mLive |= mIns[j + 2].mLive;
				mIns[j + 2].mLive &= ~LIVE_CPU_REG_Y;
				mIns.Insert(j, mIns[j + 2]);
				mIns.Remove(j + 3);
				j++;
			}
		}
		else if (mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
			(mIns[i + 2].mLive & LIVE_CPU_REG_X))
		{
			int j = i;
			while (j + 2 < mIns.Size() &&
				!mIns[j + 2].ReferencesXReg() && !(mIns[j + 2].SameEffectiveAddress(mIns[j + 0]) && mIns[j + 2].ChangesAddress()) && !mIns[j + 2].MayBeChangedOnAddress(mIns[j + 1]) && !(mIns[j + 2].mLive & LIVE_CPU_REG_Z))
			{
				mIns[j + 0].mLive |= mIns[j + 2].mLive;
				mIns[j + 1].mLive |= mIns[j + 2].mLive;
				mIns[j + 2].mLive &= ~LIVE_CPU_REG_X;
				mIns.Insert(j, mIns[j + 2]);
				mIns.Remove(j + 3);
				j++;
			}
		}
	}
#endif

#if 1
	// move clc and sec down
	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if ((mIns[i].mType == ASMIT_CLC || mIns[i].mType == ASMIT_SEC) && !mIns[i + 1].RequiresCarry() && !mIns[i + 1].ChangesCarry())
		{
			if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && mIns[i + 2].RequiresCarry())
				;
			else if (i + 2 < mIns.Size() && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mMode == ASMIM_INDIRECT_Y)
				;
			else
			{
				NativeCodeInstruction	pins = mIns[i];
				mIns[i] = mIns[i + 1];
				mIns[i + 1] = pins;
				mIns[i + 1].mLive |= mIns[i].mLive;
				//					changed = true;
			}
		}
	}
	CheckLive();


#endif

#if 1
	// move iny/dey/inx/dex down

	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if ((mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY) && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
		{
			if (i + 3 == mIns.Size() && mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_CPX)
				;	// Avoid bypassing loop iterator
			else if (!mIns[i + 1].RequiresYReg())
			{
				NativeCodeInstruction	pins = mIns[i];
				mIns[i] = mIns[i + 1];
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 1] = pins;
				mIns[i + 1].mLive |= mIns[i].mLive;
			}
			else if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y)
			{
				int cy = RetrieveYValue(i - 1, 2);
				if (mIns[i].mType == ASMIT_INY)
				{
					if (cy == 255)
						mIns[i + 1].mMode = ASMIM_ABSOLUTE;
					else
						mIns[i + 1].mAddress++;
				}
				else
					mIns[i + 1].mAddress--;
				NativeCodeInstruction	pins = mIns[i];
				mIns[i] = mIns[i + 1];
				mIns[i].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 1] = pins;
				mIns[i + 1].mLive |= mIns[i].mLive;
			}
		}
		else if ((mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX) && !mIns[i + 1].ChangesXReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
		{
			if (i + 3 == mIns.Size() && mIns[i + 1].mType == ASMIT_INY && mIns[i + 2].mType == ASMIT_CPY)
				;	// Avoid bypassing loop iterator
			else if (!mIns[i + 1].RequiresXReg())
			{
				NativeCodeInstruction	pins = mIns[i];
				mIns[i] = mIns[i + 1];
				mIns[i].mLive |= LIVE_CPU_REG_X;
				mIns[i + 1] = pins;
				mIns[i + 1].mLive |= mIns[i].mLive;
			}
			else if (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X)
			{
				int cx = RetrieveXValue(i - 1, 2);
				if (mIns[i].mType == ASMIT_INX)
				{
					if (cx == 255)
						mIns[i + 1].mMode = ASMIM_ABSOLUTE;
					else
						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 lda zp/and/tay down
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].IsLogic() && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			if (MoveZpImmTAYDown(i))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	// move tya/clc/adc/tay down
	for (int i = 0; i + 5 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
		{
			if (mIns[i + 4].mType == ASMIT_LDA && (mIns[i + 4].mMode == ASMIM_IMMEDIATE || mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 4].mMode == ASMIM_ZERO_PAGE) &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode != ASMIM_INDIRECT_Y && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
				if (mIns[i + 5].mMode == ASMIM_ABSOLUTE_Y)
					mIns[i + 5].mAddress += mIns[i + 2].mAddress;

				mIns.Insert(i + 0, mIns[i + 4]); mIns.Remove(i + 5);
				mIns.Insert(i + 1, mIns[i + 5]); mIns.Remove(i + 6);
			}
#if 1
			else if (i + 6 < mIns.Size() &&
				mIns[i + 4].mType == ASMIT_LDA && (mIns[i + 4].mMode == ASMIM_IMMEDIATE || mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 4].mMode == ASMIM_ZERO_PAGE) &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode != ASMIM_INDIRECT_Y &&
				mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode != ASMIM_INDIRECT_Y && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
			{
				mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 6].mLive |= LIVE_CPU_REG_Y;
				if (mIns[i + 5].mMode == ASMIM_ABSOLUTE_Y)
					mIns[i + 5].mAddress += mIns[i + 2].mAddress;
				if (mIns[i + 6].mMode == ASMIM_ABSOLUTE_Y)
					mIns[i + 6].mAddress += mIns[i + 2].mAddress;

				mIns.Insert(i + 0, mIns[i + 4]); mIns.Remove(i + 5);
				mIns.Insert(i + 1, mIns[i + 5]); mIns.Remove(i + 6);
				mIns.Insert(i + 2, mIns[i + 6]); mIns.Remove(i + 7);
			}
#endif
		}
	}
	CheckLive();


#endif

#if 1

	// reverse "sta t,lda abs,clc,adc t" to "sta t,clc,adc abs,nop"

	for (int i = 1; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 2].IsCommutative() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mType == ASMIT_CLC || mIns[i + 1].mType == ASMIT_SEC) && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE)
		{
			if (ReverseLoadCommutativeOpUp(i, i + 2))
				changed = true;
		}
		else if (mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE)
		{
			if (ReverseLoadCommutativeOpUp(i, i + 1))
				changed = true;
		}
	}
	CheckLive();

#endif

	// shortcut index
#if 1
	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_TAY)
		{
			int j = i + 2, k = i, n = i;
			while (j < mIns.Size() && !mIns[j].ChangesXReg() && !mIns[j].ChangesYReg())
			{
				if (mIns[j].mMode == ASMIM_ABSOLUTE_Y)
				{
					assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_X));
					mIns[j].mMode = ASMIM_ABSOLUTE_X;
					mIns[j].mFlags |= NICT_INDEXFLIPPED;
					n = j;
					changed = true;
				}
				j++;
			}

			while (k < n)
			{
				mIns[k].mLive |= LIVE_CPU_REG_X;
				k++;
			}
		}
		else if (mIns[i].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_TAX)
		{
			int j = i + 2, k = i, n = i;

			while (j < mIns.Size() && !mIns[j].ChangesXReg() && !mIns[j].ChangesYReg())
			{
				if (mIns[j].mMode == ASMIM_ABSOLUTE_X)
				{
					assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_ABSOLUTE_Y));
					mIns[j].mMode = ASMIM_ABSOLUTE_Y;
					mIns[j].mFlags |= NICT_INDEXFLIPPED;
					n = j;
					changed = true;
				}
				j++;
			}

			while (k < n)
			{
				mIns[k].mLive |= LIVE_CPU_REG_Y;
				k++;
			}
		}
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TAX &&
			mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
		{
			if (MoveLoadStoreOutOfXYRangeUp(i))
				changed = true;
		}
		else if (
			mIns[i + 0].mType == ASMIT_TAY &&
			mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
		{
			if (MoveLoadStoreOutOfXYRangeUp(i))
				changed = true;
		}
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
		{
			if (ReverseReplaceTAX(i))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	// Move TAX and TAY down

	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_TAX)
		{
			int j = i + 1;
			while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ChangesAccu())
				j++;
			if (j < mIns.Size() && mIns[j].mType == ASMIT_CPX && !(mIns[j].mLive & LIVE_CPU_REG_X))
			{
				mIns[j].mType = ASMIT_CMP;
				while (j > i)
				{
					j--;
					mIns[j].mLive |= LIVE_CPU_REG_A;
				}
				changed = true;
			}
		}
		else if (mIns[i].mType == ASMIT_TAY)
		{
			int j = i + 1;
			while (j < mIns.Size() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesAccu())
				j++;
			if (j < mIns.Size() && mIns[j].mType == ASMIT_CPY && !(mIns[j].mLive & LIVE_CPU_REG_Y))
			{
				mIns[j].mType = ASMIT_CMP;
				while (j > i)
				{
					j--;
					mIns[j].mLive |= LIVE_CPU_REG_A;
				}
				changed = true;
			}
		}
	}
	CheckLive();
#endif
#if 1
	int		taxPos = -1, tayPos = -1;
	for (int i = 0; i < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_TAX)
		{
			if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				taxPos = i;
			else
				taxPos = -1;
		}
		else if (mIns[i].mType == ASMIT_TAY)
		{
			if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
				tayPos = i;
			else
				tayPos = -1;
		}
		else if (mIns[i].ChangesXReg())
			taxPos = -1;
		else if (mIns[i].ChangesYReg())
			tayPos = -1;
		else if (mIns[i].mType == ASMIT_TXA)
		{
			if (taxPos >= 0)
			{
				if (!(mIns[i].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)) && JoinTAXARange(taxPos, i) || JoinTAXARangeLive(taxPos, i))
					changed = true;
				taxPos = -1; tayPos = -1;
			}
			else
				taxPos = -1;

		}
		else if (mIns[i].mType == ASMIT_TYA)
		{
			if (tayPos >= 0)
			{
				if (!(mIns[i].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)) && JoinTAYARange(tayPos, i) || JoinTAYARangeLive(tayPos, i))
					changed = true;
				taxPos = -1; tayPos = -1;
			}
			else
				tayPos = -1;
		}
		else if (mIns[i].RequiresXReg())
			taxPos = -1;
		else if (mIns[i].RequiresYReg())
			tayPos = -1;
	}
	CheckLive();

#endif

#if 1
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_TAY ||
			mIns[i].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_TAX)
		{
			if (MergeXYSameValue(i + 2))
				changed = true;
		}
	}
	CheckLive();

#endif


#if 1
	if (pass > 1)
	{
		// move high byte load down, if low byte is immediately needed afterwards

		for (int i = 0; i + 4 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress != mIns[i + 3].mAddress && mIns[i + 2].mAddress + 1 != mIns[i + 3].mAddress &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z))
			{
				if (MoveStoreHighByteDown(i))
					changed = true;
			}
		}
		CheckLive();

		for (int i = 0; i + 4 < mIns.Size(); i++)
		{
			if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
				mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
				mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z))
			{
				if (MoveAddHighByteDown(i))
					changed = true;
			}
		}

		CheckLive();
	}
#endif

#if 1
	for (int i = 2; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
			mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_ZERO_PAGE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
		{
			if (MoveLoadImmStoreAbsoluteUp(i + 0))
				changed = true;
		}
	}
	CheckLive();
#endif

#if 1
	for (int i = 2; i < mIns.Size(); i++)
	{
		if ((mIns[i].mType == ASMIT_ASL || mIns[i].mType == ASMIT_LSR) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z))
		{
			if (MoveASLMemUp(i))
				changed = true;
		}
	}
	CheckLive();
#endif

	if (pass > 1)
	{
#if 1
		// replace zero page down

		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && (mIns[i + 0].mLive & LIVE_MEM))
			{
				if (ReplaceZeroPageDown(i))
					changed = true;
			}
		}
		CheckLive();

#endif
	}
#endif

	CheckLive();

#if 1
	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
			mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 2].mAddress &&
			mIns[i + 3].mType == ASMIT_ROR && mIns[i + 3].mMode == ASMIM_IMPLIED)
		{
			int j = 2;
			while (i + 3 + j < mIns.Size() &&
				mIns[i + 2 + j].mType == ASMIT_LSR && mIns[i + 2 + j].mMode == ASMIM_ZERO_PAGE && mIns[i + 2 + j].mAddress == mIns[i + 1].mAddress &&
				mIns[i + 3 + j].mType == ASMIT_ROR && mIns[i + 3 + j].mMode == ASMIM_IMPLIED)
			{
				j += 2;
			}

			if (i + 2 + j < mIns.Size() && mIns[i + 2 + j].mType == ASMIT_STA && mIns[i + 2 + j].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2 + j].mAddress == mIns[i + 2].mAddress && !(mIns[i + 2 + j].mLive & LIVE_CPU_REG_A))
			{
				int	addrl = mIns[i + 2].mAddress, addrh = mIns[i + 1].mAddress;
				const InterInstruction* iins(mIns[i + 1].mIns);

				for (int k = 0; k < j; k += 2)
				{
					mIns[i + k + 0] = NativeCodeInstruction(iins, ASMIT_LSR, ASMIM_IMPLIED);
					mIns[i + k + 1] = NativeCodeInstruction(iins, ASMIT_ROR, ASMIM_ZERO_PAGE, addrl);
				}
				mIns[i + j] = NativeCodeInstruction(iins, ASMIT_STA, ASMIM_ZERO_PAGE, addrh);
				mIns[i + j + 1].mType = ASMIT_NOP; mIns[i + j + 1].mMode = ASMIM_IMPLIED;
				mIns[i + j + 2].mType = ASMIT_NOP; mIns[i + j + 2].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}
	}

	CheckLive();
#endif

	// move sta zp, tax, lda abs,x , sta zp down to use
#if 1
	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_TAX &&
			mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
		{
			if (MoveStaTaxLdaStaDown(i))
				changed = true;
		}
	}
	CheckLive();


#endif


#if 1
	for (int i = 0; i + 4 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TXA &&
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress >= -2 && mIns[i + 2].mAddress <= 2 || mIns[i + 2].mAddress >= 254 && mIns[i + 2].mAddress < 256) &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
		{
			if (MoveTXADCDown(i))
				changed = true;
		}
	}

	CheckLive();

#endif

#if 1
	for (int i = 0; i + 3 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_TXA &&
			mIns[i + 1].IsLogic() && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
		{
			if (MoveTXALogicTAXDown(i))
				changed = true;
		}
	}

	CheckLive();

#endif

#if 1
	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
			mIns[i + 1].mType == ASMIT_ROR && 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))
		{
			if (ReverseShiftByteOrder(i))
				changed = true;
		}
	}

	CheckLive();

	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
		{
			if (MoveZeroPageSignToCarryDown(i))
				changed = true;
		}
	}

	CheckLive();
	
#endif

	for (int i = 2; i + 1 < mIns.Size(); i++)
	{
		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 + 0].mAddress != mIns[i + 1].mAddress &&	!(mIns[i + 1].mLive & LIVE_CPU_REG_C))
		{
			if (Move16BitShiftUp(i))
				changed = true;
		}
	}

	CheckLive();

	for (int i = 0; i + 2 < mIns.Size(); i++)
	{
		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 + 0].mAddress != mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
		{
			if (Move16BitShiftDown(i))
				changed = true;
		}
		else if (
			mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_ROR && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 0].mAddress != mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
		{
			if (Move16BitShiftDown(i))
				changed = true;
		}
	}

	CheckLive();

#if 1
	for (int i = 3; i + 2 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
			mIns[i + 1].mType == ASMIT_ROR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
			mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_MEM)))
		{
			int at = i - 3;
			while (at >= 0 &&
				!(mIns[at + 0].mType == ASMIT_LDA && mIns[at + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[at + 1].mType == ASMIT_LSR && mIns[at + 1].mMode == ASMIM_IMPLIED &&
					mIns[at + 2].mType == ASMIT_STA && mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[at + 2].mAddress == mIns[i + 2].mAddress))
			{
				at--;
			}

			if (at >= 0 && !ChangesZeroPage(mIns[at + 0].mAddress, at + 2, i) && !ChangesZeroPage(mIns[at + 2].mAddress, at + 3, i))
			{
				mIns[i + 0].CopyMode(mIns[at + 0]);
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}
	}

	CheckLive();

#endif

	
#if 1
	for (int i = 0; i + 1 < mIns.Size(); i++)
	{
		if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
			mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
		{
			int j = 1;
			while (i >= j && i + j + 1 < mIns.Size() &&
				mIns[i - j].mType == ASMIT_ASL && mIns[i - j].mMode == ASMIM_IMPLIED &&
				mIns[i + 1 + j].mType == ASMIT_LSR && mIns[i + 1 + j].mMode == ASMIM_IMPLIED && !(mIns[i + 1 + j].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
				j++;
			mIns[i + 1 - j].mType = ASMIT_AND;
			mIns[i + 1 - j].mMode = ASMIM_IMMEDIATE;
			mIns[i + 1 - j].mAddress = 0xff >> j;

			while (j > 1)
			{
				mIns[i + j].mType = ASMIT_NOP;
				mIns[i + j].mMode = ASMIM_IMPLIED;
				j--;
				mIns[i + 1 - j].mType = ASMIT_NOP;
				mIns[i + 1 - j].mMode = ASMIM_IMPLIED;
			}
			mIns[i + 1].mType = ASMIT_NOP;
			mIns[i + 1].mMode = ASMIM_IMPLIED;
			changed = true;
		}
	}

	CheckLive();

#endif
#if 1
#if 0
	for (int i = 0; i + 6 < 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].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 + 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)))
		{
			if (Move16BitAddUp(i))
				changed = true;
		}
	}
#endif

#if 1
	if (pass > 4 && pass < 8)
	{
		for (int i = 0; i + 1 < mIns.Size(); i++)
		{
			if ((mIns[i].mType == ASMIT_INC || mIns[i].mType == ASMIT_DEC) && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z) && !(mIns[i].mFlags & NCIF_VOLATILE))
			{
				if (mIns[i + 1].mType != ASMIT_INC && mIns[i + 1].mType != ASMIT_DEC && mIns[i].MayBeMovedBehind(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
				{
					NativeCodeInstruction	ins = mIns[i + 1];
					mIns[i + 1] = mIns[i];
					mIns[i] = ins;
					mIns[i + 1].mLive |= ins.mLive;
				}
				else if (i > 0 && mIns[i - 1].mType == ASMIT_LDA && !mIns[i - 1].MayBeSameAddress(mIns[i]))
				{
					NativeCodeInstruction	ins = mIns[i];
					mIns[i] = mIns[i - 1];
					mIns[i - 1] = ins;
					mIns[i].mLive |= ins.mLive;
				}
			}
		}
	}
#endif

#endif

	return changed;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate1(int i, int pass)
{
	if (mIns[i].mMode == ASMIM_ABSOLUTE && mIns[i].mLinkerObject && (mIns[i].mLinkerObject->mFlags & LOBJF_CONST) && 
		mIns[i].mLinkerObject->mReferences.Size() == 0 &&
		mIns[i].mAddress < mIns[i].mLinkerObject->mSize &&
		!mIns[i].ChangesAddress() && HasAsmInstructionMode(mIns[i].mType, ASMIM_IMMEDIATE))
	{
		mIns[i].mMode = ASMIM_IMMEDIATE;
		mIns[i].mAddress = mIns[i].mLinkerObject->mData[mIns[i].mAddress];
		mIns[i].mLinkerObject = nullptr;
		return true;
	}

	if (mIns[i].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0)
	{
		mIns[i].mType = ASMIT_LDA;
		return true;
	}
	else if (mIns[i].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0xff && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
		return true;
	}
	else if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0xff)
	{
		mIns[i].mType = ASMIT_LDA;
		return true;
	}
	else if (mIns[i].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x00 && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
		return true;
	}
	else if (mIns[i].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x00 && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
		return true;
	}
	else if (mIns[i].mType == ASMIT_CMP && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0x00 && (mIns[i].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i].mType = ASMIT_SEC; mIns[i].mMode = ASMIM_IMPLIED;;
		return true;
	}
	else if (mIns[i].mType == ASMIT_ROR && mIns[i].mMode == ASMIM_IMPLIED && (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
	{
		mIns[i].mType = ASMIT_LSR;
		return true;
	}
	else if (mIns[i].mType == ASMIT_ROL && mIns[i].mMode == ASMIM_IMPLIED && (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) == 0)
	{
		mIns[i].mType = ASMIT_ASL;
		return true;
	}
	else if (mIns[i].mType == ASMIT_TAY && !(mIns[i].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i].mType = ASMIT_ORA;
		mIns[i].mMode = ASMIM_IMMEDIATE;
		mIns[i].mAddress = 0;
		return true;
	}
	else if (mIns[i].mType == ASMIT_TAX && !(mIns[i].mLive & LIVE_CPU_REG_X))
	{
		mIns[i].mType = ASMIT_ORA;
		mIns[i].mMode = ASMIM_IMMEDIATE;
		mIns[i].mAddress = 0;
		return true;
	}

	int	apos;
	if (mIns[i].mMode == ASMIM_INDIRECT_Y && FindGlobalAddress(i, mIns[i].mAddress, apos))
	{
		mIns[i].mMode = ASMIM_ABSOLUTE_Y;
		mIns[i].mAddress = mIns[apos].mAddress;
		mIns[i].mLinkerObject = mIns[apos].mLinkerObject;
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate2(int i, int pass)
{
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_LDA && !(mIns[i].mFlags & NCIF_VOLATILE))
	{
		mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;;
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && mIns[i].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;;
		return true;
	}
	if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0)
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_AND && mIns[i + 1].mType == ASMIT_AND && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
	{
		mIns[i].mAddress &= mIns[i + 1].mAddress;
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_ORA && mIns[i + 1].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
	{
		mIns[i].mAddress |= mIns[i + 1].mAddress;
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_EOR && mIns[i + 1].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
	{
		mIns[i].mAddress ^= mIns[i + 1].mAddress;
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff)
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ROR)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LSR;
		return true;
	}
	if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].mAddress = (-mIns[i + 1].mAddress) & 0xff;
		return true;
	}
	if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x80 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_EOR;
		return true;
	}
	if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x80 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_EOR;
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i].mAddress == 0 && mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mType = ASMIT_CLC;
		return true;
	}
	if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_CLC;
		mIns[i + 1].mAddress++;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]))
	{
		mIns[i + 1].mType = ASMIT_ROL;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesFlagToAccu())
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesAccuAndFlag() && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_CMP && 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_SEC; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_CMP && !(mIns[i + 1].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDA;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED)
	{
		int	aval = mIns[i + 0].mAddress << 1;
		mIns[i + 0].mAddress = aval & 0xff;
		if (aval & 0x100)
			mIns[i + 1].mType = ASMIT_SEC;
		else
			mIns[i + 1].mType = ASMIT_CLC;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (pass >= 3 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		NativeCodeInstruction	ins(mIns[i + 1]);
		mIns[i + 1].CopyMode(mIns[i + 0]);
		mIns[i + 0].CopyMode(ins);
		if (mIns[i + 1].RequiresXReg())
			mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 1].RequiresYReg())
			mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 0].mLive |= mIns[i + 1].mLive & LIVE_MEM;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress &&
		(mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR) && !(mIns[i + 0].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = mIns[i + 1].mType;
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_LDA;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_ASL;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
		mIns[i + 2].mLive = mIns[i + 1].mLive;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 0].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 1].mType = ASMIT_TAY;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		mIns[i + 1].mType == ASMIT_LDX && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 0].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 1].mType = ASMIT_TAX;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_STX;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_STA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_STY;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_STX)
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1] = ins;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_STY)
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1] = ins;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_STA && !mIns[i + 1].RequiresXReg())
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1] = ins;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_STA && !mIns[i + 1].RequiresYReg())
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1] = ins;
		return true;
	}
	else if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CPX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_CMP;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_CPY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_CMP;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_AND;
		mIns[i + 0].mMode = ASMIM_IMMEDIATE;
		mIns[i + 0].mAddress = 0xfe;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	 if (
		mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 0].mType = ASMIT_AND;
		mIns[i + 0].mMode = ASMIM_IMMEDIATE;
		mIns[i + 0].mAddress = 0xfe;
		mIns[i + 0].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i].mType == ASMIT_LSR && mIns[i].mMode == ASMIM_IMPLIED && mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		NativeCodeInstruction	ins = mIns[i];
		mIns[i] = mIns[i + 1];
		mIns[i + 1] = ins;

		mIns[i].mAddress = (mIns[i].mAddress << 1) & 255;
		mIns[i].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= mIns[i].mLive & LIVE_CPU_REG_Z;
		return true;
	}
	
	if (mIns[i].mType == ASMIT_ASL && mIns[i].mMode == ASMIM_IMPLIED && mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		NativeCodeInstruction	ins = mIns[i];
		mIns[i] = mIns[i + 1];
		mIns[i + 1] = ins;

		mIns[i].mAddress = (mIns[i].mAddress >> 1) & 255;
		mIns[i].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= mIns[i].mLive & LIVE_CPU_REG_Z;
		return true;
	}

	if (
		(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
		mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
		mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_TAX)
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_TAY)
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_TXA)
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_TYA)
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INY &&
		mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INX &&
		mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INX &&
		mIns[i + 1].mType == ASMIT_DEX && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_DEX &&
		mIns[i + 1].mType == ASMIT_INX && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INY &&
		mIns[i + 1].mType == ASMIT_DEY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_DEY &&
		mIns[i + 1].mType == ASMIT_INY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_DEX)
	{
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_INX)
	{
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_DEY)
	{
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_INY)
	{
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
		mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) &&
		mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X) &&
		mIns[i + 1].mType == ASMIT_TYA && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y) &&
		mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= mIns[i + 1].mLive;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y) &&
		mIns[i + 1].mType == ASMIT_TXA && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 1].mLive;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CMP && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 1].mType = ASMIT_CPX;
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CMP && (mIns[i + 1].mMode == ASMIM_IMMEDIATE || mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE))
	{
		mIns[i + 1].mType = ASMIT_CPY;
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY &&
		mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (
		(mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_LDY) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 1].SameEffectiveAddress(mIns[i + 0]))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= ins.mLive;
		mIns[i + 1] = ins;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INY &&
		mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mAddress++;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INX &&
		mIns[i + 1].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mAddress++;
		return true;
	}
#if 1
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 1 &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 && !(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_LSR; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
#endif
	if (
		mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mAddress & 0x01) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_ASL;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mAddress & 0x80) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_LSR;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x01) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress >> 1) & 0x7f;
		mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x80) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress << 1) & 0xfe;
		mIns[i + 1].mType = ASMIT_ROR; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x7f &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0xfe &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM) &&
		mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = mIns[i + 1].mType; mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
		mIns[i + 0].mLive &= ~LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
	{
		mIns[i + 1].mType = mIns[i + 0].mType;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 0].mType = ASMIT_LDA;
		return true;
	}
	if (
		(mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS &&
		mIns[i + 1].mType == ASMIT_INX)
	{
		if (mIns[i + 0].mFlags & NCIF_UPPER)
			mIns[i + 0].mAddress += 0x100;
		else
			mIns[i + 0].mAddress++;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
	{
		mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED;  mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_TAX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP;  mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_NOP;  mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_CPX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_CMP;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_CPY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_CMP;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 1].mType == ASMIT_STY && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_STX;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_STX;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_STY;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_STY;
		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0x01 && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
	{
		if (!(mIns[i + 0].mLive & LIVE_CPU_REG_X))
		{
			mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INX));
			mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_Y))
		{
			mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INY));
			mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_C))
		{
			mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_CLC));
			mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_DEC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_INC && 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))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_DEC && 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))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}

	if ((mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_TAX || mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
		mIns[i + 1].mType == ASMIT_CPX && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mType = ASMIT_NOP;  mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if ((mIns[i + 0].mType == ASMIT_LDY || mIns[i + 0].mType == ASMIT_TAY || mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
		mIns[i + 1].mType == ASMIT_CPY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mType = ASMIT_NOP;  mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 0].mLinkerObject == mIns[i + 1].mLinkerObject &&
		mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
		!(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		!(mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = ins;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 0].mLinkerObject == mIns[i + 1].mLinkerObject &&
		mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
		!(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		!(mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = ins;
		return true;
	}

	// Ensure cannonical mode of immediate + val is val + immediate
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode != ASMIM_IMMEDIATE)
	{
		int v = mIns[i + 0].mAddress;
		mIns[i + 0].CopyMode(mIns[i + 1]);
		mIns[i + 0].mMinVal = mIns[i + 1].mMinVal;
		mIns[i + 0].mMaxVal = mIns[i + 1].mMaxVal;
		mIns[i + 1].mMode = ASMIM_IMMEDIATE; mIns[i + 1].mAddress = v;
		return true;
	}
		

#if 0
	else if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
	{
		int val = mIns[i + 0].mAddress;
		mIns[i + 0].CopyMode(mIns[i + 1]);
		mIns[i + 1].mMode = ASMIM_IMMEDIATE;
		mIns[i + 1].mAddress = val;
		progress = true;
	}
#endif
	if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
	{
		const NativeCodeInstruction* ains, * iins;

		int sreg = mIns[i + 1].mAddress;
		int	apos, addr;
		uint32	flags;

		if (FindGlobalAddressSumY(i, sreg, true, apos, ains, iins, flags, addr))
		{
			if (iins || (flags & LIVE_CPU_REG_Y) || (flags & LIVE_CPU_REG_X)) //!(mIns[i + 1].mLive & LIVE_CPU_REG_X))
			{
				RepairLoadYImmediate(i + 1, mIns[i + 0].mAddress);

				if (flags & LIVE_CPU_REG_Y)
				{
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
				}
				else if (flags & LIVE_CPU_REG_X)
				{
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
				}
				else
				{
					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
				}

				if (ains->mMode == ASMIM_IMMEDIATE)
				{
					mIns[i + 1].mLinkerObject = 0;
					mIns[i + 1].mAddress = addr + mIns[i + 0].mAddress;
				}
				else
				{
					mIns[i + 1].mLinkerObject = ains->mLinkerObject;
					mIns[i + 1].mAddress = ains->mAddress + mIns[i + 0].mAddress;
				}

				if (!iins)
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					if (flags & LIVE_CPU_REG_Y)
					{
						mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
						for (int j = apos; j < i + 2; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;
					}
					else
					{
						PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
						mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX, ASMIM_IMPLIED));
						for (int j = apos; j < i + 2; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;
					}
				}
				else if (iins->mMode != ASMIM_ZERO_PAGE)
				{
					mIns[i + 0].mMode = iins->mMode;
					mIns[i + 0].mAddress = iins->mAddress;
					mIns[i + 0].mLinkerObject = iins->mLinkerObject;
					mIns[i + 0].mFlags = iins->mFlags;

					if (!(flags & LIVE_CPU_REG_Y) && (flags & LIVE_CPU_REG_X))
						mIns[i + 0].mType = ASMIT_LDX;
				}
				else if (iins->mAddress == sreg)
				{
					mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
					if (flags & LIVE_CPU_REG_Y)
					{
						mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
						mIns[apos].mLive |= LIVE_MEM;
						for (int j = apos; j < i + 2; j++)
							mIns[j].mLive |= LIVE_CPU_REG_Y;
					}
					else
					{
						PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
						mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, iins->mAddress));
						mIns[apos].mLive |= LIVE_MEM;
						for (int j = apos; j < i + 2; j++)
							mIns[j].mLive |= LIVE_CPU_REG_X;
					}
				}
				else
				{
					mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
					mIns[i + 0].mAddress = iins->mAddress;

					if (!(flags & LIVE_CPU_REG_Y) && (flags & LIVE_CPU_REG_X))
						mIns[i + 0].mType = ASMIT_LDX;
				}

				CheckLive();

				return true;
			}
		}
	}

	CheckLive();

	if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
	{
		int	addr;
		if (FindPageStartAddress(i, mIns[i + 1].mAddress, addr))
		{
			if (mIns[i + 1].mLive & LIVE_CPU_REG_Y)
			{
				mIns.Insert(i + 2, mIns[i + 0]);
				mIns[i + 2].mLive |= mIns[i + 1].mLive;
			}

			int	absaddr = addr + mIns[i + 0].mAddress;

			mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
			mIns[i + 0].mLive |= LIVE_MEM;
			mIns[i + 0].mAddress = mIns[i + 1].mAddress;

			mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
			mIns[i + 1].mAddress = absaddr;
			mIns[i + 1].mLinkerObject = nullptr;

			CheckLive();

			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
	{
		int	sreg = mIns[i + 1].mAddress;

		int	apos, breg, ireg;

		if (FindAddressSumY(i, sreg, apos, breg, ireg))
		{
			if (PatchAddressSumY(i, sreg, apos, breg, ireg))
			{
				CheckLive();

				return true;
			}
		}
	}

	if (
		mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO) &&
		mIns[i + 1].mMode == ASMIM_INDIRECT_Y && mIns[i + 0].mAddress == mIns[i + 1].mAddress)
	{
		int	sreg = mIns[i + 0].mAddress;

		int	apos, breg, ireg;

		if (FindAddressSumY(i, sreg, apos, breg, ireg))
		{
			if (!(breg == sreg || ireg == sreg) || !(mIns[i + 1].mLive & LIVE_MEM))
			{
				if (breg == sreg || ireg == sreg)
				{
					mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
					mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
				}

				RepairLoadYImmediate(i + 1, 0);

				mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
				mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;
				mIns[i + 1].mAddress = breg; mIns[i + 1].mFlags &= ~NCIF_YZERO;
				mIns[i + 2].mAddress = breg; mIns[i + 2].mFlags &= ~NCIF_YZERO;

				CheckLive();

				return true;
			}
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 3 &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
	{
		int	apos, breg, ireg;
		if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
		{
			if (breg != mIns[i + 1].mAddress && ireg != mIns[i + 1].mAddress)// || !(mIns[i + 1].mLive & LIVE_MEM))
			{
				int yoffset = mIns[i + 0].mAddress;

				if (breg == mIns[i + 1].mAddress)
				{
					mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
					mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
				}

				RepairLoadYImmediate(i + 1, 0);

				mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
				mIns[i + 0].mAddress = ireg;
				mIns[i + 0].mLive |= LIVE_MEM;
				mIns[i + 1].mAddress = breg;
				mIns[i + 1].mFlags &= ~NCIF_YZERO;

				for (int j = 0; j < yoffset; j++)
				{
					mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_INY, ASMIM_IMPLIED));
					mIns[i + 1].mLive = mIns[i + 0].mLive;
				}

				CheckLive();

				return true;
			}
		}
	}


	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate3(int i, int pass)
{
	if (mIns[i].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_LDA && (mIns[i + 1].mType == ASMIT_CLC || mIns[i + 1].mType == ASMIT_SEC))
	{
		mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
		mIns[i + 1].mType == ASMIT_INC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && (mIns[i + 2].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_CLC;
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_ADC;
		mIns[i + 1].mMode = ASMIM_IMMEDIATE;
		mIns[i + 1].mAddress = 1;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		mIns[i + 1].IsShiftOrInc() && mIns[i + 1].mMode != ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
		!mIns[i + 2].SameEffectiveAddress(mIns[i + 1]) &&
		!(mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 2].mAddress || mIns[i + 1].mAddress == mIns[i + 2].mAddress + 1)) &&
		!(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode != ASMIM_ZERO_PAGE &&
		mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
		mIns[i + 2].IsCommutative() && HasAsmInstructionMode(mIns[i + 2].mType, mIns[i + 1].mMode) &&
		(mIns[i + 2].mLive & LIVE_MEM) == 0)
	{
		mIns[i + 1].mType = mIns[i + 2].mType;
		mIns[i + 1].mLive |= mIns[i + 2].mLive;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 2].mType == ASMIT_LDA && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
		mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
	{
		mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_LDA && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
		mIns[i + 0].SameEffectiveAddress(mIns[i + 2]))
	{
		mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		!mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !mIns[i + 1].ChangesAccu())
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;

		mIns[i + 2].mType = ASMIT_TAY;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) &&
		!mIns[i + 1].ChangesAccu() && !mIns[i + 1].RequiresAccu() && !mIns[i + 1].RequiresYReg())
	{
		mIns[i + 0].mType = ASMIT_LDY;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		if (mIns[i + 1].ChangesYReg())
		{
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		}
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 1].mType == ASMIT_DEC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_SEC; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_SBC; mIns[i + 1].mMode = ASMIM_IMMEDIATE; mIns[i + 1].mAddress = 1; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
			mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_ROR && mIns[i + 2].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LDY && !mIns[i + 1].RequiresXReg() &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_LDX && !mIns[i + 1].RequiresYReg() &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].ChangesAccuAndFlag() && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
		mIns[i + 1].mType == ASMIT_LDY &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 0].RequiresCarry())
			mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z);
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X) &&
		mIns[i + 1].IsShift() &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 2].mType = mIns[i + 1].mType;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].UsesAccu() &&
		mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 2];
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		mIns[i + 2].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress)
	{
		mIns[i + 0] = mIns[i + 2];
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 0];
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_STA;
		mIns[i + 2].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
		return true;
	}
	
	if (
		mIns[i + 0].mMode != ASMIM_RELATIVE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
		mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 2].mAddress &&
		(mIns[i + 1].mType == ASMIT_DEC || mIns[i + 1].mType == ASMIT_INC))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
	{
		mIns[i + 0].mType = ASMIT_CMP; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0x80;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_INX &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_CLC;
		mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_DEX &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_SEC;
		mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_SBC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].UsesAccu() &&
		mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_STA;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].UsesAccu() &&
		mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_STA;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_X)))
	{
		mIns[i + 0].mType = ASMIT_DEX;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_DEY;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
	{
		int	t = (mIns[i + 2].mAddress ^ 0xff) + mIns[i + 1].mAddress + 1;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mAddress = t & 0xff;
		if (t < 256)
			mIns[i + 0].mType = ASMIT_CLC;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
	{
		int	t = mIns[i + 2].mAddress + mIns[i + 1].mAddress;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mAddress = t & 0xff;
		if (t >= 256)
			mIns[i + 0].mType = ASMIT_SEC;
		return true;
	}
	
	if (pass > 0 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
		mIns[i + 2].mType == ASMIT_ADC)
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_LDA;
		return true;
	}
	
	if (pass > 0 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC)
	{
		mIns[i + 1] = mIns[i + 0];
		mIns[i + 0].mType = ASMIT_CLC;
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		if (mIns[i + 1].mFlags & NCIF_UPPER)
			mIns[i + 1].mAddress += 0x0100 * mIns[i + 2].mAddress;
		else
			mIns[i + 1].mAddress += mIns[i + 2].mAddress;

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
		mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		mIns[i + 2].mType == ASMIT_SBC)
	{
		mIns[i + 2].mType = ASMIT_EOR;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x80 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
	{
		int t = mIns[i + 2].mAddress;
		mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		if (t > 1)
		{
			mIns[i + 1].mType = ASMIT_INY;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		}
		else
		{
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		}
		mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Y)))
	{
		int t = mIns[i + 2].mAddress;
		mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		if (t > 1)
		{
			mIns[i + 1].mType = ASMIT_INY;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		}
		else
		{
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		}
		mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mAddress += mIns[i + 2].mAddress;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SBC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mAddress += mIns[i + 2].mAddress;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 2].mAddress ^= 0x80;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		pass >= 12 &&
		mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode != ASMIM_ABSOLUTE_X &&
		mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		mIns.Insert(i, NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, mIns[i + 0]));
		mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3] = mIns[i + 2]; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_TAX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		return true;
	}

	if (
		pass >= 6 &&
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1)
	{
		mIns[i + 0].mType = ASMIT_SEC; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
#if 1
	if (
		pass >= 6 &&
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_INC && mIns[i + 2].SameEffectiveAddress(mIns[i + 1]))
	{
		mIns[i + 0].mType = ASMIT_SEC; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA; 
		return true;
	}
#endif
	if (
		mIns[i + 0].mType == ASMIT_STA && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
		!mIns[i + 1].ChangesAddress() && !mIns[i + 1].ChangesGlobalMemory() &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesXReg() &&
		!(mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_LDX &&
		mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 2];
		mIns[i + 2] = ins;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_LDY &&
		mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 2];
		mIns[i + 2] = ins;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDX &&
		mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 2];
		mIns[i + 2] = ins;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDY &&
		mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 2];
		mIns[i + 2] = ins;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		mIns[i + 0] = mIns[i + 2];
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM) &&
		(!mIns[i + 1].ChangesZFlag() || !(mIns[i + 2].mLive & LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_ROL; mIns[i + 2].mAddress = mIns[i + 1].mAddress; mIns[i + 2].mLive |= LIVE_MEM;
		mIns[i + 1].mType = ASMIT_ASL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_ROR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x80 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		int addr = mIns[i + 0].mAddress;

		mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, addr));
		mIns.Insert(i + 4, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, addr));

		mIns[i + 0].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_A;
		mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mLive |= LIVE_CPU_REG_A;
		mIns[i + 4].mLive = mIns[i + 3].mLive;

		return true;
	}
#if 1
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].IsShiftOrInc() && mIns[i + 1].mMode != ASMIM_IMPLIED && !mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) &&
		(mIns[i + 2].mType == ASMIT_TAX || mIns[i + 2].mType == ASMIT_TAY) && !(mIns[i + 0].mFlags & mIns[i + 1].mFlags & NCIF_VOLATILE))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1];
		mIns[i + 1] = ins;
		return true;
	}
#endif
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() && mIns[i + 1].ChangesZFlag() &&
		mIns[i + 2].mType == ASMIT_TXA && (mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 2] = mIns[i + 0]; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_TAY &&
		mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && (mIns[i + 2].mLive & LIVE_CPU_REG_X) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 2].mType, ASMIM_ABSOLUTE_X))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mMode = ASMIM_ABSOLUTE_X;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && (mIns[i + 2].mLive & LIVE_CPU_REG_X) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 2].mType, ASMIM_ABSOLUTE_X))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mMode = ASMIM_ABSOLUTE_X;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;  mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;  mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
		mIns[i + 1].mType == ASMIT_STX &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
		mIns[i + 1].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
		mIns[i + 1].mType == ASMIT_STY &&
		mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
		mIns[i + 1].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		mIns[i + 1].mType == ASMIT_STA && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1], true) &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mFlags & NCIF_VOLATILE))
	{
		mIns[i + 0].mLive |= mIns[i + 2].mLive;
		mIns[i + 1].mLive |= mIns[i + 2].mLive;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	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;
		if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		}
		return true;
	}
	
	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;
		if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		}
		return true;
	}
	
	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 + 2].mFlags & NCIF_VOLATILE))
	{
		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;
		if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		}
		return true;
	}
	
	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 + 2].mFlags & NCIF_VOLATILE))
	{
		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;
		if (mIns[i + 2].mLive & LIVE_CPU_REG_Z)
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		}
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
		!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !(mIns[i + 1].ChangesYReg()) &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
		!mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && !(mIns[i + 1].ChangesXReg()) &&
		mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM) &&
		mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_STY;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && !mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 2].IsShift() && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]))
	{
		AsmInsType	type = mIns[i + 2].mType;
		uint32		live = mIns[i + 2].mLive;

		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 0];

		mIns[i + 0].mType = type;
		mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 0].mLive |= live;
		mIns[i + 1].mLive |= live;
		mIns[i + 2].mLive |= live;

		return true;
	}
	
	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;
		if (mIns[i + 1].ReferencesYReg()) mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_TAX && 
		mIns[i + 2].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[i + 2].mMode) && !(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_CPX;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_TAY &&
		mIns[i + 2].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[i + 2].mMode) && !(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_CPY;
		return true;
	}

	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]) &&
		!(mIns[i + 0].mFlags & (mIns[i + 1].mFlags | mIns[i + 2].mFlags) & NCIF_VOLATILE))
	{
		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;
		if (mIns[i + 2].RequiresYReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		}
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_STX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) &&
		mIns[i + 2].mType == ASMIT_STA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
		!(mIns[i + 2].mFlags & (mIns[i + 0].mFlags | mIns[i + 1].mFlags) & NCIF_VOLATILE) &&
		!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 2]) &&
		!mIns[i + 1].MayBeChangedOnAddress(mIns[i + 2]) &&
		!mIns[i + 2].MayBeChangedOnAddress(mIns[i + 1]))
	{
		NativeCodeInstruction	ins = mIns[i + 2];
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 0];
		mIns[i + 0] = ins;
		mIns[i + 1].mType = ASMIT_LDA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | mIns[i + 0].mLive;
		mIns[i + 2].mType = ASMIT_STA; mIns[i + 2].mLive |= mIns[i + 0].mLive;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_STX &&
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDY &&
		mIns[i + 1].mType == ASMIT_STY &&
		mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
		mIns[i + 1].mType = ASMIT_STA; mIns[i + 1].mLive |= LIVE_CPU_REG_A | (mIns[i + 2].mLive & LIVE_CPU_REG_Z);
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 2].mType == ASMIT_TXA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
		(mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) &&
		!mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesZFlag())
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 2].mType == ASMIT_TYA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
		(mIns[i + 0].mType == ASMIT_INY || mIns[i + 0].mType == ASMIT_DEY) &&
		!mIns[i + 1].ChangesYReg() && !mIns[i + 1].ChangesZFlag())
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress &&
		!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_MEM)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	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)))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 0x03) && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_ASL;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 0xc0) && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_LSR;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
	{
		mIns[i + 0].mAddress &= (mIns[i + 2].mAddress << 1) | 1;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE)
	{
		mIns[i + 0].mAddress &= (mIns[i + 2].mAddress >> 1) | 0x80;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
		mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mType = ASMIT_AND; mIns[i + 1].mAddress = 1;
		mIns[i + 1].mLive |= mIns[i + 2].mLive & LIVE_CPU_REG_Z;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	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);
		if (mIns[i + 1].RequiresCarry())
			mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && (mIns[i + 0].mAddress & 0x3f) == 0x3f &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP;  mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP;  mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mAddress = (mIns[i + 1].mAddress << 1) & 0xff;
		mIns[i + 2].mType = ASMIT_NOP;  mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_INY &&
		mIns[i + 1].mType == ASMIT_INY &&
		mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mAddress += 2;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_INX &&
		mIns[i + 1].mType == ASMIT_INX &&
		mIns[i + 2].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mAddress += 2;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TYA && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TYA && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_TYA; mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_STX;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TAY &&
		mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_STY;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		(mIns[i + 1].mType == ASMIT_INX || mIns[i + 1].mType == ASMIT_DEX) &&
		mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 2].mType = mIns[i + 1].mType == ASMIT_INX ? ASMIT_INC : ASMIT_DEC;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		(mIns[i + 1].mType == ASMIT_INY || mIns[i + 1].mType == ASMIT_DEY) &&
		mIns[i + 2].mType == ASMIT_STY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 2].mType = mIns[i + 1].mType == ASMIT_INY ? ASMIT_INC : ASMIT_DEC;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		(mIns[i + 0].mType == ASMIT_INC || mIns[i + 0].mType == ASMIT_DEC) &&
		mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 1].mLive & LIVE_MEM) &&
		mIns[i + 2].mType == ASMIT_STA && !(mIns[i + 2].mLive & LIVE_CPU_REG_A) &&
		(mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
		(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) != (LIVE_CPU_REG_X | LIVE_CPU_REG_Y))
	{
		if (mIns[i + 2].mLive & LIVE_CPU_REG_X)
		{
			if (mIns[i + 0].mType == ASMIT_INC)
				mIns[i + 1].mType = ASMIT_INY;
			else
				mIns[i + 1].mType = ASMIT_DEY;

			mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 2].mType = ASMIT_STY;
		}
		else
		{
			if (mIns[i + 0].mType == ASMIT_INC)
				mIns[i + 1].mType = ASMIT_INX;
			else
				mIns[i + 1].mType = ASMIT_DEX;

			mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
			mIns[i + 2].mType = ASMIT_STX;
		}
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].mType == ASMIT_CPX && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CMP;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDY &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].mType == ASMIT_CPY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y))
	{
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CMP;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_DEX;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_CPY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 1].mAddress &&
		!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
	{
		mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].CopyMode(mIns[i + 0]); mIns[i + 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_Z;
		mIns[i + 0].mType = ASMIT_TYA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;

		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mAddress = (mIns[i + 0].mAddress - mIns[i + 2].mAddress) & 0xff;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		mIns[i + 1].mType == ASMIT_STX && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) &&
		mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
		!mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
	{
		NativeCodeInstruction	ins(mIns[i + 2]);
		mIns.Remove(i + 2);
		mIns.Insert(i, ins);
		mIns[i + 1].mLive |= ins.mLive & LIVE_CPU_REG_A;
		mIns[i + 2].mLive |= ins.mLive & LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS) && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		mIns[i + 1].mType == ASMIT_STY && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) &&
		mIns[i + 2].mType == ASMIT_STA && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
		!mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]))
	{
		NativeCodeInstruction	ins(mIns[i + 2]);
		mIns.Remove(i + 2);
		mIns.Insert(i, ins);
		mIns[i + 1].mLive |= ins.mLive & LIVE_CPU_REG_A;
		mIns[i + 2].mLive |= ins.mLive & LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		(mIns[i + 1].mType == ASMIT_INC || mIns[i + 1].mType == ASMIT_DEC) &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
		mIns[i + 1].MayBeMovedBefore(mIns[i + 0]))
	{
		mIns.Insert(i, mIns[i + 1]);
		mIns[i].mLive |= LIVE_CPU_REG_A;
		if (mIns[i + 1].RequiresYReg())
			mIns[i].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 1].RequiresXReg())
			mIns[i].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Z;
		mIns.Remove(i + 2);
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 0].mType != ASMIT_TXA &&
		(mIns[i + 1].mType == ASMIT_INX || mIns[i + 1].mType == ASMIT_DEX) &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_DEX &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{		
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CPX; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff;
		return true;
	}
	
	if (
		mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 0].mType != ASMIT_TYA &&
		(mIns[i + 1].mType == ASMIT_INY || mIns[i + 1].mType == ASMIT_DEY) &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_DEY &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{		
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_CPY; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_DEY &&
		!mIns[i + 1].ReferencesYReg() &&
		mIns[i + 2].mType == ASMIT_INY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_INY &&
		!mIns[i + 1].ReferencesYReg() &&
		mIns[i + 2].mType == ASMIT_DEY && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_DEX &&
		!mIns[i + 1].ReferencesXReg() &&
		mIns[i + 2].mType == ASMIT_INX && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_INX &&
		!mIns[i + 1].ReferencesXReg() &&
		mIns[i + 2].mType == ASMIT_DEX && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
		!(mIns[i + 0].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 0].mAddress || mIns[i + 1].mAddress + 1 == mIns[i + 0].mAddress)))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_CPX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_CPY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && !(mIns[i + 1].ReferencesYReg()) &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_TAY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 2].ReferencesXReg())
			mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].IsShift() && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 2].mAddress = (mIns[i + 2].mAddress + mIns[i + 1].mAddress) & 0xff;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 2].mAddress = (mIns[i + 2].mAddress - mIns[i + 1].mAddress) & 0xff;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && !(mIns[i + 0].mAddress & 1) &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&  mIns[i + 1].mAddress == 0  &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mAddress & 1))
	{
		mIns[i + 0].mAddress |= mIns[i + 2].mAddress;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_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_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	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_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 1 &&
		mIns[i + 1].mType == ASMIT_LDA &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & LIVE_MEM))
	{
		int	apos, breg, ireg;
		if (FindAddressSumY(i, mIns[i + 2].mAddress, apos, breg, ireg))
		{
			int yoffset = mIns[i + 0].mAddress;

			if (breg == mIns[i + 2].mAddress || ireg == mIns[i + 2].mAddress)
			{
				mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
				mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
			}

			RepairLoadYImmediate(i + 2, yoffset);

			int ypos = i;
			if (mIns[i + 1].mMode != ASMIM_INDIRECT_Y && mIns[i + 1].mMode != ASMIM_ABSOLUTE_Y)
			{
				mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
				mIns[i + 0].mAddress = ireg;
				mIns[i + 0].mLive |= LIVE_MEM;
				mIns[i + 2].mAddress = breg;
			}
			else
			{
				mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
				mIns[i + 2].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
				ypos = i + 2;
				mIns[i + 3].mAddress = breg;
			}

			if (yoffset == 1)
			{
				mIns.Insert(ypos + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_INY, ASMIM_IMPLIED));
				mIns[ypos + 1].mLive = mIns[ypos].mLive;
			}

			CheckLive();

			return true;
		}
	}

	if (pass > 12 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
	{
		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].mMode = ASMIM_ABSOLUTE_Y;
		return true;
	}

	if (pass > 12 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 1].mType == ASMIT_TAY &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 2].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
	{
		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].mMode = ASMIM_ABSOLUTE_X;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_LDA &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		const NativeCodeInstruction* ains;
		if (FindImmediateStore(i, mIns[i + 2].mAddress + 1, ains))
		{
			mIns.Insert(i + 2, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i + 2].mAddress));
			mIns[i + 2].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_X;
			mIns[i + 3].mMode = ASMIM_ABSOLUTE_X;

			if (ains->mMode == ASMIM_IMMEDIATE)
				mIns[i + 3].mAddress = (ains->mAddress << 8) + mIns[i + 0].mAddress;
			else
			{
				mIns[i + 3].mLinkerObject = ains->mLinkerObject;
				mIns[i + 3].mAddress = mIns[i + 0].mAddress + ains->mAddress;
				mIns[i + 3].mFlags |= NCIF_UPPER;
				mIns[i + 3].mFlags &= ~NCIF_LOWER;
			}

			CheckLive();

			return true;
		}
	}

	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].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 1].mType = ASMIT_NOP;
		mIns[i + 2].mType = ASMIT_CPX; mIns[i + 2].mAddress = (256 - mIns[i + 2].mAddress) & 255;

		return true;
	}

	if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE_X && mIns[i].mLinkerObject && mIns[i].mAddress > 0 && mIns[i].mLinkerObject->mSize < 256 && 
		mIns[i + 1].mType == ASMIT_INX &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns.Insert(i, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INX));
		mIns[i + 1].mAddress--;
		mIns.Remove(i + 2);
		return true;
	}
	if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ABSOLUTE_Y && mIns[i].mLinkerObject && mIns[i].mAddress > 0 && mIns[i].mLinkerObject->mSize < 256 && 
		mIns[i + 1].mType == ASMIT_INY &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns.Insert(i, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INY));
		mIns[i + 1].mAddress--;
		mIns.Remove(i + 2);
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_STX &&
		mIns[i + 2].mType == ASMIT_STX && !(mIns[i + 2].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; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY &&
		mIns[i + 1].mType == ASMIT_STY &&
		mIns[i + 2].mType == ASMIT_STY && !(mIns[i + 2].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; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STA;
		return true;
	}

	if (
		mIns[i + 0].ChangesAccuAndFlag() && !mIns[i + 0].ReferencesXReg() &&
		mIns[i + 1].mType == ASMIT_LDX &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].ReferencesYReg()) mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 2].ReferencesCarry()) mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].ChangesAccuAndFlag() && !mIns[i + 0].ReferencesYReg() &&
		mIns[i + 1].mType == ASMIT_LDY &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0)
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].ReferencesXReg()) mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 2].ReferencesCarry()) mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	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 + 2].mType == ASMIT_CMP && 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_MEM)))
	{
		mIns[i + 2].mAddress = mIns[i + 1].mAddress; mIns[i + 2].mLive |= LIVE_MEM;
		mIns[i + 1].mType = mIns[i + 0].mType; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		return true;
	}

#if 1
	if (pass == 4 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		!(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mProc->ResetPatched();
		if (CheckBoolBitPropagation(this, i + 3, mIns[i + 2].mAddress))
		{
			mIns[i + 1].mType = ASMIT_ROR;
			mProc->ResetPatched();
			if (PatchBoolBitPropagation(this, i + 3, mIns[i + 2].mAddress, false))
				return true;
		}
	}
#endif

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate4(int i, int pass)
{
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_INC; mIns[i + 0].mLive |= LIVE_MEM;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_DEC; mIns[i + 0].mLive |= LIVE_MEM;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 0].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_INC; mIns[i + 1].mLive |= LIVE_MEM;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 0].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEC; mIns[i + 1].mLive |= LIVE_MEM;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
		HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_DEC; mIns[i + 0].mLive |= LIVE_MEM;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
		HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_INC; mIns[i + 0].mLive |= LIVE_MEM;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 0].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
		HasAsmInstructionMode(ASMIT_DEC, mIns[i + 1].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEC; mIns[i + 1].mLive |= LIVE_MEM;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (mIns[i + 1].mType == ASMIT_LDA && mIns[i + 3].mType == ASMIT_STA && mIns[i + 1].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 0].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) == 0xff &&
		HasAsmInstructionMode(ASMIT_INC, mIns[i + 1].mMode) &&
		(mIns[i + 3].mLive & LIVE_CPU_REG_C) == 0)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_INC; mIns[i + 1].mLive |= LIVE_MEM;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC)
	{
		mIns[i + 1].mType = ASMIT_NOP;
		mIns[i + 2].mType = ASMIT_NOP;
		return true;
	}
	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_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	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;
		}
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == mIns[i + 1].mType && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		!mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && 
		!mIns[i + 1].UsesZeroPage(mIns[i + 3].mAddress) &&
		!mIns[i + 1].ChangesZeroPage(mIns[i + 3].mAddress))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;

		mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 3].mAddress));

		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		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_LDX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mType = ASMIT_TAX; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA &&
		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_LDY && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mType = ASMIT_TAY; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
#if 1
	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_TYA &&
		mIns[i + 3].IsCommutative() && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
	{
		mIns[i + 2] = mIns[i + 0];
		mIns[i + 1].mType = ASMIT_TAY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_LDA; 
		mIns[i + 3].mMode = ASMIM_ABSOLUTE_Y;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;

		return true;
	}
#endif
#if 1
	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_STY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_LDA; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_STA; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
#endif
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y &&
		mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress)
	{
		mIns[i + 2].mType = mIns[i + 3].mType;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

#if 1
	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_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && 
		mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mType = ASMIT_ROR;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
#endif

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && mIns[i + 3].mMode != ASMIM_IMMEDIATE)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_ORA; mIns[i + 2].mLive |= mIns[i + 3].mLive & LIVE_CPU_REG_Z;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		(mIns[i + 2].mType == ASMIT_SEC || mIns[i + 2].mType == ASMIT_CLC) &&
		mIns[i + 3].mType == ASMIT_ADC)
	{
		mIns.Insert(i + 4, mIns[i + 0]);

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_LDA; mIns[i + 3].mLive |= LIVE_CPU_REG_C;
		mIns[i + 4].mType = ASMIT_SBC; mIns[i + 4].mLive |= LIVE_CPU_REG_C;

		if (mIns[i + 4].RequiresYReg())
		{
			mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		}
		if (mIns[i + 4].RequiresXReg())
		{
			mIns[i + 2].mLive |= LIVE_CPU_REG_X;
			mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		}

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 1].mAddress &&
		mIns[i + 2].mType == ASMIT_SEC &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_EOR;
		mIns[i + 0].mMode = ASMIM_IMMEDIATE;
		mIns[i + 0].mAddress = 0xff;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;

		mIns[i + 3].mType = ASMIT_ADC;
		mIns[i + 3].mAddress = mIns[i + 1].mAddress;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 2].mAddress &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_EOR;
		mIns[i + 0].mMode = ASMIM_IMMEDIATE;
		mIns[i + 0].mAddress = 0xff;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;

		mIns[i + 3].mType = ASMIT_ADC;
		mIns[i + 3].mAddress = mIns[i + 2].mAddress;

		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress != mIns[i + 2].mAddress || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 3].CopyMode(mIns[i + 1]);
		mIns[i + 3].mType = ASMIT_ADC;
		mIns[i + 2].mLive |= LIVE_CPU_REG_A;

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_ADC &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mAddress += mIns[i + 3].mAddress;
		mIns[i + 1].mLive |= (mIns[i + 3].mLive & LIVE_CPU_REG_Z);

		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x00 &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		mIns[i + 2].mType == ASMIT_AND && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 &&
		mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x01)
	{
		mIns[i + 1].mAddress = 0x00;
		mIns[i + 1].mLive |= (mIns[i + 3].mLive & LIVE_CPU_REG_Z);
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE && 
		mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		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 + 0].mAddress - mIns[i + 3].mAddress) & 0xff;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 3]) &&
		(mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE) &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_ORA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))

	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_SEC;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_ROL;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 3].mAddress &&
		mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & LIVE_MEM) &&
		(mIns[i + 2].mType == ASMIT_ASL || mIns[i + 2].mType == ASMIT_LSR || mIns[i + 2].mType == ASMIT_ROL || mIns[i + 2].mType == ASMIT_ROR) &&
		(mIns[i + 3].mType == ASMIT_ORA || mIns[i + 3].mType == ASMIT_AND || mIns[i + 3].mType == ASMIT_EOR || mIns[i + 3].mType == ASMIT_ADC || mIns[i + 3].mType == ASMIT_SBC))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mMode = mIns[i + 0].mMode;
		mIns[i + 3].mAddress = mIns[i + 0].mAddress;
		mIns[i + 3].mLinkerObject = mIns[i + 0].mLinkerObject;
		mIns[i + 3].mFlags = mIns[i + 0].mFlags;

		if (mIns[i + 3].mMode == ASMIM_INDIRECT_Y)
		{
			mIns[i + 0].mLive |= LIVE_MEM;
			mIns[i + 3].mLive |= LIVE_MEM;
		}
		if (mIns[i + 3].RequiresYReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		}
		if (mIns[i + 3].RequiresXReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		}
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
		mIns[i + 2].mType == ASMIT_EOR && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_INY;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 3].mType = ASMIT_DEY;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_DEY;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_INX;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 3].mType = ASMIT_DEX;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_DEX;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 2].mType = ASMIT_INX;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
			mIns[i + 3].mType = ASMIT_TXA;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 2].mType = ASMIT_DEX;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
			mIns[i + 3].mType = ASMIT_TXA;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	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 <= 3 &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		if (mIns[i + 2].mAddress == 3)
			mIns[i + 0].mType = ASMIT_DEX;
		else
			mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress >= 2)
			mIns[i + 2].mType = ASMIT_DEX;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
			mIns[i + 3].mType = ASMIT_TXA;
		else
			mIns[i + 3].mType = ASMIT_NOP;

		return true;
	}
	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 + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_INY;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 2].mType = ASMIT_DEY;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 3].mLive & LIVE_CPU_REG_A)
			mIns[i + 3].mType = ASMIT_TYA;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_DEY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 3].mType = ASMIT_DEY;
		else
			mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 2].mType = ASMIT_INX;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_STX;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 2].mType = ASMIT_DEX;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_STX;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
		{
			mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		}
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_STY;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 &&
		mIns[i + 3].mType == ASMIT_STA && (mIns[i + 3].mMode == ASMIM_ZERO_PAGE || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
		if (mIns[i + 2].mAddress == 2)
			mIns[i + 2].mType = ASMIT_DEY;
		else
			mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 3].mType = ASMIT_STY;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_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)))
	{
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 0].mType = ASMIT_DEY;
		else
			mIns[i + 0].mType = ASMIT_NOP;
		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 | LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_STY;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress >= 0xfe &&
		mIns[i + 3].mType == ASMIT_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)))
	{
		if (mIns[i + 2].mAddress == 0xfe)
			mIns[i + 0].mType = ASMIT_DEX;
		else
			mIns[i + 0].mType = ASMIT_NOP;
		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 | LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_STX;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff &&
		mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_INX; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 &&
		mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_DEX; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}

	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 && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_INX; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}

	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 == 0x01 &&
		mIns[i + 3].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 3].mMode) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mType = ASMIT_STX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_DEX; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}


	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STX, mIns[i + 2].mMode) &&
		mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDX;
		mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) &&
		mIns[i + 2].mType == ASMIT_STA && HasAsmInstructionMode(ASMIT_STY, mIns[i + 2].mMode) &&
		mIns[i + 3].mType == ASMIT_TYA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDY;
		mIns[i + 2].mType = ASMIT_STY; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	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 + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x00 && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = mIns[i + 1].mType;
		mIns[i + 0].mLive |= LIVE_MEM | LIVE_CPU_REG_C | LIVE_CPU_REG_Z;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_INX && mIns[i + 2].mType == ASMIT_INX &&
		mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_INC;
		mIns[i + 3].mType = ASMIT_INC;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_DEX && mIns[i + 2].mType == ASMIT_DEX &&
		mIns[i + 3].mType == ASMIT_STX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_DEC;
		mIns[i + 3].mType = ASMIT_DEC;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_INC;
		mIns[i + 3].mType = ASMIT_INC;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (pass > 10 &&
		mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_DEC;
		mIns[i + 3].mType = ASMIT_DEC;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		!(mIns[i + 1].ChangesYReg() || mIns[i + 1].mMode == ASMIM_INDIRECT_Y || mIns[i + 1].RequiresXReg()) &&
		mIns[i + 2].mType == ASMIT_TYA &&
		mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y)))
	{
		mIns[i + 0].mType = ASMIT_LDX;
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].ReplaceYRegWithXReg();
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_LDA && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress) &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 3] = mIns[i + 2];
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1].mType = mIns[i + 0].mType;
		mIns[i + 0].mType = ASMIT_LDA;
		mIns[i + 3].mType = ASMIT_ADC;

		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_SEC &&
		mIns[i + 2].mType == ASMIT_LDA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_EOR;
		mIns[i + 0].mMode = ASMIM_IMMEDIATE;
		mIns[i + 0].mAddress = 0xff;
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_ADC;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress < 4 &&
		mIns[i + 2].mType == ASMIT_TAX &&
		mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mAddress += mIns[i + 1].mAddress;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_SEC;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_SBC &&
		mIns[i + 2].mType == ASMIT_SEC &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_CLC;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		mIns[i + 3].mAddress = (mIns[i + 3].mAddress - mIns[i + 1].mAddress) & 0xff;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		int	val = mIns[i + 2].mAddress;

		mIns[i + 0].mType = ASMIT_SEC;
		mIns[i + 2].CopyMode(mIns[i + 1]);
		mIns[i + 2].mType = ASMIT_SBC;
		mIns[i + 1].mMode = ASMIM_IMMEDIATE;
		mIns[i + 1].mAddress = -(1 + val) & 255;

		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	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 + 1].mLive |= mIns[i + 3].mLive;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC)
	{
		mIns[i + 0].mAddress = 0xff;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 0].mLinkerObject != mIns[i + 2].mLinkerObject &&
		mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		int	val = mIns[i + 2].mAddress;

		mIns[i + 3].mType = ASMIT_LDA;
		mIns[i + 3].CopyMode(mIns[i + 0]);

		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
		mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
		mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress)
	{
		int	addr = mIns[i + 0].mAddress;
		mIns[i + 0].mAddress = mIns[i + 2].mAddress;
		mIns[i + 3].mAddress = mIns[i + 1].mAddress;
		mIns[i + 2].mAddress = addr;

		mIns[i + 2].mType = ASMIT_LDX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_STX;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !mIns[i + 1].SameEffectiveAddress(mIns[i + 2]) &&
		mIns[i + 3].mType == ASMIT_CMP && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 3].mAddress = mIns[i + 2].mAddress;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED && HasAsmInstructionMode(ASMIT_ROL, mIns[i + 0].mMode) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{

		mIns[i + 2].CopyMode(mIns[i + 0]);

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_ROL && 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_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress && !(mIns[i + 2].mLive & LIVE_MEM) &&
		mIns[i + 3].mType == ASMIT_AND && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1)
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}

	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_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_AND; mIns[i + 1].mAddress = 0x80;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

#if 1
	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_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_ROL; mIns[i + 3].mMode = ASMIM_IMPLIED; mIns[i + 3].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;

		return true;
	}
#endif

	if (pass >= 6 &&
		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].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{

		mIns[i + 1].CopyMode(mIns[i + 0]);
		mIns[i + 2].CopyMode(mIns[i + 0]);

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_STA && !(mIns[i + 0].mLive & LIVE_CPU_REG_A) &&
		!mIns[i + 1].ReferencesAccu() && !mIns[i + 0].MayBeSameAddress(mIns[i + 1]) &&
		!mIns[i + 2].ReferencesAccu() && !mIns[i + 0].MayBeSameAddress(mIns[i + 2]) &&
		mIns[i + 3].IsShift() && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
	{
		NativeCodeInstruction	ins = mIns[i + 0];
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1] = mIns[i + 2]; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2] = mIns[i + 3]; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3] = ins; mIns[i + 3].mLive |= mIns[i + 2].mLive;

		return true;
	}
	if (
		mIns[i + 0].IsShift() && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_MEM) &&
		!mIns[i + 1].ChangesCarry() && !mIns[i + 2].ChangesCarry() &&
		!mIns[i + 1].RequiresCarry() && !mIns[i + 2].RequiresCarry() &&
		!mIns[i + 1].MayBeSameAddress(mIns[i + 0]) && !mIns[i + 2].MayBeSameAddress(mIns[i + 0]))
	{
		mIns.Insert(i + 4, NativeCodeInstruction(mIns[i + 0].mIns, mIns[i + 0].mType, ASMIM_IMPLIED));
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mLive |= LIVE_CPU_REG_C;

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 2].mLive |= LIVE_CPU_REG_X;

		if (!(mIns[i + 3].mLive & LIVE_MEM))
		{
			mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		}
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;

		if (!(mIns[i + 3].mLive & LIVE_MEM))
		{
			mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		}
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STY &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
	{
		mIns[i + 3].CopyMode(mIns[i + 2]);
		mIns[i + 2].mType = ASMIT_TYA;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STX &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
	{
		mIns[i + 3].CopyMode(mIns[i + 2]);
		mIns[i + 2].mType = ASMIT_TXA;
		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_X;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_EOR && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0xff &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC &&
		mIns[i + 3].mType == ASMIT_EOR && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff && !(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 1].mType = ASMIT_SEC;
		mIns[i + 2].mType = ASMIT_SBC;

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDX &&
		mIns[i + 1].mType == ASMIT_DEX &&
		mIns[i + 2].mType == ASMIT_STX && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode) &&
		mIns[i + 3].mType == ASMIT_TXA && !(mIns[i + 3].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 0].mType = ASMIT_DEC;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mLive = mIns[i + 3].mLive;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_CMP && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == mIns[i + 0].mAddress && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_CMP; mIns[i + 2].mLive |= LIVE_CPU_REG_Z;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_A) &&
		!mIns[i + 1].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].ChangesCarry() &&
		!mIns[i + 2].ReferencesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 2].ChangesCarry() &&
		mIns[i + 3].IsShift() && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
	{
		AsmInsType	type = mIns[i + 3].mType;
		mIns[i + 3] = mIns[i + 2];
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 0];
		mIns[i + 0] = NativeCodeInstruction(mIns[i + 0].mIns, type);
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mLive |= LIVE_CPU_REG_C;

		return true;
	}
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].MayBeMovedBefore(mIns[i + 1]) && mIns[i + 2].MayBeMovedBefore(mIns[i + 0]) &&
		mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0)
	{
		NativeCodeInstruction	ins(mIns[i + 2]);
		mIns.Remove(i + 2);
		mIns.Insert(i, ins);
		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= mIns[i + 3].mLive;
		mIns[i + 2].mLive |= mIns[i + 3].mLive;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].ChangesAccuAndFlag() &&
		(mIns[i + 1].mType == ASMIT_LDY && !mIns[i + 0].RequiresYReg() ||
			mIns[i + 1].mType == ASMIT_LDX && !mIns[i + 0].RequiresXReg()) &&
		mIns[i + 2].mType == ASMIT_STA &&
		mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0)
	{
		NativeCodeInstruction	ins(mIns[i + 1]);
		mIns.Remove(i + 1);
		mIns.Insert(i, ins);
		mIns[i + 0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_X | LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= mIns[i + 3].mLive | mIns[i + 0].mLive;
		mIns[i + 2].mLive |= mIns[i + 3].mLive;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (
		mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 2].mType == ASMIT_TXA &&
		mIns[i + 3].IsCommutative() && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress)
	{
		mIns[i + 2].mType = ASMIT_NOP;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mAddress = mIns[i + 0].mAddress;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 1].mType == ASMIT_TAY &&
		mIns[i + 2].mType == ASMIT_TXA &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y)))
	{
		mIns[i + 2] = mIns[i + 0]; mIns[i + 2].mType = ASMIT_LDA; mIns[i + 2].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_TAX;
		mIns[i + 3].mMode = ASMIM_ABSOLUTE_X;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_CMP && mIns[i + 0].mMode == ASMIM_IMMEDIATE && 
		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_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		int val = mIns[i + 0].mAddress;
		mIns[i + 0].mType = ASMIT_EOR; mIns[i + 0].mAddress = 0xff;
		mIns[i + 1].mType = ASMIT_CLC; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mAddress = val;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		(mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_LSR) && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 3].mType == mIns[i + 1].mType && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_STA;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 2].mType == ASMIT_LDX && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) &&
		!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) && !mIns[i + 1].ChangesYReg() &&
		mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !(mIns[i + 2].mLive & LIVE_CPU_REG_Z))
	{
		if (!(mIns[i + 3].mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(mIns[i + 1].mType, ASMIM_ABSOLUTE_X))
		{
			mIns[i + 0].mType = ASMIT_LDX;
			mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (!(mIns[i + 3].mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(mIns[i + 3].mType, ASMIM_ABSOLUTE_Y))
		{
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 3].mMode = ASMIM_ABSOLUTE_Y;
			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
		!mIns[i + 2].ChangesYReg() && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mAddress == mIns[i + 3].mAddress && !(mIns[i + 3].mLive & LIVE_MEM))
	{
		int	apos, breg, ireg;
		if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
		{
			if (breg == mIns[i + 1].mAddress || ireg == mIns[i + 1].mAddress)
			{
				mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
				mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
			}

			RepairLoadYImmediate(i + 3, 0);

			mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
			mIns[i + 0].mAddress = ireg;
			mIns[i + 0].mLive |= LIVE_MEM;
			mIns[i + 1].mAddress = breg;
			mIns[i + 3].mAddress = breg;
			return true;
		}
	}

	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].mAddress == 0x80 &&
		(mIns[i + 3].mType == ASMIT_STA || mIns[i + 3].mType == ASMIT_TAY || mIns[i + 3].mType == ASMIT_TAX) && !(mIns[i + 3].mLive & LIVE_CPU_REG_A))
	{
		NativeCodeInstruction	ins = mIns[i + 3];
		mIns[i + 3] = mIns[i + 2];
		mIns[i + 2] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 0];
		mIns[i + 0] = ins;
		return true;
	}

	if (mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
		mIns[i + 3].mType == ASMIT_ROR && mIns[i + 3].mMode == ASMIM_IMPLIED)
	{
		if (mIns[i + 0].mAddress == 0x80)
		{
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (mIns[i + 0].mAddress == 0x40)
		{
			mIns[i + 1].mType = ASMIT_ASL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= mIns[i + 3].mLive;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (mIns[i + 0].mAddress == 0x20)
		{
			mIns[i + 1].mType = ASMIT_ASL; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
			mIns[i + 2].mType = ASMIT_ASL; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= mIns[i + 3].mLive;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (mIns[i + 0].mAddress == 0x01)
		{
			mIns[i + 1].mType = ASMIT_LSR; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
			mIns[i + 2].mType = ASMIT_ROR; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= mIns[i + 3].mLive;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_AND && 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 + 0].mAddress & mIns[i + 3].mAddress) == 0 &&
		!(mIns[i + 3].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		int	mask = mIns[i + 3].mAddress;
		mIns[i + 3] = mIns[i + 1];
		mIns[i + 1] = NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, mask);
		return true;
	}

	if (pass == 4 &&
		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_EOR && 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)))
	{
		bool	flipz = false;
		if (mIns[i + 3].mLive & LIVE_CPU_REG_Z)
		{
			if (i + 4 == mIns.Size() && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
				flipz = true;
		}

		if (!(mIns[i + 3].mLive & LIVE_CPU_REG_Z) || flipz)
		{
			mProc->ResetPatched();
			if (CheckBoolBitPropagation(this, i + 4, mIns[i + 3].mAddress))
			{
				mIns[i + 1].mType = ASMIT_ROR; mIns[i + 1].mLive |= mIns[i + 2].mLive;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				if (flipz)
					mBranch = InvertBranchCondition(mBranch);
				mProc->ResetPatched();
				if (PatchBoolBitPropagation(this, i + 4, mIns[i + 3].mAddress, true))
					return true;
			}
		}
	}

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate5(int i, int pass)
{
	if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
		mIns[i + 1].mType == ASMIT_CLC && mIns[i + 2].mType == ASMIT_LDA)
	{
		// Flip arguments of ADC if second parameter in accu at entry

		mIns[i + 3].CopyMode(mIns[i + 2]);
		mIns[i + 2].CopyMode(mIns[i + 0]);
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
		mIns[i + 1].mType == ASMIT_SEC && mIns[i + 2].mType == ASMIT_LDA)
	{
		// change sbc to adc to reverse order

		mIns[i + 3].CopyMode(mIns[i + 2]);
		mIns[i + 2].mType = ASMIT_EOR; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 0xff;
		mIns[i + 3].mType = ASMIT_ADC;

		if (mIns[i + 3].ReferencesYReg())
			mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		if (mIns[i + 3].ReferencesXReg())
			mIns[i + 2].mLive |= LIVE_CPU_REG_X;

		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 3].mAddress &&
		mIns[i + 2].mType == ASMIT_SEC && mIns[i + 1].mType == ASMIT_LDA)
	{
		// change sbc to adc to reverse order

		mIns[i + 3].CopyMode(mIns[i + 1]);
		mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mMode = ASMIM_IMMEDIATE; mIns[i + 1].mAddress = 0xff;
		mIns[i + 3].mType = ASMIT_ADC;

		if (mIns[i + 3].ReferencesYReg())
		{
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		}
		if (mIns[i + 3].ReferencesXReg())
		{
			mIns[i + 1].mLive |= LIVE_CPU_REG_X;
			mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		}

		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;

		return true;
	}

	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 && HasAsmInstructionMode(ASMIT_STY, mIns[i + 3].mMode) &&
		mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 4].mType = ASMIT_NOP;
		if (mIns[i + 2].mAddress == 2)
		{
			mIns.Insert(i + 3, mIns[i + 2]);
		}

		return true;
	}

	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_CMP && HasAsmInstructionMode(ASMIT_CPY, mIns[i + 3].mMode) &&
		mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		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_CPY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 4].mType = ASMIT_NOP;
		if (mIns[i + 2].mAddress == 2)
		{
			mIns.Insert(i + 3, mIns[i + 2]);
		}

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode != ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_SEC &&
		mIns[i + 3].mType == ASMIT_LDA && !mIns[i + 3].UsesZeroPage(mIns[i + 1].mAddress) &&
		mIns[i + 4].mType == ASMIT_SBC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & LIVE_MEM))
	{
		mIns[i + 4].CopyMode(mIns[i + 0]);

		if (mIns[i + 4].RequiresYReg())
		{
			mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		}
		if (mIns[i + 4].RequiresXReg())
		{
			mIns[i + 2].mLive |= LIVE_CPU_REG_X;
			mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		}

		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		!mIns[i + 1].ChangesAccu() &&
		mIns[i + 2].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_CLC &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress)
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;

		mIns[i + 3].mType = ASMIT_ADC;
		mIns[i + 3].CopyMode(mIns[i + 2]);
		mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= mIns[i + 1].mLive;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 4].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_ROR; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mAddress = 0x80; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_STA;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_SBC &&
		mIns[i + 3].mType == ASMIT_CLC &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
		!(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 1].mAddress = (mIns[i + 1].mAddress + mIns[i + 4].mAddress) & 255;

		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 3].IsCommutative() && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
		mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == mIns[i + 0].mAddress)
	{
		int	addr = mIns[i + 1].mAddress;
		mIns[i + 1].mAddress = mIns[i + 3].mAddress;
		mIns[i + 3].mAddress = addr;
		mIns[i + 0].mAddress = mIns[i + 2].mAddress;
		mIns[i + 2].mAddress = mIns[i + 4].mAddress;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
		!mIns[i + 2].ChangesYReg() && (mIns[i + 2].mMode == ASMIM_IMMEDIATE || mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress) &&
		!mIns[i + 3].ChangesYReg() && (mIns[i + 3].mMode == ASMIM_IMMEDIATE || mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 1].mAddress) &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mAddress == mIns[i + 4].mAddress && !(mIns[i + 4].mLive & LIVE_MEM))
	{
		int	apos, breg, ireg;
		if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
		{
			if (breg == mIns[i + 1].mAddress)
			{
				mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
				mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
			}

			RepairLoadYImmediate(i + 4, 0);

			mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
			mIns[i + 0].mAddress = ireg;
			mIns[i + 0].mLive |= LIVE_MEM;
			mIns[i + 1].mAddress = breg;
			mIns[i + 4].mAddress = breg;
			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress == 1 || mIns[i + 2].mAddress == 2) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		if (!(mIns[i + 4].mLive & LIVE_CPU_REG_X))
		{
			mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
			if (mIns[i + 2].mAddress == 2)
				mIns[i + 2].mType = ASMIT_INX;
			else
				mIns[i + 2].mType = ASMIT_NOP;
			mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
			mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
			mIns[i + 4].mType = ASMIT_STX;
			return true;
		}
		else if (!(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
		{
			mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 1].mType = ASMIT_INY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
			if (mIns[i + 2].mAddress == 2)
				mIns[i + 2].mType = ASMIT_INY;
			else
				mIns[i + 2].mType = ASMIT_NOP;
			mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 4].mType = ASMIT_STY;
			return true;
		}
	}

	if (
		mIns[i + 0].mType == ASMIT_SEC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress == 1 || mIns[i + 2].mAddress == 2) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		if (!(mIns[i + 4].mLive & LIVE_CPU_REG_X))
		{
			mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mType = ASMIT_DEX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
			if (mIns[i + 2].mAddress == 2)
				mIns[i + 2].mType = ASMIT_DEX;
			else
				mIns[i + 2].mType = ASMIT_NOP;
			mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
			mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
			mIns[i + 4].mType = ASMIT_STX;
			return true;
		}
		else if (!(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
		{
			mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].CopyMode(mIns[i + 1]); mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 1].mType = ASMIT_DEY; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
			if (mIns[i + 2].mAddress == 2)
				mIns[i + 2].mType = ASMIT_DEY;
			else
				mIns[i + 2].mType = ASMIT_NOP;
			mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 4].mType = ASMIT_STY;
			return true;
		}
	}

	if (
		pass > 2 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		mIns[i + 3].mType == ASMIT_STA && !mIns[i + 3].MayBeSameAddress(mIns[i + 1]) && !mIns[i + 3].RequiresYReg() &&
		mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mMode = ASMIM_IMPLIED;  mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 3].mType = ASMIT_STY; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 4].mType = ASMIT_DEY; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 1].mAddress &&
		mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&

		!mIns[i + 0].ReferencesZeroPage(mIns[i + 3].mAddress) &&
		!mIns[i + 2].ReferencesZeroPage(mIns[i + 1].mAddress) &&
		!(mIns[i + 0].mFlags & NCIF_VOLATILE) && !(mIns[i + 2].mFlags & NCIF_VOLATILE))
	{
		NativeCodeInstruction	ins(mIns[i + 0]);
		mIns[i + 0] = mIns[i + 2];
		mIns[i + 2] = ins;
		mIns[i + 1].mAddress = mIns[i + 3].mAddress;
		mIns[i + 3].mAddress = mIns[i + 4].mAddress;

		if (mIns[i + 2].RequiresYReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
			mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		}
		if (mIns[i + 2].RequiresXReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_X;
			mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		}

		mIns[i + 0].mLive |= mIns[i + 2].mLive;
		mIns[i + 2].mLive |= mIns[i + 4].mLive;
		mIns[i + 3].mLive |= mIns[i + 4].mLive;

		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAY &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].mType == ASMIT_TYA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].CopyMode(mIns[i + 3]);
		mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].mType == ASMIT_TXA && !(mIns[i + 4].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].CopyMode(mIns[i + 3]);
		mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		(mIns[i + 1].mType == ASMIT_TAY || mIns[i + 1].mType == ASMIT_TAX) &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		if (mIns[i + 1].mType == ASMIT_TAY)
		{
			mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		}
		else
		{
			mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		}

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		if (mIns[i + 3].mAddress == 0x01)
			mIns[i + 4].mType = ASMIT_INC;
		else
			mIns[i + 4].mType = ASMIT_DEC;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDY && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		if (mIns[i + 3].mAddress == 0x01)
			mIns[i + 4].mType = ASMIT_INC;
		else
			mIns[i + 4].mType = ASMIT_DEC;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDX && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		if (mIns[i + 3].mAddress == 0x01)
			mIns[i + 4].mType = ASMIT_INC;
		else
			mIns[i + 4].mType = ASMIT_DEC;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
		mIns[i + 4].mType == ASMIT_TAX && !(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_TXA;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_SEC &&
		mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
		mIns[i + 4].mType == ASMIT_TAX && !(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_DEX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_TXA;
		return true;
	}

	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_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_TXA &&
		mIns[i + 4].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_IMPLIED && !(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

		mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_ROR; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_EOR; mIns[i + 4].mMode = ASMIM_IMMEDIATE; mIns[i + 4].mAddress = 0x80;
		return true;
	}

	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 + 2].mAddress != mIns[i + 1].mAddress &&
		mIns[i + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & LIVE_MEM))
	{
		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;

		return true;
	}

	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_IMMEDIATE && mIns[i + 2].mAddress == 0 &&
		mIns[i + 3].mType == ASMIT_ROR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
	{
		mIns[i + 0] = mIns[i + 1]; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mType = ASMIT_LSR; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].CopyMode(mIns[i + 4]);
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x0f &&
		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 + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_ASL && mIns[i + 4].mMode == ASMIM_IMPLIED && !(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0xf0 &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_LSR && mIns[i + 4].mMode == ASMIM_IMPLIED && !(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		return true;
	}

	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].ChangesAccu() &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 4].mType == ASMIT_ASL && mIns[i + 4].mMode == ASMIM_IMPLIED && !(mIns[i + 4].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && 
		mIns[i + 1].mType == ASMIT_CLC && 
		mIns[i + 2].mType == ASMIT_ADC && 
		mIns[i + 3].mType == ASMIT_CLC && 
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && 
		(mIns[i + 0].mAddress & mIns[i + 4].mAddress) == 0 &&
		!(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 3] = mIns[i + 1];
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		int	mask = mIns[i + 4].mAddress;
		mIns[i + 4] = mIns[i + 2];
		mIns[i + 2] = NativeCodeInstruction(mIns[i + 2].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, mask);
		return true;
	}

	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 == 1 &&
		mIns[i + 3].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_CPX, mIns[i + 3].mMode) &&
		mIns[i + 4].mType == ASMIT_TAX && !(mIns[i + 4].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		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;
		mIns[i + 3].mType = ASMIT_CPX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		mIns[i + 4].mType = ASMIT_NOP;
		return true;
	}
#if 1
	if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].IsShiftRotOrInc() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 2].IsShiftRotOrInc() && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 3].IsShiftRotOrInc() && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 4].IsShift() && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_A))
	{
		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].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3] = mIns[i + 4]; mIns[i + 3].mLive |= LIVE_CPU_REG_A; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4] = ins;
		return true;
	}
#endif

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate4b(int i, int pass)
{
	if (
		mIns[i + 0].mType == ASMIT_INY &&
		mIns[i + 1].mType == ASMIT_TYA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 3].mAddress++;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_TAY &&
		mIns[i + 3].mType == ASMIT_INY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 1].mAddress++;
		mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_INX &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP;
		mIns[i + 3].mAddress++;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_TAX &&
		mIns[i + 3].mType == ASMIT_INX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 1].mAddress++;
		mIns[i + 3].mType = ASMIT_NOP;
		return true;
	}
	else if (pass > 8 &&
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) < 4 &&
		mIns[i + 3].mType == ASMIT_TAY &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		int n = mIns[i + 2].mAddress & 0xff;
		for (int k = 0; k < n; k++)
		{
			mIns[i + k].mType = ASMIT_INY; mIns[i + k].mMode = ASMIM_IMPLIED; mIns[i + k].mLive |= LIVE_CPU_REG_Y;
		}
		for (int k = n; k < 4; k++)
		{
			mIns[i + k].mType = ASMIT_NOP; mIns[i + k].mMode = ASMIM_IMPLIED;
		}
		return true;
	}
	else if (pass > 8 &&
		mIns[i + 0].mType == ASMIT_TXA &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && (mIns[i + 2].mAddress & 0xff) < 4 &&
		mIns[i + 3].mType == ASMIT_TAX &&
		!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		int n = mIns[i + 2].mAddress & 0xff;
		for (int k = 0; k < n; k++)
		{
			mIns[i + k].mType = ASMIT_INX; mIns[i + k].mMode = ASMIM_IMPLIED; mIns[i + k].mLive |= LIVE_CPU_REG_X;
		}
		for (int k = n; k < 4; k++)
		{
			mIns[i + k].mType = ASMIT_NOP; mIns[i + k].mMode = ASMIM_IMPLIED;
		}
		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate5b(int i, int pass)
{
	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode != ASMIM_ABSOLUTE_X &&
		mIns[i + 3].mType == ASMIT_TXA &&
		mIns[i + 4].mType == ASMIT_STA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
	{
		mIns[i + 0] = mIns[i + 4];
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_INC;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0xff &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_DEC;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
		mIns[i + 4].mType == ASMIT_STA && (mIns[i + 4].mMode == ASMIM_ZERO_PAGE || mIns[i + 4].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_STX; mIns[i + 4].mLive |= LIVE_CPU_REG_A;
		mIns.Insert(i + 5, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX));
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 2].mType == ASMIT_ASL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress != mIns[i + 0].mAddress &&
		!(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		int	a0 = mIns[i + 0].mAddress;
		int a1 = mIns[i + 4].mAddress;

		mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, a1));
		mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, a0));

		mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 5].mMode = ASMIM_ZERO_PAGE; mIns[i + 5].mAddress = a1;
		mIns[i + 6].mAddress = a0;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_MEM)))
	{
		mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_ROR;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_TYA &&
		mIns[i + 1].mType == ASMIT_TAX &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress <= 2 &&
		mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		if (mIns[i + 3].mAddress > 1)
			mIns[i + 4].mType = ASMIT_INY;
		else
			mIns[i + 4].mType = ASMIT_NOP;

		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
		HasAsmInstructionMode(ASMIT_INC, mIns[i + 0].mMode))
	{
		mIns[i + 4].mType = ASMIT_INC;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_STA &&
		mIns[i + 2].mType == ASMIT_CLC &&
		mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 255 &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
		HasAsmInstructionMode(ASMIT_DEC, mIns[i + 0].mMode))
	{
		mIns[i + 4].mType = ASMIT_DEC;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

		return true;
	}
	else if (
		pass > 8 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
		mIns[i + 3].mType == ASMIT_CLC &&
		mIns[i + 4].mType == ASMIT_ADC &&
		!(mIns[i + 4].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 3].mType = ASMIT_SEC;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

		return true;
	}
	else if (
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 3].mType == ASMIT_ROL && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 4].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 4].mLive & LIVE_CPU_REG_A))
	{
		mIns.Insert(i + 5, mIns[i + 0]);
		mIns.Remove(i);
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 1].mLive |= LIVE_CPU_REG_A;
		mIns[i + 2].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mLive |= LIVE_CPU_REG_A;
		mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mLive |= mIns[i + 3].mLive;

		return true;
	}
#if 0
	else if (
		mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y &&
		mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_CPU_REG_X))
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 2].mType = ASMIT_LDX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mMode = ASMIM_ABSOLUTE_X; mIns[i + 3].mLive |= LIVE_CPU_REG_Y;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		return true;
	}
#endif
	if (pass > 2)
	{
		if (
			mIns[i + 0].mType == ASMIT_INY &&
			mIns[i + 1].mType == ASMIT_INY &&
			mIns[i + 2].mType == ASMIT_INY &&
			mIns[i + 3].mType == ASMIT_INY &&
			mIns[i + 4].mType == ASMIT_INY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
		{
			mIns[i + 0].mType = ASMIT_TYA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
			mIns[i + 1].mType = ASMIT_CLC; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
			mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 5; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
			mIns[i + 3].mType = ASMIT_TAY;
			mIns[i + 4].mType = ASMIT_NOP;
			return true;
		}
		else if (
			mIns[i + 0].mType == ASMIT_INX &&
			mIns[i + 1].mType == ASMIT_INX &&
			mIns[i + 2].mType == ASMIT_INX &&
			mIns[i + 3].mType == ASMIT_INX &&
			mIns[i + 4].mType == ASMIT_INX && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
		{
			mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
			mIns[i + 1].mType = ASMIT_CLC; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
			mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 5; mIns[i + 2].mLive |= LIVE_CPU_REG_A;
			mIns[i + 3].mType = ASMIT_TAX;
			mIns[i + 4].mType = ASMIT_NOP;
			return true;
		}
	}

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate6(int i, int pass)
{
	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mFlags & NCIF_VOLATILE) &&
		mIns[i + 3].mType == ASMIT_TXA &&
		mIns[i + 4].mType == ASMIT_LDY && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress == mIns[i + 5].mAddress &&
		!(mIns[i + 5].mFlags & NCIF_VOLATILE) && !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		mIns[i + 3] = mIns[i + 0];
		mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED;
		int a = mIns[i + 1].mAddress; mIns[i + 1].mAddress = mIns[i + 4].mAddress; mIns[i + 4].mAddress = a;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_LDA && !mIns[i + 0].RequiresYReg() &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 1]) &&
		mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && mIns[i + 4].mAddress != mIns[i + 1].mAddress && mIns[i + 4].mAddress != mIns[i + 1].mAddress + 1 &&
		mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 5].mLive & LIVE_MEM) &&
		!mIns[i + 0].MayBeChangedOnAddress(mIns[i + 4]))
	{
		mIns[i + 5] = mIns[i + 0];
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (
		mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 1 &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_CLC &&
		mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress && !(mIns[i + 5].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
	{
		mIns[i + 0].mType = ASMIT_LSR; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_ROL;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
		return true;
	}
	
	if (pass > 0 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].IsShift() && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].IsShift() && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].IsShift() && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 5].mAddress == mIns[i + 0].mAddress && !(mIns[i + 5].mLive & LIVE_CPU_REG_A) &&
		mIns[i + 5].mAddress != mIns[i + 1].mAddress && mIns[i + 5].mAddress != mIns[i + 3].mAddress)
	{
		mIns[i + 2].CopyMode(mIns[i + 0]); mIns[i + 2].mLive |= LIVE_MEM;
		mIns[i + 4].CopyMode(mIns[i + 0]); mIns[i + 4].mLive |= LIVE_MEM;
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (pass > 0 &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_STA && 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_IMPLIED &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress && !(mIns[i + 5].mLive & LIVE_MEM))
	{
		mIns[i + 2].CopyMode(mIns[i + 0]); mIns[i + 2].mLive |= LIVE_MEM;
		mIns[i + 3].CopyMode(mIns[i + 0]); mIns[i + 3].mLive |= LIVE_MEM;

		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].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;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && !mIns[i + 3].MayBeSameAddress(mIns[i + 2]) &&
		mIns[i + 4].mType == ASMIT_ASL && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 5].mType == ASMIT_ORA && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 5].mLive & LIVE_MEM))
	{
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mLive |= LIVE_CPU_REG_C;
		mIns[i + 4].mType = ASMIT_ROL;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		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 + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && (mIns[i + 2].mMode == ASMIM_ABSOLUTE || mIns[i + 2].mMode == ASMIM_ABSOLUTE_X || mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y) &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 5].mType == ASMIT_ROR && mIns[i + 5].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 5].mLive & LIVE_CPU_REG_A))
	{
		int livexy = mIns[i + 0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y);

		mIns.Insert(i + 5, mIns[i + 0]);
		mIns.Insert(i + 7, mIns[i + 1]);
		mIns.Remove(i, 2);

		mIns[i + 4].mMode = ASMIM_IMPLIED; mIns[i + 4].mLive |= LIVE_CPU_REG_A;
		mIns[i + 5].mLive |= (mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z));
		mIns[i + 0].mLive |= livexy;
		mIns[i + 1].mLive |= livexy;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C | livexy;
		mIns[i + 3].mLive |= LIVE_CPU_REG_C;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && !(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
		mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_LDA && !(mIns[i + 2].mFlags & NCIF_VOLATILE) && !mIns[i + 2].SameEffectiveAddress(mIns[i + 1]) &&
		mIns[i + 3].IsShift() && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].IsShift() && mIns[i + 4].SameEffectiveAddress(mIns[i + 1]) &&
		mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].SameEffectiveAddress(mIns[i + 1]))
	{
		mIns[i + 1] = mIns[i + 3];
		mIns[i + 3] = mIns[i + 0]; mIns[i + 3].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C;
		mIns[i + 0] = mIns[i + 2];
		if (mIns[i + 3].RequiresXReg())
		{
			mIns[i + 0].mLive |= LIVE_CPU_REG_X; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		}
		if (mIns[i + 3].RequiresYReg())
		{
			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;
		mIns[i + 4].mMode = ASMIM_IMPLIED; mIns[i + 4].mLive |= LIVE_CPU_REG_A;
		mIns[i + 5].mType = ASMIT_STA;

		return true;
	}


#if 1
	if (pass == 0 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 3].mFlags & NCIF_UPPER) && (mIns[i + 3].mLinkerObject == mIns[i + 1].mLinkerObject) &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
		!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
	{
		mProc->ResetPatched();
		if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
		{
			assert(mIns[i + 3].mAddress == mIns[i + 1].mAddress);

			mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

			mProc->ResetPatched();
			if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress + mIns[i + 4].mAddress * 256))
				return true;
		}
	}
#endif
	if (pass == 0 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
		!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
	{
		mProc->ResetPatched();
		if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
		{
			mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

			mProc->ResetPatched();
			if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, mIns[i + 1].mAddress + (mIns[i + 3].mAddress + mIns[i + 4].mAddress) * 256))
				return true;
		}
	}
	else if (pass == 0 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
		!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
	{
		mProc->ResetPatched();
		if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
		{
			mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

			mProc->ResetPatched();
			if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, 256 * mIns[i + 3].mAddress))
				return true;
		}
	}

	if (pass > 8 &&
		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_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_CLC &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 1 &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE &&
		!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C))
		)
	{
		mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
		mIns[i + 1].mType = ASMIT_INX; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
		mIns[i + 2].mType = ASMIT_STX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mType = ASMIT_INX; mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 5].mType = ASMIT_STX;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_TAX &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		!mIns[i + 2].ReferencesCarry() && !mIns[i + 2].ChangesXReg() &&
		mIns[i + 3].mType == ASMIT_TXA &&
		mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01 &&
		mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_LDA; mIns[i + 4].mMode = ASMIM_IMMEDIATE; mIns[i + 4].mAddress = 0x00; mIns[i + 4].mLive |= LIVE_CPU_REG_C;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

		return true;
	}

	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_ROR) && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		!mIns[i + 2].ReferencesCarry() && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 2], true) &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0x01 &&
		mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].mMode == ASMIM_IMPLIED)
	{
		mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mLive |= LIVE_CPU_REG_C;
		mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
		mIns[i + 4].mType = ASMIT_LDA; mIns[i + 4].mMode = ASMIM_IMMEDIATE; mIns[i + 4].mAddress = 0x00; mIns[i + 4].mLive |= LIVE_CPU_REG_C;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

		return true;
	}

	// 20c7 : b1 10 __ LDA(P3), y; (marr + 0)
	// 20c9 : 05 0d __ ORA P0; (sig + 0)
	// 20cb : 85 1b __ STA ACCU + 0
	// 20cd : b1 0e __ LDA(P1), y; (arr + 0)
	// 20cf : 11 10 __ ORA(P3), y; (marr + 0)
	// 20d1 : c5 1b __ CMP ACCU + 0

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_ORA &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && 
		mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 5].mType == ASMIT_CMP && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress &&
		!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
	{
		mIns[i + 0].CopyMode(mIns[i + 3]);
		mIns[i + 5].CopyMode(mIns[i + 4]);
		mIns[i + 1].mType = ASMIT_EOR;

		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 + 1].mLive |= (mIns[i + 0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y));
		mIns[i + 4].mLive |= (mIns[i + 0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y));

		return true;
	}

	// 20d5 : b1 10 __ LDA(P3), y; (marr + 0)
	// 20d7 : 11 0e __ ORA(P1), y; (arr + 0)
	// 20d9 : 85 1b __ STA ACCU + 0
	// 20db : b1 10 __ LDA(P3), y; (marr + 0)
	// 20dd : 05 0d __ ORA P0; (sig + 0)
	// 20df : c5 1b __ CMP ACCU + 0

	if (
		mIns[i + 0].mType == ASMIT_LDA &&
		mIns[i + 1].mType == ASMIT_ORA &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 4].mType == ASMIT_ORA && 
		mIns[i + 5].mType == ASMIT_CMP && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress &&
		!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
	{
		mIns[i + 0].CopyMode(mIns[i + 4]);
		mIns[i + 4].CopyMode(mIns[i + 3]);
		mIns[i + 5].CopyMode(mIns[i + 3]);
		mIns[i + 1].mType = ASMIT_EOR;

		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 + 1].mLive |= (mIns[i + 0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y));
		mIns[i + 4].mLive |= (mIns[i + 0].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Y));

		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_ROR && 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 + 3].mType == ASMIT_AND && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 0x80 &&
		mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
		!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 2].mIns, ASMIT_LDA, mIns[i + 2]));
		mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 3].mIns, ASMIT_ASL));
		mIns[i + 2].mType = ASMIT_ROR;

		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;
		mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
		mIns[i + 1].mType == ASMIT_ROR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_EOR && 
		mIns[i + 3].mType == ASMIT_ASL && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_EOR &&
		mIns[i + 5].mType == ASMIT_ROR && mIns[i + 5].mMode == ASMIM_IMPLIED &&
		!(mIns[i + 5].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].CopyMode(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;
		mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
		return true;
	}


	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterateN(int i, int pass)
{
	if (i + 5 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_INY && mIns[i + 3].mType == ASMIT_DEY &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
		mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_INDIRECT_Y &&
		!(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
	{
		if (mIns[i + 5].mType == ASMIT_TAX)
		{
			if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 4].mAddress && mIns[i + 2].mAddress != mIns[i + 4].mAddress + 1)
			{
				mIns[i + 5] = mIns[i + 2];
				mIns[i + 2].mType = ASMIT_TAX; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mLive |= LIVE_CPU_REG_X;
				mIns[i + 3].mLive |= LIVE_CPU_REG_X;
				mIns[i + 4].mLive |= LIVE_CPU_REG_X;
				mIns[i + 5].mLive |= LIVE_CPU_REG_X;
				mIns[i + 3].mType = ASMIT_INY;
				mIns.Insert(i + 6, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_DEY));
				return true;
			}
		}
	}

	if (i + 6 < mIns.Size() && pass > 3 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i + 1].mLinkerObject && mIns[i + 1].mAddress <= 256 &&
		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 + 1].mLinkerObject == mIns[i + 3].mLinkerObject &&
		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)
	{
		if (mIns[i + 1].mLinkerObject->mFlags & LOBJF_NEVER_CROSS)
		{
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			return true;
		}

	}

	if (i + 7 < mIns.Size() && pass > 3 &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA &&
		mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
		mIns[i + 6].mType == ASMIT_LDY && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 7].mMode == ASMIM_INDIRECT_Y && mIns[i + 7].mAddress == mIns[i + 2].mAddress && !(mIns[i + 7].mLive & LIVE_MEM))
	{
		int total = mIns[i + 1].mAddress + mIns[i + 6].mAddress + 256 * mIns[i + 4].mAddress;
		if (!(mIns[i + 7].mLive & LIVE_CPU_REG_Y) || !(mIns[i + 7].mLive & LIVE_CPU_REG_Z))
		{
			if (mIns[i + 7].mLive & LIVE_CPU_REG_Y)
				mIns.Insert(i + 8, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, mIns[i + 6].mAddress));
			mIns[i + 6].mAddress = total & 255;
			mIns[i + 4].mAddress = total >> 8;
			mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
			return true;
		}
	}

	if (i + 7 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && 
		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].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 5].mType == ASMIT_AND && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 6].mType == ASMIT_CLC && 
		mIns[i + 7].mType == ASMIT_ADC && mIns[i + 7].SameEffectiveAddress(mIns[i + 3]) && !(mIns[i + 7].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
	{
		NativeCodeInstruction	i4(mIns[i + 4]);
		NativeCodeInstruction	i5(mIns[i + 5]);
		NativeCodeInstruction	i6(mIns[i + 6]);

		i4.mLive |= LIVE_CPU_REG_C;
		i5.mLive |= LIVE_CPU_REG_C;

		mIns.Remove(i + 3, 5);
		mIns.Insert(i + 1, i4);
		mIns.Insert(i + 2, i5);
		mIns[i + 3].mType = ASMIT_ADC;
		mIns.Insert(i + 4, i6);
		return true;
	}

	if (i + 6 < mIns.Size())
	{
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
		{
			mIns[i + 1].mAddress = mIns[i + 4].mAddress = mIns[i + 1].mAddress + mIns[i + 2].mAddress + 256 * mIns[i + 5].mAddress;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
		{
			mIns[i + 1].mAddress = mIns[i + 5].mAddress = mIns[i + 1].mAddress + mIns[i + 2].mAddress + 256 * mIns[i + 4].mAddress;
			mIns[i + 5].mType = ASMIT_LDA;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			return true;
		}
		else if (
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_AND && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 1 &&
			mIns[i + 5].mType == ASMIT_CLC &&
			mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress && !(mIns[i + 6].mLive & (LIVE_MEM | LIVE_CPU_REG_C)))
		{
			int	addr = mIns[i + 0].mAddress;
			mIns[i + 0].mAddress = mIns[i + 3].mAddress;
			mIns[i + 3].mAddress = addr;
			mIns[i + 1].mType = ASMIT_LSR; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
			mIns[i + 3].mLive |= LIVE_CPU_REG_C;
			mIns[i + 5].mType = ASMIT_ROL;
			mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
			mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
			mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
			return true;
		}
#if 1
		if (pass == 0 &&
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
			mIns[i + 2].mType == ASMIT_ADC &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			mProc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
			{
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_LDA;
				mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
				mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
				mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

				mProc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress + mIns[i + 5].mAddress * 256))
				{
					CheckLive();
					return true;
				}
			}
			else if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress)
			{
				mProc->ResetPatched();
				if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1))
				{
					mProc->ResetPatched();
					if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress + mIns[i + 5].mAddress * 256))
					{
						CheckLive();
						return true;
					}
				}
			}
		}

#endif
#if 1
		if (pass == 0 &&
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 2].mFlags & NCIF_LOWER) &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 2].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 2].mAddress &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			mProc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
			{
//				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
				mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
				mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

				mProc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 4].mAddress * 256))
				{
					CheckLive();
					return true;
				}
			}
			else if (mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 3].mAddress)
			{
				mProc->ResetPatched();
				if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, i + 7, -1))
				{
					mProc->ResetPatched();
					if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, i + 7, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 4].mAddress * 256))
					{
						CheckLive();
						return true;
					}
				}
			}
		}

#endif
#if 1
		if (pass == 0 && i + 7 < mIns.Size() &&
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 0].mFlags & NCIF_LOWER) &&
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
			mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && mIns[i + 5].mLinkerObject == mIns[i + 0].mLinkerObject && mIns[i + 5].mAddress == mIns[i + 0].mAddress &&
			mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 4].mAddress + 1 &&
			!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
		{
			mProc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 4].mAddress, mIns[i + 4].mAddress, i + 8, mIns[i + 2].mAddress))
			{
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 3].mType = ASMIT_LDA;
				mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
				mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
				mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;

				mProc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 4].mAddress, mIns[i + 4].mAddress, i + 8, mIns[i + 2].mAddress, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress + mIns[i + 6].mAddress * 256))
				{
					CheckLive();
					return true;
				}
			}
		}

#endif
#if 1
		if (pass == 0 &&
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 2].mType == ASMIT_ADC &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			mProc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
			{
				mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
				mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
				mIns[i + 2].mType = ASMIT_LDA;
				mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
				mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
				mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

				mProc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, nullptr, mIns[i + 1].mAddress + 256 * mIns[i + 4].mAddress + mIns[i + 5].mAddress * 25))
				{
					CheckLive();
					return true;
				}
			}
		}

#endif

#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 2].mAddress &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 5].mAddress &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();

					return true;
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject && mIns[i + 4].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
				{
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();

					return true;
				}
			}
		}
#endif
#if 1
		if (pass == 0 &&
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 3].mFlags & NCIF_UPPER) && (mIns[i + 3].mLinkerObject == mIns[i + 1].mLinkerObject) &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 4].mAddress &&
			!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);

			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval, 0))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					CheckLive();
					return true;
				}
			}
		}
#endif

#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);

			bool	subs1 = mIns[i + 3].mAddress != mIns[i + 1].mAddress;
			bool	subs2 = mIns[i + 3].mAddress != mIns[i + 2].mAddress;

			if (subs1 && subs2)
			{
				if (mLoopHead)
				{
					if (ChangesZeroPage(mIns[i + 1].mAddress))
						subs2 = false;
					else if (ChangesZeroPage(mIns[i + 2].mAddress))
						subs1 = false;
				}
			}

			mProc->ResetPatched();
			if (subs1 && CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_LDA;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();

					return true;
				}

			}
			else if (subs2)
			{
				mProc->ResetPatched();
				if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0))
				{
					mProc->ResetPatched();
					if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
					{
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
						return true;
					}
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && /*mIns[i + 3].mAddress != mIns[i + 1].mAddress && mIns[i + 3].mAddress != mIns[i + 2].mAddress && */
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval, intmax(3, 255 - mIns[i + 2].mMaxVal)))
			{
				NativeCodeInstruction	inins(mIns[i + 2]);
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, inins, i + 7, yval))
				{
					if (mIns[i + 3].mAddress == mIns[i + 1].mAddress || mIns[i + 3].mAddress == mIns[i + 2].mAddress)
					{
						for (int j = 0; j < 7; j++)
						{
							mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
						}
					}

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 2].mAddress &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval, 3))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
				{
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
			else if (mIns[i + 3].mAddress != mIns[i + 1].mAddress)
			{
				mProc->ResetPatched();
				if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 3], i + 7, yval, 3))
				{
					mProc->ResetPatched();
					if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 3], i + 7, yval))
					{
						mIns[i + 1].CopyMode(mIns[i + 2]);
						mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
						mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
						mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
						mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
						return true;
					}
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_STA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 1].mType == ASMIT_CLC &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval, 3))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval))
				{

					if (mIns[i + 3].mAddress == mIns[i + 2].mAddress)
					{
						for (int j = 1; j < 7; j++)
						{
							mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
						}
					}

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			mIns[i + 2].mAddress != mIns[i + 3].mAddress &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, intmax(3, 255 - mIns[i + 2].mMaxVal)))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
				{
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
			mIns[i + 3].mAddress != BC_REG_STACK &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();

			if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, intmax(3, 255 - mIns[i + 2].mMaxVal)))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval))
				{
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_LDA &&
			mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 2].mAddress != BC_REG_STACK &&
			!(mIns[i + 6].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();

			if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval, 3))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
			mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 && !(mIns[i + 3].mLive & LIVE_MEM) &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
			!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 0))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 5].mAddress = mIns[i + 3].mAddress;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
			mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
			!(mIns[i + 5].mLive & LIVE_CPU_REG_A))
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 3))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1)
		{
			int yval = RetrieveYValue(i);
			int reg = FindFreeAccu(i);
			if (reg >= 0)
			{
				NativeCodeInstruction	iins(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg);

				mProc->ResetPatched();
				if (CheckForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval, 3))
				{
					mIns[i + 0] = iins;
					for (int j = 1; j < 6; j++)
					{
						mIns[i + j].mType = ASMIT_NOP; mIns[i + j].mMode = ASMIM_IMPLIED;
					}

					mProc->ResetPatched();
					if (PatchForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval))
					{
						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
						return true;
					}
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 1].mAddress &&
			mIns[i + 3].mType == ASMIT_LDA && (mIns[i + 3].mMode == ASMIM_ABSOLUTE_X || mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1)
		{
			int yval = RetrieveYValue(i);
			int reg = FindFreeAccu(i);
			if (reg >= 0)
			{
				NativeCodeInstruction	iins(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg);

				mProc->ResetPatched();
				if (CheckForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval, 3))
				{
					mIns[i + 0] = iins;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
					mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

					mProc->ResetPatched();
					if (PatchForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval))
					{
						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
						return true;
					}
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_LDA && (mIns[i + 3].mMode == ASMIM_ABSOLUTE_X || mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
			mIns[i + 1].mAddress != mIns[i + 2].mAddress && mIns[i + 1].mAddress != mIns[i + 5].mAddress)
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval, 3))
			{
				mProc->ResetPatched();
				if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 6, yval))
				{
					mIns[i + 0].mType = ASMIT_NOP;
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif
#if 1
		if (
			mIns[i + 0].mType == ASMIT_CLC &&
			mIns[i + 1].mType == ASMIT_ADC && (mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 3].mType == ASMIT_LDA && (mIns[i + 3].mMode == ASMIM_ABSOLUTE_X || mIns[i + 3].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 3].mMode == ASMIM_ABSOLUTE) &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1)
		{
			int yval = RetrieveYValue(i);
			int reg = FindFreeAccu(i);
			if (reg >= 0)
			{
				NativeCodeInstruction	iins(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg);

				mProc->ResetPatched();
				if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, iins, i + 6, yval, 3))
				{
					mIns[i + 0] = iins;
					mIns[i + 1].mType = ASMIT_LDA;
					mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;

					mProc->ResetPatched();
					if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, iins, i + 6, yval))
					{
						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
						return true;
					}
				}
			}
		}
#endif
#if 1
		if (
			mLoopHead &&
			mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
			mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
			mIns[i + 2].mType == ASMIT_CLC &&
			mIns[i + 3].mType == ASMIT_LDA &&
			mIns[i + 4].mType == ASMIT_ADC &&
			mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
		{
			int yval = RetrieveYValue(i);
			mProc->ResetPatched();
			if (CheckForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
			{
				mProc->ResetPatched();
				if (PatchForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
				{
					mIns[i + 0].mMode = ASMIM_IMMEDIATE;
					mIns[i + 0].mAddress = 0;

					CheckLive();
					if (mTrueJump)
						mTrueJump->CheckLive();
					if (mFalseJump)
						mFalseJump->CheckLive();
					return true;
				}
			}
		}
#endif

#if 1
		if (
			mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
			mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y &&
			mIns[i + 2].mType == ASMIT_CLC &&
			mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress != mIns[i + 0].mAddress &&
			mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 4].mLive & LIVE_CPU_REG_Y))
		{
			int j = i + 5;
			while (j < mIns.Size() && !mIns[j].ChangesYReg())
				j++;
			if (j < mIns.Size() && mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE && mIns[j].mAddress == mIns[i + 0].mAddress)
			{
				int	reg = mIns[i + 1].mAddress; mIns[i + 1].mAddress = mIns[i + 4].mAddress; mIns[i + 4].mAddress = reg;
				int yr = mIns[i + 0].mAddress; mIns[i + 0].mAddress = mIns[i + 3].mAddress; mIns[i + 3].mAddress = yr;
				mIns[i + 1].mLive |= LIVE_MEM;
				mIns[i + 4].mLive |= LIVE_MEM;
				mIns[j].mType = ASMIT_NOP; mIns[j].mMode = ASMIM_IMPLIED;
				while (j > i)
				{
					j--;
					mIns[j].mLive |= LIVE_CPU_REG_Y;
				}
				return true;
			}
		}
#endif
	}

#if 1
	if (i + 7 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_CLC &&
		mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 3].mAddress &&
		mIns[i + 4].mType == ASMIT_LDA && 
		mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress != mIns[i + 0].mAddress &&
		mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
		mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 7].mAddress &&
		!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
	{
		int yval = RetrieveYValue(i);
		mProc->ResetPatched();
		if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 8, yval, 0))
		{
			mProc->ResetPatched();
			if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 8, yval))
			{
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;

				CheckLive();
				if (mTrueJump)
					mTrueJump->CheckLive();
				if (mFalseJump)
					mFalseJump->CheckLive();

				return true;
			}
		}
	}
#endif

#if 1
	if (pass == 0 &&
		i + 7 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&

		mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 4].mFlags & NCIF_UPPER) && (mIns[i + 4].mLinkerObject == mIns[i + 1].mLinkerObject) &&
		mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress + 1 &&
		mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 3].mAddress + 1 &&
		!(mIns[i + 7].mLive & LIVE_CPU_REG_A))
	{
		mProc->ResetPatched();
		if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 8, -1))
		{
			NativeCodeInstruction	ins(mIns[i + 2]);
			mIns[i + 2] = mIns[i + 1];
			mIns[i + 1] = ins;

			mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;

			mProc->ResetPatched();
			if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
			{
				CheckLive();
				return true;
			}
		}
		else
		{
			mProc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 8, -1))
			{
				NativeCodeInstruction	ins(mIns[i + 3]);
				mIns[i + 3] = mIns[i + 2];
				mIns[i + 2] = mIns[i + 1];
				mIns[i + 1] = ins;

				mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;

				mProc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
				{
					CheckLive();
					return true;
				}
			}
		}
	}
	if (pass == 0 &&
		i + 8 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_CLC &&
		mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_LOWER) &&
		mIns[i + 2].mType == ASMIT_ADC && (mIns[i + 2].mMode == ASMIM_ZERO_PAGE || mIns[i + 2].mMode == ASMIM_ABSOLUTE) &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&

		mIns[i + 5].mType == ASMIT_LDA && mIns[i + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 5].mFlags & NCIF_UPPER) && (mIns[i + 5].mLinkerObject == mIns[i + 1].mLinkerObject) &&
		mIns[i + 6].mType == ASMIT_ADC && mIns[i + 6].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].mMode == ASMIM_ZERO_PAGE && mIns[i + 7].mAddress == mIns[i + 3].mAddress + 1 &&
		mIns[i + 8].mType == ASMIT_STA && mIns[i + 8].mMode == ASMIM_ZERO_PAGE && mIns[i + 8].mAddress == mIns[i + 4].mAddress + 1 &&
		!(mIns[i + 8].mLive & LIVE_CPU_REG_A))
	{
		mProc->ResetPatched();
		if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 9, -1))
		{
			NativeCodeInstruction	ins(mIns[i + 3]);
			mIns[i + 3] = mIns[i + 1];
			mIns[i + 1] = mIns[i + 2];
			mIns[i + 2] = ins;

			mIns[i + 1].mType = ASMIT_LDA;
			mIns[i + 3].mType = ASMIT_ADC;

			mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;

			mProc->ResetPatched();
			if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 9, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress + mIns[i + 6].mAddress * 256))
			{
				CheckLive();
				return true;
			}
		}
#if 0
		else
		{
			proc->ResetPatched();
			if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 8, -1))
			{
				NativeCodeInstruction	ins(mIns[i + 3]);
				mIns[i + 3] = mIns[i + 2];
				mIns[i + 2] = mIns[i + 1];
				mIns[i + 1] = ins;

				mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;

				proc->ResetPatched();
				if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, i + 8, -1, mIns[i + 2].mLinkerObject, mIns[i + 2].mAddress + mIns[i + 5].mAddress * 256))
					progress = true;
			}
		}
#endif
	}
#endif


	if (i + 5 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED &&
		mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
		mIns[i + 4].mType == ASMIT_LSR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].mMode == ASMIM_IMPLIED && !(mIns[i + 5].mLive & LIVE_CPU_REG_C))
	{
		mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
		mIns[i + 2].mType = ASMIT_ROL;
		mIns[i + 3].mType = ASMIT_NOP;
		mIns[i + 4].mType = ASMIT_NOP;
		mIns[i + 5].mType = ASMIT_AND; mIns[i + 5].mMode = ASMIM_IMMEDIATE; mIns[i + 5].mAddress = 3;
		return true;
	}

	if (i + 6 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 1].mType == ASMIT_TXA &&
		mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_INDIRECT_Y &&
		mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_MEM) &&
		mIns[i + 5].mType == ASMIT_LDY && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress != mIns[i + 5].mAddress &&
		mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_INDIRECT_Y && mIns[i + 3].mAddress == mIns[i + 6].mAddress && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
	{
		int t = mIns[i + 5].mAddress;
		mIns[i + 5].mAddress = mIns[i + 2].mAddress;
		mIns[i + 2].mAddress = t;
		mIns[i + 4] = mIns[i + 1];
		mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mLive |= LIVE_CPU_REG_X;
		mIns[i + 3].mLive |= LIVE_CPU_REG_X;
		return true;
	}

	if (i + 9 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 4].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) &&
		mIns[i + 6].mType == ASMIT_ROR && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 8].mLive & LIVE_MEM) &&
		mIns[i + 9].mType == ASMIT_STA && mIns[i + 9].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 9].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_LSR; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_ROR;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 5].CopyMode(mIns[i + 0]);
		mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
		mIns[i + 7].mType = ASMIT_ROR;
		mIns[i + 8].mType = ASMIT_NOP; mIns[i + 8].mMode = ASMIM_IMPLIED;
		mIns[i + 9].mType = ASMIT_NOP; mIns[i + 9].mMode = ASMIM_IMPLIED;
		return true;
	}
	if (i + 9 < mIns.Size() &&
		mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X &&
		mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED &&
		mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ABSOLUTE_X && !mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) &&
		mIns[i + 4].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 5].mType == ASMIT_ASL && mIns[i + 5].SameEffectiveAddress(mIns[i + 2]) &&
		mIns[i + 6].mType == ASMIT_ROL && mIns[i + 4].mMode == ASMIM_IMPLIED &&
		mIns[i + 7].mType == ASMIT_STA && mIns[i + 7].SameEffectiveAddress(mIns[i + 3]) &&
		mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].SameEffectiveAddress(mIns[i + 2]) && !(mIns[i + 8].mLive & LIVE_MEM) &&
		mIns[i + 9].mType == ASMIT_STA && mIns[i + 9].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 9].mLive & LIVE_CPU_REG_A))
	{
		mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
		mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
		mIns[i + 3].mType = ASMIT_ROL;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
		mIns[i + 5].CopyMode(mIns[i + 0]);
		mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
		mIns[i + 7].mType = ASMIT_ROL;
		mIns[i + 8].mType = ASMIT_NOP; mIns[i + 8].mMode = ASMIM_IMPLIED;
		mIns[i + 9].mType = ASMIT_NOP; mIns[i + 9].mMode = ASMIM_IMPLIED;
		return true;
	}

	if (i + 6 < 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_DEY &&
		mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_INDIRECT_Y && mIns[i + 3].mAddress != mIns[i + 0].mAddress && mIns[i + 3].mAddress != mIns[i + 0].mAddress + 1 &&
		mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress &&
		mIns[i + 5].mType == ASMIT_INY &&
		mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_INDIRECT_Y && mIns[i + 6].mAddress == mIns[i + 3].mAddress && !(mIns[i + 6].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y))
		)
	{
		mIns[i + 0].mLive |= LIVE_CPU_REG_A;
		mIns[i + 4] = mIns[i + 1];
		mIns[i + 1] = mIns[i + 3];
		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 + 5].mType = ASMIT_DEY;
		return true;
	}

	if (i + 7 < mIns.Size() && pass > 3 &&
		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_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE &&
		mIns[i + 3].mType == ASMIT_LDY && 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_ABSOLUTE_Y && !(mIns[i + 4].mLive & LIVE_CPU_REG_Y) &&
		mIns[i + 5].mType == ASMIT_SEC && 
		mIns[i + 6].mType == ASMIT_SBC && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 2].mAddress && !(mIns[i + 6].mLive & LIVE_MEM) &&
		!(mIns[i + 1].mFlags & NCIF_VOLATILE) && !(mIns[i + 4].mFlags & NCIF_VOLATILE))
	{
		int a0 = mIns[i + 0].mAddress, a1 = mIns[i + 3].mAddress;

		mIns[i + 6].CopyMode(mIns[i + 1]);
		mIns[i + 1].CopyMode(mIns[i + 4]);
		mIns[i + 0].mAddress = a1;
		mIns[i + 3].mAddress = a0;
		mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMMEDIATE;
		mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMMEDIATE;
		mIns[i + 5].mLive |= LIVE_CPU_REG_Y;

		return true;
	}

	return false;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerIterate(int pass)
{
	bool	changed = false;

	bool	progress = false;
	do {
		progress = false;

		mIns.Reserve(mIns.Size() * 2 + 32);

		if (RemoveNops())
			changed = true;

		CheckLive();

		// Replace (a & 0x80) != 0 with bpl/bmi
		int	sz = mIns.Size();

		if (sz > 1 &&
			mIns[sz - 2].ChangesAccuAndFlag() &&
			mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			if (mBranch == ASMIT_BEQ)
			{
				mBranch = ASMIT_BPL;
				mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
				mIns[sz - 1].mType = ASMIT_NOP;	mIns[sz - 1].mMode = ASMIM_IMPLIED;
				changed = true;
			}
			else if (mBranch == ASMIT_BNE)
			{
				mBranch = ASMIT_BMI;
				mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
				mIns[sz - 1].mType = ASMIT_NOP;	mIns[sz - 1].mMode = ASMIM_IMPLIED;
				changed = true;
			}
		}

		if (sz > 4 &&
			mIns[sz - 4].mType == ASMIT_ASL && mIns[sz - 4].mMode == ASMIM_IMPLIED &&
			mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
			mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
			mIns[sz - 1].mType == ASMIT_EOR && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0xff && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			if (mBranch == ASMIT_BEQ)
			{
				mBranch = ASMIT_BPL;
				mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
				mIns[sz - 3].mType = ASMIT_NOP;	mIns[sz - 3].mMode = ASMIM_IMPLIED;
				mIns[sz - 2].mType = ASMIT_NOP;	mIns[sz - 2].mMode = ASMIM_IMPLIED;
				mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0;
				changed = true;
			}
			else if (mBranch == ASMIT_BNE)
			{
				mBranch = ASMIT_BMI;
				mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
				mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
				mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
				mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0;
				changed = true;
			}
		}

		if (sz > 2 &&
			mIns[sz - 3].mType == ASMIT_STA &&
			mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
			mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 3]) && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)))
		{
			if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff)
			{
				mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
				mIns[sz - 1].mAddress = mIns[sz - 2].mAddress + 1;
				mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
				mBranch = ASMIT_BCS;
				changed = true;
			}
			else if (mBranch == ASMIT_BCS && mIns[sz - 2].mAddress < 0xff)
			{
				mIns[sz - 3].mLive |= LIVE_CPU_REG_A;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
				mIns[sz - 1].mAddress = mIns[sz - 2].mAddress + 1;
				mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
				mBranch = ASMIT_BCC;
				changed = true;
			}
		}

		for (int i = 0; i < mIns.Size(); i++)
		{
			if (PeepHoleOptimizerIterate1(i, pass)) progress = true;

			if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO))
			{
				const NativeCodeInstruction* ains, * iins;

				int	sreg = mIns[i + 0].mAddress;

				int	apos, breg, ireg, addr;
				uint32	flags;

				if (FindAddressSumY(i, sreg, apos, breg, ireg))
				{
					if (!(breg == sreg || ireg == sreg) || !(mIns[i + 0].mLive & LIVE_MEM))
					{
						if (breg == sreg || ireg == sreg)
						{
							mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED;
							mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mMode = ASMIM_IMPLIED;
						}

						RepairLoadYImmediate(i, 0);

						mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
						mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;

						mIns[i + 1].mAddress = breg;
						mIns[i + 1].mFlags &= ~NCIF_YZERO;
						progress = true;

						CheckLive();

					}
				}
				else if (FindGlobalAddressSumY(i, sreg, true, apos, ains, iins, flags, addr))
				{
					if (iins || (flags & LIVE_CPU_REG_Y) || (flags & LIVE_CPU_REG_X)) //!(mIns[i + 1].mLive & LIVE_CPU_REG_X))
					{
						RepairLoadYImmediate(i, 0);

						if (flags & LIVE_CPU_REG_Y)
						{
							mIns[i + 0].mMode = ASMIM_ABSOLUTE_Y;
						}
						else if (flags & LIVE_CPU_REG_X)
						{
							mIns[i + 0].mMode = ASMIM_ABSOLUTE_X;
						}
						else
						{
							mIns[i + 0].mMode = ASMIM_ABSOLUTE_Y;
						}


						if (ains->mMode == ASMIM_IMMEDIATE)
						{
							mIns[i + 0].mLinkerObject = nullptr;
							mIns[i + 0].mAddress = addr;
						}
						else
						{
							mIns[i + 0].mLinkerObject = ains->mLinkerObject;
							mIns[i + 0].mAddress = ains->mAddress;
						}

						mIns[i + 0].mFlags &= ~NCIF_YZERO;

						if (!iins)
						{
							if (flags & LIVE_CPU_REG_Y)
							{
								mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY, ASMIM_IMPLIED));
								for (int j = apos; j < i + 1; j++)
									mIns[j].mLive |= LIVE_CPU_REG_Y;
							}
							else
							{
								PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
								mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAX, ASMIM_IMPLIED));
								for (int j = apos; j < i + 2; j++)
									mIns[j].mLive |= LIVE_CPU_REG_X;
							}
						}
						else
						{
							if (iins->mMode != ASMIM_ZERO_PAGE)
								mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, iins->mMode, iins->mAddress, iins->mLinkerObject, iins->mFlags));
							else if (iins->mAddress == sreg)
							{
								if (flags & LIVE_CPU_REG_Y)
								{
									mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
									mIns[apos].mLive |= LIVE_MEM;
									for (int j = apos; j < i + 2; j++)
										mIns[j].mLive |= LIVE_CPU_REG_Y;
								}
								else
								{
									PatchGlobalAdressSumYByX(i + 1, sreg, *ains, addr);
									mIns.Insert(apos, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, iins->mAddress));
									mIns[apos].mLive |= LIVE_MEM;
									for (int j = apos; j < i + 2; j++)
										mIns[j].mLive |= LIVE_CPU_REG_X;
								}
								i++;
							}
							else
								mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, iins->mAddress));
							if (i > 0)
								mIns[i + 0].mLive |= mIns[i - 1].mLive | LIVE_CPU_REG_Y | LIVE_MEM;
						}

						progress = true;

						CheckLive();

					}
				}
				else if (FindExternAddressSumY(i, sreg, breg, ireg))
				{
					RepairLoadYImmediate(i, 0);

					mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));
					mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;

					mIns[i + 1].mAddress = breg;
					mIns[i + 1].mFlags &= ~NCIF_YZERO;
					progress = true;

					CheckLive();
				}
				else if (FindSharedGlobalAddressSumY(i, sreg, ains, iins))
				{
					RepairLoadYImmediate(i, 0);

					mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, *iins));
					mIns[i + 0].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;

					mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
					mIns[i + 1].mLinkerObject = ains->mLinkerObject;
					mIns[i + 1].mAddress = ains->mAddress;
					mIns[i + 1].mFlags &= ~NCIF_YZERO;
					progress = true;

					CheckLive();
				}
				else if (!(mIns[i + 0].mLive & LIVE_MEM) && FindLoadAddressSumY(i, sreg, apos, ireg))
				{
					RepairLoadYImmediate(i, 0);
					PatchLoadAddressSumY(i, sreg, apos, ireg);

					mIns.Insert(i + 0, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, ireg));

					mIns[i + 1].mFlags &= ~NCIF_YZERO;
					progress = true;

					CheckLive();
				}
				if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO) && !(mIns[i + 0].mLive & LIVE_CPU_REG_X))
				{
					const NativeCodeInstruction* ains;
					if (FindImmediateStore(i, mIns[i].mAddress + 1, ains))
					{
						mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i].mAddress));
						mIns[i + 1].mMode = ASMIM_ABSOLUTE_X;

						if (ains->mMode == ASMIM_IMMEDIATE)
							mIns[i + 1].mAddress = ains->mAddress << 8;
						else
						{
							mIns[i + 1].mLinkerObject = ains->mLinkerObject;
							mIns[i + 1].mAddress = ains->mAddress;
							mIns[i + 1].mFlags |= NCIF_UPPER;
							mIns[i + 1].mFlags &= ~NCIF_LOWER;
						}
						progress = true;

						CheckLive();
					}
				}

			}

			CheckLive();

			if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_INDIRECT_Y)
			{
				const NativeCodeInstruction* ains, * iins;

				int	sreg = mIns[i + 1].mAddress;

				int	yimm = mIns[i + 0].mAddress;


				if (FindSharedGlobalAddressSumY(i, sreg, ains, iins))
				{
					RepairLoadYImmediate(i + 1, yimm);

					mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_LDY, *iins));
					mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_MEM;

					mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y;
					mIns[i + 2].mLinkerObject = ains->mLinkerObject;
					mIns[i + 2].mAddress = ains->mAddress + yimm;
					mIns[i + 2].mFlags &= ~NCIF_YZERO;
					progress = true;

					CheckLive();
				}
			}

#if _DEBUG
			NativeCodeInstruction	h0(mIns[i + 0]);
			NativeCodeInstruction	h1(mIns[i + 1 < mIns.Size() ? i + 1 : 0]);
#endif
			if (i + 1 < mIns.Size() && PeepHoleOptimizerIterate2(i, pass)) progress = true;
			CheckLive();
#if _DEBUG
			NativeCodeInstruction	i0(mIns[i + 0]);
			NativeCodeInstruction	i1(mIns[i + 1 < mIns.Size() ? i + 1 : 0]);
			NativeCodeInstruction	i2(mIns[i + 2 < mIns.Size() ? i + 2 : 0]);
#endif
			if (i + 2 < mIns.Size() && PeepHoleOptimizerIterate3(i, pass)) progress = true;
			CheckLive();
			if (i + 3 < mIns.Size() && PeepHoleOptimizerIterate4(i, pass)) progress = true;
			CheckLive();
			if (i + 4 < mIns.Size() && PeepHoleOptimizerIterate5(i, pass)) progress = true;
			CheckLive();
			if (i + 3 < mIns.Size() && PeepHoleOptimizerIterate4b(i, pass)) progress = true;
			CheckLive();
			if (i + 4 < mIns.Size() && PeepHoleOptimizerIterate5b(i, pass)) progress = true;
			CheckLive();

			if (mTrueJump)
				mTrueJump->CheckLive();
			if (mFalseJump)
				mFalseJump->CheckLive();

#if 1
			if (pass == 8 && i + 1 < mIns.Size() && (mProc->mCompilerOptions & COPT_OPTIMIZE_BASIC))
			{
				if (
					mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y) &&
					!(mIns[i + 0].mFlags & NCIF_VOLATILE) &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE && mIns[i + 1].mLinkerObject && 
					mIns[i + 1].mLinkerObject->mVariable && (mIns[i + 1].mLinkerObject->mFlags & LOBJF_LOCAL_VAR))
				{
					mProc->ResetPatched();
					if (CheckSingleUseGlobalLoadStruct(this, mIns[i + 1], i + 2, mIns[i + 0], false, false))
					{
						mProc->ResetPatched();
						if (PatchSingleUseGlobalLoadStruct(this, mIns[i + 1], i + 2, mIns[i + 0]))
						{
							mIns[i + 1].mType = ASMIT_NOP;
							mIns[i + 1].mMode = ASMIM_IMPLIED;
							changed = true;
						}
					}
				}
			}
#endif
#if 1
			if (pass < 10 && i + 1 < mIns.Size())
			{
				if (
					mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_INDIRECT_Y) &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					int	n = 3;
					if (mIns[i + 0].mLinkerObject && (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
						n = 100;
					if (mIns[i + 0].mFlags & NCIF_VOLATILE)
						n = 1;
					if (mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
						n--;

					if (n > 0 && (mIns[i + 0].mMode != ASMIM_INDIRECT_Y || (mIns[i + 1].mAddress != mIns[i + 0].mAddress && mIns[i + 1].mAddress != mIns[i + 0].mAddress + 1 && pass > 1)))
					{
						mProc->ResetPatched();
						if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n))
						{
							mProc->ResetPatched();
							if (PatchSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i]))
							{
								if (mIns[i + 0].mMode == ASMIM_ABSOLUTE_X)
								{
									mIns[i + 0].mLive |= LIVE_CPU_REG_X;
									mIns[i + 1].mLive |= LIVE_CPU_REG_X;
								}
								else if (mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_INDIRECT_Y)
								{
									mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
									mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
								}

								if (mIns[i + 0].mFlags & NCIF_VOLATILE)
								{
									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;
							}
							CheckLive();
							if (mTrueJump)
								mTrueJump->CheckLive();
							if (mFalseJump)
								mFalseJump->CheckLive();
						}
					}
				}
				else if (
					mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_ABSOLUTE &&
					mIns[i + 1].mType == ASMIT_STX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
				{
					int	n = 3;
					if (mIns[i + 0].mLinkerObject && (mIns[i + 0].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
						n = 100;
					if (mIns[i + 0].mFlags & NCIF_VOLATILE)
						n = 1;
					if (mIns[i + 1].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))
						n--;

					if (n > 0)
					{
						mProc->ResetPatched();
						if (CheckSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i], n))
						{
							mProc->ResetPatched();
							if (PatchSingleUseGlobalLoad(this, mIns[i + 1].mAddress, i + 2, mIns[i]))
								progress = true;
							CheckLive();
							if (mTrueJump)
								mTrueJump->CheckLive();
							if (mFalseJump)
								mFalseJump->CheckLive();
						}
					}
				}
				else if (
					mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE && !(mIns[i + 1].mFlags & NCIF_VOLATILE))
				{
					int	n = 2;
					if (mIns[i + 1].mLinkerObject && (mIns[i + 1].mLinkerObject->mFlags & LOBJF_ZEROPAGE))
						n = 100;

					mProc->ResetPatched();
					if (CheckSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1], n))
					{
						mProc->ResetPatched();
						if (PatchSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1]))
							progress = true;
						CheckLive();
						if (mTrueJump)
							mTrueJump->CheckLive();
						if (mFalseJump)
							mFalseJump->CheckLive();
					}
				}
			}
#endif
			CheckLive();
			if (mTrueJump)
				mTrueJump->CheckLive();
			if (mFalseJump)
				mFalseJump->CheckLive();

#if 1
			if (i + 5 < mIns.Size() && PeepHoleOptimizerIterate6(i, pass)) progress = true;
			CheckLive();
#endif

#if 1
			if (i + 3 < mIns.Size() && pass == 0 &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
				mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 &&
				!(mIns[i + 3].mLive & LIVE_CPU_REG_A))
			{
				mProc->ResetPatched();
				if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, 0, i + 4, -1))
				{
					mProc->ResetPatched();
					if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress, 0, i + 4, -1, nullptr, 256 * mIns[i + 2].mAddress + mIns[i + 0].mAddress))
						progress = true;
				}
			}
			CheckLive();
#endif

#if 1
			if (i + 2 < mIns.Size() && pass == 0 &&
					mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
					mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 &&
					!(mIns[i + 2].mLive & LIVE_CPU_REG_A))
			{
				mProc->ResetPatched();
				if (CheckGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1))
				{
					mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
					mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;

					mProc->ResetPatched();
					if (PatchGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1, nullptr, 256 * mIns[i + 1].mAddress))
						progress = true;
				}
			}
			CheckLive();
#endif
#if 1
			if (i + 1 < mIns.Size() &&
				mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 0].mFlags & NCIF_UPPER) &&
				mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
			{
				mProc->ResetPatched();
				if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1))
				{
					mProc->ResetPatched();
					if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress, NCIF_UPPER))
						progress = true;
				}
			}
			CheckLive();
#endif

			if (PeepHoleOptimizerIterateN(i, pass)) progress = true;

			CheckLive();
#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 (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, yoffset;
				if (FindAbsoluteAddressSumY(i, mIns[i + 1].mAddress, apos, yoffset))
				{
					if (PatchAbsoluteAddressSumY(i, mIns[i + 1].mAddress, apos))
					{
						mIns[i + 0].mAddress = yoffset;
						progress = true;
					}
				}
			}
#endif

			
#if 1
			if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO))
			{
				int	apos, breg;
				if (FindDirectAddressSumY(i, mIns[i].mAddress, apos, breg))
				{
					if (PatchDirectAddressSumY(i, mIns[i].mAddress, apos, breg))
						progress = true;
				}
			}
#endif

#endif


#if 0
			if (i + 13 < mIns.Size())
			{
				if (mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1)
				{
					printf("CHECK\n");
				}

				if (mIns[i + 0].mType == ASMIT_CLC &&
					mIns[i + 1].mType == ASMIT_LDA &&
					mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 &&
					mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
					mIns[i + 4].mType == ASMIT_LDA &&
					mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 &&
					mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE &&

					mIns[i + 7].mType == ASMIT_CLC &&
					mIns[i + 8].mType == ASMIT_LDA && mIns[i + 8].mMode == ASMIM_ZERO_PAGE && mIns[i + 8].mAddress == mIns[i + 3].mAddress && !(mIns[i + 8].mLive & LIVE_MEM) &&
					mIns[i + 9].mType == ASMIT_ADC &&
					mIns[i + 10].mType == ASMIT_STA &&
					mIns[i + 11].mType == ASMIT_LDA && mIns[i + 11].mMode == ASMIM_ZERO_PAGE && mIns[i + 11].mAddress == mIns[i + 6].mAddress && !(mIns[i + 11].mLive & LIVE_MEM) &&
					mIns[i + 12].mType == ASMIT_ADC &&
					mIns[i + 12].mType == ASMIT_STA)
				{
					mIns[i + 7].CopyMode(mIns[i + 0]);
					mIns[i + 11].CopyMode(mIns[i + 4]);
					mIns[i + 8].mType = ASMIT_SEC;

					for (int j = 0; j < 7; j++)
					{
						mIns[i + j].mType = ASMIT_NOP;
						mIns[i + j].mMode = ASMIM_IMPLIED;
						mIns[i + j + 7].mLive |= mIns[i + 0].mLive;
					}

					progress = true;
				}

			}
#endif


#if 1
			if (i + 7 < mIns.Size() && pass > 0 &&
				mIns[i + 0].mType == ASMIT_CLC &&
				mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 2].mAddress &&
				mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_ZERO_PAGE &&
				mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 &&
				mIns[i + 6].mType == ASMIT_LDY && mIns[i + 6].mMode == ASMIM_IMMEDIATE && mIns[i + 6].mAddress == 0 &&
				mIns[i + 7].mMode == ASMIM_INDIRECT_Y && mIns[i + 7].mAddress == mIns[i + 2].mAddress &&
				!(mIns[i + 7].mLive & LIVE_MEM))
			{
				if (mIns[i + 7].mLive & LIVE_CPU_REG_Y)
					mIns.Insert(i + 8, mIns[i + 6]);

				mIns[i + 1] = NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_TAY); mIns[i + 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_C;
				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 | LIVE_CPU_REG_C;
				mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
				mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
				mIns[i + 4].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 5].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 6].mLive |= LIVE_CPU_REG_Y;
				mIns[i + 7].mType = ASMIT_NOP; mIns[i + 7].mMode = ASMIM_IMPLIED;
				progress = true;
			}
#endif
			CheckLive();

#if 1
			if (pass > 1 && mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[i].mLinkerObject && (mIns[i].mFlags & NCIF_LOWER) && !(mIns[i].mAddress & 0xff) && !(mIns[i].mLinkerObject->mAlignment & 0xff))
			{
				mIns[i].mMode = ASMIM_IMMEDIATE;
				mIns[i].mAddress = 0;
				mIns[i].mLinkerObject = nullptr;
				mIns[i].mFlags &= ~NCIF_LOWER;
				progress = true;
			}
#endif
			CheckLive();
			if (mTrueJump)
				mTrueJump->CheckLive();
			if (mFalseJump)
				mFalseJump->CheckLive();

		}

		if (progress)
			changed = true;

	} while (progress);

	CheckLive();
	if (mTrueJump)
		mTrueJump->CheckLive();
	if (mFalseJump)
		mFalseJump->CheckLive();

	return changed;
}

bool NativeCodeBasicBlock::PeepHoleOptimizerExits(int pass)
{
	bool	changed = false;

#if 1
	int	sz = mIns.Size();

	if (sz >= 1 && (mIns[sz - 1].mType == ASMIT_SEC || mIns[sz - 1].mType == ASMIT_CLC) && mExitRequiredRegs[CPU_REG_C])
	{
		if (mTrueJump && mTrueJump->mIns.Size() == 1 && mTrueJump->mNumEntries == 1 && mTrueJump->mIns[0].mType == mIns[sz - 1].mType)
		{
			mTrueJump->mIns[0].mType = ASMIT_NOP;
			mTrueJump->mEntryRequiredRegs += CPU_REG_C;
			changed = true;
		}
		if (mFalseJump && mFalseJump->mIns.Size() == 1 && mFalseJump->mNumEntries == 1 && mFalseJump->mIns[0].mType == mIns[sz - 1].mType)
		{
			mFalseJump->mIns[0].mType = ASMIT_NOP;
			mFalseJump->mEntryRequiredRegs += CPU_REG_C;
			changed = true;
		}
	}

	if (sz >= 1 && mIns[sz - 1].mType == ASMIT_SEC)
	{
		if (mTrueJump && mTrueJump->mIns.Size() == 0)
		{
			if (mTrueJump->mBranch == ASMIT_BCC)
			{
				mTrueJump->RemEntryBlock(this);
				if (mTrueJump->mFalseJump == mFalseJump)
				{
					mTrueJump = mFalseJump;
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mTrueJump->mFalseJump->AddEntryBlock(this);
					mTrueJump = mTrueJump->mFalseJump;
				}
				changed = true;
			}
			else if (mTrueJump->mBranch == ASMIT_BCS)
			{
				mTrueJump->RemEntryBlock(this);
				if (mTrueJump->mTrueJump == mFalseJump)
				{
					mTrueJump = mFalseJump;
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mTrueJump->mTrueJump->AddEntryBlock(this);
					mTrueJump = mTrueJump->mTrueJump;
				}
				changed = true;
			}
		}
		if (mFalseJump && mFalseJump->mIns.Size() == 0)
		{
			if (mFalseJump->mBranch == ASMIT_BCC)
			{
				mFalseJump->RemEntryBlock(this);
				if (mFalseJump->mFalseJump == mTrueJump)
				{
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mFalseJump->mFalseJump->AddEntryBlock(this);
					mFalseJump = mFalseJump->mFalseJump;
				}
				changed = true;
			}
			else if (mTrueJump->mBranch == ASMIT_BCS)
			{
				mFalseJump->RemEntryBlock(this);
				if (mFalseJump->mTrueJump == mTrueJump)
				{
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mFalseJump->mTrueJump->AddEntryBlock(this);
					mFalseJump = mFalseJump->mTrueJump;
				}
				changed = true;
			}
		}
	}
	if (sz >= 1 && mIns[sz - 1].mType == ASMIT_CLC)
	{
		if (mTrueJump && mTrueJump->mIns.Size() == 0)
		{
			if (mTrueJump->mBranch == ASMIT_BCS)
			{
				mTrueJump->RemEntryBlock(this);
				if (mTrueJump->mFalseJump == mFalseJump)
				{
					mTrueJump = mFalseJump;
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mTrueJump->mFalseJump->AddEntryBlock(this);
					mTrueJump = mTrueJump->mFalseJump;
				}
				changed = true;
			}
			else if (mTrueJump->mBranch == ASMIT_BCC)
			{
				mTrueJump->RemEntryBlock(this);
				if (mTrueJump->mTrueJump == mFalseJump)
				{
					mTrueJump = mFalseJump;
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mTrueJump->mTrueJump->AddEntryBlock(this);
					mTrueJump = mTrueJump->mTrueJump;
				}
				changed = true;
			}
		}
		if (mFalseJump && mFalseJump->mIns.Size() == 0)
		{
			if (mFalseJump->mBranch == ASMIT_BCS)
			{
				mFalseJump->RemEntryBlock(this);
				if (mFalseJump->mFalseJump == mTrueJump)
				{
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mFalseJump->mFalseJump->AddEntryBlock(this);
					mFalseJump = mFalseJump->mFalseJump;
				}
				changed = true;
			}
			else if (mTrueJump->mBranch == ASMIT_BCC)
			{
				mFalseJump->RemEntryBlock(this);
				if (mFalseJump->mTrueJump == mTrueJump)
				{
					mFalseJump = nullptr;
					mBranch = ASMIT_JMP;
				}
				else
				{
					mFalseJump->mTrueJump->AddEntryBlock(this);
					mFalseJump = mFalseJump->mTrueJump;
				}
				changed = true;
			}
		}
	}

	if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
		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)))
	{
		if (mBranch == ASMIT_BNE)
		{
			mBranch = ASMIT_BCS;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mBranch = ASMIT_BCC;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
			changed = true;
		}
	}

	if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
		mIns[sz - 1].mType == ASMIT_CMP)
	{
		if (mBranch == ASMIT_BNE)
		{
			if (mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
			{
				mTrueJump = mTrueJump->mTrueJump;
				changed = true;
			}
			else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCS)
			{
				mTrueJump = mTrueJump->mFalseJump;
				changed = true;
			}
		}
		else if (mBranch == ASMIT_BEQ)
		{
			if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BCS)
			{
				mFalseJump = mFalseJump->mTrueJump;
				changed = true;
			}
			else if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BCC)
			{
				mFalseJump = mFalseJump->mFalseJump;
				changed = true;
			}
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].ChangesAccuAndFlag() &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 &&
		(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC)
			mBranch = ASMIT_BEQ;
		else
			mBranch = ASMIT_BNE;

		mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
		mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
		changed = true;
	}
	else if (sz >= 2 &&
		(mIns[sz - 2].ChangesAccuAndFlag() || mIns[sz - 2].mType == ASMIT_TAX || mIns[sz - 2].mType == ASMIT_TAY) &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 &&
		(mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC)
			mBranch = ASMIT_BPL;
		else
			mBranch = ASMIT_BMI;

		mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
		mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
		changed = true;
	}
	else if (pass != 28 && sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode != ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && 
		!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z])
	{
		int v = mIns[sz - 2].mAddress;
		if (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ)
		{
			mIns[sz - 2].CopyMode(mIns[sz - 1]);
			mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = v;
			changed = true;
		}
		else if (mBranch == ASMIT_BCC)
		{
			if (v < 255)
			{
				mIns[sz - 2].CopyMode(mIns[sz - 1]);
				mBranch = ASMIT_BCS;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = v + 1;
				changed = true;
			}
		}
		else if (mBranch == ASMIT_BCS)
		{
			if (v < 255)
			{
				mIns[sz - 2].CopyMode(mIns[sz - 1]);
				mBranch = ASMIT_BCC;
				mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = v + 1;
				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 >= 3 &&
		mIns[sz - 3].ChangesAccuAndFlag() &&
		mIns[sz - 2].mType == ASMIT_STA &&
		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 - 2].mLive |= LIVE_CPU_REG_Z;
			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 - 2].mLive |= LIVE_CPU_REG_Z;
			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].mType == ASMIT_ROR) && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 2);
			sz -= 2;
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 2);
			sz -= 2;
			changed = true;
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
		(mIns[sz - 1].mType == ASMIT_ROL || mIns[sz - 1].mType == ASMIT_ROR) && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C) && !mExitRequiredRegs[CPU_REG_Z] &&
		mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
	{
		mBranch = ASMIT_BCS;
		mIns.SetSize(sz - 1);
		sz -= 1;
		changed = true;
	}
	else if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
		(mIns[sz - 1].mType == ASMIT_ROL || mIns[sz - 1].mType == ASMIT_ROR) && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C) && !mExitRequiredRegs[CPU_REG_Z] &&
		mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
	{
		mBranch = ASMIT_BCC;
		mIns.SetSize(sz - 1);
		sz -= 1;
		changed = true;
	}
	else if (sz >= 3 &&
		mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
		mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x0 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 3);
			sz -= 3;
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 3);
			sz -= 3;
			changed = true;
		}
	}
	else if (sz >= 3 &&
		mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 &&
		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 | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 3);
			sz -= 3;
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 3);
			sz -= 3;
			changed = true;
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_EOR && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
		{
			NativeCodeBasicBlock* tblock = mProc->AllocateBlock();

			tblock->mTrueJump = mTrueJump->mTrueJump;
			tblock->mFalseJump = mTrueJump->mFalseJump;
			tblock->mBranch = ASMIT_BMI;
			tblock->mTrueJump->mNumEntries++;
			tblock->mTrueJump->mEntryBlocks.Push(tblock);
			tblock->mFalseJump->mNumEntries++;
			tblock->mFalseJump->mEntryBlocks.Push(tblock);

			mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
			mTrueJump->mNumEntries--;
			mTrueJump = tblock;
			tblock->mNumEntries++;
			tblock->mEntryBlocks.Push(this);

			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;

			mExitRequiredRegs -= CPU_REG_C;

			CheckLive();
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].ChangesAccuAndFlag() &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC)
		{
			mBranch = ASMIT_BPL;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCS)
		{
			mBranch = ASMIT_BMI;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_CMP && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C] &&
		(mIns[sz - 1].mType == ASMIT_TAX || mIns[sz - 1].mType == ASMIT_TAY))
	{
		if (mBranch == ASMIT_BCC)
		{
			mBranch = ASMIT_BPL;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCS)
		{
			mBranch = ASMIT_BMI;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;

			CheckLive();
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].ChangesXReg() &&
		mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC)
		{
			mBranch = ASMIT_BPL;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCS)
		{
			mBranch = ASMIT_BMI;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
	}
	else if (sz >= 2 &&
		mIns[sz - 2].ChangesYReg() &&
		mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC)
		{
			mBranch = ASMIT_BPL;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCS)
		{
			mBranch = ASMIT_BMI;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			CheckLive();
		}
	}

	else if (sz >= 4 &&
		mIns[sz - 4].mType == ASMIT_EOR && mIns[sz - 4].mMode == ASMIM_IMMEDIATE && mIns[sz - 4].mAddress == 0x80 &&
		mIns[sz - 3].mType == ASMIT_STA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x80 &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mIns[sz - 1].mAddress == mIns[sz - 3].mAddress && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
		{
			NativeCodeBasicBlock* tblock = mProc->AllocateBlock();

			tblock->mTrueJump = mTrueJump->mFalseJump;
			tblock->mFalseJump = mTrueJump->mTrueJump;
			tblock->mBranch = ASMIT_BMI;
			tblock->mTrueJump->mNumEntries++;
			tblock->mTrueJump->mEntryBlocks.Push(tblock);
			tblock->mFalseJump->mNumEntries++;
			tblock->mFalseJump->mEntryBlocks.Push(tblock);

			mTrueJump->mEntryBlocks.Remove(mTrueJump->mEntryBlocks.IndexOf(this));
			mTrueJump->mNumEntries--;
			mTrueJump = tblock;
			tblock->mNumEntries++;
			tblock->mEntryBlocks.Push(this);

			mIns[sz - 4].mType = ASMIT_NOP; mIns[sz - 4].mMode = ASMIM_IMPLIED;
			mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mMode = ASMIM_IMMEDIATE;  mIns[sz - 1].mAddress = 0; 
			
			mIns[sz - 1].mLive &= ~LIVE_CPU_REG_C;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			mExitRequiredRegs -= CPU_REG_C;

			CheckLive();
		}
	}

	else if (sz >= 4 &&
		mIns[sz - 4].mType == ASMIT_TXA &&
		mIns[sz - 3].mType == ASMIT_CLC &&
		mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
		mIns[sz - 1].mType == ASMIT_TAX && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		{
			mIns[sz - 4].mType = ASMIT_DEX; mIns[sz - 4].mLive |= LIVE_CPU_REG_X;
			mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
			mIns[sz - 2].mType = ASMIT_CPX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			if (mBranch == ASMIT_BCC)
				mBranch = ASMIT_BEQ;
			else
				mBranch = ASMIT_BNE;

			CheckLive();
		}
	}

	else if (sz >= 3 &&
		mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0x00 &&
		mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x01 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		{
			mIns.SetSize(sz - 3);
			sz -= 3;
			changed = true;
		}
	}
#if 1
	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_ROL && mIns[sz - 3].mMode == ASMIM_IMPLIED &&
		mIns[sz - 2].mType == ASMIT_AND && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0x01 &&
		mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x00 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mBranch == ASMIT_BEQ)
		{
			mIns.Remove(sz - 4);
			mBranch = ASMIT_BNE;
			changed = true;
		}
		else if (mBranch == ASMIT_BNE)
		{
			mIns.Remove(sz - 4);
			mBranch = ASMIT_BEQ;
			changed = true;
		}
	}
#endif
	else if (sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 &&
		mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 2);
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 2);
			changed = true;
		}

		sz -= 2;
		CheckLive();
	}
	else if (pass >= 7 && sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 2].mLive & LIVE_MEM) &&
		mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 1);
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 1);
			changed = true;
		}

		sz -= 1;
		CheckLive();
	}
	else if (pass >= 7 && sz >= 2 &&
		mIns[sz - 2].mType == ASMIT_AND && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
		mIns[sz - 1].mType == ASMIT_EOR && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && 
		!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BNE)
		{
			mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mMode = ASMIM_IMPLIED; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mBranch = ASMIT_BCC;
			mIns.SetSize(sz - 1);
			changed = true;
		}
		else if (mBranch == ASMIT_BEQ)
		{
			mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mMode = ASMIM_IMPLIED; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mBranch = ASMIT_BCS;
			mIns.SetSize(sz - 1);
			changed = true;
		}

		sz -= 1;
		CheckLive();
	}
	
	sz = mIns.Size();
	if (sz >= 4 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
		mIns[sz - 4].mType == ASMIT_LDA && !(mIns[sz - 4].ReferencesXReg()) &&
		mIns[sz - 3].mType == ASMIT_STA && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 2].mType == ASMIT_ASL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
		mIns[sz - 1].mType == ASMIT_LDX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE &&
		!(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[CPU_REG_C])
	{
		mIns[sz - 2] = mIns[sz - 3]; mIns[sz - 2].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[sz - 3] = mIns[sz - 4]; mIns[sz - 3].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
		mIns[sz - 4] = mIns[sz - 1];
		mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
		mIns[sz - 3].RequiresYReg(); mIns[sz - 4].mLive |= LIVE_CPU_REG_Y;

		if (mBranch == ASMIT_BCC)
			mBranch = ASMIT_BPL;
		else
			mBranch = ASMIT_BMI;

		CheckLive();
	}
#if 1
	sz = mIns.Size();
	if (sz >= 2 && mIns[sz - 1].mType == ASMIT_CPX && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
	{
		int k = sz - 2;
		while (k >= 0 && !(mIns[k].ChangesZFlag() || mIns[k].ChangesXReg()))
			k--;
		if (k >= 0 && (mIns[k].mType == ASMIT_LDX || mIns[k].mType == ASMIT_INX || mIns[k].mType == ASMIT_DEX || mIns[k].mType == ASMIT_TAX))
		{
			while (k < sz)
				mIns[k++].mLive |= LIVE_CPU_REG_Z;
			mIns.Remove(sz - 1);
			changed = true;
		}
	}
	else if (sz >= 2 && mIns[sz - 1].mType == ASMIT_CPY && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
	{
		int k = sz - 2;
		while (k >= 0 && !(mIns[k].ChangesZFlag() || mIns[k].ChangesYReg()))
			k--;
		if (k >= 0 && (mIns[k].mType == ASMIT_LDY || mIns[k].mType == ASMIT_INY || mIns[k].mType == ASMIT_DEY || mIns[k].mType == ASMIT_TAY))
		{
			while (k < sz)
				mIns[k++].mLive |= LIVE_CPU_REG_Z;
			mIns.Remove(sz - 1);
			changed = true;
		}
	}
#endif
	sz = mIns.Size();
	if (sz >= 1 &&
		mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
		(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE))
	{
		mIns[sz - 1].mType = ASMIT_ORA; mIns[sz - 1].mAddress = 0x00; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;

		if (mBranch == ASMIT_BEQ)
			mBranch = ASMIT_BPL;
		else
			mBranch = ASMIT_BMI;

		changed = true;
	}
	else if (pass >= 7 && sz >= 1 &&
		mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x01 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
		(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
	{
		mIns[sz - 1].mType = ASMIT_LSR; mIns[sz - 1].mLive |= LIVE_CPU_REG_C; mIns[sz - 1].mMode = ASMIM_IMPLIED;

		if (mBranch == ASMIT_BEQ)
			mBranch = ASMIT_BCC;
		else
			mBranch = ASMIT_BCS;

		changed = true;
	}
#if 1
	else if (pass >= 7 && sz >= 1 &&
		mIns[sz - 1].mType == ASMIT_LDA && (mIns[sz - 1].mMode == ASMIM_ABSOLUTE || mIns[sz - 1].mMode == ASMIM_ZERO_PAGE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
		(mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) && !mExitRequiredRegs[CPU_REG_Z])
	{
		mIns[sz - 1].mType = ASMIT_BIT;

		changed = true;
	}
#endif
	else if (pass >= 7 && sz >= 1 &&
		mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x40 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
		(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
	{
		mIns[sz - 1].mType = ASMIT_ASL; mIns[sz - 1].mMode = ASMIM_IMPLIED;

		if (mBranch == ASMIT_BEQ)
			mBranch = ASMIT_BPL;
		else
			mBranch = ASMIT_BMI;

		changed = true;
	}

	if (sz == 1 && mBranch == ASMIT_BNE && mTrueJump == this)
	{
		if (mIns[0].mType == ASMIT_DEX || mIns[0].mType == ASMIT_INX)
		{
			mIns[0] = NativeCodeInstruction(mIns[0].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, 0);
			changed = true;
		}
		else if (mIns[0].mType == ASMIT_DEY || mIns[0].mType == ASMIT_INY)
		{
			mIns[0] = NativeCodeInstruction(mIns[0].mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0);
			changed = true;
		}
	}

#endif
#endif

#if 1
	if (sz >= 4 && (mBranch == ASMIT_BMI || mBranch == ASMIT_BPL) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mIns[sz - 4].mType == ASMIT_LDA &&
			(mIns[sz - 3].mType == ASMIT_ASL || mIns[sz - 3].mType == ASMIT_ROL) && mIns[sz - 3].mMode == ASMIM_IMPLIED &&
			mIns[sz - 2].mType == ASMIT_STA && !mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
			mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 4]))
		{
			if (mBranch == ASMIT_BMI)
				mBranch = ASMIT_BCS;
			else
				mBranch = ASMIT_BCC;
			mIns[sz - 3].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
			changed = true;
		}
	}

	if (sz >= 4 && (mBranch == ASMIT_BMI || mBranch == ASMIT_BPL) && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mIns[sz - 4].mType == ASMIT_STA &&
			(mIns[sz - 3].mType == ASMIT_ASL || mIns[sz - 3].mType == ASMIT_ROL) && mIns[sz - 3].mMode == ASMIM_IMPLIED &&
			mIns[sz - 2].mType == ASMIT_STA && !mIns[sz - 2].SameEffectiveAddress(mIns[sz - 4]) &&
			mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].SameEffectiveAddress(mIns[sz - 4]))
		{
			if (mBranch == ASMIT_BMI)
				mBranch = ASMIT_BCS;
			else
				mBranch = ASMIT_BCC;
			mIns[sz - 3].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
			changed = true;
		}
	}

#endif
#if 1
	if (sz >= 3 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_A])
	{
		if (mIns[sz - 3].mType == ASMIT_LDA && mIns[sz - 3].mMode == ASMIM_IMMEDIATE && mIns[sz - 3].mAddress == 0 &&
			mIns[sz - 2].mType == ASMIT_ROL && mIns[sz - 2].mMode == ASMIM_IMPLIED &&
			mIns[sz - 1].mType == ASMIT_EOR && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1)
		{
			if (mBranch == ASMIT_BEQ)
				mBranch = ASMIT_BCS;
			else
				mBranch = ASMIT_BCC;

			mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
			changed = true;
		}
	}

#endif

	if (sz >= 1 && mIns[sz - 1].mType == ASMIT_TXA && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[sz - 1].mType = ASMIT_CPX;
		mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
		mIns[sz - 1].mAddress = 0;
		changed = true;
	}
	if (sz >= 1 && mIns[sz - 1].mType == ASMIT_TYA && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
	{
		mIns[sz - 1].mType = ASMIT_CPY;
		mIns[sz - 1].mMode = ASMIM_IMMEDIATE;
		mIns[sz - 1].mAddress = 0;
		changed = true;
	}

	if (sz >= 4 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mIns[sz - 4].mType == ASMIT_TYA &&
			mIns[sz - 3].mType == ASMIT_CLC &&
			mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
			mIns[sz - 1].mType == ASMIT_TAY)
		{
			if (mBranch == ASMIT_BCC)
				mBranch = ASMIT_BNE;
			else
				mBranch = ASMIT_BEQ;
			mIns[sz - 4].mType = ASMIT_INY; mIns[sz - 4].mLive |= LIVE_CPU_REG_Y;
			mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_TYA; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			changed = true;
		}
		else if (mIns[sz - 4].mType == ASMIT_TXA &&
			mIns[sz - 3].mType == ASMIT_CLC &&
			mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 &&
			mIns[sz - 1].mType == ASMIT_TAX)
		{
			if (mBranch == ASMIT_BCC)
				mBranch = ASMIT_BNE;
			else
				mBranch = ASMIT_BEQ;
			mIns[sz - 4].mType = ASMIT_INX; mIns[sz - 4].mLive |= LIVE_CPU_REG_X;
			mIns[sz - 3].mType = ASMIT_NOP; mIns[sz - 3].mMode = ASMIM_IMPLIED;
			mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
			mIns[sz - 1].mType = ASMIT_TXA; mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			changed = true;
		}
	}

#if 1
	if (sz >= 3 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) &&
		mIns[sz - 1].mType == ASMIT_INY && mIns[sz - 2].mType == ASMIT_CPX && mIns[sz - 3].mType == ASMIT_INX &&
		!(mIns[sz - 1].mLive & LIVE_CPU_REG_Z))
	{
		mIns[sz - 1] = mIns[sz - 2];
		mIns[sz - 2] = mIns[sz - 3];
		mIns[sz - 3].mType = ASMIT_INY;
		changed = true;
	}
#endif
#if 1
	if (sz >= 3 && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C])
	{
		if (mIns[sz - 3].mType == ASMIT_LDA && !(mIns[sz - 3].ReferencesXReg()) &&
			mIns[sz - 2].mType == ASMIT_ASL && mIns[sz - 2].mMode == ASMIM_IMPLIED && !(mIns[sz - 2].mLive & LIVE_CPU_REG_A) &&
			mIns[sz - 1].mType == ASMIT_LDX)
		{
			mIns[sz - 2] = mIns[sz - 3];
			mIns[sz - 3] = mIns[sz - 1];
			mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;

			mIns[sz - 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X;
			if (mIns[sz - 2].ReferencesYReg()) mIns[sz - 3].mLive |= LIVE_CPU_REG_Y;
			if (mBranch == ASMIT_BCC)
				mBranch = ASMIT_BPL;
			else
				mBranch = ASMIT_BMI;
			changed = true;
		}
	}
#endif

#if 1
	if (pass == 28 && sz >= 2 && mFalseJump &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode != ASMIM_IMMEDIATE && mIns[sz - 2].mMode != ASMIM_ZERO_PAGE &&
		mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
		!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z])
	{
		int v = mIns[sz - 1].mAddress;
		if ((mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
		{
			mIns[sz - 1].CopyMode(mIns[sz - 2]); mIns[sz - 2].mLive |= mIns[sz - 1].NeedsLive();
			mIns[sz - 2].mMode = ASMIM_IMMEDIATE;
			mIns[sz - 2].mAddress = v;
			changed = true;
		}
		else if (mBranch == ASMIT_BCC && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z) && v > 0)
		{
			mBranch = ASMIT_BCS;
			mIns[sz - 1].CopyMode(mIns[sz - 2]); mIns[sz - 2].mLive |= mIns[sz - 1].NeedsLive();
			mIns[sz - 2].mMode = ASMIM_IMMEDIATE;
			mIns[sz - 2].mAddress = v - 1;
			changed = true;
		}
		else if (mBranch == ASMIT_BCS && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z) && v > 0)
		{
			mBranch = ASMIT_BCC;
			mIns[sz - 1].CopyMode(mIns[sz - 2]); mIns[sz - 2].mLive |= mIns[sz - 1].NeedsLive();
			mIns[sz - 2].mMode = ASMIM_IMMEDIATE;
			mIns[sz - 2].mAddress = v - 1;
			changed = true;
		}
	}
#endif

#if 1
	if (sz > 1 && mFalseJump &&
		mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0xff &&
		mIns[sz - 1].mType == ASMIT_CMP &&
		!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BCC)
		{
			mTrueJump->RemEntryBlock(this);
			mTrueJump = mFalseJump;
			mFalseJump = nullptr;
			mBranch = ASMIT_JMP;
			changed = true;
		}
		else if (mBranch == ASMIT_BCS)
		{
			mFalseJump->RemEntryBlock(this);
			mFalseJump = nullptr;
			mBranch = ASMIT_JMP;
			changed = true;
		}
	}
#endif

	if (sz > 0 && mFalseJump && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY) &&
		mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z) &&
		!mExitRequiredRegs[CPU_REG_C] && !mExitRequiredRegs[CPU_REG_Z])
	{
		if (mBranch == ASMIT_BCC)
		{
			mIns[sz - 1].mAddress = 0;
			mBranch = ASMIT_BEQ;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			changed = true;
		}
		else if (mBranch == ASMIT_BCS)
		{
			mIns[sz - 1].mAddress = 0;
			mBranch = ASMIT_BNE;
			mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			changed = true;
		}
	}
#if 1
	if (sz > 0 && mFalseJump && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE)
	{
		if (mBranch == ASMIT_BCC)
		{
			if (mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_CMP && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE)
			{
				if (mTrueJump->mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
					!mTrueJump->mExitRequiredRegs[CPU_REG_Z] && !mTrueJump->mExitRequiredRegs[CPU_REG_C])
				{
					mTrueJump->RemEntryBlock(this);
					mTrueJump = mTrueJump->mTrueJump;
					mTrueJump->AddEntryBlock(this);
					changed = true;
				}
				else if (mTrueJump->mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
					!mTrueJump->mExitRequiredRegs[CPU_REG_Z] && !mTrueJump->mExitRequiredRegs[CPU_REG_C])
				{
					mTrueJump->RemEntryBlock(this);
					mTrueJump = mTrueJump->mFalseJump;
					mTrueJump->AddEntryBlock(this);
					changed = true;
				}
			}
		}
		else if (mBranch == ASMIT_BCS)
		{
			if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_CMP && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
			{
				if (mFalseJump->mBranch == ASMIT_BCC && mFalseJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
					!mFalseJump->mExitRequiredRegs[CPU_REG_Z] && !mFalseJump->mExitRequiredRegs[CPU_REG_C])
				{
					mFalseJump->RemEntryBlock(this);
					mFalseJump = mFalseJump->mTrueJump;
					mFalseJump->AddEntryBlock(this);
					changed = true;
				}
				else if (mFalseJump->mBranch == ASMIT_BCS && mFalseJump->mIns[0].mAddress >= mIns[sz - 1].mAddress &&
					!mFalseJump->mExitRequiredRegs[CPU_REG_Z] && !mFalseJump->mExitRequiredRegs[CPU_REG_C])
				{
					mFalseJump->RemEntryBlock(this);
					mFalseJump = mFalseJump->mFalseJump;
					mFalseJump->AddEntryBlock(this);
					changed = true;
				}
			}
		}
	}
#endif

#if 1
	if (sz >= 1 && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_Z))
	{
		if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		{
			AsmInsType	ty = ASMIT_INV;
			NativeCodeBasicBlock* nblock = nullptr;
			int tr;

			if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TAY && !(mTrueJump->mIns[0].mLive & LIVE_CPU_REG_A) && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y])
			{
				ty = ASMIT_TAY;
				tr = CPU_REG_Y;
				nblock = mTrueJump;
			}
			else if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TAX && !(mTrueJump->mIns[0].mLive & LIVE_CPU_REG_A) && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X])
			{
				ty = ASMIT_TAX;
				tr = CPU_REG_X;
				nblock = mTrueJump;
			}
			else if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_TAY && !(mFalseJump->mIns[0].mLive & LIVE_CPU_REG_A) && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
			{
				ty = ASMIT_TAY;
				tr = CPU_REG_Y;
				nblock = mFalseJump;
			}
			else if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].mType == ASMIT_TAX && !(mFalseJump->mIns[0].mLive & LIVE_CPU_REG_A) && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X])
			{
				ty = ASMIT_TAX;
				tr = CPU_REG_X;
				nblock = mFalseJump;
			}

			if (nblock)
			{
				mIns[sz - 1].mType = ty;
				mIns[sz - 1].mMode = ASMIM_IMPLIED;
				if (tr == CPU_REG_Y)
					mIns[sz - 1].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z;
				else
					mIns[sz - 1].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_Z;
				nblock->mIns.Remove(0);
				mExitRequiredRegs += tr;
				nblock->mEntryRequiredRegs += tr;
				if (mBranch == ASMIT_BCC)
					mBranch = ASMIT_BPL;
				else
					mBranch = ASMIT_BMI;
				changed = true;
			}
		}
	}
#endif

#if 1
	if (sz > 0 && mFalseJump && mIns[sz - 1].ChangesAccuAndFlag() && mBranch == ASMIT_BMI)
	{
		if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_CMP && mFalseJump->mBranch == ASMIT_BCS && mFalseJump->mTrueJump == mTrueJump)
		{
			mTrueJump->RemEntryBlock(this);
			mTrueJump = mFalseJump;
			mFalseJump = nullptr;
			mBranch = ASMIT_JMP;
			changed = true;
		}
	}
#endif

	sz = mIns.Size();
	if (sz >= 4 && mFalseJump && (mBranch == ASMIT_BPL || mBranch == ASMIT_BMI))
	{
		if (mIns[sz - 4].mType == ASMIT_TAY &&
			mIns[sz - 3].mType == ASMIT_ASL && mIns[sz - 3].mMode == ASMIM_IMPLIED &&
			mIns[sz - 2].mType == ASMIT_TAX &&
			mIns[sz - 1].mType == ASMIT_TYA && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
		{
			mIns[sz - 3].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
			mIns[sz - 1].mType = ASMIT_NOP;
			if (mBranch == ASMIT_BPL)
				mBranch = ASMIT_BCC;
			else
				mBranch = ASMIT_BCS;
			changed = true;
		}
	}

	sz = mIns.Size();
	if (sz > 1 && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) && mIns[sz - 1].mType == ASMIT_LDA && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A))
	{
		int reg = mIns[sz - 1].mAddress;
		int k = sz - 2;
		while (k >= 0 && !mIns[k].ReferencesZeroPage(reg))
			k--;

		if (k >= 0 && (mIns[k].mType == ASMIT_INC || mIns[k].mType == ASMIT_DEC))
		{
			mIns[sz - 1].mType = mIns[k].mType;
			mIns[k].mType = ASMIT_NOP; mIns[k].mMode = ASMIM_IMPLIED;
			changed = true;
		}
	}

#if 1
	if (pass > 15 && sz > 0 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY))
	{
		if (mTrueJump && mTrueJump->mEntryBlocks.Size() == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].IsSame(mIns[sz - 1]))
		{
			mTrueJump->mIns[0].mType = ASMIT_NOP; mTrueJump->mIns[0].mMode = ASMIM_IMPLIED;
			if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z)
			{
				mExitRequiredRegs += CPU_REG_Z;
				mTrueJump->mEntryRequiredRegs += CPU_REG_Z;
				mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			}
			if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_C)
			{
				mExitRequiredRegs += CPU_REG_C;
				mTrueJump->mEntryRequiredRegs += CPU_REG_C;
				mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
			}
			changed = true;
		}
		if (mFalseJump && mFalseJump->mEntryBlocks.Size() == 1 && mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].IsSame(mIns[sz - 1]))
		{
			mFalseJump->mIns[0].mType = ASMIT_NOP; mFalseJump->mIns[0].mMode = ASMIM_IMPLIED;
			if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_Z)
			{
				mExitRequiredRegs += CPU_REG_Z;
				mFalseJump->mEntryRequiredRegs += CPU_REG_Z;
				mIns[sz - 1].mLive |= LIVE_CPU_REG_Z;
			}
			if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_C)
			{
				mExitRequiredRegs += CPU_REG_C;
				mFalseJump->mEntryRequiredRegs += CPU_REG_C;
				mIns[sz - 1].mLive |= LIVE_CPU_REG_C;
			}
			changed = true;
		}
	}
#endif
	CheckLive();
	if (mTrueJump)
		mTrueJump->CheckLive();
	if (mFalseJump)
		mFalseJump->CheckLive();

	if (sz >= 9 && mFalseJump && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) &&
		mIns[sz - 9].mType == ASMIT_TAY &&
		mIns[sz - 8].mType == ASMIT_CLC &&
		mIns[sz - 7].mType == ASMIT_LDA && mIns[sz - 7].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 6].mType == ASMIT_ADC && mIns[sz - 6].mMode == ASMIM_IMMEDIATE &&
		mIns[sz - 5].mType == ASMIT_STA && mIns[sz - 5].mMode == ASMIM_ZERO_PAGE && mIns[sz - 5].mAddress == mIns[sz - 7].mAddress &&
		mIns[sz - 4].mType == ASMIT_LDA && mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
		mIns[sz - 3].mType == ASMIT_ADC && mIns[sz - 3].mMode == ASMIM_IMMEDIATE &&
		mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == mIns[sz - 4].mAddress &&
		mIns[sz - 1].mType == ASMIT_TYA && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C))
	{
		NativeCodeBasicBlock* ublock = nullptr;
		if (mTrueJump->mEntryBlocks.Size() == 1 && !mFalseJump->mEntryRequiredRegs[mIns[sz - 5].mAddress] && !mFalseJump->mEntryRequiredRegs[mIns[sz - 2].mAddress])
			ublock = mTrueJump;
		else if (mFalseJump->mEntryBlocks.Size() == 1 && !mTrueJump->mEntryRequiredRegs[mIns[sz - 5].mAddress] && !mTrueJump->mEntryRequiredRegs[mIns[sz - 2].mAddress])
			ublock = mFalseJump;

		if (ublock)
		{
			mIns[sz - 9].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_A;
			mExitProvidedRegs += CPU_REG_Y;
			mExitProvidedRegs += CPU_REG_A;
			ublock->mEntryRequiredRegs += CPU_REG_Y;
			for (int i = 0; i < 8; i++)
				ublock->mIns.Insert(i, mIns[sz - 8 + i]);
			mIns.Remove(sz - 8, 8);
			changed = true;
		}
	}


#if 1
	if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump &&
		mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 &&
		mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE &&
		mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE)
	{
		if (mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0 && !(mExitRequiredRegs[CPU_REG_C]))
		{
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
			mExitProvidedRegs += CPU_REG_A;
			mBranch = ASMIT_JMP;
			mTrueJump = mTrueJump->mTrueJump;
			mFalseJump = nullptr;
			changed = true;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1 && !(mExitRequiredRegs[CPU_REG_C]))
		{
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
			mExitProvidedRegs += CPU_REG_A;
			mBranch = ASMIT_JMP;
			mTrueJump = mTrueJump->mTrueJump;
			mFalseJump = nullptr;
			changed = true;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCS && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1 && !(mExitRequiredRegs[CPU_REG_C]))
		{
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, 1));
			mExitProvidedRegs += CPU_REG_A;
			mBranch = ASMIT_JMP;
			mTrueJump = mTrueJump->mTrueJump;
			mFalseJump = nullptr;
			changed = true;

			CheckLive();
		}
		else if (mBranch == ASMIT_BCC && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0 && !(mExitRequiredRegs[CPU_REG_C]))
		{
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
			mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_EOR, ASMIM_IMMEDIATE, 1));
			mExitProvidedRegs += CPU_REG_A;
			mBranch = ASMIT_JMP;
			mTrueJump = mTrueJump->mTrueJump;
			mFalseJump = nullptr;
			changed = true;

			CheckLive();
		}
		else if (mIns.Size() > 0 && mIns.Last().mType == ASMIT_LDA)
		{
			if (mBranch == ASMIT_BEQ && mTrueJump->mIns[0].mAddress == 1 && mFalseJump->mIns[0].mAddress == 0)
			{
				mIns.Insert(mIns.Size() - 1, NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
				mExitProvidedRegs += CPU_REG_A;
				mBranch = ASMIT_JMP;
				mTrueJump = mTrueJump->mTrueJump;
				mFalseJump = nullptr;
				changed = true;

				CheckLive();
			}
			else if (mBranch == ASMIT_BNE && mTrueJump->mIns[0].mAddress == 0 && mFalseJump->mIns[0].mAddress == 1)
			{
				mIns.Insert(mIns.Size() - 1, NativeCodeInstruction(mBranchIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				mIns[mIns.Size() - 1].mType = ASMIT_CMP; mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A;
				mIns.Push(NativeCodeInstruction(mBranchIns, ASMIT_ROL, ASMIM_IMPLIED));
				mExitProvidedRegs += CPU_REG_A;
				mBranch = ASMIT_JMP;
				mTrueJump = mTrueJump->mTrueJump;
				mFalseJump = nullptr;
				changed = true;

				CheckLive();
			}
		}
	}
#endif
	CheckLive();

	if (mTrueJump)
		mTrueJump->CheckLive();
	if (mFalseJump)
		mFalseJump->CheckLive();

	assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

	return changed;
}

bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
{
	if (!mVisited)
	{
		assert(mBranch != ASMIT_JMP || mFalseJump == nullptr);
		assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);

		assert(mIndex == 1000 || mNumEntries == mEntryBlocks.Size());

		bool	changed = RemoveNops();

		mIns.Reserve(mIns.Size() * 2 + 32);

		mVisited = true;

		CheckLive();
		if (mTrueJump)
			mTrueJump->CheckLive();
		if (mFalseJump)
			mFalseJump->CheckLive();

		if (PeepHoleOptimizerShuffle(pass))
			changed = true;
		if (PeepHoleOptimizerIterate(pass))
			changed = true;
		if (PeepHoleOptimizerExits(pass))
			changed = true;

		if (changed)
			RemoveNops();

		if (this->mTrueJump && this->mTrueJump->PeepHoleOptimizer(pass))
			changed = true;
		if (this->mFalseJump && this->mFalseJump->PeepHoleOptimizer(pass))
			changed = true;

		assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV);

		return changed;
	}

	return false;
}

void NativeCodeBasicBlock::AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree * tree)
{
	if (!mVisited)
	{
		mVisited = true;

		if (mSuffixString && mIns.Size() + 50 > mSuffixStringLength)
		{
			delete[] mSuffixString;
			mSuffixString = nullptr;
		}
		if (!mSuffixString)
		{
			mSuffixStringLength = mIns.Size() + 100;
			mSuffixString = new int[mSuffixStringLength];
		}

		bool rel = false;
		for (int i = 0; i < mIns.Size(); i++)
		{
			if (mIns[i].mMode == ASMIM_RELATIVE)
				rel = true;
			mSuffixString[i] = mapper.MapInstruction(mIns[i], mProc->mLinkerObject->mSection);
		}
		mSuffixString[mIns.Size()] = mapper.MapBasicBlock(this);
		mSuffixString[mIns.Size() + 1] = -1;

		if (!rel)
			tree->AddString(mSuffixString);

		if (mTrueJump) mTrueJump->AddToSuffixTree(mapper, tree);
		if (mFalseJump) mFalseJump->AddToSuffixTree(mapper, tree);
	}
}

void NativeCodeBasicBlock::CheckVisited(void)
{
#if _DEBUG
	if (!mPatched)
	{
		mPatched = true;
		assert(mVisited);

		if (mTrueJump)
			mTrueJump->CheckVisited();
		if (mFalseJump)
			mFalseJump->CheckVisited();
	}

#endif
}

void NativeCodeBasicBlock::CheckAsmCode(void)
{
#if _DEBUG
	if (!mVisited)
	{
		mVisited = true;

		for (int j = 0; j < mIns.Size(); j++)
		{
			if (mIns[j].mMode == ASMIM_IMMEDIATE_ADDRESS)
				assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE));
			else
				assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode));
#if CHECK_NULLPTR
			if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ABSOLUTE_Y || mIns[j].mMode == ASMIM_ABSOLUTE_X)
				assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0);
#endif
		}

		if (mTrueJump) mTrueJump->CheckAsmCode();
		if (mFalseJump) mFalseJump->CheckAsmCode();
	}
#endif
}


void NativeCodeBasicBlock::CheckBlocks(bool sequence)
{
#if _DEBUG
	if (!mChecked)
	{
		mChecked = true;

		assert(this != mProc->mEntryBlock || mNumEntries < 2);

		CheckLive();

		if (sequence)
		{
			if (mTrueJump)
				assert(mTrueJump->mEntryBlocks.Contains(this));
			if (mFalseJump)
				assert(mFalseJump->mEntryBlocks.Contains(this));
		}

		if (mTrueJump) mTrueJump->CheckBlocks();
		if (mFalseJump) mFalseJump->CheckBlocks();
	}
#endif
}

void NativeCodeBasicBlock::CheckLive(void)
{
#if _DEBUG
	uint32	live = 0;

	if (mFalseJump && mFalseJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mExitRequiredRegs.Size() > 0)
	{
		if (mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].RequiresXReg())
		{
			assert(mExitRequiredRegs[CPU_REG_X]);
			live |= LIVE_CPU_REG_X;
		}
	}
	if (mTrueJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mExitRequiredRegs.Size() > 0)
	{
		if (mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].RequiresXReg())
		{
			assert(mExitRequiredRegs[CPU_REG_X]);
			live |= LIVE_CPU_REG_X;
		}
	}

	assert(mBranch == ASMIT_RTS || (mBranch == ASMIT_JMP) == (mFalseJump == nullptr));

	if (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS)
		live |= LIVE_CPU_REG_C;
	if (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE || mBranch == ASMIT_BPL || mBranch == ASMIT_BMI)
		live |= LIVE_CPU_REG_Z;

	if (mIns.Size() > 0 && mIns[0].mMode == ASMIM_INDIRECT_Y && mEntryRequiredRegs.Size() > 0)
	{
		assert(mEntryRequiredRegs[CPU_REG_Y]);
	}

	if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_Z])
	{
		if (mFalseJump)
			live |= LIVE_CPU_REG_Z;
		else if (mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
		{
			if (mTrueJump->mIns.Size() == 0 || !mTrueJump->mIns[0].ChangesZFlag())
				live |= LIVE_CPU_REG_Z;
		}
	}
	if (mExitRequiredRegs.Size() > 0 && mTrueJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_C] && (mFalseJump || mTrueJump->mEntryRequiredRegs[CPU_REG_C]))
		live |= LIVE_CPU_REG_C;

	for (int j = mIns.Size() - 1; j >= 0; j--)
	{
		assert(mIns[j].mType != ASMIT_INV);

		if (mIns[j].mMode == ASMIM_IMMEDIATE_ADDRESS)
			assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE));
		else
			assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode));

#if CHECK_NULLPTR
		if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_ABSOLUTE_X || mIns[j].mMode == ASMIM_ABSOLUTE_Y)
			assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0);
#endif
		if (mIns[j].mType != ASMIT_NOP)
		{
			assert(!(live & ~mIns[j].mLive));

			if (mIns[j].mType == ASMIT_JSR)
			{
				assert((mIns[j].mFlags & NCIF_PROVIDE_CPU_REG_X) || (mIns[j].mFlags & NCIF_PRESERVE_CPU_REG_X) || !(live & LIVE_CPU_REG_X));
				assert((mIns[j].mFlags & NCIF_PROVIDE_CPU_REG_Y) || (mIns[j].mFlags & NCIF_PRESERVE_CPU_REG_Y) || !(live & LIVE_CPU_REG_Y));
				if (!(mIns[j].mFlags & NCIF_JSRFLAGS))
					assert(!(live & (LIVE_CPU_REG_C | LIVE_CPU_REG_Z)));
			}

			if (mIns[j].ChangesAccu()) live &= ~LIVE_CPU_REG_A;
			if (mIns[j].ChangesXReg()) live &= ~LIVE_CPU_REG_X;
			if (mIns[j].ChangesYReg()) live &= ~LIVE_CPU_REG_Y;
			if (mIns[j].ChangesCarry()) live &= ~LIVE_CPU_REG_C;
			if (mIns[j].ChangesZFlag()) live &= ~LIVE_CPU_REG_Z;

			if (mIns[j].RequiresAccu()) live |= LIVE_CPU_REG_A;
			if (mIns[j].RequiresXReg()) live |= LIVE_CPU_REG_X;
			if (mIns[j].RequiresYReg()) live |= LIVE_CPU_REG_Y;
			if (mIns[j].RequiresCarry()) live |= LIVE_CPU_REG_C;
		}
	}

	if (mEntryRequiredRegs.Size() > 0)
	{
		if (live & LIVE_CPU_REG_A)
			assert(mEntryRegA || mEntryRequiredRegs[CPU_REG_A]);
		if (live & LIVE_CPU_REG_X)
			assert(mEntryRegX || mEntryRequiredRegs[CPU_REG_X]);
		if (live & LIVE_CPU_REG_Y)
			assert(mEntryRegY || mEntryRequiredRegs[CPU_REG_Y]);
	}
#endif
}

void NativeCodeBasicBlock::Assemble(void)
{
	if (!mAssembled)
	{	
		mAssembled = true;

		for (int i = 0; i < mIns.Size(); i++)
			mIns[i].Assemble(this);

		if (this->mTrueJump)
			this->mTrueJump->Assemble();
		if (this->mFalseJump)
			this->mFalseJump->Assemble();
	}
}

void NativeCodeBasicBlock::Close(const InterInstruction* ins, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch)
{
	this->mTrueJump = trueJump;
	this->mFalseJump = falseJump;
	this->mBranch = branch;
	this->mBranchIns = ins;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::SplitAt(int at)
{
	NativeCodeBasicBlock* eblock = mProc->AllocateBlock();
	eblock->Close(mBranchIns, mTrueJump, mFalseJump, mBranch);
	this->mBranch = ASMIT_JMP;
	this->mFalseJump = nullptr;
	this->mTrueJump = eblock;
	for (int i = at; i < mIns.Size(); i++)
		eblock->mIns.Push(mIns[i]);
	mIns.SetSize(at);
	eblock->mNumEntries = 1;
	eblock->mEntryBlocks.Push(this);
	eblock->mTrueJump->mEntryBlocks.RemoveAll(this);
	eblock->mTrueJump->mEntryBlocks.Push(eblock);
	if (eblock->mFalseJump)
	{
		eblock->mFalseJump->mEntryBlocks.RemoveAll(this);
		eblock->mFalseJump->mEntryBlocks.Push(eblock);
	}
	return eblock;
}

NativeCodeBasicBlock* NativeCodeBasicBlock::BypassEmptyBlocks(void)
{
	if (mBypassed)
		return this;
	else if (mTrueJump && !mFalseJump && mCode.Size() == 0 && this != mTrueJump)
		return mTrueJump->BypassEmptyBlocks();
	else
	{
		mBypassed = true;

		if (mFalseJump)
			mFalseJump = mFalseJump->BypassEmptyBlocks();
		if (mTrueJump)
			mTrueJump = mTrueJump->BypassEmptyBlocks();

		return this;
	}
}

int NativeCodeBasicBlock::LeadsInto(NativeCodeBasicBlock* block, int dist)
{
	if (mPlaced)
		return 1000;
	else if (this == block)
		return 0;
	else if (dist < 6)
	{
		int d0 = mTrueJump ? mTrueJump->LeadsInto(block, dist + 1) : 1000;
		int d1 = mFalseJump ? mFalseJump->LeadsInto(block, dist + 1) : 1000;

		int d = (d0 < d1 ? d0 : d1) + mCode.Size();

		if (d < 100)
			return d;
	}

	return 1000;
}

NativeCodeBasicBlock * NativeCodeBasicBlock::PlaceSequence(ExpandingArray<NativeCodeBasicBlock*>& placement, NativeCodeBasicBlock* block)
{
	int size = 0;
	do {
		block->mPlaced = true;
		block->mPlace = placement.Size();
		placement.Push(block);
		size += block->mCode.Size();
		block = block->mTrueJump;
	} while (block && !block->mFalseJump && !block->mPlaced && size + block->mCode.Size() < 32);
	return block;
}

void NativeCodeBasicBlock::BuildPlacement(ExpandingArray<NativeCodeBasicBlock*>& placement)
{
	if (!mPlaced)
	{
		if (mTrueJump && mFalseJump && mTrueJump == mFalseJump)
		{
			mFalseJump = nullptr;
			mBranch = ASMIT_JMP;
		}

		assert(mBranch != ASMIT_JMP || mIns.Size() > 0 || mTrueJump == this);

		mPlaced = true;
		mPlace = placement.Size();
		placement.Push(this);

		if (mFalseJump)
		{
			if (mFalseJump->mPlaced)
				mTrueJump->BuildPlacement(placement);
			else if (mTrueJump->mPlaced)
				mFalseJump->BuildPlacement(placement);
			else if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
			{
				if (mTrueJump->mNDataSet[CPU_REG_C].mMode == NRDM_IMMEDIATE || mTrueJump->mNDataSet[CPU_REG_Z].mMode == NRDM_IMMEDIATE)
				{
					mTrueJump->mPlaced = true;
					mTrueJump->mPlace = placement.Size();
					placement.Push(mTrueJump);
					mFalseJump->BuildPlacement(placement);
				}
				else
				{
					mFalseJump->mPlaced = true;
					mFalseJump->mPlace = placement.Size();
					placement.Push(mFalseJump);

					mTrueJump->BuildPlacement(placement);
				}
			}
			else if (mTrueJump->LeadsInto(mFalseJump, 0) < mFalseJump->LeadsInto(mTrueJump, 0))
			{
				mTrueJump->BuildPlacement(placement);
				mFalseJump->BuildPlacement(placement);
			}
			else if (mTrueJump->LeadsInto(mFalseJump, 0) > mFalseJump->LeadsInto(mTrueJump, 0))
			{
				mFalseJump->BuildPlacement(placement);
				mTrueJump->BuildPlacement(placement);
			}
			else if (mTrueJump->mCode.Size() < 32 && (mTrueJump->mTrueJump && mTrueJump->mTrueJump->mPlaced) || (mTrueJump->mFalseJump && mTrueJump->mFalseJump->mPlaced))
			{
				mTrueJump->BuildPlacement(placement);
				mFalseJump->BuildPlacement(placement);
			}
			else if (mFalseJump->mCode.Size() < 32 && (mFalseJump->mTrueJump && mFalseJump->mTrueJump->mPlaced) || (mFalseJump->mFalseJump && mFalseJump->mFalseJump->mPlaced))
			{
				mFalseJump->BuildPlacement(placement);
				mTrueJump->BuildPlacement(placement);
			}
			else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump->mFalseJump && 
				     mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump->mTrueJump &&
					 mTrueJump->mCode.Size() < 20 && mTrueJump->mTrueJump->mCode.Size() < 20 &&
					 mFalseJump->mFalseJump->LeadsInto(mTrueJump->mTrueJump->mTrueJump, 0) < 10 &&
					 mFalseJump->mFalseJump->LeadsInto(mTrueJump->mTrueJump->mFalseJump, 0) < 10)
			{
				mTrueJump->mPlaced = true;
				mTrueJump->mPlace = placement.Size();
				placement.Push(mTrueJump);

				mTrueJump->mTrueJump->mPlaced = true;
				mTrueJump->mTrueJump->mPlace = placement.Size();
				placement.Push(mTrueJump->mTrueJump);

				mFalseJump->BuildPlacement(placement);
				mTrueJump->mTrueJump->mTrueJump->BuildPlacement(placement);
				mTrueJump->mTrueJump->mFalseJump->BuildPlacement(placement);
			}
			else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 100 && mFalseJump->LeadsInto(mTrueJump->mTrueJump, 0) < 100)
			{
				NativeCodeBasicBlock	*	xblock = PlaceSequence(placement, mTrueJump);
				mFalseJump->BuildPlacement(placement);
				if (xblock) xblock->BuildPlacement(placement);
			}
			else if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump && mFalseJump->mCode.Size() < 100 && mTrueJump->LeadsInto(mFalseJump->mTrueJump, 0) < 100)
			{
				NativeCodeBasicBlock	*	xblock = PlaceSequence(placement, mFalseJump);
				mTrueJump->BuildPlacement(placement);
				if (xblock) xblock->BuildPlacement(placement);
			}
			else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump == mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump)
			{
				mTrueJump->mPlaced = true;
				mTrueJump->mPlace = placement.Size();
				placement.Push(mTrueJump);

				mFalseJump->BuildPlacement(placement);
			}
			else if (mTrueJump->mIns.Size() == 0 && mTrueJump->mFalseJump == mFalseJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mFalseJump)
			{
				mTrueJump->mPlaced = true;
				mTrueJump->mPlace = placement.Size();
				placement.Push(mTrueJump);

				mFalseJump->BuildPlacement(placement);
			}
			else if (
				!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump->mPlaced && mTrueJump->mCode.Size() < 120 ||
				mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mFalseJump->mPlaced && mTrueJump->mTrueJump->mPlaced && mTrueJump->mCode.Size() < 120)
			{
				mTrueJump->BuildPlacement(placement);
				mFalseJump->BuildPlacement(placement);
			}
			else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mFalseJump->mFalseJump && !mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mNumEntries > 1 && mTrueJump->mTrueJump->mTrueJump != mTrueJump->mTrueJump)
			{
				mTrueJump->mPlaced = true;
				mTrueJump->mPlace = placement.Size();
				placement.Push(mTrueJump);

				mFalseJump->BuildPlacement(placement);
				mTrueJump->mTrueJump->BuildPlacement(placement);
			}
			else
			{
				mFalseJump->BuildPlacement(placement);
				mTrueJump->BuildPlacement(placement);
			}
		}
		else if (mTrueJump && !mTrueJump->mPlaced)
		{
			if (mTrueJump->mLoopHead && mTrueJump->mFalseJump)
			{
				if (!mTrueJump->mFalseJump->mFalseJump && mTrueJump->mFalseJump->mTrueJump == mTrueJump)
				{
					if (!mTrueJump->mFalseJump->mPlaced && mTrueJump->mFalseJump->mCode.Size() + mTrueJump->mCode.Size() < 100)
					{
						mTrueJump->mFalseJump->mPlaced = true;
						mTrueJump->mFalseJump->mPlace = placement.Size();
						placement.Push(mTrueJump->mFalseJump);
					}
				}
				if (!mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == mTrueJump)
				{
					if (!mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mCode.Size() + mTrueJump->mCode.Size() < 100)
					{
						mTrueJump->mTrueJump->mPlaced = true;
						mTrueJump->mTrueJump->mPlace = placement.Size();
						placement.Push(mTrueJump->mTrueJump);
					}
				}
				if (mTrueJump->mEntryBlocks.Size() == 2 && this == mTrueJump->mEntryBlocks[0] && !mTrueJump->mEntryBlocks[1]->mFalseJump)
				{
					if (!mTrueJump->mEntryBlocks[1]->mPlaced && mTrueJump->mEntryBlocks[1]->mCode.Size() + mTrueJump->mCode.Size() < 40)
					{
						mTrueJump->mEntryBlocks[1]->mPlaced = true;
						mTrueJump->mEntryBlocks[1]->mPlace = placement.Size();
						placement.Push(mTrueJump->mEntryBlocks[1]);
					}
				}
			}

			mTrueJump->BuildPlacement(placement);
		}
	}
}

void NativeCodeBasicBlock::OptimizePlacement(void)
{
	if (!mFalseJump && mTrueJump && !mTrueJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump->mPlace == mPlace + 1 && mTrueJump->mCode.Size() <= 3)
	{
		for (int i = 0; i < mTrueJump->mRelocations.Size(); i++)
		{
			LinkerReference	rl = mTrueJump->mRelocations[i];
			rl.mOffset += mCode.Size();
			if (rl.mFlags & LREF_INBLOCK)
			{
				rl.mRefOffset += mCode.Size();
				rl.mFlags &= ~LREF_INBLOCK;
			}
			mRelocations.Push(rl);
		}
		for (int i = 0; i < mTrueJump->mCode.Size(); i++)
			mCode.Push(mTrueJump->mCode[i]);
		mTrueJump->mEntryBlocks.RemoveAll(this);
		mTrueJump->mNumEntries--;
		mTrueJump = mTrueJump->mTrueJump;
		mTrueJump->mEntryBlocks.Push(this);
		mTrueJump->mNumEntries++;
	}
}

void NativeCodeBasicBlock::InitialOffset(int& total)
{
	mAsmFromJump = -1;

	mOffset = total;
	total += mCode.Size();
	if (mFalseJump)
	{
		total += 5;
		if (mFalseJump->mPlace != mPlace + 1 && mTrueJump->mPlace != mPlace + 1)
			total += 3;
	}
	else if (mTrueJump)
	{
		if (mTrueJump->mPlace != mPlace + 1)
			total += 3;
	}

	mSize = total - mOffset;
}

bool NativeCodeBasicBlock::CalculateOffset(int& total, bool final)
{
	bool	changed = total != mOffset;
	mOffset = total;

	total += mCode.Size();

	if (mFalseJump)
	{
		if (mFalseJump->mPlace == mPlace + 1)
			total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final);
		else if (mTrueJump->mPlace == mPlace + 1)
			total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset, final);
		else if (mFalseJump->mPlace < mPlace && mTrueJump->mPlace < mPlace && mPlace - mTrueJump->mPlace < 126 &&
			mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_RTS)
		{
			total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final);
			total += JumpByteSize(mFalseJump, total, mFalseJump->mOffset, true, final);
		}
#if 1
		else if (final && CheckFinalBranchByteSize(mFalseJump, total, mFalseJump->mOffset) < CheckFinalBranchByteSize(mTrueJump, total, mTrueJump->mOffset))
		{
			total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset, final);
			total += JumpByteSize(mTrueJump, total, mTrueJump->mOffset, true, final);
		}
		else if (final && CheckFinalBranchByteSize(mTrueJump, total, mTrueJump->mOffset) < CheckFinalBranchByteSize(mFalseJump, total, mFalseJump->mOffset))
		{
			total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final);
			total += JumpByteSize(mFalseJump, total, mFalseJump->mOffset, true, final);
		}
#endif
		else if (
			mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace ||
			mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace)
		{
			total += BranchByteSize(mFalseJump, total, mFalseJump->mOffset, final);
			total += JumpByteSize(mTrueJump, total, mTrueJump->mOffset, true, final);
		}
		else
		{
			total += BranchByteSize(mTrueJump, total, mTrueJump->mOffset, final);
			total += JumpByteSize(mFalseJump, total, mFalseJump->mOffset, true, final);
		}
	}
	else if (mTrueJump)
	{
		if (mTrueJump->mPlace != mPlace + 1)
		{
			if (!mTrueJump->mTrueJump && mTrueJump->mCode.Size() < 3)
			{
				total += mTrueJump->mCode.Size();
				for (int i = 0; i < mTrueJump->mCode.Size(); i++)
					mCode.Push(mTrueJump->mCode[i]);
				mTrueJump = nullptr;
			}
			else
				total += JumpByteSize(mTrueJump, total, mTrueJump->mOffset, false, final);
		}
	}

	if (mOffset + mSize != total)
		changed = true;

	mSize = total - mOffset;

	return changed;
}

void NativeCodeBasicBlock::ShortcutJump(int offset)
{
	if (mCode[offset] == 0x4c)
	{
		int i = 0;
		while (i < mRelocations.Size() && mRelocations[i].mOffset != offset + 1)
			i++;
		if (i < mRelocations.Size())
		{
			LinkerReference& ref(mRelocations[i]);
			if (ref.mRefObject && ref.mRefObject->mData)
			{
				LinkerObject* lo = ref.mRefObject;

				if (lo->mData[ref.mRefOffset] == 0x4c || lo->mData[ref.mRefOffset] == 0x6c)
				{
					int j = 0;
					while (j < lo->mReferences.Size() && lo->mReferences[j]->mOffset != ref.mRefOffset + 1)
						j++;
					if (j < lo->mReferences.Size())
					{
						mCode[offset] = lo->mData[ref.mRefOffset];
						ref.mRefObject = lo->mReferences[j]->mRefObject;
						ref.mRefOffset = lo->mReferences[j]->mRefOffset;
						ref.mFlags = lo->mReferences[j]->mFlags;
					}
					else
					{
						mCode[offset] = lo->mData[ref.mRefOffset];
						mCode[offset + 1] = lo->mData[ref.mRefOffset + 1];
						mCode[offset + 2] = lo->mData[ref.mRefOffset + 2];
						mRelocations.Remove(i);
					}
				}
			}
		}
	}
}

void NativeCodeBasicBlock::ShortcutTailRecursion()
{
	if (!mVisited)
	{
		mVisited = true;
		if (!mFalseJump && mTrueJump && mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_RTS)
		{
			if (mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
			{
				this->mCode[this->mCode.Size() - 3] = 0x4c;
				mTrueJump->mNumEntries--;
				mTrueJump = nullptr;
				ShortcutJump(this->mCode.Size() - 3);
			}
#if 0
			else
			{
				this->mCode.Push(0x60);
				mTrueJump->mNumEntries--;
				mTrueJump = nullptr;
			}
#endif
		}
		else if (!mFalseJump && !mTrueJump)
		{
			int ns = mIns.Size();
			if (ns >= 2 && mIns[ns - 1].mType == ASMIT_RTS && mIns[ns - 2].IsSimpleJSR())
			{
				this->mCode.Remove(this->mCode.Size() - 1);
				this->mCode[this->mCode.Size() - 3] = 0x4c;
				ShortcutJump(this->mCode.Size() - 3);
			}
		}

		if (mTrueJump) mTrueJump->ShortcutTailRecursion();
		if (mFalseJump) mFalseJump->ShortcutTailRecursion();
	}
}

void NativeCodeBasicBlock::CopyCode(NativeCodeProcedure * proc, uint8* target)
{
	int i;
	int next, end;

	end = mOffset + mCode.Size();
	next = mOffset + mSize;

	if (mFalseJump)
	{
		if (mBranchIns)
			PutLocation(mBranchIns->mLocation, false);

		if (mFalseJump->mPlace == mPlace + 1)
			end += PutBranch(proc, mTrueJump, mBranch, end, mTrueJump->mOffset);
		else if (mTrueJump->mPlace == mPlace + 1)
			end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), end, mFalseJump->mOffset);
		else if (mFalseJump->mPlace < mPlace && mTrueJump->mPlace < mPlace && mPlace - mTrueJump->mPlace < 126 &&
			mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_RTS)
			{
				end += PutBranch(proc, mTrueJump, mBranch, end, mTrueJump->mOffset);
				end += PutJump(proc, mFalseJump, end, mFalseJump->mOffset, mBranch);
		}
#if 1
		else if (CheckFinalBranchByteSize(mFalseJump, end, mFalseJump->mOffset) < CheckFinalBranchByteSize(mTrueJump, end, mTrueJump->mOffset))
		{
			end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), end, mFalseJump->mOffset);
			end += PutJump(proc, mTrueJump, end, mTrueJump->mOffset, InvertBranchCondition(mBranch));
		}
		else if (CheckFinalBranchByteSize(mTrueJump, end, mTrueJump->mOffset) < CheckFinalBranchByteSize(mFalseJump, end, mFalseJump->mOffset))
		{
			end += PutBranch(proc, mTrueJump, mBranch, end, mTrueJump->mOffset);
			end += PutJump(proc, mFalseJump, end, mFalseJump->mOffset, mBranch);
		}
#endif
		else if (
			mFalseJump->mPlace > mTrueJump->mPlace && mFalseJump->mPlace < mPlace ||
			mFalseJump->mPlace < mTrueJump->mPlace && mFalseJump->mPlace > mPlace)
			{
				end += PutBranch(proc, mFalseJump, InvertBranchCondition(mBranch), end, mFalseJump->mOffset);
				end += PutJump(proc, mTrueJump, end, mTrueJump->mOffset, InvertBranchCondition(mBranch));
		}
		else
		{
			end += PutBranch(proc, mTrueJump, mBranch, end, mTrueJump->mOffset);
			end += PutJump(proc, mFalseJump, end, mFalseJump->mOffset, mBranch);
		}

		if (mBranchIns)
			PutLocation(mBranchIns->mLocation, false);
	}
	else if (mTrueJump)
	{
		if (mTrueJump->mPlace != mPlace + 1)
		{
			if (mBranchIns)
				PutLocation(mBranchIns->mLocation, false);

			end += PutJump(proc, mTrueJump, end, mTrueJump->mOffset);

			if (mBranchIns)
				PutLocation(mBranchIns->mLocation, false);
		}
		else if (mTrueJump->mIns.Size() == 1 && mTrueJump->mIns[0].mType == ASMIT_RTS && mIns.Size() > 0 && mIns.Last().IsSimpleJSR())
			this->mCode[this->mCode.Size() - 3] = 0x4c;
	}


	assert(end == next);

	for (int i = 0; i < mRelocations.Size(); i++)
	{
		LinkerReference& rl(mRelocations[i]);
		rl.mOffset += mOffset;
		if (rl.mFlags & LREF_INBLOCK)
		{
			rl.mRefOffset += mOffset;
			rl.mFlags &= ~LREF_INBLOCK;
		}
		proc->mRelocations.Push(rl);
	}

	for (int i = 0; i < mCodeLocations.Size(); i++)
	{
		CodeLocation	loc(mCodeLocations[i]);
		loc.mStart += mOffset;
		loc.mEnd += mOffset;
		proc->mCodeLocations.Push(loc);
	}

	for (int i = 0; i < mCodeOrigins.Size(); i++)
	{
		CodeLocation	loc(mCodeOrigins[i]);
		loc.mStart += mOffset;
		loc.mEnd += mOffset;
		proc->mCodeOrigins.Push(loc);
	}

	for (i = 0; i < mCode.Size(); i++)
	{
		target[i + mOffset] = mCode[i];
	}
}

bool NativeCodeBasicBlock::CheckAllAccuReturn(void)
{
	if (!mVisited)
	{
		mVisited = true;
		if (mTrueJump)
		{
			if (!mTrueJump->CheckAllAccuReturn())
				return false;
			if (mFalseJump && !mFalseJump->CheckAllAccuReturn())
				return false;
		}
		else
		{
			int sz = mIns.Size();
			if (sz >= 2 &&
				mIns[sz - 1].mType == ASMIT_RTS &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == BC_REG_ACCU)
			{
				return true;
			}

			return false;
		}
	}

	return true;
}

void NativeCodeBasicBlock::ReplaceAccuReturn(void)
{
	if (!mVisited)
	{
		mVisited = true;
		if (mTrueJump)
		{
			mTrueJump->ReplaceAccuReturn();
			if (mFalseJump)
				mFalseJump->ReplaceAccuReturn();
		}
		else
		{
			int sz = mIns.Size();
			if (sz >= 2 &&
				mIns[sz - 1].mType == ASMIT_RTS &&
				mIns[sz - 2].mType == ASMIT_STA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 2].mAddress == BC_REG_ACCU)
			{
				mIns.Remove(sz - 2);
				mExitRegA = true;
			}
		}
	}
}

NativeCodeBasicBlock::NativeCodeBasicBlock(NativeCodeProcedure* proc)
{
	mProc = proc;
	mBranch = ASMIT_RTS;
	mBranchIns = nullptr;
	mTrueJump = mFalseJump = NULL;
	mOffset = -1;
	mPlaced = false;
	mCopied = false;
	mKnownShortBranch = false;
	mBypassed = false;
	mAssembled = false;
	mLocked = false;
	mDominator = nullptr;
	mLoopHeadBlock = nullptr;
	mLoopTailBlock = nullptr;
	mSuffixString = nullptr;
	mSuffixStringLength = 0;
	mEntryRegA = false;
	mEntryRegX = false;
	mEntryRegY = false;
	mExitRegA = false;
	mExitRegX = false;
	mVisited = false;
	mLoopHead = false;
	mNumEntries = 0;
}

NativeCodeBasicBlock::~NativeCodeBasicBlock(void)
{

}

NativeCodeProcedure::NativeCodeProcedure(NativeCodeGenerator* generator)
	: mGenerator(generator), mSimpleInline(false)
{
	mTempBlocks = 1000;
}

NativeCodeProcedure::~NativeCodeProcedure(void)
{

}

void NativeCodeProcedure::DisassembleDebug(const char* name)
{
#if DISASSEMBLE_OPT
#ifdef _WIN32
	FILE* file;
	static bool	initial = true;

	if (!CheckFunc)
		return;

	if (!initial)
	{
		fopen_s(&file, "r:\\ntivdiss.txt", "a");
	}
	else
	{
		fopen_s(&file, "r:\\ntivdiss.txt", "w");
		initial = false;
	}

	if (file)
	{
		fprintf(file, "--------------------------------------------------------------------\n");
		fprintf(file, "%s : %s:%d\n", name, mLocation.mFileName, mLocation.mLine);
		fprintf(file, "\n");

		ResetVisited();
		mEntryBlock->Disassemble(file);

		fclose(file);
	}
#endif
#endif
}

void NativeCodeProcedure::Disassemble(FILE* file)
{
	fprintf(file, "--------------------------------------------------------------------\n");
	fprintf(file, "%s: %s:%d\n", mIdent->mString, mLocation.mFileName, mLocation.mLine);

	ResetVisited();
	mEntryBlock->Disassemble(file);
}

void NativeCodeProcedure::AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree* tree)
{
	ResetVisited();
	mEntryBlock->AddToSuffixTree(mapper, tree);
}

void NativeCodeProcedure::CompressTemporaries(bool singles)
{
	if (mInterProc->mTempSize > 0)
	{
		ResetVisited();

		NumberSet	used(256), modified(256), pairs(256);

		mEntryBlock->CollectZeroPageUsage(used, modified, pairs);

		uint8	remap[256];
		for (int i = 0; i < 256; i++)
			remap[i] = i;

		int tpos = BC_REG_TMP + mInterProc->mFreeCallerSavedTemps;
		int spos = BC_REG_TMP_SAVED;

		NumberSet	*	collisionSet = new NumberSet[NUM_REGS];

		for (int i = 0; i < NUM_REGS; i++)
			collisionSet[i].Reset(NUM_REGS);

		ResetVisited();
		mEntryBlock->BuildCollisionTable(collisionSet);


//		for (int tsize = 4; tsize > 0; tsize >>= 1)
		{
			for (int i = 0; i < mInterProc->mTempOffset.Size(); i++)
			{
				bool	tused = false;

				int	reg = BC_REG_TMP + mInterProc->mTempOffset[i];
				//			if (mInterProc->mLeafProcedure || reg >= BC_REG_TMP_SAVED)
				if (reg >= BC_REG_TMP + mInterProc->mFreeCallerSavedTemps)
				{
					int size = mInterProc->mTempSizes[i];
//					if (size == tsize)
					{
						int usize = 0;

						for (int j = 0; j < size; j++)
							if (used[reg + j])
								usize = j + 1;

						if (usize)
						{
							int pos = spos;

#if 1
//							if (mInterProc->mLeafProcedure)
							{
								if (singles && usize == 1)
								{
									int k = 0;
									while (k < 4 && collisionSet[k + BC_REG_ACCU][reg])
										k++;
									if (k < 4)
									{
										pos = BC_REG_ACCU + k;
										for (int i = 0; i < 256; i++)
										{
											if (collisionSet[reg][i])
											{
												collisionSet[pos] += i;
												collisionSet[i] += pos;
											}
										}
									}
								}
								else
								{
									int k = 0;
									while (k < usize && !collisionSet[k + BC_REG_ACCU][k + reg])
										k++;
									if (k == usize)
									{
										pos = BC_REG_ACCU;
										for (int i = 0; i < 256; i++)
										{
											for (int j = 0; j < usize; j++)
											{
												if (collisionSet[j + reg][i])
												{
													collisionSet[j + BC_REG_ACCU] += i;
													collisionSet[i] += j + BC_REG_ACCU;
												}
											}
										}
									}
								}
							}
#endif

							if (pos == spos)
							{
								if (tpos + usize <= BC_REG_TMP + mInterProc->mCallerSavedTemps)
								{
									pos = tpos;
									tpos += usize;
								}
								else
									spos += usize;
								mInterProc->mTempOffset[i] = pos - BC_REG_TMP;
								mInterProc->mTempSizes[i] = usize;
							}
							else
							{
								mInterProc->mTempOffset[i] = 0;
								mInterProc->mTempSizes[i] = 0;
							}

							for (int j = 0; j < usize; j++)
								remap[reg + j] = pos + j;

						}
						else
						{
							mInterProc->mTempOffset[i] = 0;
							mInterProc->mTempSizes[i] = 0;
						}
					}
				}
			}
		}

		delete[] collisionSet;

		mInterProc->mCallerSavedTemps = tpos - BC_REG_TMP;

		ResetVisited();
		mEntryBlock->RemapZeroPage(remap);

		assert(mInterProc->mTempSize >= tpos - BC_REG_TMP);

		if (spos > BC_REG_TMP_SAVED)
			mInterProc->mTempSize = spos - BC_REG_TMP;
		else
			mInterProc->mTempSize = tpos - BC_REG_TMP;

		if (mNoFrame && !used[BC_REG_STACK] && mInterProc->mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP)
			mStackExpand = 0;
	}
}

void NativeCodeProcedure::SaveTempsToStack(int tempSave)
{
	if (mInterProc->mSaveTempsLinkerObject)
	{
		assert(tempSave <= mInterProc->mSaveTempsLinkerObject->mSize);

		if (tempSave > 3)
		{
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
		}
		else if (tempSave > 0)
		{
			for (int i = 0; i < tempSave; i++)
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject));
			}
		}
	}
}

void NativeCodeProcedure::LoadTempsFromStack(int tempSave)
{
	if (mInterProc->mSaveTempsLinkerObject)
	{
		if (tempSave > 3)
		{
			mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
			mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_X, 0, mInterProc->mSaveTempsLinkerObject));
			mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
			mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
			mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
		}
		else if (tempSave > 0)
		{
			for (int i = 0; i < tempSave; i++)
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE, i, mInterProc->mSaveTempsLinkerObject));
				mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + i));
			}
		}
	}
}


void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
{
	mInterProc = proc;
	mLinkerObject = proc->mLinkerObject;
	mIdent = proc->mIdent;
	mLocation = proc->mLocation;
	mCompilerOptions = proc->mCompilerOptions;
		
	mInterProc->mLinkerObject->mNativeProc = this;

	CheckFunc = !strcmp(mIdent->mString, "enemies_iterate");

	int	nblocks = proc->mBlocks.Size();
	tblocks = new NativeCodeBasicBlock * [nblocks];
	for (int i = 0; i < nblocks; i++)
		tblocks[i] = nullptr;

	mIndex = proc->mID;
	mFastCallBase = proc->mFastCallBase;

	int		tempSave = proc->mTempSize > BC_REG_TMP_SAVED - BC_REG_TMP && !proc->mSaveTempsLinkerObject && !mInterProc->mInterrupt ? proc->mTempSize - (BC_REG_TMP_SAVED - BC_REG_TMP) : 0;
	int		commonFrameSize = proc->mCommonFrameSize;

	mStackExpand = tempSave + proc->mLocalSize;

	if (proc->mCallsByteCode || commonFrameSize > 0)
		commonFrameSize += 2;

	mFrameOffset = 0;
	if (proc->mHasDynamicStack)
		mNoFrame = false;
	else if (mStackExpand + proc->mCommonFrameSize + proc->mParamVarsSize < 256)
		mNoFrame = true;
	else
		mNoFrame = false;

#if 0
	if (!(proc->mCompilerOptions & COPT_OPTIMIZE_BASIC) && (proc->mCompilerOptions & COPT_DEBUGINFO))
		mNoFrame = mStackExpand + proc->mCommonFrameSize == 0 && !proc->mHasDynamicStack;
#endif

	if (mNoFrame)
		proc->mLinkerObject->mFlags |= LOBJF_NO_FRAME;

	if (mNoFrame)
	{
		if (mStackExpand > 0)
			mFrameOffset = tempSave;
	}
	else
	{
		mStackExpand += 2;
	}

	if (!proc->mLeafProcedure)
	{
		if (mNoFrame)
			mFrameOffset = commonFrameSize + tempSave;
	}

	mEntryBlock = AllocateBlock();
	mEntryBlock->mLocked = true;
	mBlocks.Push(mEntryBlock);

	mExitBlock = AllocateBlock();
	mExitBlock->mLocked = true;
	mBlocks.Push(mExitBlock);

	// Place a temporary RTS

	uint32	rflags = 0;
	switch (proc->mReturnType)
	{ 
	case IT_BOOL:
	case IT_INT8:
		rflags = NCIF_LOWER;
		break;
	case IT_INT16:
	case IT_POINTER:
		rflags = NCIF_LOWER | NCIF_UPPER;
		break;
	case IT_INT32:
	case IT_FLOAT:
		rflags = NCIF_LOWER | NCIF_UPPER | NCIF_LONG;
		break;

	}

	mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_RTS, ASMIM_IMPLIED, 0, nullptr, rflags));

	mEntryBlock->mTrueJump = CompileBlock(mInterProc, mInterProc->mBlocks[0]);
	mEntryBlock->mBranch = ASMIT_JMP;

	bool	simpleProcedure = proc->mFastCallProcedure && !proc->mInterrupt && !proc->mDispatchedCall && mNoFrame && mStackExpand == 0 && commonFrameSize == 0 && proc->mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP && (mGenerator->mCompilerOptions & COPT_NATIVE);

	if (proc->mLeafProcedure && simpleProcedure)
	{
#if 1
		if (proc->mParamVars.Size() == 1 && proc->mParamVars[0]->mSize == 1)
		{
//			printf("A Args %s\n", proc->mIdent->mString);

			proc->mLinkerObject->mFlags |= LOBJF_ARG_REG_A;
			proc->mLinkerObject->mTemporaries[0]++;
			proc->mLinkerObject->mTempSizes[0]--;
			mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS));
			mEntryBlock->mEntryRegA = true;
		}
#endif
#if 1
		else if (proc->mParamVars.Size() == 1 && proc->mParamVars[0]->mSize == 2 && proc->mParamVars[0]->mDeclaration && proc->mParamVars[0]->mDeclaration->mBase->IsIntegerType())
		{
//			printf("AX Args %s\n", proc->mIdent->mString);

			proc->mLinkerObject->mFlags |= LOBJF_ARG_REG_A | LOBJF_ARG_REG_X;
			proc->mLinkerObject->mTemporaries[0] += 2;
			proc->mLinkerObject->mTempSizes[0] -= 2;
			mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS));
			mEntryBlock->mTrueJump->mIns.Insert(1, NativeCodeInstruction(nullptr, ASMIT_STX, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + 1));
			mEntryBlock->mEntryRegA = true;
			mEntryBlock->mEntryRegX = true;
		}
#endif
#if 1
		if (mExitBlock->mIns[0].mFlags == NCIF_LOWER)
		{
			mExitBlock->mIns[0].mFlags = NCIF_USE_CPU_REG_A;
			mExitBlock->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU));
			mExitBlock->mExitRegA = true;
			proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A;
		}
#endif
	}

	mGenerator->PopulateShortMulTables();

	Optimize();
#if 1
	if (simpleProcedure && !(proc->mLinkerObject->mFlags & LOBJF_RET_REG_A) && rflags == NCIF_LOWER)
	{
		ResetVisited();
		if (mEntryBlock->CheckAllAccuReturn())
		{
			proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A;
			ResetVisited();
			mEntryBlock->ReplaceAccuReturn();
		}
	}
#endif
	if (mEntryBlock->mIns.Size() > 0)
	{
		NativeCodeBasicBlock* eblock = AllocateBlock();
		eblock->mTrueJump = mEntryBlock;
		mEntryBlock = eblock;
	}

	// Remove temporary RTS

	mExitBlock->mIns.Pop();

	int frameSpace = tempSave;

	tempSave = proc->mTempSize > BC_REG_TMP_SAVED - BC_REG_TMP ? proc->mTempSize - (BC_REG_TMP_SAVED - BC_REG_TMP) : 0;

	if (!(mGenerator->mCompilerOptions & COPT_NATIVE))
		mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BYTE, ASMIM_IMPLIED, 0xea));

	bool	ignoreExpandCommonFrame = false;


	if (mInterProc->mInterrupt)
	{
		if (!mNoFrame || commonFrameSize > 0)
			mGenerator->mErrors->Error(mLocation, ERRR_INTERRUPT_TO_COMPLEX, "Function to complex for interrupt");

		ZeroPageSet	zpLocal, zpGlobal;
		ResetVisited();
		if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true))
			zpLocal |= zpGlobal;
		else
			mGenerator->mErrors->Error(mLocation, ERRR_INTERRUPT_TO_COMPLEX, "No recursive functions in interrupt");

		if (proc->mHardwareInterrupt)
		{
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_TXA));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_TYA));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
		}

		bool	usesStack = mStackExpand;

		if (zpLocal[BC_REG_STACK])
		{
			usesStack = true;
			zpLocal -= BC_REG_STACK;
			zpLocal -= BC_REG_STACK + 1;
		}

		if (usesStack)
		{
			if (mStackExpand)
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, ((mStackExpand + commonFrameSize) >> 8) + 1));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
			else
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
		}

		for (int i = 2; i < 256; i++)
		{
			if (zpLocal[i])
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, i));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_PHA));
			}
		}

		for (int i = 255; i >= 2; i--)
		{
			if (zpLocal[i])
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, i));
			}
		}
		if (usesStack)
		{
			if (mStackExpand)
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, ((mStackExpand + commonFrameSize) >> 8) + 1));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
			else
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
		}

		if (proc->mHardwareInterrupt)
		{
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_TAY));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_TAX));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_PLA));
		}
	
		// We safe all registers
		proc->mLinkerObject->mFlags |= LOBJF_ZEROPAGESET;
	}
	else
	{
		if (mNoFrame)
		{
			if (mStackExpand > 0)
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BCS, ASMIM_RELATIVE, 2));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
				ignoreExpandCommonFrame = true;

				if (proc->mSaveTempsLinkerObject)
					SaveTempsToStack(tempSave);
				else if (tempSave)
				{
					mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1));
					if (tempSave == 1)
					{
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
					}
					else if (tempSave == 2)
					{
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));

					}
					else if (commonFrameSize > 0)
					{
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEX, ASMIM_IMPLIED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
					}
					else
					{
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
						mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
					}
				}
			}
			else if (proc->mSaveTempsLinkerObject)
				SaveTempsToStack(tempSave);
		}
		else
		{
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, mStackExpand & 0xff));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));

			if (proc->mSaveTempsLinkerObject)
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
			else
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_IMMEDIATE, tempSave));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_INY, ASMIM_IMPLIED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));

			if (proc->mSaveTempsLinkerObject)
				SaveTempsToStack(tempSave);
			else if (tempSave)
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));

				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				if (tempSave > 1)
				{
					mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEY, ASMIM_IMPLIED));
					mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BPL, ASMIM_RELATIVE, -8));
				}
			}

			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_CLC, ASMIM_IMPLIED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_ADC, ASMIM_IMMEDIATE, frameSpace + 2));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_ADC, ASMIM_IMMEDIATE, 0));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));
		}

		if (!proc->mLeafProcedure && commonFrameSize > 0 && !ignoreExpandCommonFrame)
		{
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SEC, ASMIM_IMPLIED));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
			mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			if (commonFrameSize >= 256)
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
			else
			{
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_BCS, ASMIM_RELATIVE, 2));
				mEntryBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}

			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			if (commonFrameSize >= 256)
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
			else
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BCC, ASMIM_RELATIVE, 2));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
		}

		if (mNoFrame)
		{
			if (mStackExpand > 0)
			{
				if (proc->mSaveTempsLinkerObject)
					LoadTempsFromStack(tempSave);
				else if (tempSave)
				{
					mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, commonFrameSize + tempSave - 1));
					if (tempSave == 1)
					{
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));
					}
					else if (tempSave == 2)
					{
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED + 1));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP_SAVED));

					}
					else if (commonFrameSize > 0)
					{
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDX, ASMIM_IMMEDIATE, tempSave - 1));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE_X, BC_REG_TMP_SAVED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEX, ASMIM_IMPLIED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
					}
					else
					{
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
						mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
					}
				}

				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand + commonFrameSize) & 0xff));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BCC, ASMIM_RELATIVE, 2));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			}
			else if (proc->mSaveTempsLinkerObject)
				LoadTempsFromStack(tempSave);

		}
		else
		{
			if (proc->mSaveTempsLinkerObject)
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
			else
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDY, ASMIM_IMMEDIATE, tempSave));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_INY, ASMIM_IMPLIED));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_LOCALS + 1));

			if (proc->mSaveTempsLinkerObject)
				LoadTempsFromStack(tempSave);
			else if (tempSave)
			{
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));

				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_STACK));
				mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ABSOLUTE_Y, BC_REG_TMP_SAVED));
				if (tempSave > 1)
				{
					mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_DEY, ASMIM_IMPLIED));
					mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_BPL, ASMIM_RELATIVE, -8));
				}
			}

			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_CLC, ASMIM_IMPLIED));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, mStackExpand & 0xff));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_ADC, ASMIM_IMMEDIATE, (mStackExpand >> 8) & 0xff));
			mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));

		}

		ZeroPageSet	zpLocal, zpGlobal;
		ResetVisited();
		if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, false))
		{
			zpLocal |= zpGlobal;

			for (int i = BC_REG_TMP_SAVED; i < BC_REG_TMP_SAVED + tempSave; i++)
				zpLocal -= i;

			proc->mLinkerObject->mZeroPageSet = zpLocal;
			proc->mLinkerObject->mFlags |= LOBJF_ZEROPAGESET;
		}
	}

	ResetVisited();

	bool	globalStores = false, globalLoads = false;
	mEntryBlock->CheckGlobalAliasing(globalStores, globalLoads);

	if (!globalStores)
		proc->mLinkerObject->mFlags |= LOBJF_NO_GLOBAL_STORES;
	if (!globalLoads)
		proc->mLinkerObject->mFlags |= LOBJF_NO_GLOBAL_LOADS;

	proc->mFramePointer = !mNoFrame;
	for (int i = 0; i < proc->mParamVars.Size(); i++)
	{
		if (proc->mParamVars[i])
			proc->mParamVars[i]->mOffset = i + proc->mLocalSize + 2 + mFrameOffset;
	}
	for (int i = 0; i < proc->mLocalVars.Size(); i++)
	{
		if (proc->mLocalVars[i])
			proc->mLocalVars[i]->mOffset += mFrameOffset;
	}

	if (proc->mHardwareInterrupt)
		mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_RTI, ASMIM_IMPLIED));
	else
		mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_RTS, ASMIM_IMPLIED));


	if (mExitBlock->mIns.Size() == 1 && rflags == NCIF_LOWER && !mExitBlock->mExitRegA && (mGenerator->mCompilerOptions & COPT_NATIVE))
	{
		if (mExitBlock->mEntryBlocks.Size() == 1)
		{
			NativeCodeBasicBlock* eblock = mExitBlock->mEntryBlocks[0];
			int sz = eblock->mIns.Size();
			while (sz > 0 && !eblock->mIns[sz - 1].ReferencesAccu())
				sz--;
			if (sz > 0 && eblock->mIns[sz - 1].mType == ASMIT_STA && eblock->mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && eblock->mIns[sz - 1].mAddress == BC_REG_ACCU)
			{
				mExitBlock->mExitRegA = true;
				eblock->mIns.Remove(sz - 1);
				proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A;
			}
		}
	}

	proc->mLinkerObject->mType = LOT_NATIVE_CODE;

	if (!mInterProc->mNoInline)
	{
		if (mEntryBlock->mIns.Size() == 0 && mExitBlock->mIns.Size() == 1 && !mEntryBlock->mTrueJump->mFalseJump && mEntryBlock->mTrueJump->mTrueJump == mExitBlock)
		{
			NativeCodeBasicBlock* block = mEntryBlock->mTrueJump;
			int sz = block->mIns.Size();
			if (sz < 20)
			{
				int cost = -6;
				for (int i = 0; i < sz; i++)
				{
					const NativeCodeInstruction& ins(block->mIns[i]);
					switch (ins.mType)
					{
					case ASMIT_LDA:
					case ASMIT_LDX:
					case ASMIT_LDY:
						if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress >= BC_REG_FPARAMS && ins.mAddress < BC_REG_FPARAMS_END)
							cost -= 2;
						else
							cost += AsmInsSize(ins.mType, ins.mMode);
						break;
					case ASMIT_STA:
					case ASMIT_STX:
					case ASMIT_STY:
						if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4)
							cost -= 2;
						else
							cost += AsmInsSize(ins.mType, ins.mMode);
						break;
					case ASMIT_JSR:
						if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_INLINE))
							cost += 1000;
						else
							cost += 3;
						break;

					case ASMIT_TAX:
					case ASMIT_TXA:
					case ASMIT_TAY:
					case ASMIT_TYA:
					case ASMIT_ASL:
					case ASMIT_LSR:
					case ASMIT_ROL:
					case ASMIT_ROR:
					case ASMIT_CLC:
					case ASMIT_SEC:
					case ASMIT_INX:
					case ASMIT_INY:
					case ASMIT_DEX:
					case ASMIT_DEY:
					case ASMIT_ADC:
					case ASMIT_SBC:
					case ASMIT_AND:
					case ASMIT_ORA:
					case ASMIT_EOR:
					case ASMIT_BIT:
					case ASMIT_CMP:
					case ASMIT_CPX:
					case ASMIT_CPY:
						cost += AsmInsSize(ins.mType, ins.mMode);
						break;

					default:
						cost += 1000;
						break;
					}
				}

				if (cost <= 0)
				{
					mSimpleInline = true;
				}
			}
		}
	}

	if (mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
	{
		ResetVisited();
		mEntryBlock->RegisterFunctionCalls();
	}
}

void NativeCodeProcedure::Assemble(void)
{
	CheckFunc = !strcmp(mIdent->mString, "cwin_edit_char");

	if (mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
	{
		ResetVisited();
		mEntryBlock->MergeFunctionCalls();
	}

	mEntryBlock->Assemble();

	ResetVisited();
	mEntryBlock = mEntryBlock->BypassEmptyBlocks();

	ResetVisited();
	mEntryBlock->ShortcutTailRecursion();

	ExpandingArray<NativeCodeBasicBlock*>	placement;

	int	total;
	total = 0;

	mEntryBlock->BuildPlacement(placement);

	for (int i = 0; i < placement.Size(); i++)
		placement[i]->OptimizePlacement();;

	for (int i = 0; i < placement.Size(); i++)
		placement[i]->InitialOffset(total);

	bool	progress;
	do {
		progress = false;
		total = 0;
		for (int i = 0; i < placement.Size(); i++)
			if (placement[i]->CalculateOffset(total, false))
				progress = true;
	} while (progress);

	// final run to recycle jumps
	do {
		progress = false;

		for (int i = 0; i < placement.Size(); i++)
			placement[i]->mAsmFromJump = -1;

		total = 0;

		for (int i = 0; i < placement.Size(); i++)
			if (placement[i]->CalculateOffset(total, true))
				progress = true;
	} while (progress);

	for (int i = 0; i < placement.Size(); i++)
		placement[i]->mAsmFromJump = -1;

	uint8* data = mLinkerObject->AddSpace(total);

	for (int i = 0; i < placement.Size(); i++)
	{
		LinkerObjectRange	range;
		char buffer[100];
		if (placement[i]->mLoopHead)
			sprintf_s(buffer, "l%d", placement[i]->mIndex);
		else
			sprintf_s(buffer, "s%d", placement[i]->mIndex);

		range.mIdent = Ident::Unique(buffer);
		range.mOffset = placement[i]->mOffset;
		range.mSize = placement[i]->mSize;
		mLinkerObject->mRanges.Push(range);
		placement[i]->CopyCode(this, data);
	}

	for (int i = 0; i < mRelocations.Size(); i++)
	{
		LinkerReference& rl(mRelocations[i]);
		rl.mObject = mLinkerObject;
		if (!rl.mRefObject)
			rl.mRefObject = mLinkerObject;
		if (rl.mFlags & LREF_SELFMOD)
		{
			int offset = rl.mOffset;
			int id = rl.mRefOffset >> 1;
			NativeCodeBasicBlock* block = mSelfModSources[id].mBlock;
			int target = block->mOffset + mSelfModSources[id].mOffset;
			target += rl.mRefOffset & 1;
			rl.mFlags |= LREF_HIGHBYTE | LREF_LOWBYTE;
			rl.mRefOffset = target;
		}
		mLinkerObject->AddReference(rl);
	}

	if (mGenerator->mCompilerOptions & (COPT_DEBUGINFO | COPT_PROFILEINFO))
	{
		if (mCodeLocations.Size() > 0)
		{
			int i = 1, j = 0;
			while (i < mCodeLocations.Size())
			{
				if (mCodeLocations[j].mEnd == mCodeLocations[i].mStart &&
					mCodeLocations[j].mLocation.mFileName == mCodeLocations[i].mLocation.mFileName &&
					mCodeLocations[j].mLocation.mLine == mCodeLocations[i].mLocation.mLine)
					mCodeLocations[j].mEnd = mCodeLocations[i].mEnd;
				else
					mCodeLocations[++j] = mCodeLocations[i];

				i++;
			}
			mCodeLocations.SetSize(j + 1);

			mLinkerObject->AddLocations(mCodeLocations);
		}
		if (mCodeOrigins.Size() > 0)
		{
			int i = 1, j = 0;
			while (i < mCodeOrigins.Size())
			{
				if (mCodeOrigins[j].mEnd == mCodeOrigins[i].mStart &&
					mCodeOrigins[j].mLocation.mFileName == mCodeOrigins[i].mLocation.mFileName &&
					mCodeOrigins[j].mLocation.mLine == mCodeOrigins[i].mLocation.mLine)
					mCodeOrigins[j].mEnd = mCodeOrigins[i].mEnd;
				else
					mCodeOrigins[++j] = mCodeOrigins[i];

				i++;
			}
			mCodeOrigins.SetSize(j + 1);

			mLinkerObject->AddOrigins(mCodeOrigins);
		}
	}
}

bool NativeCodeProcedure::MapFastParamsToTemps(void)
{
	NumberSet	used(256), modified(256), statics(256), pairs(256);

	ResetVisited();
	mEntryBlock->CollectZeroPageUsage(used, modified, pairs);

	used.Fill();

	for (int i = BC_REG_TMP; i < 256; i++)
		used -= i;
	
	for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
		if (!modified[i])
			statics += i;

	uint8	alias[256];
	for (int i = 0; i < 256; i++)
		alias[i] = 0;

	ResetVisited();
	mEntryBlock->FindZeroPageAlias(statics, used, alias, -1);

	for (int i = 1; i < 256; i++)
	{
		if (used[i] || !alias[i] ||
			(pairs[i] && (used[i + 1] || alias[i + 1] != alias[i] + 1)) ||
			(pairs[i - 1] && (used[i - 1] || alias[i - 1] + 1 != alias[i])))
		{
			alias[i] = i;
		}
	}

	NativeCodeBasicBlock* block = mEntryBlock;
	while (block && block->mIns.Size() == 0 && !block->mFalseJump && block->mTrueJump != block)
		block = block->mTrueJump;

	if (block && block->mNumEntries == 1)
	{
		used.Clear();
		modified.Clear();

		NumberSet	tpairs(256), aliased(256);

		for (int i = 1; i < 256; i++)
		{
			if (alias[i] != i)
				aliased += alias[i];
		}

		ResetVisited();
		if (block->mTrueJump)
			block->mTrueJump->CollectZeroPageUsage(used, modified, tpairs);
		if (block->mFalseJump)
			block->mFalseJump->CollectZeroPageUsage(used, modified, tpairs);

		for (int i = 0; i + 1 < block->mIns.Size(); i++)
		{
			if (block->mIns[i + 0].mType == ASMIT_LDA && block->mIns[i + 0].mMode == ASMIM_ZERO_PAGE && block->mIns[i + 0].mAddress >= BC_REG_FPARAMS && block->mIns[i + 0].mAddress < BC_REG_FPARAMS_END &&
				block->mIns[i + 1].mType == ASMIT_STA && block->mIns[i + 1].mMode == ASMIM_ZERO_PAGE && block->mIns[i + 1].mAddress > BC_REG_TMP && 
				!used[block->mIns[i + 0].mAddress] && !modified[block->mIns[i + 0].mAddress] &&
				!aliased[block->mIns[i + 0].mAddress])
			{
				if (!block->ReferencesZeroPage(block->mIns[i + 0].mAddress, i + 1) && !block->ReferencesZeroPage(block->mIns[i + 1].mAddress, 0, i))
				{
					alias[block->mIns[i + 1].mAddress] = block->mIns[i + 0].mAddress;
					aliased += block->mIns[i + 0].mAddress;
				}
			}
		}

		for (int i = 1; i < 255; i++)
		{
			if ((pairs[i    ] && alias[i + 1]     != alias[i] + 1) ||
				(pairs[i - 1] && alias[i - 1] + 1 != alias[i]    ))
				alias[i] = i;
		}
	}


	ResetVisited();
	return mEntryBlock->RemapZeroPage(alias);
}

void NativeCodeProcedure::RebuildEntry(void)
{
	ResetVisited();
	for (int i = 0; i < mBlocks.Size(); i++)
	{
		mBlocks[i]->mNumEntries = 0;
		mBlocks[i]->mVisiting = false;
		mBlocks[i]->mLoopHead = false;
		mBlocks[i]->mFromJump = nullptr;
		mBlocks[i]->mDominator = nullptr;
		mBlocks[i]->mSameBlock = nullptr;
	}

	ResetVisited();
	ResetEntryBlocks();
	mEntryBlock->CountEntries(nullptr);

	ResetVisited();
	mEntryBlock->CollectEntryBlocks(nullptr);

	NativeCodeBasicBlock::DominatorStacks	 stacks;

	mEntryBlock->BuildDominatorTree(nullptr, stacks);
}

void NativeCodeProcedure::CheckBlocks(bool sequence)
{
#if _DEBUG
	ResetChecked();
	mEntryBlock->CheckBlocks();
#endif
}

void NativeCodeProcedure::Optimize(void)
{
#if 1
	int		step = 0;
	int cnt = 0;
	bool	swappedXY = false;

	CheckCase = false;

#if DISASSEMBLE_OPT
	DisassembleDebug("Preoptimize");
#endif
	
	CheckBlocks();

	bool	changed, xmapped = false, ymapped = false;
	do
	{
		changed = false;

		RebuildEntry();

		assert(mEntryBlock->mNumEntries < 2);
#if 1
		if (step > 3)
		{
			ResetVisited();
			if (mEntryBlock->FindSameBlocks(this))
			{
				ResetVisited();
				changed = mEntryBlock->MergeSameBlocks(this);
			}
		}
#endif
		RebuildEntry();
		assert(mEntryBlock->mNumEntries < 2);

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step == 4)
		{
			ResetVisited();
			mEntryBlock->Split16BitLoopCount(this);
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step >= 6)
		{
			ResetVisited();
			mEntryBlock->CrossBlockYAliasProgpagation(nullptr);
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		RebuildEntry();
		assert(mEntryBlock->mNumEntries < 2);

#if 1
		if (step > 3)
		{
			NativeRegisterDataSet	data;

			bool	bchanged;
			do {
				ResetVisited();
				bchanged = mEntryBlock->BitFieldForwarding(data);

				if (bchanged)
					RebuildEntry();
				else
				{
					ResetPatched();
					mEntryBlock->CheckVisited();
				}


			} while (bchanged);
		}
#endif
#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step >= 3)
		{
			ResetVisited();
			mEntryBlock->RegisterValueForwarding();
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step == 2)
		{
			BuildDataFlowSets();
			ResetVisited();
			mEntryBlock->ReplaceFinalZeroPageUse(this);
		}
#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif
		if (step > 1)
		{
			ResetVisited();
			mEntryBlock->LocalZeroPageValueNumbering();
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step == 9 || step == 16)
		{
			ResetVisited();
			if (mEntryBlock->IndexXYValueForwarding(-1, 0, 0, -1, 0, 0))
				changed = true;

		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		int t = 0;
#if 1
		do
		{
			RebuildEntry();

			BuildDataFlowSets();
			ResetVisited();

			changed = mEntryBlock->RemoveUnusedResultInstructions();

			if (step == 0)
			{
				ResetVisited();
				ExpandingArray<NativeRegisterSum16Info>	cinfo;

				if (mEntryBlock->Propagate16BitSum(cinfo))
					changed = true;
			}

			if (!changed)
			{
				ResetVisited();
				NativeRegisterDataSet	data;

				if (mEntryBlock->ValueForwarding(this, data, step > 0, step == 8))
				{
					changed = true;
				}
				else
				{
#if 1
					ResetPatched();
					mEntryBlock->CheckVisited();

					if (step > 1)
					{
						ResetVisited();
						if (mEntryBlock->GlobalValueForwarding(this, step == 8))
						{
							changed = true;
						}
					}
#endif
				}
			}

			t++;

		} while (changed && t < 20);
#endif

		BuildDataFlowSets();
		ResetVisited();
		mEntryBlock->RemoveUnusedResultInstructions();

		if (step == 8 || step == 25)
		{
			ResetVisited();
			ValueNumberingDataSet	data;
			if (mEntryBlock->OffsetValueForwarding(data))
			{
				changed = true;

				BuildDataFlowSets();
				ResetVisited();
				mEntryBlock->RemoveUnusedResultInstructions();
			}

			ResetVisited();
			ValueReuseDataSet	rdata;
			if (mEntryBlock->CrossBlockShiftForwarding(rdata))
			{
				changed = true;

				BuildDataFlowSets();
				ResetVisited();
				mEntryBlock->RemoveUnusedResultInstructions();
			}
		}

		CheckBlocks();

		if (step == 9)
		{
			ResetVisited();
			ExpandingArray<NativeCodeLoadStorePair>	pairs;
			if (mEntryBlock->AbsoluteValueForwarding(pairs))
			{
				changed = true;

				BuildDataFlowSets();
				ResetVisited();
				mEntryBlock->RemoveUnusedResultInstructions();
			}
		}

		CheckBlocks();

#if 1
		ResetVisited();
		if (mEntryBlock->PeepHoleOptimizer(step))
			changed = true;
#endif

		if (step == 2)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutIndirectLoadStore())
				changed = true;
		}

#if 1
		if (step >= 3)
		{
			ResetVisited();
			if (mEntryBlock->ReverseBitfieldForwarding())
				changed = true;
		}
#endif


		if (step == 5)
		{
			ResetVisited();
			if (mEntryBlock->FoldLoopEntry())
				changed = true;
		}

#if 1
		if (step < 7)
		{
			ResetVisited();
			if (mEntryBlock->OptimizeSelect(this))
			{
				changed = true;
			}
		}

#if 1
		if (step == 3)
		{
			ResetVisited();
			if (mEntryBlock->RemoveSimpleLoopUnusedIndex())
				changed = true;
		}
#endif

#if 1
		if (step == 3)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutPointerAddForward())
				changed = true;
		}
#endif

		if (step == 5 && cnt < 10)
		{
			ResetVisited();
			if (mEntryBlock->RemoveDoubleZPStore())
				changed = true;
		}

		if (step == 3 || step == 5 || step == 9)
		{
			ResetVisited();
			if (mEntryBlock->PropagateCommonSubExpression())
				changed = true;
		}

#if 1
		CheckBlocks();

		if (step > 0)
		{
			RebuildEntry();

			ResetVisited();
			if (mEntryBlock->OptimizeSimpleLoop(this, step > 5))
				changed = true;

			ResetVisited();
			if (mEntryBlock->SimpleLoopReversal(this))
				changed = true;
		}
#endif

#if 1
		CheckBlocks();

		ResetVisited();
		if (mEntryBlock->MergeBasicBlocks())
		{
//			changed = true;
			BuildDataFlowSets();
			CheckBlocks();
		}

#endif

		RebuildEntry();

		CheckBlocks();

#if 1
		if (step == 2)
		{
			if (MapFastParamsToTemps())
				changed = true;
		}
#endif

#if 1
		if (step > 5 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutCrossBlockMoves(this))
				changed = true;
		}
#endif

		if (step == 4 || step == 14)
		{
			ResetVisited();
			if (mEntryBlock->OptimizeSimpleForLoop())
				changed = true;

			ResetVisited();
			if (mEntryBlock->OptimizeSimpleFixLoop())
				changed = true;
		}

		if (step > 6 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutCrossBlockCondition())
				changed = true;
		}

		CheckBlocks();
#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step > 2 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->JoinTailCodeSequences(step > 4))
			{
				changed = true;
				BuildDataFlowSets();
			}

			ResetVisited();
			if (mEntryBlock->PropagateSinglePath())
			{
				changed = true;
				BuildDataFlowSets();
			}
		}

		CheckBlocks();

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step > 2 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->JoinCommonBranchCodeSequences())
			{
				changed = true;
				BuildDataFlowSets();
			}
		}

		CheckBlocks();

		if (step > 4 && step != 6)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutBlockExit())
			{
				changed = true;
				BuildDataFlowSets();
			}
		}

		if (step == 1)
		{
			ResetVisited();
			if (mEntryBlock->CompressSwitchCascade(0x00, 0xff, -1, ASMIT_JMP))
				changed = true;
		}

		CheckBlocks();

		if (step > 3)
		{
			ResetVisited();
			if (mEntryBlock->JoinCommonHeadSequence())
				changed = true;
		}
#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step > 4)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutORACascade())
				changed = true;
		}

		if (step > 6)
		{
			ResetVisited();
			if (mEntryBlock->JoinEntryLoadStoreZP())
				changed = true;			
		}

#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		CheckBlocks();

#if 1
		if (step == 3 || step == 4 || step == 8 || (step == 15 && cnt > 0))
		{
#if 1
			ResetVisited();
			if (mEntryBlock->OptimizeInnerLoops(this))
				changed = true;
#endif

			CheckBlocks(true);

#if 1
			ResetVisited();
			if (mEntryBlock->OptimizeFindLoop(this))
				changed = true;
#endif

			CheckBlocks(true);
			
#if 1
			ResetVisited();
			if (mEntryBlock->ReduceLocalYPressure())
				changed = true;
#endif
			CheckBlocks(true);

#if 1
			if (step == 4)
			{
#if 1
				ResetVisited();
				if (!changed && mEntryBlock->LoopRegisterXYMap())
					changed = true;
#endif

				CheckBlocks(true);

				ResetVisited();
				if (!changed && mEntryBlock->OptimizeGenericLoop())
					changed = true;
			}
#endif

			CheckBlocks(true);

#if 1
			ResetVisited();
			if (!changed && mEntryBlock->ShortcutZeroPageCopyUp(this))
				changed = true;
#endif

			CheckBlocks(true);

#if 1
			ResetVisited();
			if (!changed && mEntryBlock->CrossBlockXYShortcut())
				changed = true;
#endif

			CheckBlocks(true);

#if 1
			ResetVisited();
			if (!changed && mEntryBlock->CrossBlockXYPreservation())
				changed = true;
#endif
		}
#endif

		CheckBlocks();
#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step > 4 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->OptimizeXYSimpleLoop())
				changed = true;
		}

		if (step == 3)
		{
			ResetVisited();
			if (mEntryBlock->EliminateUpper16BitSum(this))
				changed = true;
		}

		CheckBlocks();

		if (step == 3)
		{
			ResetVisited();
			if (mEntryBlock->CrossBlockIncToZeroShortcut())
				changed = true;
		}

		if (step == 12)
		{
			ResetVisited();
			if (mEntryBlock->RemoveUnusedBitOps())
				changed = true;
		}

#if 1
		if (!changed && (step == 5 || step == 6 || step == 19))
		{

#if 1
			int	xregs[256], yregs[256];

			for (int i = 0; i < 256; i++)
				xregs[i] = yregs[i] = 0;

			for (int i = 0; i < 4; i++)
			{
				xregs[BC_REG_ACCU + i] = -1;
				yregs[BC_REG_ACCU + i] = -1;
				xregs[BC_REG_WORK + i] = -1;
				yregs[BC_REG_WORK + i] = -1;
			}

			if (!mInterProc->mLeafProcedure)
			{
				for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++)
				{
					xregs[i] = -1;
					yregs[i] = -1;
				}
			}

			if (xmapped)
				xregs[0] = -1;
			if (ymapped)
				yregs[0] = -1;

			ResetVisited();
			mEntryBlock->GlobalRegisterXYCheck(xregs, yregs);

			if (xregs[0] >= 0)
			{
				int j = 1;
				for (int i = 0; i < 256; i++)
					if (xregs[i] > xregs[j])
						j = i;
				if (xregs[j] > 2)
				{
					ResetVisited();
					mEntryBlock->GlobalRegisterXMap(j);
					if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA)
						mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDX, ASMIM_ZERO_PAGE, j));
					changed = true;
					xmapped = true;
					continue;
				}
			}

			if (!changed && yregs[0] >= 0)
			{
				int j = 1;
				for (int i = 0; i < 256; i++)
					if (yregs[i] > yregs[j])
						j = i;
				if (yregs[j] > 2)
				{
					ResetVisited();
					mEntryBlock->GlobalRegisterYMap(j);
					if (j >= BC_REG_FPARAMS && j < BC_REG_FPARAMS_END && !mEntryBlock->mEntryRegA)
						mEntryBlock->mTrueJump->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDY, ASMIM_ZERO_PAGE, j));
					changed = true;
					ymapped = true;
					continue;
				}
			}
#endif

			if (!changed)
			{
				if (step == 5)
				{
					ResetVisited();
					mEntryBlock->ReduceLocalXPressure();
				}
				else
				{
					ResetVisited();
					if (mEntryBlock->LocalRegisterXYMap())
						changed = true;
				}
			}
		}
#endif

		CheckBlocks();

#if 1
		ResetVisited();
		NativeRegisterDataSet	data;
		mEntryBlock->BuildEntryDataSet(data);

		ResetVisited();
		if (mEntryBlock->ApplyEntryDataSet())
			changed = true;
#endif

		if (step == 2 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->CombineSameXY())
				changed = true;
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step >= 5)
		{
			if (step == 9)
			{
				ResetVisited();
				mEntryBlock->ReduceLocalYPressure();
			}

			ResetVisited();
			if (mEntryBlock->MoveAccuTrainsUp())
				changed = true;

			ResetVisited();
			if (mEntryBlock->MoveAccuTrainsDown())
				changed = true;

			ResetVisited();
			if (mEntryBlock->CombineSameXY())
				changed = true;

			ResetVisited();
			if (mEntryBlock->RecycleImmediates())
				changed = true;			

			ResetVisited();
			if (mEntryBlock->RecycleLoadStore())
				changed = true;
		}
#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step == 7 || step == 29)
		{
			ResetVisited();
			if (mEntryBlock->SinglePathRegisterForward())
			{
				BuildDataFlowSets();
				changed = true;
			}

		}

		if (step > 7)
		{
			ResetVisited();
			if (mEntryBlock->SinglePathStoreForward())
				changed = true;
		}

		CheckBlocks();

		if (step == 7 || step == 14)
		{
			RebuildEntry();
			ResetVisited();
			if (mEntryBlock->CrossBlockRegisterAlias(false, false))
			{
				BuildDataFlowSets();
				changed = true;
			}
		}


		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->JoinXYCascade())
				changed = true;
		}

#if 1
		if (step == 9 && cnt < 10)
		{
			CheckBlocks();

			ResetVisited();
			while (mEntryBlock->OptimizeXYSpilling())
			{
				BuildDataFlowSets();
				ResetVisited();
				mEntryBlock->RemoveUnusedResultInstructions();

				changed = true;
			}

			CheckBlocks();
		}
#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step == 6)
		{
			ResetVisited();
			if (mEntryBlock->AlternateXYUsage())
				changed = true;
			ResetVisited();
			if (mEntryBlock->OptimizeXYPairUsage())
				changed = true;
			ResetVisited();
			if (mEntryBlock->UntangleXYUsage(false))
				changed = true;
		}
#endif

		CheckBlocks();

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		ResetVisited();
		if (mEntryBlock->ForwardAccuAddSub())
			changed = true;		

#endif
#if 1
		ResetVisited();
		if (mEntryBlock->ForwardZpYIndex(step >= 5))
			changed = true;
#endif

#if 1
		ResetVisited();
		if (mEntryBlock->ForwardZpXIndex(step >= 5))
			changed = true;
#endif

		CheckBlocks();
#if 1
		if (step == 6)
		{
			ResetVisited();
			if (mEntryBlock->SimplifyDiamond(this))
				changed = true;

			CheckBlocks();

			ResetVisited();
			if (mEntryBlock->SimplifyLoopEnd(this))
				changed = true;

			CheckBlocks();

			ResetVisited();
			if (mEntryBlock->JoinDiamondArithmetic())
				changed = true;

			CheckBlocks();
		}

#endif


#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step >= 6)
		{
			ResetVisited();
			if (mEntryBlock->BypassRegisterConditionBlock())
				changed = true;
		}

		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->LoopRegisterWrapAround())
				changed = true;
		}

#if 0
		if (step == 12)
		{
			ResetVisited();
			if (mEntryBlock->JoinXYCrossBlock())
				changed = true;
		}
#endif
		if (step >= 9)
		{
			ResetVisited();
			if (mEntryBlock->EliminateDeadLoops())
				changed = true;
		}

		CheckBlocks();

		if (step == 6 || step == 7)
		{
			ResetVisited();
			if (mEntryBlock->Propagate16BitHighSum())
				changed = true;
		}		

		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->SimplifyDiamond(this))
				changed = true;
		}

		CheckBlocks();

#if 1
		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->CrossBlockXYFlood(this))
				changed = true;
		}
#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->CrossBlockY2XFlood(this))
				changed = true;
		}
#endif

		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->CrossBlock16BitFlood(this))
				changed = true;
		}

#if 1
		if (step >= 7)
		{
			ResetVisited();
			NativeRegisterDataSet	data;
			mEntryBlock->BuildEntryDataSet(data);

			ResetVisited();
			if (mEntryBlock->ExpandADCToBranch(this))
			{
				changed = true;
				BuildDataFlowSets();
			}

			if (!changed)
			{
				ResetVisited();
				if (mEntryBlock->ExpandADCShortCascadeToBranch())
				{
					changed = true;
					BuildDataFlowSets();
				}
			}
		}
#endif

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

#if 1
		if (step == 9 || step == 26)
		{
			RebuildEntry();
			ResetVisited();
			if (mEntryBlock->OptimizeSingleEntryLoop(this))
				changed = true;
		}
#endif
		RebuildEntry();

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif
#if 1
		if (step == 2 && !changed)
		{
			ResetVisited();
			if (mEntryBlock->CrossBlockStoreLoadBypass(this))
				changed = true;
		}
#endif

#if 1
		if (step == 10 && (mCompilerOptions & COPT_OPTIMIZE_BASIC))
		{
			ResetVisited();
			mEntryBlock->MarkLocalUsedLinkerObjects();

			ResetVisited();
			if (mEntryBlock->RemoveLocalUnusedLinkerObjects())
				changed = true;
		}
#endif

#endif

		if (step == 8)
		{
			ResetVisited();
			if (mEntryBlock->ForwardAXYReg())
				changed = true;			
		}

		if (step == 14)
		{
			ResetVisited();
			if (mEntryBlock->AbsoluteLocalRegisterValueReuse())
				changed = true;
		}

#if 1
#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step == 10)
		{
			if (changed)
				swappedXY = false;
			else if (!swappedXY)
			{
				NativeCodeBasicBlock* eblock = mEntryBlock;
				for (;;)
				{
					if (!eblock->mEntryRequiredRegs[CPU_REG_X] && !eblock->mEntryRequiredRegs[CPU_REG_Y])
					{
						ResetVisited();
						if (eblock->CanGlobalSwapXY())
						{
							ResetVisited();
							changed = eblock->GlobalSwapXY();
							swappedXY = true;
							break;
						}
					}
					
					if (eblock->mNumEntries <= 1 && eblock->mTrueJump && !eblock->mFalseJump)
						eblock = eblock->mTrueJump;
					else
						break;
				}
			}
		}

#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif

		if (step == 11)
		{
			if (changed && cnt < 20)
				swappedXY = false;
			else if (!swappedXY)
			{
				ResetVisited();
				changed = mEntryBlock->LocalSwapXY();
				swappedXY = true;
			}
		}

#if 1
		if (step == 13)
		{
			if (changed && cnt < 20)
				swappedXY = false;
			else if (!swappedXY)
			{
				ResetVisited();
				changed = mEntryBlock->ShortSwapXY();
				swappedXY = true;
			}
		}
#endif

#endif
#if 1
		if (step == 12)
		{
			ResetVisited();
			bool cc = mEntryBlock->GlobalLoadStoreForwarding(false, NativeCodeInstruction(), NativeCodeInstruction(), NativeCodeInstruction());
			if (!cc)
			{
				ResetVisited();
				cc = mEntryBlock->GlobalLoadStoreForwarding(true, NativeCodeInstruction(), NativeCodeInstruction(), NativeCodeInstruction());
			}
			if (cc)
			{
				ResetVisited();
				NativeRegisterDataSet	data;
				mEntryBlock->BuildEntryDataSet(data);
				changed = true;
			}
		}
#endif

		if (step == 14 && cnt == 0)
		{
			ResetVisited();
			mEntryBlock->BypassAccuLoadStoreXY();
			changed = true;
		}

		if (step == 9)
		{
			ResetVisited();
			if (mEntryBlock->MoveStoresBehindCondition())
				changed = true;
		}

#if 1
		if (step == 15 && cnt == 0)
		{
			ResetVisited();
			mEntryBlock->RemoveUnusedResultInstructions();

			BuildDataFlowSets();

			ResetVisited();
			if (mEntryBlock->AlternateXXUsage())
				changed = true;
		}
#endif

		if (step == 16)
		{
			ResetVisited();
			if (mEntryBlock->PropagateCrossBlockAccuExpression())
			{
				changed = true;
				BuildDataFlowSets();
			}
		}

		if (step == 16)
		{
			ResetVisited();
			if (mEntryBlock->JoinConditionSequence())
				changed = true;			
		}

		if (step == 16)
		{
			if (mCompilerOptions & COPT_OPTIMIZE_INLINE)
			{
				ResetVisited();
				if (mEntryBlock->SimpleInlineCalls())
					changed = true;
			}
		}

		if (step == 17)
		{
			if (!(mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
			{
				ResetVisited();
				if (mEntryBlock->Expand16BitLoopBranch())
					changed = true;

			}			
		}

		if (step == 18)
		{
			ResetVisited();
			if (mEntryBlock->BackwardValuePropagation())
			{
				changed = true;
				BuildDataFlowSets();
			}
		}

		if (step == 18)
		{
			ResetVisited();
			if (mEntryBlock->PartialBackwardValuePropagation())
				changed = true;

			if (!changed)
			{
				ResetVisited();
				if (mEntryBlock->HoistCommonLoads())
					changed = true;
			}

		}

		if (step == 19)
		{
			ResetVisited();
			if (mEntryBlock->MoveStoresBeforeDiamond())
				changed = true;
		}

		if (step == 20)
		{
			ResetVisited();
			if (mEntryBlock->ReduceIndexXYZeroShuffle(nullptr, -1, -1))
				changed = true;
		}

		if (step == 21)
		{
			ResetVisited();
			if (mEntryBlock->OptimizeLoopRegisterWrapAround())
				changed = true;

			ResetVisited();
			if (mEntryBlock->RemoveJumpToBranch())
				changed = true;

			ResetVisited();
			if (mEntryBlock->ReverseLoadAccuToRegXY())
				changed = true;
		}

		if (step == 22 && (mCompilerOptions & COPT_OPTIMIZE_BASIC))
		{
			ResetVisited();
			if (mEntryBlock->EliminateNonAliasedLocalStores())
				changed = true;
		}

		if (step == 22)
		{
			ResetVisited();
			if (mEntryBlock->MergeDuplicateCondition())
				changed = true;
		}

		if (step == 23)
		{
			ResetVisited();
			if (mEntryBlock->PatchBitBoolConstOrigin())
				changed = true;
		}

		if (step == 24)
		{
			ResetVisited();
			if (mEntryBlock->SortIndirectStores())
				changed = true;
		}

		if (step == 25)
		{
			ResetVisited();
			if (mEntryBlock->Simplify16BitSum8BitRange())
				changed = true;
		}

		if (step == 26)
		{
			ResetVisited();
			if (mEntryBlock->SimplifyLoopExitCondition())
				changed = true;			
		}

		if (step == 27)
		{
			ResetVisited();
			if (mEntryBlock->ReverseCrossBlockRegisterUnification())
				changed = true;
		}

		if (step == 28)
		{
			if (cnt < 4)
			{
				ResetVisited();
				if (mEntryBlock->ReverseZeroPageRecycling())
					changed = true;
			}

			ResetVisited();
			if (mEntryBlock->CrossBlockRegZPForward(-1, -1, -1))
				changed = true;
		}

		if (step == 29)
		{
			ResetVisited();
			if (mEntryBlock->SplitSinglePath())
				changed = true;
		}

		if (step == 30)
		{
			ResetVisited();
			if (mEntryBlock->ShortcutBranchSequence())
				changed = true;
		}


#if _DEBUG
		ResetVisited();
		mEntryBlock->CheckAsmCode();
#endif


#if DISASSEMBLE_OPT
		char fname[100];
		sprintf_s(fname, "Optimize %d, %d", step, cnt);
		DisassembleDebug(fname);
#endif

#if 1
		if (cnt > 190)
		{
			printf("Oops %d\n", step);
		}
#endif

		if (cnt > 200)
		{
			changed = false;
			mGenerator->mErrors->Error(mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mIdent);
		}

#if 1
		if (!changed && step < 31)
		{
			ResetIndexFlipped();

			cnt = 0;
			step++;
			changed = true;
			swappedXY = false;
		}
#endif
		else
			cnt++;

	} while (changed);

#if 1
	ResetVisited();
	mEntryBlock->CombineAlternateLoads();
#endif

#if 1
	ResetVisited();
	mEntryBlock->ReduceLocalYPressure();
#endif

#if 1
	BuildDataFlowSets();
	CompressTemporaries(false);
	BuildDataFlowSets();
	CompressTemporaries(false);
	BuildDataFlowSets();
	CompressTemporaries(true);
#endif

#if DISASSEMBLE_OPT
	DisassembleDebug("Post Op 1");
#endif

	do {
		ResetVisited();
		NativeRegisterDataSet	data;
		mEntryBlock->BuildEntryDataSet(data);

		ResetVisited();
	} while (mEntryBlock->ExpandADCToBranch(this));

	do {
		ResetVisited();
	} while (mEntryBlock->EliminateMicroBlocks());

#if DISASSEMBLE_OPT
	DisassembleDebug("Post Op 2");
#endif

	if (mExitBlock && mExitBlock->mIns.Size() == 1 && mExitBlock->mIns[0].mType == ASMIT_RTS && mExitBlock->mEntryBlocks.Size() == 1)
	{
		const NativeCodeInstruction& rins(mExitBlock->mIns[0]);
		NativeCodeBasicBlock* pblock = mExitBlock->mEntryBlocks[0];
		int sz = pblock->mIns.Size();

		int size = 0, reg = 0;
		if (rins.mFlags & NCIF_LONG)
		{
			if (sz >= 8)
			{
				if (pblock->mIns[sz - 8].mType == ASMIT_LDA && pblock->mIns[sz - 8].mMode == ASMIM_ZERO_PAGE &&
					pblock->mIns[sz - 7].mType == ASMIT_STA && pblock->mIns[sz - 7].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 7].mAddress == BC_REG_ACCU &&
					pblock->mIns[sz - 6].mType == ASMIT_LDA && pblock->mIns[sz - 6].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 6].mAddress == pblock->mIns[sz - 8].mAddress + 1 &&
					pblock->mIns[sz - 5].mType == ASMIT_STA && pblock->mIns[sz - 5].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 5].mAddress == BC_REG_ACCU + 1 &&
					pblock->mIns[sz - 4].mType == ASMIT_LDA && pblock->mIns[sz - 4].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 4].mAddress == pblock->mIns[sz - 8].mAddress + 2 &&
					pblock->mIns[sz - 3].mType == ASMIT_STA && pblock->mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 3].mAddress == BC_REG_ACCU + 2 &&
					pblock->mIns[sz - 2].mType == ASMIT_LDA && pblock->mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 2].mAddress == pblock->mIns[sz - 8].mAddress + 3 &&
					pblock->mIns[sz - 1].mType == ASMIT_STA && pblock->mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 1].mAddress == BC_REG_ACCU + 3)
					{
					reg = pblock->mIns[sz - 8].mAddress;
					size = 4;
				}
			}
		}
		else if (rins.mFlags & NCIF_UPPER)
		{
			if (sz >= 4)
			{
				if (pblock->mIns[sz - 4].mType == ASMIT_LDA && pblock->mIns[sz - 4].mMode == ASMIM_ZERO_PAGE &&
					pblock->mIns[sz - 3].mType == ASMIT_STA && pblock->mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 3].mAddress == BC_REG_ACCU &&
					pblock->mIns[sz - 2].mType == ASMIT_LDA && pblock->mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 2].mAddress == pblock->mIns[sz - 4].mAddress + 1 &&
					pblock->mIns[sz - 1].mType == ASMIT_STA && pblock->mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 1].mAddress == BC_REG_ACCU + 1)
				{
					reg = pblock->mIns[sz - 4].mAddress;
					size = 2;
				}
			}
		}
		else
		{
			if (sz >= 4)
			{
				if (pblock->mIns[sz - 2].mType == ASMIT_LDA && pblock->mIns[sz - 2].mMode == ASMIM_ZERO_PAGE &&
					pblock->mIns[sz - 1].mType == ASMIT_STA && pblock->mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && pblock->mIns[sz - 1].mAddress == BC_REG_ACCU)
				{
					reg = pblock->mIns[sz - 1].mAddress;
					size = 2;
				}
			}
		}

		if (size > 0 && (reg < BC_REG_FPARAMS || reg >= BC_REG_FPARAMS_END))
		{
			ResetVisited();
			if (mEntryBlock->CanSwapAccuZP(reg, size))
			{
				ResetVisited();
				mEntryBlock->SwapAccuZP(reg, size);
			}
		}
	}
#if 1
	cnt = 0;
	do
	{
		RebuildEntry();

		BuildDataFlowSets();
		ResetVisited();
		changed = mEntryBlock->RemoveUnusedResultInstructions();

		if (!changed)
		{
			ResetVisited();
			NativeRegisterDataSet	data;
			if (mEntryBlock->ValueForwarding(this, data, true, true))
			{
				changed = true;
			}
			else
			{
#if 1
				ResetPatched();
				mEntryBlock->CheckVisited();

				ResetVisited();
				if (mEntryBlock->GlobalValueForwarding(this, true))
					changed = true;
#endif
			}
		}

		BuildDataFlowSets();
		ResetVisited();
		if (mEntryBlock->RemoveUnusedResultInstructions())
			changed = true;

		CheckBlocks();

#if DISASSEMBLE_OPT
		DisassembleDebug("Post Op 3a");
#endif

		if (!changed)
		{
			ResetVisited();
			changed = mEntryBlock->PropagateSinglePath();
		}

		if (!changed)
		{
			ResetVisited();
			changed = mEntryBlock->PeepHoleOptimizer(20);
		}

#if DISASSEMBLE_OPT
		DisassembleDebug("Post Op 3b");
#endif

		if (!changed)
		{
			ResetVisited();
			changed = mEntryBlock->JoinTailCodeSequences(true);
		}
#if DISASSEMBLE_OPT
		DisassembleDebug("Post Op 3c");
#endif

		if (!changed)
		{
			ResetVisited();
			changed = mEntryBlock->UntangleXYUsage(true);
		}
#if DISASSEMBLE_OPT
		DisassembleDebug("Post Op 3d");
#endif

		if (!changed)
		{
			ResetVisited();
			changed = mEntryBlock->JoinCommonBranchCodeSequences();
		}
#if DISASSEMBLE_OPT
		DisassembleDebug("Post Op 3e");
#endif

		cnt++;
	} while (changed && cnt < 100);
#endif

#if DISASSEMBLE_OPT
	DisassembleDebug("Post Op 3");
#endif

	ResetVisited();
	mEntryBlock->OptimizeLoopCarryOver();

	ResetVisited();
	NativeRegisterDataSet	data;
	mEntryBlock->ValueForwarding(this, data, true, true);

	ResetVisited();
	mEntryBlock->CrossBlockFlagsForwarding();

	ResetVisited();
	data.Reset();
	mEntryBlock->PropagateZPAbsolute(data);

	ResetVisited();
	mEntryBlock->PropagateAddGlobalCarry();

	BuildDataFlowSets();
	ResetVisited();
	mEntryBlock->RemoveUnusedResultInstructions();

	ResetVisited();
	mEntryBlock->RemoveJumpToBranch();

	ResetVisited();
	mEntryBlock->MergeSameBranch();

#if 1
	CheckBlocks();

	ResetVisited();
	if (mEntryBlock->MergeBasicBlocks())
	{
		BuildDataFlowSets();
		CheckBlocks();
	}

#endif

	RebuildEntry();

	if (mCompilerOptions & COPT_OPTIMIZE_SELF_MOD)
	{
		ResetVisited();
		if (mEntryBlock->CollectSelfModTargets())
		{
			ResetVisited();
			NativeRegisterDataSet	data;
			mEntryBlock->ValueForwarding(this, data, true, true);

			BuildDataFlowSets();
			ResetVisited();
			mEntryBlock->RemoveUnusedResultInstructions();

			ResetVisited();
			mEntryBlock->PeepHoleOptimizer(299);
#if 0
			ResetVisited();
			mEntryBlock->JoinTailCodeSequences(true);

#endif
		}
	}

	ResetVisited();
	if (mEntryBlock->FinalCheckedSizeReduction())
	{
		BuildDataFlowSets();
		ResetVisited();
		mEntryBlock->RemoveUnusedResultInstructions();
		CheckBlocks();
	}


#if 1
	ResetVisited();
	data.Reset();
	mEntryBlock->BuildEntryDataSet(data);

	ResetVisited();
	if (mEntryBlock->ApplyEntryDataSet())
		changed = true;
#endif
#if DISASSEMBLE_OPT
	DisassembleDebug("Post Op 4");
#endif

	TrimBlocks();

#if DISASSEMBLE_OPT
	DisassembleDebug("Trimmed");
#endif

#if 1

	RebuildEntry();
	
	ResetVisited();
	mEntryBlock->BranchAccuAlternativeElimination();

	ResetVisited();
	mEntryBlock->BlockSizeReduction(this, -1, -1, -1);

#if DISASSEMBLE_OPT
	DisassembleDebug("Reduced");
#endif

	ResetVisited();
	mEntryBlock->MergeBasicBlocks();
#endif

#endif
}

void NativeCodeProcedure::BuildDataFlowSets(void)
{
	//
	//	Build set with local provided/required temporaries
	//
	ResetVisited();
	mBlocks[0]->BuildLocalRegSets();

	//
	// Build set of globally provided temporaries
	//
	ResetVisited();
	mBlocks[0]->BuildGlobalProvidedRegSet(NumberSet(NUM_REGS));

	//
	// Build set of globally required temporaries, might need
	// multiple iterations until it stabilizes
	//
	NumberSet	totalRequired(NUM_REGS);

	do {
		ResetVisited();
	} while (mBlocks[0]->BuildGlobalRequiredRegSet(totalRequired));
}

NativeCodeBasicBlock* NativeCodeProcedure::AllocateBlock(void)
{
	NativeCodeBasicBlock* block = new NativeCodeBasicBlock(this);
	block->mNoFrame = mNoFrame;
	block->mFrameOffset = mFrameOffset;
	block->mIndex = mTempBlocks++;
	mBlocks.Push(block);

	return block;
}

void NativeCodeProcedure::TrimBlocks(void)
{
#if DISASSEMBLE_OPT
	if (CheckFunc) return;
#endif

	int n = 0;
	int j = 1;
	for (int i = 1; i < mBlocks.Size(); i++)
	{
		NativeCodeBasicBlock* block = mBlocks[i];
		if (block->mNumEntries > 0 || block->mLocked)
		{
			block->mIndex = j;
			mBlocks[j++] = block;
		}
		else
		{
			delete block;
			n++;
		}
	}
	mBlocks.SetSize(j, false);
}

NativeCodeBasicBlock* NativeCodeProcedure::CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* sblock)
{
	if (tblocks[sblock->mIndex])
		return tblocks[sblock->mIndex];

	NativeCodeBasicBlock* block = new NativeCodeBasicBlock(this);
	block->mNoFrame = mNoFrame;
	block->mFrameOffset = mFrameOffset;
	mBlocks.Push(block);

	tblocks[sblock->mIndex] = block;
	block->mIndex = sblock->mIndex;

	CompileInterBlock(iproc, sblock, block);

	return block;
}

void NativeCodeProcedure::ResetEntryBlocks(void)
{
	for (int i = 0; i < mBlocks.Size(); i++)
		mBlocks[i]->mEntryBlocks.SetSize(0);
}

void NativeCodeProcedure::ResetIndexFlipped(void)
{
	for (int i = 0; i < mBlocks.Size(); i++)
	{
		for (int j = 0; j < mBlocks[i]->mIns.Size(); j++)
			mBlocks[i]->mIns[j].mFlags &= ~NICT_INDEXFLIPPED;
	}
}


void NativeCodeProcedure::ResetPatched(void)
{
	for (int i = 0; i < mBlocks.Size(); i++)
	{
		NativeCodeBasicBlock* b = mBlocks[i];
		b->mPatched = false;
		b->mPatchFail = false;
		b->mPatchUsed = false;
		b->mPatchChecked = false;
		b->mPatchStart = false;
		b->mPatchLoop = false;
		b->mPatchLoopChanged = false;
		b->mPatchExit = false;
	}
}

void NativeCodeProcedure::ResetChecked(void)
{
	for (int i = 0; i < mBlocks.Size(); i++)
	{
		mBlocks[i]->mChecked = false;

	}
}

void NativeCodeProcedure::ResetVisited(void)
{
	for (int i = 0; i < mBlocks.Size(); i++)
	{
//		assert(mBlocks[i]->mIns.Size() > 0 || (mBlocks[i]->mTrueJump != mBlocks[i] && mBlocks[i]->mFalseJump != mBlocks[i]));

		mBlocks[i]->mVisited = false;
		mBlocks[i]->mNumEntered = 0;
		mBlocks[i]->mLoopHeadBlock = nullptr;

	}
}


void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* iblock, NativeCodeBasicBlock* block)
{
	// Detect copy loop
	if (iblock->mInstructions.Size() == 7)
	{
		// 0000 (34)		LOADI2	R6(I)[-32768..65535] < -R0(P) + 0	{}
		// 0001 (34)		STOREI2 < -R3(P) + 0 {V(175 'rooms' A)}, R6(IF)[-32768..65535]	{}
		// 0002 (34)		LEAI	R0(P) + 0 < -R0(PF) + 0, CI:2	{}
		// 0003 (34)		LEAI	R3(P) + 0 {V(175 'rooms' A)} < -R3(PF) + 0 {V(175 'rooms' A)}, CI : 2	{}
		// 0004 (33)		BINOP2	R5(I)[0..35] < -R5(IF)[1..36], CI : 1	{}
		// 0005 (33)		RELOP27	R6(B)[0..1] < -R5(I)[0..35], CI : 0	{}
		// 0006 (33)		BRANCH < -R6(BF)[0..1]	{}
		
		if (iblock->mTrueJump == iblock && iblock->mEntryBlocks.Size() == 2)
		{ 
			if (iblock->mInstructions[0]->mCode == IC_LOAD && 
					iblock->mInstructions[0]->mSrc[0].mTemp >= 0 &&
				iblock->mInstructions[1]->mCode == IC_STORE && 
					iblock->mInstructions[1]->mSrc[0].mTemp == iblock->mInstructions[0]->mDst.mTemp && iblock->mInstructions[1]->mSrc[1].mTemp >= 0 &&
					iblock->mInstructions[1]->mSrc[0].mType == iblock->mInstructions[0]->mDst.mType &&
				iblock->mInstructions[2]->mCode == IC_LEA && 
					iblock->mInstructions[2]->mSrc[1].mTemp == iblock->mInstructions[0]->mSrc[0].mTemp &&
					iblock->mInstructions[2]->mDst.mTemp == iblock->mInstructions[2]->mSrc[1].mTemp && 
					iblock->mInstructions[2]->mSrc[0].mTemp < 0 && iblock->mInstructions[2]->mSrc[0].mIntConst == InterTypeSize[iblock->mInstructions[0]->mDst.mType] &&
				iblock->mInstructions[3]->mCode == IC_LEA && 
					iblock->mInstructions[3]->mSrc[1].mTemp == iblock->mInstructions[1]->mSrc[1].mTemp &&
					iblock->mInstructions[3]->mDst.mTemp == iblock->mInstructions[3]->mSrc[1].mTemp &&
					iblock->mInstructions[3]->mSrc[0].mTemp < 0 && iblock->mInstructions[3]->mSrc[0].mIntConst == InterTypeSize[iblock->mInstructions[0]->mDst.mType] &&
				iblock->mInstructions[4]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[4]->mOperator == IA_SUB &&
					iblock->mInstructions[4]->mDst.mTemp == iblock->mInstructions[4]->mSrc[1].mTemp &&
					iblock->mInstructions[4]->mSrc[0].mTemp < 0 && iblock->mInstructions[4]->mSrc[0].mIntConst == 1 &&
				iblock->mInstructions[5]->mCode == IC_RELATIONAL_OPERATOR && iblock->mInstructions[5]->mOperator == IA_CMPGU &&
					iblock->mInstructions[4]->mDst.mTemp == iblock->mInstructions[5]->mSrc[1].mTemp &&
					iblock->mInstructions[5]->mSrc[0].mTemp < 0 && iblock->mInstructions[5]->mSrc[0].mIntConst == 0 &&
				iblock->mInstructions[6]->mCode == IC_BRANCH &&
					iblock->mInstructions[5]->mDst.mTemp == iblock->mInstructions[6]->mSrc[0].mTemp
				)
			{
				if (!iblock->mFalseJump->mEntryRequiredTemps[iblock->mInstructions[0]->mSrc[0].mTemp] && 
					!iblock->mFalseJump->mEntryRequiredTemps[iblock->mInstructions[1]->mSrc[1].mTemp] &&
					iblock->mInstructions[4]->mSrc[1].IsUByte() && iblock->mInstructions[4]->mSrc[1].mRange.mMaxValue * InterTypeSize[iblock->mInstructions[0]->mDst.mType] < 256)
				{
					int	ireg = BC_REG_TMP + iproc->mTempOffset[iblock->mInstructions[4]->mDst.mTemp];
					int	sreg = BC_REG_TMP + iproc->mTempOffset[iblock->mInstructions[0]->mSrc[0].mTemp];
					int	dreg = BC_REG_TMP + iproc->mTempOffset[iblock->mInstructions[1]->mSrc[1].mTemp];

					InterInstruction* ins = iblock->mInstructions[0];

					int sz = InterTypeSize[iblock->mInstructions[0]->mDst.mType];
					if (sz == 1)
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, ireg));
					else
					{
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, ireg));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
						if (sz == 4)
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_TAX));
					}
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDY, ASMIM_IMMEDIATE, 0));

					NativeCodeBasicBlock* lblock = AllocateBlock();

					block->Close(ins, lblock, nullptr, ASMIT_JMP);
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_INY));
					lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX));

					lblock->Close(ins, lblock, CompileBlock(iproc, iblock->mFalseJump), ASMIT_BNE);

					return;
				}
			}
		}
	}

	int	i = 0;
	while (i < iblock->mInstructions.Size())
	{
		const InterInstruction * ins = iblock->mInstructions[i];

		switch (ins->mCode)
		{
		case IC_STORE:
			if (i + 1 < iblock->mInstructions.Size() &&
				ins->mSrc[0].mType == IT_INT8 &&
				ins->mSrc[0].mTemp >= 0 &&
				ins->mSrc[1].mTemp >= 0 &&
				iblock->mInstructions[i + 1]->mCode == IC_STORE &&
				iblock->mInstructions[i + 1]->mSrc[0].mType == IT_INT8 &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mSrc[0].mTemp &&
				iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp >= 0)
			{
				block->LoadStoreIndirectPair(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else
				block->StoreValue(iproc, ins);
			break;
		case IC_LOAD:
			if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_STORE &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp &&
				iblock->mInstructions[i + 1]->mSrc[0].mFinal)
			{
				block->LoadStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 2]->mCode == IC_STORE &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && 
				(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
				block->LoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], 1, iblock->mInstructions[i + 2]))
			{				
				i += 2;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 2]->mCode == IC_STORE &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp &&
				(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
				block->LoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], 0, iblock->mInstructions[i + 2]))
			{				
				i += 2;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
				iblock->mInstructions[i + 1]->mCode == IC_UNARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 2]->mCode == IC_STORE &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp &&
				(iblock->mInstructions[i + 2]->mSrc[0].mFinal || iblock->mInstructions[i + 2]->mSrc[0].mTemp != ins->mSrc[0].mTemp) &&
				block->LoadUnopStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]))
			{
				i += 2;
			}
			else if (i + 3 < iblock->mInstructions.Size() &&
				(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD &&
				iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 3]->mCode == IC_STORE &&
				iblock->mInstructions[i + 3]->mSrc[0].mTemp == iblock->mInstructions[i + 2]->mDst.mTemp && //iblock->mInstructions[i + 3]->mSrc[0].mFinal &&
				block->LoadLoadOpStoreIndirectValue(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2], iblock->mInstructions[i + 3]))
			{
				i += 3;
			}
			else if (i + 3 < iblock->mInstructions.Size() &&
				(ins->mDst.mType == IT_INT8 || ins->mDst.mType == IT_INT16 || ins->mDst.mType == IT_INT32) &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD &&
				iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 2]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 3]->mCode == IC_STORE &&
				iblock->mInstructions[i + 3]->mSrc[0].mTemp == iblock->mInstructions[i + 2]->mDst.mTemp && //iblock->mInstructions[i + 3]->mSrc[0].mFinal &&
				block->LoadLoadOpStoreIndirectValue(iproc, iblock->mInstructions[i + 1], ins, iblock->mInstructions[i + 2], iblock->mInstructions[i + 3]))
			{
				i += 3;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal)
			{
				block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], ins, ins);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
			{
				block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], nullptr, ins);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride < 256 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal)
			{
				block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 1], ins, nullptr);
				i++;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD && InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] >= 2 &&
				InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] * iblock->mInstructions[i + 1]->mSrc[0].mStride <= 256 &&
				iblock->mInstructions[i + 1]->mDst.mTemp != ins->mDst.mTemp &&
				iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mType == iblock->mInstructions[i + 1]->mDst.mType && iblock->mInstructions[i + 2]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 2]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 2]->mSrc[1].mFinal)
			{
				block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 2], ins, iblock->mInstructions[i + 1]);
				i += 2;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				InterTypeSize[ins->mDst.mType] * ins->mSrc[0].mStride <= 256 &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD && InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] >= 2 &&
				InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] * iblock->mInstructions[i + 1]->mSrc[0].mStride <= 256 &&
				iblock->mInstructions[i + 1]->mDst.mTemp != ins->mDst.mTemp &&
				iblock->mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mType == iblock->mInstructions[i + 1]->mDst.mType && iblock->mInstructions[i + 2]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 2]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mType == ins->mDst.mType && iblock->mInstructions[i + 2]->mSrc[0].mFinal)
			{
				block = block->BinaryOperator(iproc, this, iblock->mInstructions[i + 2], iblock->mInstructions[i + 1], ins);
				i += 2;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				InterTypeSize[ins->mDst.mType] >= 2 &&
				iblock->mInstructions[i + 1]->mCode == IC_LEA &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mType == ins->mDst.mType && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				!(iblock->mInstructions[i + 1]->mSrc[0].IsUByte() && 
				 iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 &&
				 i + 2 < iblock->mInstructions.Size() &&
				 iblock->mInstructions[i + 2]->mCode == IC_LOAD &&
				 iblock->mInstructions[i + 2]->mSrc->mTemp == iblock->mInstructions[i + 1]->mDst.mTemp))
			{
				block->LoadEffectiveAddress(iproc, iblock->mInstructions[i + 1], ins, nullptr, false);
				i++;
			}
			else
				block->LoadValue(iproc, ins);
			break;
		case IC_FILL:
			block = block->FillValue(iproc, ins, this);
			break;
		case IC_COPY:
			block = block->CopyValue(iproc, ins, this);
			break;
		case IC_STRCPY:
			block = block->StrcpyValue(iproc, ins, this);
			break;

		case IC_MALLOC:
			block->CallMalloc(iproc, ins, this);
			break;
		case IC_FREE:
			block->CallFree(iproc, ins, this);
			break;
		case IC_BREAKPOINT:
		{
			NativeCodeGenerator::Runtime& frt(mGenerator->ResolveRuntime(Ident::Unique("breakpoint")));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_LOWER | NCIF_UPPER | NCIF_VOLATILE | NCIF_BREAKPOINT));
		}	break;

		case IC_LOAD_TEMPORARY:
		{
			if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			{
				for (int i = 0; i < InterTypeSize[ins->mDst.mType]; i++)
				{
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + i));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + i));
				}
			}
		}	break;
		case IC_BINARY_OPERATOR:
			if (i + 1 < iblock->mInstructions.Size() &&
				ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_ADD && ins->mSrc[1].IsSByte() && ins->mSrc[0].mTemp < 0 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[i + 1]->mOperator == IA_SAR &&
				iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0 && iblock->mInstructions[i + 1]->mSrc[0].mIntConst <= 4 &&
				ins->mSrc[0].mIntConst == (1LL << (iblock->mInstructions[i + 1]->mSrc[0].mIntConst - 1)))
			{
				block->AddAsrSignedByte(iproc, ins, iblock->mInstructions[i + 1]);
				i ++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_DIVU && 
				iblock->mInstructions[i + 1]->mOperator == IA_MODU &&
				ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
				ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
				ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
			{
				block->BinaryDivModPair(iproc, this, ins, iblock->mInstructions[i + 1], false);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_MODU &&
				iblock->mInstructions[i + 1]->mOperator == IA_DIVU &&
				ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
				ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
				ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
			{
				block->BinaryDivModPair(iproc, this, iblock->mInstructions[i + 1], ins, false);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_DIVS &&
				iblock->mInstructions[i + 1]->mOperator == IA_MODS &&
				ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
				ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
				ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
			{
				block->BinaryDivModPair(iproc, this, ins, iblock->mInstructions[i + 1], true);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mCode == IC_BINARY_OPERATOR && ins->mOperator == IA_MODS &&
				iblock->mInstructions[i + 1]->mOperator == IA_DIVS &&
				ins->mSrc[0].IsEqual(iblock->mInstructions[i + 1]->mSrc[0]) &&
				ins->mSrc[1].IsEqual(iblock->mInstructions[i + 1]->mSrc[1]) &&
				ins->mSrc[0].mTemp != ins->mDst.mTemp && ins->mSrc[1].mTemp != ins->mDst.mTemp)
			{
				block->BinaryDivModPair(iproc, this, iblock->mInstructions[i + 1], ins, true);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mDst.mType == IT_INT16 &&
				ins->mOperator == IA_AND &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				iblock->mInstructions[i + 1]->mOperator == IA_MUL &&
				ins->mSrc[0].mTemp < 0 &&
				ins->mDst.mTemp == iblock->mInstructions[i + 1]->mSrc[1].mTemp &&
				ins->mDst.IsUByte() &&
				iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0 &&
				iblock->mInstructions[i + 1]->mSrc[0].mIntConst >= 0 && iblock->mInstructions[i + 1]->mSrc[0].mIntConst < 256)
			{
				block->BinaryAndMulConst(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mDst.mType == IT_INT16 && ins->mOperator == IA_SHL && ins->mSrc[1].IsUByte() && ins->mSrc[0].mTemp < 0 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && (iblock->mInstructions[i + 1]->mOperator == IA_ADD || iblock->mInstructions[i + 1]->mOperator == IA_SUB) &&
				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->BinaryShlAddConstPair(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mDst.mType == IT_INT16 && ins->mOperator == IA_ADD && ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte() &&

				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[i + 1]->mOperator == IA_ADD &&
				iblock->mInstructions[i + 1]->mSrc[0].mRange.IsRange(0, 1) && 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->BinaryAddCarry(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				ins->mDst.mType == IT_INT16 && ins->mOperator == IA_ADD && ins->mSrc[0].IsUByte() && ins->mSrc[1].IsUByte() &&

				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && iblock->mInstructions[i + 1]->mOperator == IA_ADD &&
				iblock->mInstructions[i + 1]->mSrc[1].mRange.IsRange(0, 1) && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
			{
				block->BinaryAddCarry(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 if (i + 1 < iblock->mInstructions.Size() &&
				(iproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) &&
				(ins->mOperator == IA_INT2FLOAT || ins->mOperator == IA_UINT2FLOAT) &&
				ins->mSrc[0].IsSByte() && ins->mSrc[0].mRange.mMaxValue - ins->mSrc[0].mRange.mMinValue < 16 &&
				iblock->mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
				(iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal && iblock->mInstructions[i + 1]->mSrc[1].mTemp < 0 ||
					iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && iblock->mInstructions[i + 1]->mSrc[0].mTemp < 0))
			{
				block->BinaryFloatOperatorLookup(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else
				block->NumericConversion(iproc, this, ins);
			break;
		case IC_LEA:
		{
			bool	avalid = false;
			if (i + 1 < iblock->mInstructions.Size())
			{
				if (iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp)
					avalid = true;
				else if (iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp)
					avalid = true;
				else if (iblock->mInstructions[i + 1]->mCode == IC_COPY && (iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp || iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp))
					avalid = true;
			}

#if 1
#if 1
			if (i + 3 < iblock->mInstructions.Size() &&
				ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mDst.mTemp != ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mTemp != ins->mDst.mTemp &&
				iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mSrc[0].mTemp && iblock->mInstructions[i + 1]->mSrc[1].mTemp >= 0 &&
				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 &&
				iblock->mInstructions[i + 3]->mCode == IC_STORE && iblock->mInstructions[i + 3]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 3]->mSrc[1].mFinal &&
				iblock->mInstructions[i + 3]->mSrc[0].mTemp == iblock->mInstructions[i + 2]->mDst.mTemp && iblock->mInstructions[i + 3]->mSrc[0].mFinal &&
				iblock->mInstructions[i + 2]->mSrc[0].mStride == iblock->mInstructions[i + 3]->mSrc[1].mStride)
			{
				block->CopyByteIndexedValue(iproc, iblock->mInstructions[i + 1], ins, iblock->mInstructions[i + 2], iblock->mInstructions[i + 3]);
				i += 3;
			}
			else 
#endif
				if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				iblock->mInstructions[i + 1]->mSrc[0].mIntConst == 0 && 
				ins->mSrc[0].mRange.mMaxValue + (InterTypeSize[iblock->mInstructions[i + 1]->mDst.mType] - 1) * iblock->mInstructions[i + 1]->mSrc[0].mStride < 256)
			{
				block->LoadByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				iblock->mInstructions[i + 1]->mSrc[1].mIntConst == 0 && (iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) &&
				ins->mSrc[0].mRange.mMaxValue + (InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] - 1) * iblock->mInstructions[i + 1]->mSrc[1].mStride < 256)
			{
				block->StoreByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				iblock->mInstructions[i + 1]->mSrc[1].mIntConst + ins->mSrc[0].mRange.mMaxValue + InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] <= 256 && 
				(iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) &&
				(InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] == 1 || iblock->mInstructions[i + 1]->mSrc[1].mStride == 1))
			{
				block->StoreByteOffsetIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
				ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
			{
				block->StoreAbsoluteByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}
			else if (i + 1 < iblock->mInstructions.Size() &&
				iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal &&
				ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 &&
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
			{
				block->LoadAbsoluteByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]);
				i++;
			}

			else if (i + 2 < iblock->mInstructions.Size() &&
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mLinkerObject->mSize <= 256 && 
//				ins->mSrc[0].IsUByte() &&
				iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && 
//				iblock->mInstructions[i + 1]->mSrc[0].IsUByte() &&
				iblock->mInstructions[i + 2]->mCode == IC_LOAD && iblock->mInstructions[i + 2]->mSrc[0].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[0].mFinal)				
			{
				block->LoadStoreOpAbsolute2D(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]);
				i += 2;
			}
			else if (i + 2 < iblock->mInstructions.Size() &&
				ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mLinkerObject->mSize <= 256 &&
//				ins->mSrc[0].IsUByte() &&
				iblock->mInstructions[i + 1]->mCode == IC_LEA && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal &&
//				iblock->mInstructions[i + 1]->mSrc[0].IsUByte() &&
				iblock->mInstructions[i + 2]->mCode == IC_STORE && iblock->mInstructions[i + 2]->mSrc[1].mTemp == iblock->mInstructions[i + 1]->mDst.mTemp && iblock->mInstructions[i + 2]->mSrc[1].mFinal)
			{
				block->LoadStoreOpAbsolute2D(iproc, ins, iblock->mInstructions[i + 1], iblock->mInstructions[i + 2]);
				i += 2;
			}
			else
#endif
			{
				bool	addrused = false;
				if (i + 1 < iblock->mInstructions.Size())
				{
					if (iblock->mInstructions[i + 1]->mCode == IC_TYPECAST && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
						addrused = true;
					else if (iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
						addrused = true;
				}
				block->LoadEffectiveAddress(iproc, ins, nullptr, nullptr, avalid, addrused);
			}
		}
			break;
		case IC_CONSTANT:
			block->LoadConstant(iproc, ins);
			break;
		case IC_DISPATCH:
		case IC_CALL:
			block->CallFunction(iproc, this, ins);
			break;
		case IC_CALL_NATIVE:
		case IC_ASSEMBLER:
			block->CallAssembler(iproc, this, ins);
			break;
		case IC_PUSH_FRAME:
		{
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
		}	break;
		case IC_POP_FRAME:
		{
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_CLC, ASMIM_IMPLIED));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, (ins->mConst.mIntConst + 2) & 0xff));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ADC, ASMIM_IMMEDIATE, ((ins->mConst.mIntConst + 2) >> 8) & 0xff));
			block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
		}	break;

		case IC_RELATIONAL_OPERATOR:
			if (i + 1 < iblock->mInstructions.Size() && iblock->mInstructions[i + 1]->mCode == IC_BRANCH && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal)
			{
				block->RelationalOperator(iproc, ins, this, CompileBlock(iproc, iblock->mTrueJump), CompileBlock(iproc, iblock->mFalseJump));
				return;
			}
			else if (ins->mSrc[0].mType >= IT_INT8 && ins->mSrc[0].mType <= IT_INT32 && ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mIntConst == 0 && ins->mSrc[1].IsInRange(0, 1) && ins->mOperator == IA_CMPNE)
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[1].mTemp]));
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
			}
			else if (ins->mSrc[1].mType >= IT_INT8 && ins->mSrc[1].mType <= IT_INT32 && ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mIntConst == 0 && ins->mSrc[0].IsInRange(0, 1) && ins->mOperator == IA_CMPNE)
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
			}
			else
			{
				NativeCodeBasicBlock* tblock, * fblock, * rblock;

				tblock = AllocateBlock();
				fblock = AllocateBlock();
				rblock = AllocateBlock();

				block->RelationalOperator(iproc, ins, this, tblock, fblock);

				tblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 1));
				tblock->Close(ins, rblock, nullptr, ASMIT_JMP);
				fblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
				fblock->Close(ins, rblock, nullptr, ASMIT_JMP);

				rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
				if (InterTypeSize[ins->mDst.mType] > 1)
				{
					rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
					rblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + 1));
				}

				block = rblock;
			}
			break;

		case IC_RETURN_VALUE:
		{
			if (!mExitBlock->mBranchIns)
				mExitBlock->mBranchIns = ins;

			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[0].mType == IT_FLOAT)
				{
					union { float f; unsigned int v; } cc;
					cc.f = float(ins->mSrc[0].mFloatConst);

					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 8) & 0xff));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 16) & 0xff));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (cc.v >> 24) & 0xff));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

					mExitBlock->mIns[0].mFlags |= NCIF_LOWER | NCIF_UPPER | NCIF_LONG;
				}
				else
				{
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0));

					mExitBlock->mIns[0].mFlags |= NCIF_LOWER;

					if (InterTypeSize[ins->mSrc[0].mType] > 1)
					{
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

						mExitBlock->mIns[0].mFlags |= NCIF_UPPER;

						if (InterTypeSize[ins->mSrc[0].mType] > 2)
						{
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 16) & 0xff));
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 24) & 0xff));
							block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

							mExitBlock->mIns[0].mFlags |= NCIF_LONG;
						}
					}
				}
			}				
			else
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU));

				mExitBlock->mIns[0].mFlags |= NCIF_LOWER;

				if (InterTypeSize[ins->mSrc[0].mType] > 1)
				{
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1));

					mExitBlock->mIns[0].mFlags |= NCIF_UPPER;

					if (InterTypeSize[ins->mSrc[0].mType] > 2)
					{
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 2));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3));
						block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 3));

						mExitBlock->mIns[0].mFlags |= NCIF_LONG;
					}
				}
			}

			block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
			return;
		}

		case IC_RETURN:
			if (!mExitBlock->mBranchIns)
				mExitBlock->mBranchIns = ins;

			block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
			return;

		case IC_TYPECAST:
			if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp]));
				if (InterTypeSize[ins->mDst.mType] > 1)
				{
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mDst.mTemp] + 1));
				}
			}
			break;

		case IC_BRANCH:
			if (ins->mSrc[0].mTemp < 0)
			{
				if (ins->mSrc[0].mIntConst == 0)
					block->Close(ins, CompileBlock(iproc, iblock->mFalseJump), nullptr, ASMIT_JMP);
				else
					block->Close(ins, CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP);
			}
			else
			{
				block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp]));
				if (InterTypeSize[ins->mSrc[0].mType] > 1)
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 1));
				if (InterTypeSize[ins->mSrc[0].mType] > 2)
				{
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 2));
					block->mIns.Push(NativeCodeInstruction(ins, ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins->mSrc[0].mTemp] + 3));
				}
				block->Close(ins, CompileBlock(iproc, iblock->mTrueJump), CompileBlock(iproc, iblock->mFalseJump), ASMIT_BNE);
			}
			return;

		case IC_UNREACHABLE:
			block->Close(ins, mExitBlock, nullptr, ASMIT_JMP);
			return;
		}

		i++;
	}

	block->Close(nullptr, CompileBlock(iproc, iblock->mTrueJump), nullptr, ASMIT_JMP);
}


NativeCodeGenerator::NativeCodeGenerator(Errors* errors, Linker* linker, LinkerSection* runtimeSection)
	: mErrors(errors), mLinker(linker), mRuntimeSection(runtimeSection), mCompilerOptions(COPT_DEFAULT), mFunctionCalls(nullptr)
{
}

NativeCodeGenerator::~NativeCodeGenerator(void)
{

}

void NativeCodeGenerator::CompleteRuntime(void)
{
	PopulateShortMulTables();
}


void NativeCodeGenerator::PopulateShortMulTables(void)
{
	for (int i = 0; i < mMulTables.Size(); i++)
	{
		const MulTable& m(mMulTables[i]);
		if (m.mLinkerLSB->mSize != m.mSize)
		{
			m.mLinkerLSB->AddSpace(m.mSize);
			m.mLinkerMSB->AddSpace(m.mSize);

			for (int j = 0; j < m.mSize; j++)
			{
				int val = m.mFactor;
				switch (m.mOperator)
				{
				case IA_MUL:
					val *= j;
					break;
				case IA_SHL:
					val <<= j;
					break;
				case IA_SHR:
					val = (val & 0xffff) >> j;
					break;
				case IA_SAR:
					val = (int)(short)val >> j;
					break;
				}

				m.mLinkerLSB->mData[j] = (uint8)(val);
				m.mLinkerMSB->mData[j] = (uint8)(val >> 8);
			}
		}
	}

	for (int i = 0; i < mFloatTables.Size(); i++)
	{
		const FloatTable& f(mFloatTables[i]);
		if (f.mLinker[0]->mSize != f.mMaxValue + 1 - f.mMinValue)
		{
			for (int j = 0; j < 4; j++)
				f.mLinker[j]->AddSpace(f.mMaxValue + 1 - f.mMinValue);
		}

		for (int j = f.mMinValue; j <= f.mMaxValue; j++)
		{
			union {
				float	f;
				uint8	u[4];
			}	fu;

			switch (f.mOperator)
			{
			case IA_MUL:
				fu.f = f.mConst * float(j);
				break;
			case IA_ADD:
				fu.f = f.mConst * float(j);
				break;
			case IA_SUB:
				if (f.mReverse)
					fu.f = f.mConst - float(j);
				else
					fu.f = float(j) - f.mConst;
				break;
			case IA_DIVS:
				if (f.mReverse)
					fu.f = f.mConst / float(j);
				else
					fu.f = float(j) / f.mConst;
				break;
			}

			for (int k = 0; k < 4; k++)
				f.mLinker[k]->mData[j - f.mMinValue] = fu.u[k];
		}
	}
}

LinkerObject* NativeCodeGenerator::AllocateFloatTable(InterOperator op, bool reverse, int minval, int maxval, float fval, int index)
{
	int	i = 0;
	while (i < mFloatTables.Size() && 
		(mFloatTables[i].mOperator != op || 
		 mFloatTables[i].mReverse != reverse ||
		 mFloatTables[i].mConst != fval ||
		 mFloatTables[i].mMinValue != minval))
		i++;

	if (i == mFloatTables.Size())
	{
		Location	loc;
		FloatTable	ft;

		char	name[60];
		const char* base = "";

		switch (op)
		{
		case IA_MUL:
			base = "fmul";
			break;
		case IA_ADD:
			base = "fadd";
			break;
		case IA_SUB:
			if (reverse)
				base = "frsub";
			else
				base = "fsub";
			break;
		case IA_DIVS:
			if (reverse)
				base = "frdiv";
			else
				base = "fdiv";
			break;
		}

		for (int i = 0; i < 4; i++)
		{
			sprintf_s(name, "__%stab%d_%d_%f", base, i, minval, fval);
			ft.mLinker[i] = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);
			ft.mLinker[i]->mFlags |= LOBJF_CONST;
		}

		ft.mOperator = op;
		ft.mReverse = reverse;
		ft.mConst = fval;
		ft.mMinValue = minval;
		ft.mMaxValue = maxval;

		mFloatTables.Push(ft);

		return ft.mLinker[index];
	}
	else
	{
		if (maxval > mFloatTables[i].mMaxValue)
			mFloatTables[i].mMaxValue = maxval;

		return mFloatTables[i].mLinker[index];
	}
}

LinkerObject* NativeCodeGenerator::AllocateShortMulTable(InterOperator op, int factor, int size, bool msb)
{
	assert(size > 0);

	int	i = 0;
	while (i < mMulTables.Size() && (mMulTables[i].mFactor != factor || mMulTables[i].mOperator != op))
		i++;

	if (i == mMulTables.Size())
	{
		Location	loc;
		MulTable	mt;
		
		char	name[20];
		const char* base = "";

		switch (op)
		{
		case IA_MUL:
			base = "mul";
			break;
		case IA_SHL:
			base = "shl";
			break;
		case IA_SHR:
			base = "shr";
			break;
		case IA_SAR:
			base = "sar";
			break;
		}

		sprintf_s(name, "__%stab%dL", base, factor);
		mt.mLinkerLSB = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);
		sprintf_s(name, "__%stab%dH", base, factor);
		mt.mLinkerMSB = mLinker->AddObject(loc, Ident::Unique(name), mRuntimeSection, LOT_DATA);

		mt.mLinkerLSB->mFlags |= LOBJF_CONST;
		mt.mLinkerMSB->mFlags |= LOBJF_CONST;

		mt.mFactor = factor;
		mt.mSize = size;
		mt.mOperator = op;

		mMulTables.Push(mt);

		return msb ? mt.mLinkerMSB : mt.mLinkerLSB;
	}
	else
	{
		if (size > mMulTables[i].mSize)
			mMulTables[i].mSize = size;

		return msb ? mMulTables[i].mLinkerMSB : mMulTables[i].mLinkerLSB;
	}
}

NativeCodeGenerator::Runtime& NativeCodeGenerator::ResolveRuntime(const Ident* ident)
{
	int	i = 0;
	while (i < mRuntime.Size() && mRuntime[i].mIdent != ident)
		i++;
	Location	loc;
	if (i == mRuntime.Size() || !mRuntime[i].mLinkerObject)
		mErrors->Error(loc, EERR_RUNTIME_CODE, "Undefined runtime function", ident->mString);
	return mRuntime[i];
}

static inline bool isfparam(const NativeCodeInstruction & cins, const NativeCodeInstruction & ins)
{
	if (cins.mFlags & NCIF_RUNTIME)
	{
		if (ins.mAddress >= BC_REG_WORK && ins.mAddress < BC_REG_WORK + 8)
			return true;
		if (ins.mAddress >= BC_REG_ACCU && ins.mAddress < BC_REG_ACCU + 4)
			return true;
	}
	else
	{
		if (ins.mAddress >= BC_REG_FPARAMS && ins.mAddress < BC_REG_FPARAMS_END)
			return true;
	}
	return false;
}

void NativeCodeGenerator::RegisterFunctionCall(NativeCodeBasicBlock* block, int at)
{
	LinkerObject* lo = block->mIns[at].mLinkerObject;
	if (lo->mIdent)// && !(block->mIns[at].mFlags & NCIF_USE_ZP_32_X))
	{
		uint64	fpmask = 0;

		int i = at;
		while (i >= 2 &&
			block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE &&
			isfparam(block->mIns[at], block->mIns[i - 1]) &&
			block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE || block->mIns[i - 2].mMode == ASMIM_ABSOLUTE))
		{
			if (block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE && block->mIns[i - 2].mAddress >= BC_REG_FPARAMS && block->mIns[i - 2].mAddress < BC_REG_FPARAMS_END)
			{
				if (fpmask & (1ull << (block->mIns[i - 2].mAddress - BC_REG_WORK)))
					break;
			}
			fpmask |= 1ull << (block->mIns[i - 1].mAddress - BC_REG_WORK);

			i -= 2;
		}


		if (i < at)
		{
			// Check conflicting local branch
			if (i > 0 && block->mIns[i - 1].mMode == ASMIM_RELATIVE && block->mIns[i - 1].mAddress > 0)
				return;

			FunctionCall* ncp = new FunctionCall();
			ncp->mLinkerObject = lo;
			ncp->mOffset = block->mIns[at].mAddress;

			ncp->mProxyObject = nullptr;
			ncp->mCount = 1;
			while (i < at)
			{
				ncp->mIns[block->mIns[i + 1].mAddress - BC_REG_WORK] = block->mIns[i];
				i += 2;
			}

			FunctionCall* cp = mFunctionCalls;
			while (cp && (cp->mLinkerObject != ncp->mLinkerObject || cp->mOffset != ncp->mOffset))
				cp = cp->mNext;
			if (!cp)
			{
				ncp->mNext = mFunctionCalls;
				mFunctionCalls = ncp;
				ncp->mSame = nullptr;
			}
			else
			{
				FunctionCall* scp = cp;
				while (scp && !scp->IsSame(ncp))
					scp = scp->mSame;
				if (!scp)
				{
					ncp->mSame = cp->mSame;
					cp->mSame = ncp;
				}
				else
				{
					scp->mCount++;
					ncp = scp;
				}
			}
		}
	}

}

bool NativeCodeGenerator::MergeFunctionCall(NativeCodeBasicBlock* block, int at)
{
	LinkerObject* lo = block->mIns[at].mLinkerObject;
	if (lo->mIdent)
	{
		uint64	fpmask = 0;

		int i = at;
		while (i >= 2 &&
			block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE &&
			isfparam(block->mIns[at], block->mIns[i - 1]) &&
			block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE || block->mIns[i - 2].mMode == ASMIM_ABSOLUTE))
		{
			if (block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE && block->mIns[i - 2].mAddress >= BC_REG_FPARAMS && block->mIns[i - 2].mAddress < BC_REG_FPARAMS_END)
			{
				if (fpmask & (1ull << (block->mIns[i - 2].mAddress - BC_REG_WORK)))
					break;
			}
			fpmask |= 1ull << (block->mIns[i - 1].mAddress - BC_REG_WORK);

			i -= 2;
		}

		if (i < at)
		{
			// Check conflicting local branch
			if (i > 0 && block->mIns[i - 1].mMode == ASMIM_RELATIVE && block->mIns[i - 1].mAddress > 0)
				return false;

			FunctionCall	ncp;
			ncp.mLinkerObject = lo;
			ncp.mOffset = block->mIns[at].mAddress;
			int j = i;
			while (i < at)
			{
				ncp.mIns[block->mIns[i + 1].mAddress - BC_REG_WORK] = block->mIns[i];
				i += 2;
			}

			FunctionCall* cp = mFunctionCalls;
			while (cp && (cp->mLinkerObject != ncp.mLinkerObject || cp->mOffset != ncp.mOffset))
				cp = cp->mNext;
			if (cp)
			{
				FunctionCall* bcp = nullptr;
				int			bmatch = 0;

				FunctionCall* scp = cp;
				while (scp)
				{
					if (scp->mProxyObject)
					{
						int m = ncp.Matches(scp);
						if (m > bmatch)
						{
							bmatch = m;
							bcp = scp;
						}
					}
					scp = scp->mSame;
				}

				if (bcp)
				{
					while (j < at)
					{
						if (bcp->mIns[block->mIns[j + 1].mAddress - BC_REG_WORK].mType != ASMIT_INV)
						{
							block->mIns[j + 0].mType = ASMIT_NOP; block->mIns[j + 0].mMode = ASMIM_IMPLIED;
							block->mIns[j + 1].mType = ASMIT_NOP; block->mIns[j + 1].mMode = ASMIM_IMPLIED;
						}
						j += 2;
					}
					block->mIns[j].mLinkerObject = bcp->mProxyObject;
					block->mIns[j].mAddress = 0;
					return true;
				}
			}
		}
	}
	return false;
}

void NativeCodeGenerator::OutlineFunctions(void)
{
	NativeCodeMapper	mapper;

	bool	progress;

	int k = 0;

	int numOutlines = 0;
	do {
		progress = false;

		SuffixTree* tree = new SuffixTree(nullptr, 0, nullptr);

		for (int i = 0; i < mProcedures.Size(); i++)
		{
			if ((mProcedures[i]->mCompilerOptions & COPT_OPTIMIZE_OUTLINE))
				mProcedures[i]->AddToSuffixTree(mapper, tree);
		}
		tree->AddParents(nullptr);

#if 0
		FILE* f;

		if (!fopen_s(&f, "r:\\suffix.txt", "w"))
		{
			tree->Print(f, mapper, 0);
			fclose(f);
		}
#endif

		SuffixTree* ltree = nullptr;
		int lsize = 6;

		tree->LongestMatch(mapper, 0, 0, lsize, ltree);
		if (lsize > 6)
		{
			ExpandingArray<SuffixSegment>	segs;
			ltree->ReplaceCalls(mapper, segs);

			NativeCodeBasicBlock* block = segs[0].mBlock;

			NativeCodeProcedure* nproc = new NativeCodeProcedure(this);

			NativeCodeBasicBlock* nblock = nproc->AllocateBlock();

//			printf("Suffix %s,%d:%s\n", block->mProc->mIdent->mString, block->mIndex, block->mProc->mLinkerObject->mSection->mIdent->mString);

			nproc->mLocation = block->mIns[0].mIns ? block->mIns[0].mIns->mLocation : block->mProc->mLocation;
			nproc->mCompilerOptions = block->mProc->mCompilerOptions;
			nproc->mIdent = Ident::Unique("$outline", numOutlines);
			nproc->mLinkerObject = mLinker->AddObject(nproc->mLocation, nproc->mIdent, block->mProc->mLinkerObject->mSection, LOT_NATIVE_CODE);
			nproc->mEntryBlock = nblock;
			nproc->mInterProc = nullptr;

			bool dojmp = false;

			ltree->ParentCollect(mapper, nblock);
			if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JSR)
				nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JMP;
			else if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_RTS || nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP)
				dojmp = true;
			else
				nblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS));

			segs.Sort([](const SuffixSegment& l, const SuffixSegment& r)->bool {
				return l.mBlock == r.mBlock ? l.mStart > r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock);
			});

			bool	mergeBlocks = false;

			// Check for complete loop block replacement
			bool	trueLoop = false, falseLoop = false;

			int k = 0;
			while (k < segs.Size() && segs[k].mStart == 0 && segs[k].mEnd == segs[k].mBlock->mIns.Size() && segs[k].mBlock->mTrueJump == segs[k].mBlock && segs[k].mBlock->mBranch == segs[0].mBlock->mBranch)
				k++;

			if (k == segs.Size())
				trueLoop = true;
			else if (k == 0)
			{
				while (k < segs.Size() && segs[k].mStart == 0 && segs[k].mEnd == segs[k].mBlock->mIns.Size() && segs[k].mBlock->mFalseJump == segs[k].mBlock && segs[k].mBlock->mBranch == segs[0].mBlock->mBranch)
					k++;
				if (k == segs.Size())
					falseLoop = true;
			}

			if (trueLoop || falseLoop)
			{
				NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

				if (trueLoop)
				{
					nblock->mTrueJump = nblock;
					nblock->mFalseJump = eblock;
				}
				else
				{
					nblock->mTrueJump = eblock;
					nblock->mFalseJump = nblock;
				}
				nblock->mBranch = segs[0].mBlock->mBranch;

				for (int i = 0; i < segs.Size(); i++)
				{
					SuffixSegment& s(segs[i]);
					if (trueLoop)
						segs[i].mBlock->mTrueJump = segs[i].mBlock->mFalseJump;
					segs[i].mBlock->mFalseJump = nullptr;
					segs[i].mBlock->mBranch = ASMIT_JMP;
					segs[i].mBlock->mNumEntries = 1;
				}

				eblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS));
				if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP)
					nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR;
				else
					nblock->mIns.Remove(nblock->mIns.Size() - 1);

				mergeBlocks = true;
			}
			else
			{
				bool	falseDetour = false, trueDetour = false;

				int k = 0;
				while (k < segs.Size() && 
					segs[k].mEnd == segs[k].mBlock->mIns.Size() && 
					segs[k].mBlock->mFalseJump && 
					!segs[k].mBlock->mFalseJump->mFalseJump &&
					segs[k].mBlock->mFalseJump->mIns.Size() == 1 &&
					segs[k].mBlock->mFalseJump->mTrueJump == segs[k].mBlock->mTrueJump &&
					segs[k].mBlock->mBranch == segs[0].mBlock->mBranch &&
					segs[k].mBlock->mIns[0].IsSame(segs[0].mBlock->mIns[0]))
					k++;

				if (k == segs.Size())
				{
					falseDetour = true;
				}

				if (trueDetour || falseDetour)
				{
					NativeCodeBasicBlock* dblock = nproc->AllocateBlock();
					NativeCodeBasicBlock* eblock = nproc->AllocateBlock();

					dblock->Close(segs[0].mBlock->mBranchIns, eblock, nullptr, ASMIT_JMP);
					if (trueDetour)
					{
						dblock->mIns.Push(segs[0].mBlock->mTrueJump->mIns[0]);
						nblock->Close(segs[0].mBlock->mBranchIns, dblock, eblock, segs[0].mBlock->mBranch);
					}
					else
					{
						dblock->mIns.Push(segs[0].mBlock->mFalseJump->mIns[0]);
						nblock->Close(segs[0].mBlock->mBranchIns, eblock, dblock, segs[0].mBlock->mBranch);
					}

					for (int i = 0; i < segs.Size(); i++)
					{
						SuffixSegment& s(segs[i]);
						if (trueDetour)
							segs[i].mBlock->mTrueJump = segs[i].mBlock->mFalseJump;
						segs[i].mBlock->mFalseJump = nullptr;
						segs[i].mBlock->mBranch = ASMIT_JMP;
						segs[i].mBlock->mTrueJump->mNumEntries--;
					}

					eblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS));
					if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP)
						nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR;
					else
						nblock->mIns.Remove(nblock->mIns.Size() - 1);

					mergeBlocks = true;
				}
			}

			NativeCodeBasicBlock* pblock = nullptr;
			int							pstart;
			for (int i = 0; i < segs.Size(); i++)
			{
				SuffixSegment& s(segs[i]);
//				printf("Seg %s,%d\n", segs[i].mBlock->mProc->mIdent->mString, segs[i].mBlock->mIndex);
				if (s.mBlock != pblock || s.mEnd <= pstart)
				{
					s.mBlock->mIns.Remove(s.mStart + 1, s.mEnd - s.mStart - 1);
					s.mBlock->mIns[s.mStart] = NativeCodeInstruction(s.mBlock->mIns[s.mStart].mIns, dojmp ? ASMIT_JMP : ASMIT_JSR, ASMIM_ABSOLUTE, 0, nproc->mLinkerObject);
					pblock = s.mBlock;
					pstart = s.mStart;
				}
			}

			mProcedures.Push(nproc);

			if (mergeBlocks)
			{
				ExpandingArray<NativeCodeProcedure *>	procs;

				for (int i = 0; i < segs.Size(); i++)
				{
					SuffixSegment& s(segs[i]);
					NativeCodeProcedure* p = s.mBlock->mProc;
					if (!procs.Contains(p))
					{
						procs.Push(p);
						p->ResetVisited();
						p->mEntryBlock->MergeBasicBlocks();
					}			
				}
			}

			numOutlines++;
			progress = true;
		}
#if 0
		if (!fopen_s(&f, "r:\\lsuffix.txt", "w"))
		{
			ltree->ParentPrint(f, mapper);
			fclose(f);
		}
#endif
		delete tree;
		mapper.Reset();

#if 0
		k++;
		if (k == 2)
			break;
#endif
	} while (progress);
}

void NativeCodeGenerator::BuildFunctionProxies(void)
{
	FunctionCall* cp = mFunctionCalls;
	while (cp)
	{
		ExpandingArray<FunctionCall*>	ocalls;

		FunctionCall* ncp = cp;
		while (ncp)
		{
			if (ncp->mCount == 1)
				ocalls.Push(ncp);
			ncp = ncp->mSame;
		}

		// Loop while we have unmatched calls
		while (ocalls.Size() > 1)
		{
			int i = 0;
			while (i < ocalls.Size())
			{
				int j = 0;
				while (j < ocalls.Size() && (i == j || ocalls[i]->PotentialMatches(ocalls[j]) == 0))
					j++;
				if (j == ocalls.Size())
					ocalls.Remove(i);
				else
					i++;
			}

			if (ocalls.Size() > 1)
			{
				// Find best matching pair
				int besti = 0, bestj = 0, bestm = 0;
				for (int i = 0; i < ocalls.Size(); i++)
				{
					for (int j = i + 1; j < ocalls.Size(); j++)
					{
						int m = ocalls[i]->PotentialMatches(ocalls[j]);
						if (m > bestm)
						{
							besti = i;
							bestj = j;
							bestm = m;
						}
					}
				}

				FunctionCall* fi = ocalls[besti], * fj = ocalls[bestj];

				ocalls.Remove(besti);

				for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
				{
					if (fi->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
					{
						if (!fi->mIns[i - BC_REG_WORK].IsSame(fj->mIns[i - BC_REG_WORK]))
						{
							fi->mIns[i - BC_REG_WORK].mType = ASMIT_INV;
						}
					}
				}

				int i = 0;
				while (i < ocalls.Size())
				{
					if (ocalls[i]->Matches(fi) > 0)
					{
						ocalls.Remove(i);
						fi->mCount++;
					}
					else
						i++;
				}
			}
		}

		ncp = cp;
		while (ncp)
		{
			if (ncp->mCount > 1)
			{
//				printf("RFC %s : %d\n", ncp->mLinkerObject->mIdent->mString, ncp->mCount);
				ncp->mProxyObject = mLinker->AddObject(ncp->mLinkerObject->mLocation, ncp->mLinkerObject->mIdent->Mangle("@proxy"), ncp->mLinkerObject->mSection, ncp->mLinkerObject->mType);

				ExpandingArray<uint8>				code;
				for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
				{
					NativeCodeInstruction& ins(ncp->mIns[i - BC_REG_WORK]);
					if (ins.mType == ASMIT_LDA)
					{
						switch (ins.mMode)
						{
						case ASMIM_IMMEDIATE:
							code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE]));
							code.Push(uint8(ins.mAddress));
							break;
						case ASMIM_ZERO_PAGE:
							code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ZERO_PAGE]));
							if (ins.mLinkerObject)
							{
								LinkerReference		rl;
								rl.mObject = ncp->mProxyObject;
								rl.mOffset = code.Size();

								rl.mRefObject = ins.mLinkerObject;
								rl.mRefOffset = ins.mAddress;
								rl.mFlags = LREF_LOWBYTE;

								ncp->mProxyObject->AddReference(rl);
								code.Push(0);
							}
							else
								code.Push(uint8(ins.mAddress));
							break;
						case ASMIM_IMMEDIATE_ADDRESS:
							code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE]));
							if (ins.mLinkerObject)
							{
								LinkerReference		rl;
								rl.mObject = ncp->mProxyObject;
								rl.mOffset = code.Size();
								rl.mFlags = 0;
								if (ins.mFlags & NCIF_LOWER)
									rl.mFlags |= LREF_LOWBYTE;
								if (ins.mFlags & NCIF_UPPER)
									rl.mFlags |= LREF_HIGHBYTE;
								rl.mRefObject = ins.mLinkerObject;
								rl.mRefOffset = ins.mAddress;

								ins.mLinkerObject->mFlags |= LOBJF_NO_CROSS;

								ncp->mProxyObject->AddReference(rl);
								code.Push(0);
							}
							else
								code.Push(uint8(ins.mAddress));
							break;
						case ASMIM_ABSOLUTE:
							if (ins.mLinkerObject && (ins.mLinkerObject->mFlags & LOBJF_ZEROPAGE))
							{
								code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ZERO_PAGE]));
								LinkerReference		rl;
								rl.mObject = ncp->mProxyObject;
								rl.mOffset = code.Size();

								rl.mRefObject = ins.mLinkerObject;
								rl.mRefOffset = ins.mAddress;
								rl.mFlags = LREF_LOWBYTE;

								ncp->mProxyObject->AddReference(rl);
								code.Push(0);
							}
							else
							{
								code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ABSOLUTE]));
								if (ins.mLinkerObject)
								{
									LinkerReference		rl;
									rl.mObject = ncp->mProxyObject;
									rl.mOffset = code.Size();
									rl.mRefObject = ins.mLinkerObject;
									rl.mRefOffset = ins.mAddress;
									rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
									ncp->mProxyObject->AddReference(rl);
									code.Push(0);
									code.Push(0);
								}
								else
								{
									code.Push(uint8(ins.mAddress & 0xff));
									code.Push(uint8(ins.mAddress >> 8));
								}
							}
							break;
						}
						code.Push(uint8(AsmInsOpcodes[ASMIT_STA][ASMIM_ZERO_PAGE]));
						code.Push(uint8(i));
					}
				}
				code.Push(uint8(AsmInsOpcodes[ASMIT_JMP][ASMIM_ABSOLUTE]));

				LinkerReference		rl;
				rl.mObject = ncp->mProxyObject;
				rl.mOffset = code.Size();
				rl.mRefObject = ncp->mLinkerObject;
				rl.mRefOffset = ncp->mOffset;
				rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
				ncp->mProxyObject->AddReference(rl);
				code.Push(0);
				code.Push(0);

				ncp->mProxyObject->AddData(&(code[0]), code.Size());
			}
			ncp = ncp->mSame;
		}
		cp = cp->mNext;
	}
}


void NativeCodeGenerator::RegisterRuntime(const Ident* ident, LinkerObject* object, int offset)
{
	Runtime	rt;
	rt.mIdent = ident;
	rt.mLinkerObject = object;
	rt.mOffset = offset;
	mRuntime.Push(rt);
}

bool NativeCodeGenerator::FunctionCall::IsSame(const FunctionCall* fc) const
{
	for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
		if (!mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
			return false;
	return true;
}

int NativeCodeGenerator::FunctionCall::Matches(const FunctionCall* fc) const
{
	int	match = 0;

	for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
	{
		if (fc->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
		{
			if (!mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
				return -1;
			match++;
		}
	}

	return match;
}

int  NativeCodeGenerator::FunctionCall::PotentialMatches(const FunctionCall* fc) const
{
	int	match = 0;

	for (int i = BC_REG_WORK; i < BC_REG_ACCU + 4; i++)
	{
		if (fc->mIns[i - BC_REG_WORK].mType != ASMIT_INV)
		{
			if (mIns[i - BC_REG_WORK].IsSame(fc->mIns[i - BC_REG_WORK]))
				match++;
		}
	}

	return match;
}

