// Generator.cpp: implementation of the CGenerator class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "archimedes.h"
#include "Generator.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// note, to invoke objdump from command line use
// objdump --target binary --architecture=i386 --disassemble-all dump.obj > dump.txt

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CGenerator::CGenerator()
{
	TRACE("construct CGenerator \n");
	defaultAreaSize = 1024;
}

CGenerator::~CGenerator()
{

}

//
// Takes a list of armlets forming a chunk, generates x86 code to
// represent them and passes that to the code cache
//

// ??? define wrapping function to call a native support function
void testInvokeWrapper()
{
	//codeCache.testInvoke();
}

void invokeIntCheck()
{
	// ARM.context.arg1;

	TRACE("invoke intcheck");
}

void CGenerator::generate(Armlet** aArmletChunk, int aTotalArmlets)
{
	armletChunk = aArmletChunk;
	totalArmlets = aTotalArmlets;

	// create array to hold armlet number to area address mapping
	armletNumberToAreaAddress = new uint32[totalArmlets];
	// create array to hold register allocations for each basic block
	basicBlockRA = new RegisterAllocation*[totalArmlets];
	// blank array, this won't be necessary if can test for NULL ???
	for(int eachArmlet = 0; eachArmlet<totalArmlets; eachArmlet++)
		basicBlockRA[eachArmlet] = NULL;

	// allocate an empty reg allocation for first armlet in chunk
	regAl = new RegisterAllocation;
	// record this as being my reg allocation
	basicBlockRA[0] = regAl;

	// set all constant pool values to invalid
	// and reg allocations to be in memory
	for(int varCounter = 0; varCounter<maxTemp; varCounter++)
	{
		constantValid[varCounter] = FALSE;
		regAl->varLocation[varCounter].location = locMEMORY;
	}
	for(int nativeReg=0; nativeReg<EDI; nativeReg++)
	{
		regAl->registerUse[nativeReg] = vUNUSED;
	}

	// create area to hold x86 code
	nativeChunk = new NativeChunk;
	// set up default values
	nativeChunk->area = (uint8*)malloc(defaultAreaSize);
	nativeChunk->allocatedSize = defaultAreaSize;
	nativeChunk->amountUsed = 0;

	// create linked list for forward-referencing-gotos to be backpatched
	gotoPatchList = new CLinkedList();


	// for each armlet choose rule and generate code into code area
	for(armletCounter=0; armletCounter<totalArmlets; armletCounter++)
	{		

		// if this instruction is the start of a new basic block
		if(armletChunk[armletCounter]->leader)
		{	
			// ??? 000
			
			// check for predefined reg allocation
			if(basicBlockRA[armletCounter] == NULL)
			{
				// if no predefined reg allocation

				// make copy of previous armlets reg allocation for this basic block
				regAl = copyRegisterAllocation(regAl);
				basicBlockRA[armletCounter] = regAl;
			}
			else
			{
				// there is a predefined reg allocation created by a branch
				// forward to this armlet (or by first armlet initialisation)

				// need to spill regs from armlet that comes before this one
				// and set up new regs in it's place (check it's not first armlet
				// though as there is no current reg al to spill then) if first
				// armlet just use the regAl there since it's just been
				// defined empty
				if(armletCounter > 0)
					allocateRegAllocation( regAl, basicBlockRA[armletCounter] );
			}
			

			

			// ??? unnecessary to shed constant pool to code
			shedConstantPool();

		}
		
		// ??? debugging
		CArmletDisassembler diss;
		TRACE("generating code @ 0x%x: %s \n", nativeChunk->amountUsed, diss.disassemble(armletCounter, armletChunk[armletCounter]) );

		// keep record of where the armlet starts in the code area
		armletNumberToAreaAddress[armletCounter] = nativeChunk->amountUsed;

		// choose rule for generating single armlet
		chooseRule(armletChunk[armletCounter]);

	}

	// backpatch list of forward referencing gotos
	while( !gotoPatchList->empty() )
	{
		// take next goto reference
		GotoBackpatch* patch = (GotoBackpatch*)gotoPatchList->removeHead();
		// get address that goto points to
		uint32 destination = armletNumberToAreaAddress[patch->armletNumber];
		// calculate offset
		// add 6 for the bytes taken up by the JMP instruction since
		// the x86 PC points to the location after the JMP instruction
		uint32 offset = destination - (patch->gotoPtr + 6);

		TRACE("backpatching: patch->gotoPtr=%d, destination=%d, offset=%d \n", patch->gotoPtr, destination, offset);

		// skip 2 bytes for opcode and fill in values, low bytes first
		nativeChunk->area[ patch->gotoPtr + 2 ] = offset       & 0xff;
		nativeChunk->area[ patch->gotoPtr + 3 ] = (offset>>8)  & 0xff;
		nativeChunk->area[ patch->gotoPtr + 4 ] = (offset>>16) & 0xff;
		nativeChunk->area[ patch->gotoPtr + 5 ] = (offset>>24) & 0xff;
	}
	
	// add native code to code cache
	//codeCache.addCodeToCache(address, nativeChunk);

	// dump area to file
	CFile dumpFile;
	CString dumpName = _T("D:\\Work\\Project\\dump.obj");
	BOOL successfulDumpOpen = dumpFile.Open(
		dumpName,
		CFile::modeCreate		|
		CFile::modeWrite		|
		CFile::shareDenyWrite	|
		CFile::typeBinary
		);
	if( successfulDumpOpen )
	{
		dumpFile.Write(nativeChunk->area, nativeChunk->amountUsed);
		dumpFile.Close();

		// invoke external x86 disassembler
		system("D:\\work\\project\\objdump --target binary --architecture=i386 --disassemble-all D:\\work\\project\\dump.obj > D:\\work\\project\\x86dump.txt");
	}
	else
	{
		TRACE("Dump file %s could not be opened \n", dumpName);
	}

	// clean up
	delete []armletNumberToAreaAddress;
	gotoPatchList->clear();
}

//
// Chooses the rule to translate a given armlet into x86
//

