#ifndef PENTCODE_H
#define PENTCODE_H

#ifndef ISX_H
#include "isx.h"
#endif 

#ifndef PENTCONST_H
#include "pentConst.h"
#endif 


#define pentCodeBufSize 256
#define pentRegCount 22

enum pentDataOp
/* Some of the pentium op codes that apply to many types */
    {
    opMov, opAdd, opSub, opMul, opDiv, opAnd, opOr, opXor, opSal, 
    opSar, opNeg, opNot, opCmp, opTest, 
    };

char *pentOpOfType(enum pentDataOp opType, enum isxValType valType);
/* Return string for given opCode and data type */

struct pentCoder
/* A factory for pentCodes */
    {
    struct hash *storeHash;	/* Save strings, floats here to reuse */
    struct hash *constStringHash; /* String constants, not allocated here. */
    struct pentCode *list;	/* List of instructions */
    char destBuf[pentCodeBufSize];	/* Space to print dest */
    char sourceBuf[pentCodeBufSize];	/* Space to print source */
    int tempIx;				/* Index (negative) for temps */
    bool regsUsed[pentRegCount];	/* One for each register, set to TRUE if
					 * register is used. */
    };

struct pentCoder *pentCoderNew(struct hash *constStringHash);
/* Make new pentCoder. */

void pentCoderFree(struct pentCoder **pCoder);
/* Free up pentCoder. */

void pentCoderAdd(struct pentCoder *coder, char *op, char *source, char *dest);
/* Add new instruction */

struct pentCode
/* Pentium code.  None of the strings are allocated here. */
    {
    struct pentCode *next;	/* Next in list */
    char *op;			/* Opcode. NULL here means just a label */
    char *source;		/* Source operand, may be NULL */
    char *dest;			/* Destination operand, may be NULL */
    };

struct pentCode *pentCodeNew(struct pentCoder *coder,
	char *op, char *source, char *dest);
/* Make a new bit of pentium code. */

#define pentCodeFree(ppt) freez(ppt)
/* Free up a pentium code. */

#define pentCodeFreeList(list) slFreeList(list)
/* Free up a list of pentium code. */

void pentCodeSave(struct pentCode *code, FILE *f);
/* Save single instruction to file */

void pentCodeSaveAll(struct pentCode *code, FILE *f);
/* Save list of instructions. */

struct pentFunctionInfo
/* Info about a function */
    {
    int savedContextSize;/* Size of saved regs & return address on stack */
    int savedRegSize;	/* Saved registers. */
    int savedRetEbpSize;/* Saved ebp/return address */
    int outVarSize;	/* Output variables. */
    int locVarSize;	/* Local variables. */
    int tempVarSize;	/* Temp variables. */
    int callParamSize;	/* Size needed for calls */
    int stackSubAmount;	/* Total amount to subtract from stack */
    struct pentCoder *coder;  /* Place for instructions */
    };

struct pentFunctionInfo *pentFunctionInfoNew(struct hash *constStringHash);
/* Create new pentFunctionInfo */

void pentSubCallsForHardStuff(struct pfCompile *pfc, struct hash *varHash,
	struct isxList *isxList);
/* Substitute subroutine calls for some of the harder
 * instructions, particularly acting on longs. */

void pentFromIsx(struct pfCompile *pfc, struct isxList *isxList, 
	struct pentFunctionInfo *pfi);
/* Convert isx code to pentium instructions in pfi. */

int pentTypeSize(enum isxValType valType);
/* Return size of a val type */

void pentFunctionStart(struct pfCompile *pfc, struct pentFunctionInfo *pfi, 
	char *cName, boolean isGlobal, char *protectLabel, char *skipLabel,
	FILE *f);
/* Start coding up a function in pentium assembly language. */

void pentFunctionEnd(struct pfCompile *pfc, struct pentFunctionInfo *pfi, 
	char *skipLabel, FILE *asmFile);
/* Finish coding up a function in pentium assembly language. */

void pentInitFuncVars(struct pfCompile *pfc, struct ctar *ctar, 
	struct hash *varHash, struct pentFunctionInfo *pfi);
/* Set up variables and offsets for parameters and local variables
 * in hash. */

struct isxReg *pentFreeReg(struct pfCompile *pfc,
	struct isx *isx, enum isxValType valType,
	struct dlNode *nextNode,  struct pentCoder *coder);
/* Find free register for instruction result. */

void pentLinkReg(struct isxAddress *iad, struct isxReg *reg);
/* Link register to new address. */

void pentLinkRegSave(struct pfCompile *pfc,
	struct isxAddress *dest, struct isxReg *reg,
	struct pentCoder *coder);
/* Unlink whatever old variable was in register and link in dest.
 * Also copy dest to memory if it's a real variable. */

boolean pentTempJustInReg(struct isxAddress *iad);
/* Return TRUE if address is for a temp that only exists in
 * a register, not in memory */

void pentSwapTempFromReg(struct pfCompile *pfc,
	struct isxReg *reg,  struct pentCoder *coder);
/* If reg contains temp var not also in memory then save it out. */

void pentSwapAllMmx(struct pfCompile *pfc,
	struct isx *isx, struct pentCoder *coder);
/* Swap out all Mmx registers to memory locations */

void pentPrintVarMemAddress(struct isxAddress *iad, char *buf, int offset);
/* Print out an address for variable in memory to buffer. */

void pentPrintAddress(struct pfCompile *pfc, struct pentCoder *coder,
	struct isxAddress *iad, char *buf);
/* Print out an address for an instruction. */

void pentCodeDestReg(struct pfCompile *pfc,
	enum pentDataOp opType, struct isxAddress *source, 
	struct isxReg *reg,  struct pentCoder *coder);
/* Code op where dest is a register. */

#endif /* PENTCODE_H */

