// Generator.h: interface for the CGenerator class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_GENERATOR_H__BD70E9FD_FD67_4D65_9D95_983152A8C543__INCLUDED_)
#define AFX_GENERATOR_H__BD70E9FD_FD67_4D65_9D95_983152A8C543__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// note, to invoke objdump from command line use
// objdump --target binary --architecture=i386 --disassemble-all dump.obj > dump.txt

#include "TarmacGlobals.h"
#include "Profiler.h"
#include "x86asm.h"
#include "CodeCache.h"

typedef enum
{
	EAX = 0,
	ECX,
	EDX,
	EBX,
	ESP,
	EBP,
	ESI,
	EDI
} x86Registers;

// 
// Details of where each armlet variable is held
//

typedef enum
{
	locNATIVEREGISTER,
	locNATIVEFLAG,
	locMEMORY
} variableLocations;

struct VariableLocation
{
	uint32 location;
	uint8 reg;				// x86 reg if their
};

struct RegisterAllocation
{
	VariableLocation varLocation[maxTemp];		// array of all locations of variables
	uint8 registerUse[EDI];						// array of x86 registers detailing which armlet variable is in each one
};

//
// Structure for keeping track of gotos to be backpatched
//

struct GotoBackpatch
{
	uint32 armletNumber;	// armlet number goto was jumping to
	uint32 gotoPtr;			// offset to instruction in nativeChunk->area
};

class CGenerator
{
public:
	void setCodeCache(CCodeCache* aCodeCache);
	void generate(Armlet** aArmletChunk, int aTotalArmlets);
	CGenerator();
	virtual ~CGenerator();

private:
	void allocateRegAllocation(RegisterAllocation* oldRegAl, RegisterAllocation* newRegAl);
	RegisterAllocation* copyRegisterAllocation(RegisterAllocation* sourceRA);
	void spillAll();
	void regAllocateChangeBlock(Armlet* armlet);
	void shedConstantPool();
	void genCmp2(Armlet* armlet);
	void genSub6(Armlet* armlet);
	void genSub1(Armlet* armlet);
	CLinkedList* gotoPatchList;					// list of forward-referencing-gotos to be backpatched
	void addConstant(uint8 variable, uint32 value);
	void genMov2(uint8 rd, uint32 value);
	void genCmp1(Armlet* armlet);
	void genMov1(Armlet* armlet);
	void postFlags(uint8 outflags, uint8 nativeChanged, uint8 destReg);
	void preFlags(uint8 outflags, uint8 nativeChanged);
	uint8 getVariableOffset(uint8 variable);
	uint8 getVariableInRegister(uint8 variable);
	uint8 putVariableInRegister(uint8 variable);
	void genAdd4(Armlet* armlet, uint8 rb, uint8 rc);
	void genAdd3(Armlet* armlet, uint8 ra, uint8 rb);
	void genAdd2(Armlet* armlet, uint8 rb, uint32 value);
	void genAdd1(Armlet* armlet, uint32 value);
	inline void updateAddFlags(uint32 result, uint32 operand1, uint32 operand2);
	inline void updateSubFlags(uint32 result, uint32 operand1, uint32 operand2);
	inline void updateNZFlags(uint32 value);
	RegisterAllocation* regAl;					// current register allocation
	RegisterAllocation** basicBlockRA;			// array of reg allocations for each leader of basic block
	BOOL constantValid[maxTemp];				// flag for whether entry is valid or not
	uint32 constantPool[maxTemp];				// create constant pool
	uint32* armletNumberToAreaAddress;			// array of code area addresses from armlet numbers
	uint defaultAreaSize;						// size of buffer to allocate initially
	void assemble(const int wasteArgument, ... );
	int totalArmlets;							// number of armlets in chunk
	Armlet** armletChunk;						// buffer of armlets representing the chunk
	NativeChunk* nativeChunk;					// current native chunk being recompiled
	int armletCounter;							// number of next armlet to be recompiled
	void chooseStw(Armlet* armlet);
	void chooseLdw(Armlet* armlet);
	void chooseStb(Armlet* armlet);
	void chooseLdb(Armlet* armlet);
	void chooseMul(Armlet* armlet);
	void chooseRor(Armlet* armlet);
	void chooseAsr(Armlet* armlet);
	void chooseLsr(Armlet* armlet);
	void chooseLsl(Armlet* armlet);
	void chooseOrr(Armlet* armlet);
	void chooseSbc(Armlet* armlet);
	void chooseAdc(Armlet* armlet);
	void chooseAdd(Armlet* armlet);
	void chooseSub(Armlet* armlet);
	void chooseEor(Armlet* armlet);
	void chooseAnd(Armlet* armlet);
	void chooseRrx(Armlet* armlet);
	void chooseCmn(Armlet* armlet);
	void chooseCmp(Armlet* armlet);
	void chooseTeq(Armlet* armlet);
	void chooseTst(Armlet* armlet);
	void chooseMvn(Armlet* armlet);
	void chooseMov(Armlet* armlet);
	void chooseIntCheck(Armlet* armlet);
	void chooseGetPC(Armlet* armlet);
	void chooseMovc(Armlet* armlet);
	void chooseSetPC(Armlet* armlet);
	void chooseSetTrans(Armlet* armlet);
	void chooseClearTrans(Armlet* armlet);
	void chooseLeave(Armlet* armlet);
	void chooseGoto(Armlet* armlet, uint8 conditionCode);
	void chooseRule(Armlet* armlet);
};

#endif // !defined(AFX_GENERATOR_H__BD70E9FD_FD67_4D65_9D95_983152A8C543__INCLUDED_)