void CGenerator::chooseRule(Armlet* armlet)
{

	switch(armlet->opcode)
	{
	
		// no operands

		case irCLEARTRANS	: chooseClearTrans(armlet); break;
		case irSETTRANS		: chooseSetTrans(armlet); break;
		case irSETPC		: chooseSetPC(armlet); break;

		// one variable and one value operand, emit1()
		
		case irMOVC			: chooseMovc(armlet); break;
		case irGETPC		: chooseGetPC(armlet); break;
		case irINTCHECK		: chooseIntCheck(armlet); break;
		
		// two variable operands, emit2()
		
		case irMOV			: chooseMov(armlet); break;
		case irMVN			: chooseMvn(armlet); break;
		case irTST			: chooseTst(armlet); break;
		case irTEQ			: chooseTeq(armlet); break;
		case irCMP			: chooseCmp(armlet); break;
		case irCMN			: chooseCmn(armlet); break;
		case irRRX			: chooseRrx(armlet); break;

		// three variable operands, emit3()
		
		case irAND			: chooseAnd(armlet); break;
		case irEOR			: chooseEor(armlet); break;
		case irSUB			: chooseSub(armlet); break;
		case irADD			: chooseAdd(armlet); break;
		case irADC			: chooseAdc(armlet); break;
		case irSBC			: chooseSbc(armlet); break;
		case irORR			: chooseOrr(armlet); break;
		case irLSL			: chooseLsl(armlet); break;
		case irLSR			: chooseLsr(armlet); break;
		case irASR			: chooseAsr(armlet); break;
		case irROR			: chooseRor(armlet); break;
		case irMUL			: chooseMul(armlet); break;
		case irLDB			: chooseLdb(armlet); break;
		case irSTB			: chooseStb(armlet); break;
		case irLDW			: chooseLdw(armlet); break;
		case irSTW			: chooseStw(armlet); break;

		// one value operand, emitV()
		
		case irGOTOEQ		: chooseGoto(armlet, irGOTOEQ - irGOTOEQ); break;
		case irGOTONE		: chooseGoto(armlet, irGOTONE - irGOTOEQ); break;
		case irGOTOCS		: chooseGoto(armlet, irGOTOCS - irGOTOEQ); break;
		case irGOTOCC		: chooseGoto(armlet, irGOTOCC - irGOTOEQ); break;
		case irGOTOMI		: chooseGoto(armlet, irGOTOMI - irGOTOEQ); break;
		case irGOTOPL		: chooseGoto(armlet, irGOTOPL - irGOTOEQ); break;
		case irGOTOVS		: chooseGoto(armlet, irGOTOVS - irGOTOEQ); break;
		case irGOTOVC		: chooseGoto(armlet, irGOTOVC - irGOTOEQ); break;
		case irGOTOHI		: chooseGoto(armlet, irGOTOHI - irGOTOEQ); break;
		case irGOTOLS		: chooseGoto(armlet, irGOTOLS - irGOTOEQ); break;
		case irGOTOGE		: chooseGoto(armlet, irGOTOGE - irGOTOEQ); break;
		case irGOTOLT		: chooseGoto(armlet, irGOTOLT - irGOTOEQ); break;
		case irGOTOGT		: chooseGoto(armlet, irGOTOGT - irGOTOEQ); break;
		case irGOTOLE		: chooseGoto(armlet, irGOTOLE - irGOTOEQ); break; 
		case irGOTO			: chooseGoto(armlet, irGOTO - irGOTOEQ); break;
		case irLEAVE		: chooseLeave(armlet); break;
		
		default: TRACE("ERROR chooseRule() unable to decode armlet opcode 0x%x \n", armlet->opcode);
	}
}

void CGenerator::chooseClearTrans(Armlet *armlet)
{

}

void CGenerator::chooseSetTrans(Armlet *armlet)
{

}

void CGenerator::chooseSetPC(Armlet *armlet)
{

}

void CGenerator::chooseMovc(Armlet *armlet)
{
	// add value to constant pool

	if(armlet->outflags)
	{
		// ??? debugging
		TRACE("ERROR movc shouldn't be setting any outflags! opcode=0x%x \n", armlet->opcode );
	}
	else
	{

		// ??? if variable is not an ARM processor flag since these are
		// made use of implicitly so must be updated eagerly
		// then can use lazy updating with constant pool
		addConstant(armlet->rd, armlet->value);
		TRACE("constant pool addition: v%d = 0x%x \n", armlet->rd, armlet->value );
	}
}

void CGenerator::chooseGetPC(Armlet *armlet)
{

}

void CGenerator::chooseIntCheck(Armlet *armlet)
{
	// generate code to call int check function

	// note
	// address of returnVal context[194]
	// address of arg1 = context[198]
	// address of arg2 = context[202]

	//  preflags

	preFlags(armlet->outflags, MOVdef | MOVundef | CALLdef | CALLundef );

	// put intcheck argument into arg1 in context
	int mod = mod_DISP32;
	uint32 disp = 198; // arg1 address
	uint8 rm = EBP;
	uint32 imm = armlet->value;
	#define MODSIBDISP MODDISP32
	assemble(0, MOVlmi, 0);
	#undef MODSIBDISP

	// allocate success variable for putting address of
	// invokeIntCheck() into and call intcheck function
	imm = (uint32)&invokeIntCheck;
	uint8 successVarReg = getVariableInRegister(armlet->rd);
	rm = successVarReg;
	assemble(0, MOVlri, CALLnar, 0);

	// move result from memory in context.returnVal into success variable
	mod = mod_DISP32;
	disp = 194; // returnVal address
	rm = EBP;
	int reg = successVarReg;
	#define MODSIBDISP MODDISP32
	assemble(0, MOVlrm, 0);
	#undef MODSIBDISP

	// postflags
	preFlags(armlet->outflags, MOVundef | CALLundef );

}

void CGenerator::chooseMov(Armlet *armlet)
{

	CArmletDisassembler diss;
	TRACE("actually generating %s \n", diss.disassemble(armletCounter, armlet) );

	if(constantValid[armlet->rx])
	{
		// mov ra, #
		if(armlet->outflags)
		{
			// ??? flags need setting
		}
		else
		{
			// update constant pool
			constantPool[armlet->rd] = constantPool[armlet->rx];
			constantValid[armlet->rd] = TRUE;
		}
	}
	else
	{
		if(armlet->rd == armlet->rx)
		{
			// mov ra, ra
			if(armlet->outflags)
			{
				genMov1(armlet);
			}
			else
			{
				// ??? generate a nop placeholder (mov r0,r0 is the recommended
				// nop on ARM) so that if an instruction were to branch
				// to the mov, there is something to go to, need to investigate
				// the use of nops in real ARM code.
				assemble(0, NOP, 0);
			}
		}
		else
		{

			// mov ra, rb
			genMov1(armlet);
		}
	}
}

void CGenerator::chooseMvn(Armlet *armlet)
{

}

void CGenerator::chooseTst(Armlet *armlet)
{

}

void CGenerator::chooseTeq(Armlet *armlet)
{

}

void CGenerator::chooseCmp(Armlet *armlet)
{

	// ??? same for CMP,CMN,TEQ,TST
	
	if(constantValid[armlet->rx])
	{
		if(constantValid[armlet->ry])
		{
			// cmp #,#
			// ??? set flags
			return;
		}
		else
		{
			// cmp #,ra
			return;
		}
	}
	else
	{
		if(constantValid[armlet->ry])
		{
			// cmp ra, #
			genCmp2(armlet);
			return;
		}
	}
	
	if(armlet->rx == armlet->ry)
	{
		// cmp ra, ra
	}
	else
	{
		// cmp ra, rb
		genCmp1(armlet);
	}
	
}

void CGenerator::chooseCmn(Armlet *armlet)
{

}

void CGenerator::chooseRrx(Armlet *armlet)
{

}

void CGenerator::chooseAnd(Armlet *armlet)
{

}

void CGenerator::chooseEor(Armlet *armlet)
{

}

void CGenerator::chooseSub(Armlet *armlet)
{
	// ??? similar for SBC?

	if(constantValid[armlet->rx])
	{
		if(constantValid[armlet->ry])
		{
			// sub ra # #  4
		}
		else
		{
			// sub ra # ra 3
			// sub ra # rb 3
		}
	}
	else
	{
		if(armlet->rd == armlet->rx)
		{
			if(constantValid[armlet->ry])
			{
				// sub ra ra #  2
			}
			else
			{
				// sub ra ra ra 1
				// sub ra ra rb 1

				genSub1(armlet);
			}			
		}
		else
		{
			if(constantValid[armlet->ry])
			{
				// sub ra rb #  5
			}
			else
			{
				// sub ra rb rb 6
				// sub ra rb ra 6
				// sub ra rb rc 6
				genSub6(armlet);
			}
		}	
	}
}

void CGenerator::chooseAdd(Armlet *armlet)
{
	// ??? apply to and, or, eor too!

	// check for constants
	if(constantValid[armlet->rx])
	{
		if(constantValid[armlet->ry])
		{
			// add ra # #

			// put value in constant pool
			switch(armlet->opcode)
			{
				// ??? also ADC but can't be constant eval'd since C flag is not constant!
				case irADD	: constantPool[armlet->rd] = constantPool[armlet->rx] + constantPool[armlet->ry]; break;
				case irEOR	: constantPool[armlet->rd] = constantPool[armlet->rx] ^ constantPool[armlet->ry]; break;
				case irORR	: constantPool[armlet->rd] = constantPool[armlet->rx] | constantPool[armlet->ry]; break;
				case irAND	: constantPool[armlet->rd] = constantPool[armlet->rx] & constantPool[armlet->ry]; break;
			}
			constantValid[armlet->rd] = TRUE;

			// if any flags to be set then must calculate them too
			if(armlet->outflags)
			{
				// switch on operation as logic stuff just does N and Z
				switch(armlet->opcode)
				{
					case irADD					: updateAddFlags(armlet->rd, armlet->rx, armlet->ry); break;
					case irEOR					: // fall through to irAND
					case irORR					: // fall through to irORR
					case irAND					: updateNZFlags(armlet->rd); break;
					default						: TRACE("ERROR, bad opcode being used in chooseAdd \n"); break;
				}
			}
			return;
		}
		else
		{
			if(armlet->rd == armlet->ry)
			{
				// add ra # ra (same as add ra ra #)
				// ??? complete switch table
				switch(armlet->opcode)
				{
					case irADD : genAdd1(armlet, constantPool[armlet->rx]); break;
				}
			}
			else
			{
				// add ra # rb (same as add ra rb #)
				switch(armlet->opcode)
				{
					case irADD : genAdd2(armlet, armlet->ry, constantPool[armlet->rx]); break;
				}
			}
			return;
		}
	}
	if(constantValid[armlet->ry])
	{
		if(armlet->rd == armlet->rx)
		{
			// add ra ra #
			// ??? complete switch table
			switch(armlet->opcode)
			{
				case irADD : genAdd1(armlet, constantPool[armlet->ry]); break;
			}
		}
		else
		{
			// add ra rb #
			// ??? complete switch table
			switch(armlet->opcode)
			{
				case irADD : genAdd2(armlet, armlet->rx, constantPool[armlet->ry]); break;
			}
		}
		return;
	}

	if(armlet->rd == armlet->rx)
	{
		// add ra ra ra
		// add ra ra rb
		genAdd3(armlet, armlet->rd, armlet->ry);
		return;
	}
	else
	{
		if(armlet->rd == armlet->ry)
		{
			// add ra rb ra (same as add ra ra rb)
			genAdd3(armlet, armlet->rd, armlet->rx);
			return;
		}
		else
		{
			if(armlet->rx == armlet->ry)
			{
				// add ra rb rb
				genAdd4(armlet, armlet->rx, armlet->rx); 
			}
			else
			{
				// add ra rb rc
				genAdd4(armlet, armlet->rx, armlet->ry);
			}
		}
	}
}

void CGenerator::chooseAdc(Armlet *armlet)
{

}

void CGenerator::chooseSbc(Armlet *armlet)
{

}

void CGenerator::chooseOrr(Armlet *armlet)
{

}

void CGenerator::chooseLsl(Armlet *armlet)
{

}

void CGenerator::chooseLsr(Armlet *armlet)
{

}

void CGenerator::chooseAsr(Armlet *armlet)
{

}

void CGenerator::chooseRor(Armlet *armlet)
{

}

void CGenerator::chooseMul(Armlet *armlet)
{

}

void CGenerator::chooseLdb(Armlet *armlet)
{

}

void CGenerator::chooseStb(Armlet *armlet)
{

}

void CGenerator::chooseLdw(Armlet *armlet)
{

}

void CGenerator::chooseStw(Armlet *armlet)
{

}

void CGenerator::chooseGoto(Armlet *armlet, uint8 conditionCode)
{
	// end of basic block so:
	// ??? shed unused constant pool values to code since may be used in this basic block
	// ??? would be best if the constant pool were shed direct to memory (where suitable)
	// in this situation since the basic block has ended, some vars will be left in regs
	// though so not suitable for all to be shed direct to memory if I do that
	shedConstantPool();

	// deal with reg allocation ready for the goto's destination
	regAllocateChangeBlock(armlet);

	// see if goto is forward/backward
	if(armlet->value <= armletCounter)
	{
		// goto to before this instruction

		// ??? pre flags
		preFlags(armlet->outflags, Jdef | Jundef);

		// get relative address
		// note, x86 PC appears to point to after jump so +6 for number of bytes in jmp instruction
		uint32 disp = armletNumberToAreaAddress[armlet->value] - (nativeChunk->amountUsed + 6);
		
		switch(conditionCode)
		{
			case ccEQ		: assemble(0, JZnr, 0); break;
			case ccNE		: assemble(0, JNZnr, 0); break;
			case ccCS		: assemble(0, JCnr, 0); break;
			case ccCC		: assemble(0, JNCnr, 0); break;
			case ccMI		: assemble(0, JSnr, 0); break;
			case ccPL		: assemble(0, JNSnr, 0); break;
			case ccVS		: assemble(0, JOnr, 0); break;
			case ccVC		: assemble(0, JNOnr, 0); break;
			case ccHI		: assemble(0, JAnr, 0); break;
			case ccLS		: assemble(0, JBEnr, 0); break;
			case ccGE		: assemble(0, JGEnr, 0); break;
			case ccLT		: assemble(0, JLnr, 0); break;
			case ccGT		: assemble(0, JGnr, 0); break;
			case ccLE		: assemble(0, JLEnr, 0); break;
			case ccAL		: assemble(0, JMPnr, 0); break;
		}

		// ??? post flags
		postFlags(armlet->outflags, Jundef, 0);
	}
	else
	{
		// goto to this instruction or afterward

		preFlags(armlet->outflags, Jdef | Jundef);

		// get relative address
		uint32 disp = 0;

		// store reference to this goto for backpatching
		GotoBackpatch* patch = new GotoBackpatch;
		patch->armletNumber = armlet->value;
		patch->gotoPtr = (uint32)nativeChunk->amountUsed;
		gotoPatchList->addToTail(patch);
		
		// ??? debugging
		TRACE("add to list forwardref nativeChunk->amountUsed=%d armletNumber=%d \n", nativeChunk->amountUsed, armlet->value);
		
		switch(conditionCode)
		{
			case ccEQ		: assemble(0, JZnr, 0); break;
			case ccNE		: assemble(0, JNZnr, 0); break;
			case ccCS		: assemble(0, JCnr, 0); break;
			case ccCC		: assemble(0, JNCnr, 0); break;
			case ccMI		: assemble(0, JSnr, 0); break;
			case ccPL		: assemble(0, JNSnr, 0); break;
			case ccVS		: assemble(0, JOnr, 0); break;
			case ccVC		: assemble(0, JNOnr, 0); break;
			case ccHI		: assemble(0, JAnr, 0); break;
			case ccLS		: assemble(0, JBEnr, 0); break;
			case ccGE		: assemble(0, JGEnr, 0); break;
			case ccLT		: assemble(0, JLnr, 0); break;
			case ccGT		: assemble(0, JGnr, 0); break;
			case ccLE		: assemble(0, JLEnr, 0); break;
			case ccAL		: assemble(0, JMPnr, 0); break;
		}

		// ??? post flags
		postFlags(armlet->outflags, Jundef, 0);
	}
}

void CGenerator::chooseLeave(Armlet *armlet)
{
	// end of basic block so:
	// shed unused constant pool values to code since may be used in this basic block
	shedConstantPool();

	// ??? spill all regs to memory
	spillAll();

	// ???  preflagging is likely to be unnecessary if everything has
	// just been spilt to memory
	preFlags(armlet->outflags, MOVdef | MOVundef);

	// move leave argument to EAX to return it
	{
	uint8 rm = EAX;
	uint32 imm = armlet->value;
	assemble(0, MOVlri, 0);
	}

	// return
	assemble(0, RET, 0);
}

//
// Assemble x86 instruction (variable argument list function)
// Based on work done by Julian Brown in ARMphetamine
//

void CGenerator::assemble(const int wasteArgument, ... )
{
	// note, variable argument list functions must have at least 1 argument
	// that is always passed to them for them to work, hence wasted argument

	// set up ptr to point to arguments
	va_list ptr;
	va_start(ptr, wasteArgument);

	int bit = 0;
	int numBits;	// total number of bits in this argument
	int value;

	// clear first byte in instruction (since later clearing is done at end of loop)
	nativeChunk->area[nativeChunk->amountUsed] = 0;

	// while there are more arguments to get (terminate list with 0)
	while( numBits = va_arg(ptr, uint8) )
	{
		// new byte then clear it???	
		if(!bit)
			nativeChunk->area[nativeChunk->amountUsed] = 0;

		// get value of argument
		value = va_arg(ptr, uint32); 
		
		// while there are still bits to output
		while(numBits > 0)
		{

			// calculate how many bits of the value are to be output this time
			uint8 chunk;
			if(numBits > 8)
				chunk = 8;
			else
				chunk = numBits;

			// ??? debugging
			// TRACE("asm: numBits=%d, chunk=%d, value=0x%x nativeChunk->amountUsed=%d \n", numBits, chunk, value, nativeChunk->amountUsed);

			// set the bits
			nativeChunk->area[nativeChunk->amountUsed] |= ((value << bit) & 0xff);

			// update details of what's been output already
			bit += chunk;
			value >>= chunk;
			numBits -= chunk;

			// if over into next byte, increment area index
			if( bit >= 8)
			{
				bit -= 8;
				nativeChunk->amountUsed++;
				// when moving on to next byte, clear it
				nativeChunk->area[nativeChunk->amountUsed] = 0;
				// if area is full, double the area size
				if(nativeChunk->amountUsed == nativeChunk->allocatedSize)
				{
					nativeChunk->allocatedSize *= 2;
					nativeChunk->area = (uint8*)realloc(nativeChunk->area, nativeChunk->allocatedSize);
				}
			}
		}
	
	}
	// end of variable argument list
	va_end(ptr);

	if(bit)
		TRACE("Instruction that didn't fit into byte output! \n");
}


void CGenerator::setCodeCache(CCodeCache *aCodeCache)
{
	// codeCache = aCodeCache;
}



//////////////////////////////////////////////////////////////////////
// Actual code generation functions
//////////////////////////////////////////////////////////////////////

//
// updates the N and Z flags according to the constant value
//

inline void CGenerator::updateNZFlags(uint32 value)
{
	/*
	clearConditionFlags( N_FLAG | Z_FLAG );
	
	// check N and Z flags
	if(value == 0)
	{
		setConditionFlags(Z_FLAG);
	}
	else 
	{
		if( getNegative(value) )
		{
			setConditionFlags(N_FLAG);
		}
	}
	*/
}

//
// updates NZCV flags for subtractions according to constant values
//

inline void CGenerator::updateSubFlags(uint32 result, uint32 operand1, uint32 operand2)
{
	/*
	// all flags need adjusting
	clearConditionFlags( N_FLAG | Z_FLAG | C_FLAG | V_FLAG );

	// carry flag - calculate if there was NOT a borrow from the subtraction
	// logic borrowed from ArcEm, incidentally the same as ARMphetamine and RedSquirrel
	if( ( getNegative(operand1)  && getPositive(operand2) ) ||
		( getNegative(operand1)  && getPositive(result)   ) ||
		( getPositive(operand2) && getPositive(result)    ) )
	{
		setConditionFlags(C_FLAG);
	}

	// if need to set V flag
	if( ( getNegative(operand1) && getPositive(operand2) && getPositive(result) ) ||
		( getPositive(operand1) && getNegative(operand2) && getNegative(result) ) )
	{
		setConditionFlags(V_FLAG);
	}

	// check N and Z flags
	if(result == 0)
	{
		setConditionFlags(Z_FLAG);
	}
	else 
	{
		if( getNegative(result) )
		{
			setConditionFlags(N_FLAG);
		}
	}
	*/
}

//
// updates NZCV flags for additions according to constant values
//

inline void CGenerator::updateAddFlags(uint32 result, uint32 operand1, uint32 operand2)
{
	/*
	// all flags need adjusting
	clearConditionFlags( N_FLAG | Z_FLAG | C_FLAG | V_FLAG );

	// check if C or V can possibly need updating
	if( (operand1 | operand2) >> 30)
	{
		// logic borrowed from ArcEm, incidentally the same as ARMphetamine and RedSquirrel

		// update carry
		if( ( getNegative(operand1) && getNegative(operand2) ) ||
			( getNegative(operand1) && getPositive(result) )   ||
			( getNegative(operand2) && getPositive(result) )   )
		{
			setConditionFlags( C_FLAG );
		}

		// update overflow
		if( ( getNegative(operand1) && getNegative(operand2) && getPositive(result) ) ||
			( getPositive(operand1) && getPositive(operand2) && getNegative(result) ) )
		{
			setConditionFlags( V_FLAG );
		}
	}

	// check N and Z flags
	if(result == 0)
	{
		setConditionFlags(Z_FLAG);
	}
	else 
	{
		if( getNegative(result) )
		{
			setConditionFlags(N_FLAG);
		}
	}
	*/
}


//
// takes an armlet variable and returns an x86 register that's allocated to it
// the x86 reg does not (necessarily) contain the value for that variable
// this is used for getting a register for instruction destinations.
// spill contents of x86 reg before hand if necessary
//

uint8 CGenerator::getVariableInRegister(uint8 variable)
{

	// ??? debugging
	TRACE("getVariableInRegister variable=%d regAl->varLocation[variable].location=%d \n", variable, regAl->varLocation[variable].location);

	// if variable is in a register already
	if( regAl->varLocation[variable].location == locNATIVEREGISTER)
	{
		// return that register
		return regAl->varLocation[variable].reg;
	}
	else
	{
	
		// search through native regs to find one that's unused
		for(int nativeReg = 0; nativeReg<EDI; nativeReg++)
		{
			if( regAl->registerUse[nativeReg] == vUNUSED )
			{
				// found one that's unused so set up details
				regAl->registerUse[nativeReg] = variable;
				regAl->varLocation[variable].location = locNATIVEREGISTER;
				regAl->varLocation[variable].reg = nativeReg;
				// return value
				return nativeReg;
			}
		}
		
		// all native regs are used, so we must spill one

		// define array detailing which x86 register allocations are used locally
		int usedLocally[EDI];
		for(int localReg = 0; localReg<EDI; localReg++)
		{
			usedLocally[localReg] = 0;
		}
		// scan vars used in this armlet and mark in usedLocally
		if( regAl->varLocation[ armletChunk[armletCounter]->rd ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->rd ]+=3;
		if( regAl->varLocation[ armletChunk[armletCounter]->rx ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->rx ]+=2;
		if( regAl->varLocation[ armletChunk[armletCounter]->ry ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->ry ]+=2;
		// do the same for the following armlet (if there is one)
		if(armletCounter + 1 < totalArmlets)
		{
			if( regAl->varLocation[ armletChunk[armletCounter+1]->rd ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->rd ]+=2;
			if( regAl->varLocation[ armletChunk[armletCounter+1]->rx ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->rx ]++;
			if( regAl->varLocation[ armletChunk[armletCounter+1]->ry ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->ry ]++;
		}
		// find first reg that's not used in this armlet nor next one
		// then find first reg not used in this armlet
		// then just find first reg
		int position = 0;
		while(position < 3)
		{
			for(int selectedReg = 0; selectedReg < EDI; selectedReg++)
			{
				if(usedLocally[selectedReg] == position)
				{
					// find out what armlet var was in that x86 reg
					uint8 displacedVariable = regAl->registerUse[selectedReg];

					// spill to memory
					int mod = mod_DISP32;
					int disp = getVariableOffset(displacedVariable);
					int rm = EBP;
					int reg = selectedReg;
					#define MODSIBDISP MODDISP32
					if(displacedVariable>= vNFLAG && displacedVariable <= vFFLAG)
						assemble(0, MOVbmr, 0);
					else
						assemble(0, MOVlmr, 0);
					#undef MODSIBDISP

					regAl->varLocation[ displacedVariable ].location = locMEMORY;

					// found suitable reg to spill
					regAl->registerUse[selectedReg] = variable;
					regAl->varLocation[variable].location = locNATIVEREGISTER;
					regAl->varLocation[variable].reg = selectedReg;
					// return value
					return selectedReg;
				}
			}
			// look for registers closer to current armlet
			position++;
		}

		// it must have found a register by now
		TRACE("ERROR - no x86 reg found to spill to! \n");
		return 0;
	}
}

//
// Same as getVariableInRegister except fetches value from memory into
// native register if it's not in one already
//

uint8 CGenerator::putVariableInRegister(uint8 variable)
{

	// this is the same as getVariableInRegister except that
	// when a register has to be allocated (i.e. the variable wasn't
	// already in a register) the variable value is loaded into that register

	// if variable is in a register already
	if( regAl->varLocation[variable].location == locNATIVEREGISTER)
	{
		// return that register
		return regAl->varLocation[variable].reg;
	}
	else
	{
	
		// search through native regs to find one that's unused
		for(int nativeReg = 0; nativeReg<EDI; nativeReg++)
		{
			if( regAl->registerUse[nativeReg] == vUNUSED )
			{
				// found one that's unused so set up details
				regAl->registerUse[nativeReg] = variable;
				regAl->varLocation[variable].location = locNATIVEREGISTER;
				regAl->varLocation[variable].reg = nativeReg;

				// fetch variable from memory
				int mod = mod_DISP32;
				int disp = getVariableOffset(variable);
				int rm = EBP;
				int reg = nativeReg;
				#define MODSIBDISP MODDISP32
				if(variable>= vNFLAG && variable <= vFFLAG)
					assemble(0, MOVZXlrbm, 0);
				else
					assemble(0, MOVlrm, 0);
				#undef MODSIBDISP

				// return register used
				return nativeReg;
			}
		}
		
		// all native regs are used, so we must spill one

		// define array detailing which x86 register allocations are used locally
		int usedLocally[EDI];
		for(int localReg = 0; localReg<EDI; localReg++)
		{
			usedLocally[localReg] = 0;
		}
		// scan vars used in this armlet and mark in usedLocally
		if( regAl->varLocation[ armletChunk[armletCounter]->rd ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->rd ]+=3;
		if( regAl->varLocation[ armletChunk[armletCounter]->rx ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->rx ]+=2;
		if( regAl->varLocation[ armletChunk[armletCounter]->ry ].location == locNATIVEREGISTER )
			usedLocally[ armletChunk[armletCounter]->ry ]+=2;
		// do the same for the following armlet (if there is one)
		if(armletCounter + 1 < totalArmlets)
		{
			if( regAl->varLocation[ armletChunk[armletCounter+1]->rd ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->rd ]+=2;
			if( regAl->varLocation[ armletChunk[armletCounter+1]->rx ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->rx ]++;
			if( regAl->varLocation[ armletChunk[armletCounter+1]->ry ].location == locNATIVEREGISTER )
				usedLocally[ armletChunk[armletCounter+1]->ry ]++;
		}
		// find first reg that's not used in this armlet nor next one
		// then find first reg not used in this armlet
		// then just find first reg
		int position = 0;
		while(position < 3)
		{
			for(int selectedReg = 0; selectedReg < EDI; selectedReg++)
			{
				if(usedLocally[selectedReg] == position)
				{
					// find out what armlet var was in that x86 reg
					uint8 displacedVariable = regAl->registerUse[selectedReg];

					// spill to memory
					int mod = mod_DISP8;
					int disp = getVariableOffset(displacedVariable);
					int rm = EBP;
					int reg = selectedReg;
					#define MODSIBDISP MODDISP8
					if(displacedVariable>= vNFLAG && displacedVariable <= vFFLAG)
						assemble(0, MOVbmr, 0);
					else
						assemble(0, MOVlmr, 0);
					#undef MODSIBDISP

					regAl->varLocation[ displacedVariable ].location = locMEMORY;

					// found suitable reg to spill
					regAl->registerUse[selectedReg] = variable;
					regAl->varLocation[variable].location = locNATIVEREGISTER;
					regAl->varLocation[variable].reg = selectedReg;

					// fetch variable from memory
					mod = mod_DISP8;
					disp = getVariableOffset(variable);
					rm = EBP;
					reg = selectedReg;
					#define MODSIBDISP MODDISP8
					if(displacedVariable>= vNFLAG && displacedVariable <= vFFLAG)
						assemble(0, MOVZXlrbm, 0);
					else
						assemble(0, MOVlrm, 0);
					#undef MODSIBDISP

					// return value
					return selectedReg;
				}
			}
			// look for registers closer to current armlet
			position++;
		}

		// it must have found a register by now
		TRACE("ERROR - no x86 reg found to spill to! \n");
		return 0;
	}
}

//
// return offset (in bytes) from base of context to the armlet variable specified
//

uint8 CGenerator::getVariableOffset(uint8 variable)
{
	// has to deal with fact that flags are stored in bytes
	// (for easy access from native flags)
	if(variable < vNFLAG)
	{
		return 4*variable;
	}
	else
	{
		if(variable < vUNUSED)
		{
			return (4*vPC) + (variable - vPC);
		}
		else
		{
			return (4*vPC) + 7 + (4* (variable - vT0) );
		}
	}
}

//
// ARM flags are kept in x86 flags most of the time except if an
// instruction is going to change them differently to the way the
// ARM instruction would in which case they are spilled to memory
// in advance.
// 

void CGenerator::preFlags(uint8 outflags, uint8 nativeChanged)
{
	// find out which flags the x86 instruction changes but
	// the ARM one doesn't (hence which ones need spilling)
	uint32 spillFlags = nativeChanged & ~outflags;

	// for each flag, check if it's to be spilt and check if it's in
	// the native flag. It could be in native reg or memory already
	// in which case we don't need to spill it

	int mod = mod_DISP8;

	// N flag
	if( (spillFlags & fN) && (regAl->varLocation[vNFLAG].location = locNATIVEFLAG) )
	{
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(vNFLAG);
		#define MODSIBDISP MODDISP8
		assemble(0, SETSm, 0);
		#undef MODSIBDISP
		regAl->varLocation[vNFLAG].location = locMEMORY;
	}

	// Z flag
	if( (spillFlags & fZ) && (regAl->varLocation[vZFLAG].location = locNATIVEFLAG) )
	{
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(vZFLAG);
		#define MODSIBDISP MODDISP8
		assemble(0, SETZm, 0);
		#undef MODSIBDISP
		regAl->varLocation[vZFLAG].location = locMEMORY;
	}

	// C flag
	if( (spillFlags & fC) && (regAl->varLocation[vCFLAG].location = locNATIVEFLAG) )
	{
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(vCFLAG);
		#define MODSIBDISP MODDISP8
		assemble(0, SETCm, 0);
		#undef MODSIBDISP
		regAl->varLocation[vCFLAG].location = locMEMORY;
	}

	// V flag
	if( (spillFlags & fV) && (regAl->varLocation[vVFLAG].location = locNATIVEFLAG) )
	{
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(vVFLAG);
		#define MODSIBDISP MODDISP8
		assemble(0, SETOm, 0);
		#undef MODSIBDISP
		regAl->varLocation[vVFLAG].location = locMEMORY;
	}
}

//
// flags that the x86 instruction changed but the ARM one doesn't are
// restored to ARM values from memory. Any flags that the ARM one changes
// but the x86 one doesn't are also updated.
//

void CGenerator::postFlags(uint8 outflags, uint8 nativeChanged, uint8 destReg)
{
	// if cmp, sbb or sub then inverts C flag

	// if N and Z weren't updated by the x86 command (e.g. MOV) and they
	// should be because the ARM instruction was MOVS then use TEST to do work
	if( (outflags & (fN|fZ)) && !(nativeChanged & fN) && !(nativeChanged | fZ) )
	{
		uint32 imm = 0;
		uint8 rm = destReg;
		preFlags(TESTdef, TESTdef|TESTundef);
		assemble(0, TESTlri, 0);
		nativeChanged |= (fN|fZ);
	}

	// update info on where flags are stored according to which ones have changed
	nativeChanged &= outflags;
	if(nativeChanged & fN) regAl->varLocation[vNFLAG].location = locNATIVEFLAG;
	if(nativeChanged & fZ) regAl->varLocation[vZFLAG].location = locNATIVEFLAG;
	if(nativeChanged & fC) regAl->varLocation[vCFLAG].location = locNATIVEFLAG;
	if(nativeChanged & fV) regAl->varLocation[vVFLAG].location = locNATIVEFLAG;

}


// add ra ra #
void CGenerator::genAdd1(Armlet* armlet, uint32 value)
{
	// add value to armlet->rd

	preFlags(armlet->outflags, ADDdef|ADDundef);

	// put ra in register and add immediate to it
	uint8 rm = getVariableInRegister(armlet->rd);
	uint32 imm = value;
	assemble(0, ADDlri, 0);
	postFlags(armlet->outflags, ADDundef, rm);

	constantValid[armlet->rd] = FALSE;
}

// add ra rb #
// add ra # rb
void CGenerator::genAdd2(Armlet* armlet, uint8 rb, uint32 value)
{
	uint8 rm = getVariableInRegister(armlet->rd);
	uint8 reg = putVariableInRegister(rb);
	uint32 imm = value;

	// mov rb to armlet->rd
	// add constant to rd
	preFlags(armlet->outflags, MOVdef | MOVundef | ADDdef | ADDundef);
	assemble(0, MOVlrr, ADDlri, 0);
	postFlags(armlet->opcode, MOVundef | ADDundef, rm);

	constantValid[armlet->rd] = FALSE;
}

// add ra ra ra
// add ra ra rb
// add ra rb ra (same as add ra ra rb)
void CGenerator::genAdd3(Armlet *armlet, uint8 ra, uint8 rb)
{
	// add rb to ra
	preFlags(armlet->outflags, ADDdef | ADDundef);

	TRACE("genAdd3 armlet->rd=%d ra=%d rb=%d \n", armlet->rd, ra, rb);

	if( regAl->varLocation[rb].location == locNATIVEREGISTER )
	{
		uint8 rm = putVariableInRegister(ra);
		uint8 reg = getVariableInRegister(rb);
		assemble(0, ADDlrr, 0);
		postFlags(armlet->opcode, ADDundef, rm);
	}
	else
	{
		uint8 reg = putVariableInRegister(ra);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(rb);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, ADDlrm, 0);
		#undef MODSIBDISP
		postFlags(armlet->opcode, ADDundef, reg);
	}

	constantValid[armlet->rd] = FALSE;
}

// add ra rb rb
// add ra rb rc
void CGenerator::genAdd4(Armlet *armlet, uint8 rb, uint8 rc)
{
	// mov rb to rd
	// add rc to rd

	preFlags(armlet->outflags, MOVdef | MOVundef | ADDdef | ADDundef);

	uint8 dest;

	if( regAl->varLocation[rb].location == locNATIVEREGISTER)
	{
		// if rb in reg already then move rb into rd
		uint8 rm = getVariableInRegister(armlet->rd);
		uint8 reg = getVariableInRegister(rb);
		assemble(0, MOVlrr, 0);
		dest = rm;
	}
	else
	{
		// otherwise fetch rb from memory into rd
		uint8 reg = getVariableInRegister(rb);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(rb);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, MOVlrm, 0);
		#undef MODSIBDISP
		dest = reg;
	}

	if( regAl->varLocation[rc].location == locNATIVEREGISTER)
	{
		// if second operand in reg already then add rc to dest
		uint8 rm = dest;
		uint8 reg = getVariableInRegister(rc);
		assemble(0, ADDlrr, 0);
	}
	else
	{
		// else add rc from memory into dest
		uint8 reg = dest;
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(rc);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, ADDlrm, 0);
		#undef MODSIBDISP
	}

	postFlags(armlet->opcode, MOVundef | ADDundef, dest);

	constantValid[armlet->rd] = FALSE;
}

// mov ra, ra
// mov rb, rb
void CGenerator::genMov1(Armlet *armlet)
{
	preFlags(armlet->outflags, MOVdef | MOVundef);
	
	int dest;

	if( regAl->varLocation[armlet->rx].location == locNATIVEREGISTER)
	{
		// if rx in reg already then move rb into rd
		uint8 rm = getVariableInRegister(armlet->rd);
		uint8 reg = putVariableInRegister(armlet->rx);
		assemble(0, MOVlrr, 0);
		dest = rm;
	}
	else
	{
		// otherwise fetch rb from memory into rd
		uint8 reg = getVariableInRegister(armlet->rd);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->rx);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, MOVlrm, 0);
		#undef MODSIBDISP
		dest = reg;
	}
	
	postFlags(armlet->opcode, MOVundef, dest);

	constantValid[armlet->rd] = FALSE;
}

// mov ra, # (used for spilling constant pool etc.)
void CGenerator::genMov2(uint8 rd, uint32 value)
{
	preFlags(fNONE, MOVdef | MOVundef);

	uint8 rm = getVariableInRegister(rd);
	uint32 imm = value;
	assemble(0, MOVlri, 0);

	postFlags(fNONE, MOVundef, rm);
}

// cmp ra,rb
void CGenerator::genCmp1(Armlet *armlet)
{
	
	preFlags(armlet->outflags, CMPdef | CMPundef );

	if( regAl->varLocation[armlet->ry].location == locNATIVEREGISTER)
	{
		// if ry in reg already then do comparison reg to reg
		uint8 rm = putVariableInRegister(armlet->rx);
		uint8 reg = putVariableInRegister(armlet->ry);
		assemble(0, CMPlrr, 0);
		if(armlet->outflags & fC)
			assemble(0, CMC, 0);
	}
	else
	{
		// otherwise fetch rx from memory into rd and to
		// comparison with ry still in memory
		
		uint8 reg = putVariableInRegister(armlet->rx);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->ry);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, CMPlrm, 0);
		#undef MODSIBDISP
		if(armlet->outflags & fC)
			assemble(0, CMC, 0);
	}

	// note, don't worry about dest reg, it doesn't affect cmp as it sets all flags
	postFlags(armlet->opcode, CMPundef, 0);

}

//
// add constant to pool
//

void CGenerator::addConstant(uint8 variable, uint32 value)
{
	constantPool[variable] = value;
	constantValid[variable] = TRUE;
}

// sub ra ra ra
// sub ra ra rb
void CGenerator::genSub1(Armlet *armlet)
{
	preFlags(armlet->outflags, SUBdef | SUBundef );

	uint8 dest;

	if( regAl->varLocation[armlet->ry].location == locNATIVEREGISTER )
	{
		// if ry in register
		uint8 rm = putVariableInRegister(armlet->rd);
		uint8 reg = putVariableInRegister(armlet->ry);
		assemble(0, SUBlrr, 0);
		dest = rm;
	}
	else
	{
		// if ry in memory
		uint8 reg = putVariableInRegister(armlet->rd);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->ry);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, SUBlrm, 0);
		#undef MODSIBDISP
		dest = reg;
	}

	// deal with inverted carry flag
	if(armlet->outflags & fC)
		assemble(0, CMC, 0);

	postFlags(armlet->opcode, SUBundef, dest);
}

// sub ra rb rb
// sub ra rb ra
// sub ra rb rc
void CGenerator::genSub6(Armlet *armlet)
{
	preFlags(armlet->outflags, SUBdef | SUBundef | MOVdef | MOVundef );

	uint8 dest;

	// move rx into rd
	if( regAl->varLocation[armlet->rx].location == locNATIVEREGISTER)
	{
		// if rx in register
		uint8 rm = getVariableInRegister(armlet->rd);
		uint8 reg = putVariableInRegister(armlet->rx);
		assemble(0, MOVlrr, 0);
		dest = rm;
	}
	else
	{
		// if rx in memory
		uint8 reg = getVariableInRegister(armlet->rd);
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->rx);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, MOVlrm, 0);
		#undef MODSIBDISP
		dest = reg;
	}

	// subtract ry from rd
	if( regAl->varLocation[armlet->ry].location == locNATIVEREGISTER)
	{
		// if ry in register
		uint8 rm = dest;
		uint8 reg = putVariableInRegister(armlet->ry);
		assemble(0, SUBlrr, 0);
	}
	else
	{
		// if ry in memory
		uint8 reg = dest;
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->ry);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, SUBlrm, 0);
		#undef MODSIBDISP
	}

	// deal with inverted carry flag
	if(armlet->outflags & fC)
		assemble(0, CMC, 0);

	postFlags(armlet->opcode, SUBundef, dest);
}

// cmp ra, #
void CGenerator::genCmp2(Armlet *armlet)
{
	preFlags(armlet->outflags, CMPdef | CMPundef );

	if( regAl->varLocation[armlet->rx].location == locNATIVEREGISTER)
	{
		// if rx in reg already then do comparison reg to imm
		uint8 rm = putVariableInRegister(armlet->rx);
		uint32 imm = constantPool[armlet->ry];
		assemble(0, CMPlri, 0);
		if(armlet->outflags & fC)
			assemble(0, CMC, 0);
	}
	else
	{
		// otherwise do cmp with rx still in memory
		uint32 imm = constantPool[armlet->ry];
		uint8 rm = EBP;
		uint8 disp = getVariableOffset(armlet->rx);
		int mod = mod_DISP8;
		#define MODSIBDISP MODDISP8
		assemble(0, CMPlmi, 0);
		#undef MODSIBDISP
		if(armlet->outflags & fC)
			assemble(0, CMC, 0);
	}

	// note, don't worry about dest reg, it doesn't affect cmp as it sets all flags
	postFlags(armlet->opcode, CMPundef, 0);
}

//
// shed all constants in constant pool to code so that they're allocated
//

void CGenerator::shedConstantPool()
{
	// ??? don't spill temps since they are never used across
	// basic block boundaries, need to confirm I never misused them
	int currentVar;
	for(currentVar=0; currentVar<vT0; currentVar++)
	{
		if(constantValid[currentVar])
		{
			TRACE("gen: mov v%d, #0x%x \n", currentVar, constantPool[currentVar] );
			genMov2(currentVar, constantPool[currentVar] );
			constantValid[currentVar] = FALSE;
		}
	}
	// wipe all temps from constant pool too (just don't spill to code)
	for( ; currentVar<maxTemp; currentVar++)
	{
		constantValid[currentVar] = FALSE;
	}
}

//
// called before a goto so that it sets up it's regs if necessary for
// the destination armlet of the goto (in case it already has a reg allocation)
// if it doesn't then we give the destination armlet this armlet's reg allocation
//

void CGenerator::regAllocateChangeBlock(Armlet* armlet)
{
	
	// if dest of this goto has a reg allocation
	if(basicBlockRA[armlet->value] != NULL)
	{
		// so spill our regs and allocate theres as necessary
		// in order to match their reg allocation
		allocateRegAllocation(regAl, basicBlockRA[armlet->value]);
	}
	else
	{
		// else it doesn't have a reg allocation already so
		// copy my reg allocation to it
		basicBlockRA[armlet->value] = copyRegisterAllocation(regAl);
	}

	// note, armlet following this goto will deal with allocating regs for itself
	// so don't need to worry about this
}

//
// called before a leave is generated so that everything can be spilled to memory
//

void CGenerator::spillAll()
{

}

//
// make copy of a register allocation
// return a ptr to a new RA that is identical to the one passed to this
//

RegisterAllocation* CGenerator::copyRegisterAllocation(RegisterAllocation *sourceRA)
{
	// ??? is there an easier way to copy structs built into C++? please?
	// should be able to cast both to struct-object and copy that way
	// using '=', then returning just pointer NB suggests:
	// memcpy((void *) X, (void *) &OldStruct, sizeof(*X));

	RegisterAllocation* newRegAl = new RegisterAllocation;
	
	// copy all armlet variable to location details
	for(int varCounter = 0; varCounter<maxTemp; varCounter++)
	{
		newRegAl->varLocation[varCounter].location = sourceRA->varLocation[varCounter].location;
		newRegAl->varLocation[varCounter].reg = sourceRA->varLocation[varCounter].reg;
	}
	// copy all x86 reg to armlet variable details
	for(int nativeReg=0; nativeReg<EDI; nativeReg++)
	{
		newRegAl->registerUse[nativeReg] = sourceRA->registerUse[nativeReg];
	}

	return newRegAl;
}

//
// spill old register allocation and allocate new register allocation
// making sure there's no overlap creating unnecessary spills
// called when leader found with predefined reg allocation
//

void CGenerator::allocateRegAllocation(RegisterAllocation *oldRegAl, RegisterAllocation *newRegAl)
{
	
	TRACE(" calling allocateRegAllocation() armletCounter=%d \n", armletCounter );

	// go through native regs
	for(int nativeReg=0; nativeReg<EDI; nativeReg++)
	{
		// ??? debugging
		TRACE("oldRegAl->registerUse[nativeReg] = %d \n" ,oldRegAl->registerUse[nativeReg]);
		TRACE("newRegAl->registerUse[nativeReg] = %d \n" ,newRegAl->registerUse[nativeReg]);
		// if allocation to this reg is different
		if( oldRegAl->registerUse[nativeReg] != newRegAl->registerUse[nativeReg] )
		{

			// can't see if the oldreg is allocated somewhere in the new reg
			// as it gets too complex trying to put the value previously
			// stored in this variable's new register somewhere while
			// we do the swap, this is not a compiler, just spill to memory

			// if reg wasn't unused
			if(oldRegAl->registerUse[nativeReg] != vUNUSED)
			{
				uint8 displacedVariable = oldRegAl->registerUse[nativeReg];
				// spill old var to memory
				int mod = mod_DISP32;
				int disp = getVariableOffset(displacedVariable);
				int rm = EBP;
				int reg = nativeReg;
				#define MODSIBDISP MODDISP32
				if(displacedVariable>= vNFLAG && displacedVariable <= vFFLAG)
					assemble(0, MOVbmr, 0);
				else
					assemble(0, MOVlmr, 0);
				#undef MODSIBDISP

				
			}

			// load new var from memory if new reg isn't unused
			if(newRegAl->registerUse[nativeReg] != vUNUSED)
			{
				// fetch new variable from memory
				uint8 newVariable = newRegAl->registerUse[nativeReg];
				int mod = mod_DISP32;
				int disp = getVariableOffset(newVariable);
				int rm = EBP;
				int reg = nativeReg;
				#define MODSIBDISP MODDISP32
				if(newVariable>= vNFLAG && newVariable <= vFFLAG)
					assemble(0, MOVZXlrbm, 0);
				else
					assemble(0, MOVlrm, 0);
				#undef MODSIBDISP
			}

			// ??? also need to check through varLocation for where to put
			// things like flags etc.
		}
	}
	
}
