// Copyright (C) 1985-1996 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
 * This source file is made available for personal use
 * only. The license is in /dmd/src/dmd/backendlicense.txt
 * or /dm/src/dmd/backendlicense.txt
 * For any other uses, please contact Digital Mars.
 */

#if __cplusplus && TX86
extern "C" {
#endif

#if MARS
struct LabelDsymbol;
struct Declaration;
#endif

#define CNIL ((code *) NULL)

/* Register definitions */

#define	AX	0
#define	CX	1
#define	DX	2
#define	BX	3
#define	SP	4
#define	BP	5
#define	SI	6
#define	DI	7

#define ES	9
#define	PSW	10
#define STACK	11	// top of stack
#define MEM	12	// memory
#define OTHER	13	// other things
#define	ST0	14	// 8087 top of stack register
#define ST01	15	// top two 8087 registers; for complex types

#define NOREG	100	// no register

#define	AL	0
#define	CL	1
#define	DL	2
#define	BL	3
#define	AH	4
#define	CH	5
#define	DH	6
#define	BH	7

#define	mAX	1
#define	mCX	2
#define	mDX	4
#define	mBX	8
#define	mSP	0x10
#define	mBP	0x20
#define	mSI	0x40
#define	mDI	0x80
#define mES	(1 << ES)	// 0x200
#define mPSW	(1 << PSW)	// 0x400

#define mSTACK	(1 << STACK)	// 0x800
#define mMEM	(1 << MEM)	// 0x1000
#define mOTHER	(1 << OTHER)	// 0x2000

#define	mST0	(1 << ST0)	// 0x4000
#define	mST01	(1 << ST01)	// 0x8000

// Flags for getlvalue (must fit in regm_t)
#define RMload	0x4000
#define RMstore	0x8000

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
    // To support positional independent code,
    // must be able to remove BX from available registers
extern regm_t ALLREGS;			
#define ALLREGS_INIT		(mAX|mBX|mCX|mDX|mSI|mDI)
#define ALLREGS_INIT_PIC	(mAX|mCX|mDX|mSI|mDI)
extern regm_t BYTEREGS;			
#define BYTEREGS_INIT		(mAX|mBX|mCX|mDX)
#define BYTEREGS_INIT_PIC	(mAX|mCX|mDX)
#else
#define ALLREGS			(mAX|mBX|mCX|mDX|mSI|mDI)
#define ALLREGS_INIT		ALLREGS
#undef BYTEREGS
#define BYTEREGS		(mAX|mBX|mCX|mDX)
#endif

/* We use the same IDXREGS for the 386 as the 8088, because if
   we used ALLREGS, it would interfere with mMSW
 */
#define IDXREGS		(mBX|mSI|mDI)

#define FLOATREGS_32	mAX
#define FLOATREGS2_32	mDX
#define DOUBLEREGS_32	(mAX|mDX)
#define DOUBLEREGS2_32	(mCX|mBX)

#define FLOATREGS_16	(mDX|mAX)
#define FLOATREGS2_16	(mCX|mBX)
#define DOUBLEREGS_16	(mAX|mBX|mCX|mDX)

/*#define _8087REGS (mST0|mST1|mST2|mST3|mST4|mST5|mST6|mST7)*/

/* Segment registers	*/
#define SEG_ES	0
#define SEG_CS	1
#define SEG_SS	2
#define SEG_DS	3

/*********************
 * Masks for register pairs.
 * Note that index registers are always LSWs. This is for the convenience
 * of implementing far pointers.
 */

#if 0
// Give us an extra one so we can enregister a long
#define mMSW	(mCX|mDX|mDI|mES)	// most significant regs
#define mLSW	(mAX|mBX|mSI)		// least significant regs
#else
#define mMSW	(mCX|mDX|mES)		/* most significant regs	*/
#define mLSW	(mAX|mBX|mSI|mDI)	/* least significant regs	*/
#endif

/* Return !=0 if there is an SIB byte	*/
#define issib(rm)	(((rm) & 7) == 4 && ((rm) & 0xC0) != 0xC0)

#if 0
// relocation field size is always 32bits
#define is32bitaddr(x,Iflags) (1)
#else
//
// is32bitaddr works correctly only when x is 0 or 1.  This is
// true today for the current definition of I32, but if the definition
// of I32 changes, this macro will need to change as well
//
// Note: even for linux targets, CFaddrsize can be set by the inline
// assembler.
#define is32bitaddr(x,Iflags) ((x) ^(((Iflags) & CFaddrsize) !=0))
#endif

/*******************
 * Some instructions.
 */

#define SEGES	0x26
#define SEGCS	0x2E
#define SEGSS	0x36
#define SEGDS	0x3E
#define SEGFS	0x64
#define SEGGS	0x65

#define	JMP	0xE9	/* Intra-Segment Direct	*/
#define JMPS	0xEB	/* JMP SHORT		*/
#define JCXZ	0xE3
#define LOOP	0xE2
#define LES	0xC4
#define LEA	0x8D

#define JO	0x70
#define JNO	0x71
#define JC	0x72
#define JB	0x72
#define JNC	0x73
#define JAE	0x73
#define JE	0x74
#define JNE	0x75
#define JBE	0x76
#define JA	0x77
#define JS	0x78
#define JNS	0x79
#define JP	0x7A
#define JNP	0x7B
#define JL	0x7C
#define JGE	0x7D
#define JLE	0x7E
#define JG	0x7F

/* NOP is used as a placeholder in the linked list of instructions, no	*/
/* actual code will be generated for it.				*/
#define NOP	0x2E	/* actually CS: (we don't use 0x90 because the	*/
			/* silly Windows stuff wants to output 0x90's)	*/

#define ESCAPE	0x3E	// marker that special information is here
			// (Iop2 is the type of special information)
			// (Same as DS:, but we will never generate
			// a separate DS: opcode anyway)
    #define ESClinnum	1	// line number information
    #define ESCctor	2	// object is constructed
    #define ESCdtor	3	// object is destructed
    #define ESCmark	4	// mark eh stack
    #define ESCrelease	5	// release eh stack
    #define ESCoffset	6	// set code offset for eh
    #define ESCadjesp	7	// adjust ESP by IEV2.Vint
    #define ESCmark2	8	// mark eh stack
    #define ESCrelease2	9	// release eh stack
    #define ESCframeptr	10	// replace with load of frame pointer

#define ASM	0x36	// string of asm bytes, actually an SS: opcode

/*********************************
 * Macros to ease generating code
 * modregrm:	generate mod reg r/m field
 * NEWREG:	change reg field of x to r
 * genorreg:	OR  t,f
 */

#define modregrm(m,r,rm)	(((m)<<6)+((r)<<3)+(rm))
#define NEWREG(x,r)		((x)=((x)&~(7<<3))|((r)<<3))
#define genorreg(c,t,f)		genregs((c),0x09,(f),(t))

/**********************
 * C library routines.
 * See callclib().
 */

enum CLIB
{
	CLIBlcmp,
	CLIBlmul,
	CLIBldiv,
	CLIBlmod,
	CLIBuldiv,
	CLIBulmod,

#if TARGET_WINDOS
	CLIBdmul,CLIBddiv,CLIBdtst0,CLIBdtst0exc,CLIBdcmp,CLIBdcmpexc,CLIBdneg,CLIBdadd,CLIBdsub,
	CLIBfmul,CLIBfdiv,CLIBftst0,CLIBftst0exc,CLIBfcmp,CLIBfcmpexc,CLIBfneg,CLIBfadd,CLIBfsub,
#endif

	CLIBdbllng,CLIBlngdbl,CLIBdblint,CLIBintdbl,
	CLIBdbluns,CLIBunsdbl,
	CLIBdblulng,
#if TARGET_WINDOS
	// used the GNU way of converting unsigned long long to signed
	CLIBulngdbl,
#endif
	CLIBdblflt,CLIBfltdbl,
	CLIBdblllng,
	CLIBllngdbl,
	CLIBdblullng,
	CLIBullngdbl,
	CLIBdtst,
	CLIBvptrfptr,CLIBcvptrfptr,

	CLIB87topsw,CLIBfltto87,CLIBdblto87,CLIBdblint87,CLIBdbllng87,
	CLIBftst,
	CLIBfcompp,
	CLIBftest,
	CLIBftest0,
	CLIBfdiv87,

	// Complex numbers
	CLIBcmul,
	CLIBcdiv,
	CLIBccmp,

	CLIBu64_ldbl,
	CLIBld_u64,

	CLIBMAX
};

/**********************************
 * Code data type
 */

union evc
{
    targ_int	Vint;		// also used for tmp numbers (FLtmp)
    targ_uns	Vuns;
    targ_long	Vlong;
    struct
    {	targ_size_t Vpointer;
	int Vseg;		// segment the pointer is in
    }_EP;
    Srcpos	Vsrcpos;	// source position for OPlinnum
    struct elem  *Vtor;		// OPctor/OPdtor elem
    struct block *Vswitch;	// when FLswitch and we have a switch table
    code *Vcode;		// when code is target of a jump (FLcode)
    struct block *Vblock;	// when block " (FLblock)
    struct
    {
	targ_size_t Voffset;	// offset from symbol
	symbol	*Vsym;		// pointer to symbol table (FLfunc,FLextern)
    } sp;
#if MARS
    struct
    {
	targ_size_t Voffset;	// offset from symbol
	Declaration *Vsym;	// pointer to D symbol table
    } dsp;
    struct
    {
	targ_size_t Voffset;	// offset from symbol
	LabelDsymbol *Vsym;	// pointer to Label
    } lab;
#endif
    struct
    {   unsigned len;
	char *bytes;
    } as;			// asm node (FLasm)
};

struct code
{
    code *next;
    unsigned Iflags;
#define CFes	          1	// generate an ES: segment override for this instr
#define CFjmp16	          2	// need 16 bit jump offset (long branch)
#define CFtarg	          4	// this code is the target of a jump
#define CFseg	          8	// get segment of immediate value
#define CFoff	       0x10	// get offset of immediate value
#define CFss	       0x20	// generate an SS: segment override (not with
				// CFes at the same time, though!)
#define CFpsw	       0x40	// we need the flags result after this instruction
#define	CFopsize       0x80	// prefix with operand size
#define CFaddrsize    0x100 	// prefix with address size
#define CFds	      0x200	// need DS override (not with es, ss, or cs )	
#define CFcs	      0x400	// need CS override
#define CFfs	      0x800	// need FS override
#define CFgs	(CFcs | CFfs)	// need GS override
#define CFwait       0x1000	// If I32 it indicates when to output a WAIT
#define CFselfrel    0x2000 	// if self-relative
#define CFunambig    0x4000    	// indicates cannot be accessed by other addressing
			    	// modes
#define CFtarg2	     0x8000	// like CFtarg, but we can't optimize this away
#define CFvolatile  0x10000	// volatile reference, do not schedule
#define CFclassinit 0x20000	// class init code

#define CFPREFIX (CFSEG | CFopsize | CFaddrsize)
#define CFSEG	(CFes | CFss | CFds | CFcs | CFfs | CFgs)

    unsigned char Ijty;		// type of operand, 0 if unknown

    unsigned char Iop;
    unsigned char Irm;		// reg/mode

    unsigned char Iop2;		// second opcode byte
    unsigned char Isib;		// SIB byte

    unsigned char Iop3;		// third opcode byte

    unsigned char IFL1,IFL2;	// FLavors of 1st, 2nd operands
    union evc IEV1;		// 1st operand, if any
      #define IEVpointer1 IEV1._EP.Vpointer
      #define IEVseg1     IEV1._EP.Vseg
      #define IEVsym1     IEV1.sp.Vsym
      #define IEVdsym1    IEV1.dsp.Vsym
      #define IEVoffset1  IEV1.sp.Voffset
      #define IEVlsym1    IEV1.lab.Vsym
      #define IEVint1     IEV1.Vint
    union evc IEV2;		// 2nd operand, if any
      #define IEVpointer2 IEV2._EP.Vpointer
      #define IEVseg2     IEV2._EP.Vseg
      #define IEVsym2     IEV2.sp.Vsym
      #define IEVdsym2    IEV2.dsp.Vsym
      #define IEVoffset2  IEV2.sp.Voffset
      #define IEVlsym2    IEV2.lab.Vsym
      #define IEVint2     IEV2.Vint
    void print();		// pretty-printer

    code() { Ijty = 0; Isib = 0; }	// constructor
};

// !=0 if we have to add FWAIT to floating point ops
#define ADDFWAIT()	(config.target_cpu <= TARGET_80286)

/********************** PUBLIC FUNCTIONS *******************/

code *code_calloc(void);
void code_free (code *);
void code_term(void);

#define code_next(c)	((c)->next)

//#define code_calloc()	((code *) mem_calloc(sizeof(code)))

typedef code *code_p;

/**********************************
 * Set value in regimmed for reg.
 * NOTE: For 16 bit generator, this is always a (targ_short) sign-extended
 *	value.
 */

#define regimmed_set(reg,e) \
	(regcon.immed.value[reg] = (e),regcon.immed.mval |= 1 << (reg))

extern con_t regcon;

/****************************
 * Table of common subexpressions stored on the stack.
 *	csextab[]	array of info on saved CSEs
 *	CSEpe		pointer to saved elem
 *	CSEregm		mask of register that was saved (so for multi-
 *			register variables we know which part we have)
 *	cstop =		# of entries in table
 */

struct CSE
{	elem	*e;		// pointer to elem
	code	csimple;	// if CSEsimple, this is the code to regenerate it
	regm_t	regm;		// mask of register stored there
	char	flags;		// flag bytes
#define CSEload		1	// set if the CSE was ever loaded
#define CSEsimple	2	// CSE can be regenerated easilly

// != 0 if CSE was ever loaded
#define CSE_loaded(i)	(csextab[i].flags & CSEload)
};

/************************************
 */

struct NDP
{
    elem *e;			// which elem is stored here (NULL if none)
    unsigned offset;		// offset from e (used for complex numbers)

    static NDP *save;
    static int savemax;		// # of entries in save[]
    static int savetop;		// # of entries used in save[]
};

extern NDP _8087elems[8];

/*******************************
 * As we generate code, collect information about
 * what parts of NT exception handling we need.
 */

extern unsigned usednteh;

#define NTEH_try	1	// used _try statement
#define NTEH_except	2	// used _except statement
#define NTEHexcspec	4	// had C++ exception specification
#define NTEHcleanup	8	// destructors need to be called
#define NTEHtry		0x10	// had C++ try statement
#define NTEHcpp		(NTEHexcspec | NTEHcleanup | NTEHtry)
#define EHcleanup	0x20
#define EHtry		0x40
#define NTEHjmonitor	0x80	// uses Jupiter monitor
#define NTEHpassthru	0x100

/********************** Code Generator State ***************/

typedef struct CGstate
{
    int stackclean;	// if != 0, then clean the stack after function call
} CGstate;

extern CGstate cgstate;

/***********************************************************/

extern regm_t msavereg,mfuncreg,allregs;

/*long cxmalloc,cxcalloc,cx1;*/

typedef code *cd_t (elem *e , regm_t *pretregs );

extern	int BPRM;
extern	regm_t FLOATREGS;
extern	regm_t FLOATREGS2;
extern	regm_t DOUBLEREGS;
extern	const char datafl[],stackfl[],segfl[],flinsymtab[];
extern	char needframe,usedalloca,gotref;
extern	targ_size_t localsize,Toff,Poff,Aoff,
	Poffset,funcoffset,
	framehandleroffset,
	Aoffset,Toffset,EEoffset;
extern	int Aalign;
extern	int cseg;
#if TARGET_OSX
extern	targ_size_t localgotoffset;
#endif

/* cgcod.c */
extern int pass;
#define PASSinit	0	// initial pass through code generator
#define PASSreg		1	// register assignment pass
#define PASSfinal	2	// final pass

extern	int dfoidx;
extern	struct CSE *csextab;
extern	unsigned cstop;
#if TX86
extern	bool floatreg;
#endif
extern	targ_size_t retoffset;
extern	unsigned stackpush;
extern	int stackchanged;
extern	int refparam;
extern	int reflocal;
extern	char anyiasm;
extern	char calledafunc;
extern	code *(*cdxxx[])(elem *,regm_t *);

void stackoffsets(int);
void codgen (void );
regm_t regmask (tym_t tym, tym_t tyf );
#ifdef DEBUG
unsigned findreg (regm_t regm , int line , const char *file );
#define findreg(regm) findreg((regm),__LINE__,__FILE__)
#else
unsigned findreg (regm_t regm );
#endif
#define findregmsw(regm) findreg((regm) & mMSW)
#define findreglsw(regm) findreg((regm) & (mLSW | mBP))
void freenode (elem *e );
int isregvar (elem *e , regm_t *pregm , unsigned *preg );
#ifdef DEBUG
code *allocreg (regm_t *pretregs , unsigned *preg , tym_t tym , int line , const char *file );
#define allocreg(a,b,c)	allocreg((a),(b),(c),__LINE__,__FILE__)
#else
code *allocreg (regm_t *pretregs , unsigned *preg , tym_t tym );
#endif
void useregs (regm_t regm );
code *getregs (regm_t r );
code *getregs_imm (regm_t r );
code *cse_flush(int);
void cssave (elem *e , regm_t regm , unsigned opsflag );
bool evalinregister (elem *e );
regm_t getscratch();
code *codelem (elem *e , regm_t *pretregs , bool constflag );
char *regm_str(regm_t rm);

/* cod1.c */
extern int clib_inited;

int isscaledindex(elem *);
int ssindex(int op,targ_uns product);
void buildEA(code *c,int base,int index,int scale,targ_size_t disp);
void andregcon (con_t *pregconsave);
code *docommas (elem **pe );
code *gencodelem(code *c,elem *e,regm_t *pretregs,bool constflag);
void gensaverestore(regm_t, code **, code **);
code *genstackclean(code *c,unsigned numpara,regm_t keepmsk);
code *logexp (elem *e , int jcond , unsigned fltarg , code *targ );
code *loadea (elem *e , code __ss *cs , unsigned op , unsigned reg , targ_size_t offset , regm_t keepmsk , regm_t desmsk );
unsigned getaddrmode (regm_t idxregs );
void getlvalue_msw(code *);
void getlvalue_lsw(code *);
code *getlvalue (code __ss *pcs , elem *e , regm_t keepmsk );
code *scodelem (elem *e , regm_t *pretregs , regm_t keepmsk , bool constflag );
code *fltregs (code __ss *pcs , tym_t tym );
code *tstresult (regm_t regm , tym_t tym , unsigned saveflag );
code *fixresult (elem *e , regm_t retregs , regm_t *pretregs );
code *callclib (elem *e , unsigned clib , regm_t *pretregs , regm_t keepmask );
cd_t cdfunc;
cd_t cdstrthis;
code *params(elem *, unsigned);
code *offsetinreg (elem *e , regm_t *pretregs );
code *loaddata (elem *e , regm_t *pretregs );

/* cod2.c */
regm_t idxregm (unsigned rm,unsigned sib);
#if TARGET_WINDOS
code *opdouble (elem *e , regm_t *pretregs , unsigned clib );
#endif
cd_t cdorth;
cd_t cdmul;
cd_t cdnot;
cd_t cdcom;
cd_t cdbswap;
cd_t cdcond;
void WRcodlst (code *c );
cd_t cdcomma;
cd_t cdloglog;
cd_t cdshift;
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
cd_t cdindpic;
#endif
cd_t cdind;
cd_t cdstrlen;
cd_t cdstrcmp;
cd_t cdstrcpy;
cd_t cdmemchr;
cd_t cdmemcmp;
cd_t cdmemcpy;
cd_t cdmemset;
cd_t cdstreq;
cd_t cdrelconst;
code *getoffset (elem *e , unsigned reg );
cd_t cdneg;
cd_t cdabs;
cd_t cdpost;
cd_t cderr;
cd_t cdinfo;
cd_t cdctor;
cd_t cddtor;
cd_t cdmark;
cd_t cdnullcheck;
cd_t cdclassinit;

/* cod3.c */
extern int BPoff;

int cod3_EA(code *c);
regm_t cod3_useBP();
void cod3_set386 (void );
void cod3_set64 (void );
void cod3_align (void );
void doswitch (block *b );
void outjmptab (block *b );
void outswitab (block *b );
int jmpopcode (elem *e );
void cod3_ptrchk(code * __ss *pc,code __ss *pcs,regm_t keepmsk);
code *prolog (void );
void epilog (block *b);
cd_t cdframeptr;
cd_t cdgot;
targ_size_t cod3_spoff();
code *cod3_load_got();
void makeitextern (symbol *s );
void fltused(void);
int branch(block *bl, int flag);
void cod3_adjSymOffsets();
void assignaddr (block *bl );
void assignaddrc (code *c );
targ_size_t cod3_bpoffset(symbol *s);
void pinholeopt (code *c , block *bn );
void jmpaddr (code *c );
int code_match(code *c1,code *c2);
targ_size_t calcblksize (code *c);
targ_size_t calccodsize(code *c);
targ_size_t codout (code *c );
void addtofixlist (symbol *s , targ_size_t soffset , int seg , targ_size_t val , int flags );
void searchfixlist (symbol *s );
void outfixlist (void );
void code_hydrate(code **pc);
void code_dehydrate(code **pc);

/* cod4.c */
extern	const unsigned dblreg[];
extern int cdcmp_flag;

code *modEA (unsigned Irm );
cd_t cdeq;
cd_t cdaddass;
cd_t cdmulass;
cd_t cdshass;
cd_t cdcmp;
cd_t cdcnvt;
cd_t cdshtlng;
cd_t cdbyteint;
cd_t cdlngsht;
cd_t cdmsw;
cd_t cdport;
cd_t cdasm;
cd_t cdsetjmp;
cd_t cdvoid;
cd_t cdhalt;
cd_t cdfar16;
cd_t cdbt;
cd_t cdbscan;
cd_t cdpair;
code *longcmp (elem *,bool,unsigned,code *);

/* cod5.c */
void cod5_prol_epi();
void cod5_noprol();

/* cg87.c */
void note87(elem *e, unsigned offset, int i);
#ifdef DEBUG
void pop87(int, const char *);
#else
void pop87();
#endif
code *push87 (void );
code *save87 (void );
code *save87regs(unsigned n);
code *genfltreg(code *c,unsigned opcode,unsigned reg,targ_size_t offset);
code *genfwait(code *c);
code *comsub87(elem *e, regm_t *pretregs);
code *fixresult87 (elem *e , regm_t retregs , regm_t *pretregs );
code *fixresult_complex87(elem *e,regm_t retregs,regm_t *pretregs);
code *orth87 (elem *e , regm_t *pretregs );
code *load87(elem *e, unsigned eoffset, regm_t *pretregs, elem *eleft, int op);
int cmporder87 (elem *e );
code *eq87 (elem *e , regm_t *pretregs );
code *complex_eq87 (elem *e , regm_t *pretregs );
code *opass87 (elem *e , regm_t *pretregs );
code *cdnegass87 (elem *e , regm_t *pretregs );
code *post87 (elem *e , regm_t *pretregs );
code *cnvt87 (elem *e , regm_t *pretregs );
code *cnvteq87 (elem *e , regm_t *pretregs );
cd_t cdrndtol;
cd_t cdscale;
code *neg87 (elem *e , regm_t *pretregs );
code *neg_complex87(elem *e, regm_t *pretregs);
code *cdind87(elem *e,regm_t *pretregs);
extern int stackused;
code *cdconvt87(elem *e, regm_t *pretregs);
code *cload87(elem *e, regm_t *pretregs);

#ifdef DEBUG
#define pop87()	pop87(__LINE__,__FILE__)
#endif

/* iasm.c */
void iasm_term( void );
regm_t iasm_regs( block *bp );

// nteh.c
code *nteh_prolog(void);
code *nteh_epilog(void);
void nteh_usevars(void);
void nteh_gentables(void);
code *nteh_setsp(int op);
code *nteh_filter(block *b);
void nteh_framehandler(symbol *);
code *nteh_gensindex(int);
#define GENSINDEXSIZE 7
code *nteh_monitor_prolog(Symbol *shandle);
code *nteh_monitor_epilog(regm_t retregs);

// cgen.c
code *code_last(code *c);
void code_orflag(code *c,unsigned flag);
code * __pascal cat (code *c1 , code *c2 );
code * cat3 (code *c1 , code *c2 , code *c3 );
code * cat4 (code *c1 , code *c2 , code *c3 , code *c4 );
code * cat6 (code *c1 , code *c2 , code *c3 , code *c4 , code *c5 , code *c6 );
code *gen (code *c , code *cs );
code *gen1 (code *c , unsigned op );
code *gen2 (code *c , unsigned op , unsigned rm );
code *gen2sib(code *c,unsigned op,unsigned rm,unsigned sib);
code *genregs (code *c , unsigned op , unsigned dstreg , unsigned srcreg );
code *gentstreg (code *c , unsigned reg );
code *genasm (code *c , char *s , unsigned slen );
code *genmovreg (code *c , unsigned to , unsigned from );
code *genjmp (code *c , unsigned op , unsigned fltarg , block *targ );
code *gencsi (code *c , unsigned op , unsigned rm , unsigned FL2 , SYMIDX si );
code *gencs (code *c , unsigned op , unsigned rm , unsigned FL2 , symbol *s );
code *genc2 (code *c , unsigned op , unsigned rm , targ_uns EV2 );
code *genc1 (code *c , unsigned op , unsigned rm , unsigned FL1 , targ_uns EV1 );
code *genc (code *c , unsigned op , unsigned rm , unsigned FL1 , targ_uns EV1 , unsigned FL2 , targ_uns EV2 );
code *genmulimm(code *c,unsigned r1,unsigned r2,targ_int imm);
code *genlinnum(code *,Srcpos);
void cgen_linnum(code **pc,Srcpos srcpos);
void cgen_prelinnum(code **pc,Srcpos srcpos);
code *genadjesp(code *c, int offset);
code *gennop(code *);
code *genshift(code *);
code *movregconst (code *c , unsigned reg , targ_int value , regm_t flags );
bool reghasvalue (regm_t regm , targ_int value , unsigned *preg );
code *regwithvalue (code *c , regm_t regm , targ_int value , unsigned *preg , regm_t flags );

// cgreg.c
void cgreg_init();
void cgreg_term();
void cgreg_reset();
void cgreg_used(unsigned bi,regm_t used);
void cgreg_spillreg_prolog(block *b,Symbol *s,code **pcstore,code **pcload);
void cgreg_spillreg_epilog(block *b,Symbol *s,code **pcstore,code **pcload);
int cgreg_assign(Symbol *retsym);
void cgreg_unregister(regm_t conflict);

// cgsched.c
void cgsched_pentium(code **pc,regm_t scratch);

//	Data and code can be in any number of sections
//	
//	Generalize the Windows platform concept of CODE,DATA,UDATA,etc
//	into multiple segments

#if OMFOBJ

struct seg_data 
{
    int                  SDseg;		// omf file segment index
    targ_size_t		 SDoffset;	// starting offset for data

    bool isfarseg;
    int seg;				// segment number
    int lnameidx;			// lname idx of segment name
    int classidx;			// lname idx of class name
    unsigned attr;			// segment attribute
    targ_size_t origsize;		// original size
    long seek;				// seek position in output file
};

extern	targ_size_t Coffset;

#endif

#if ELFOBJ || MACHOBJ

typedef unsigned int IDXSTR;
typedef unsigned int IDXSEC;
typedef unsigned int IDXSYM;

struct linnum_data
{
    char *filename;
    unsigned filenumber;	// corresponding file number for DW_LNS_set_file

    unsigned linoff_count;
    unsigned linoff_max;
    unsigned (*linoff)[2];	// [0] = line number, [1] = offset
};

struct seg_data 
{
    int                  SDseg;		// segment index
    IDXSEC		 SDshtidx;	// section header table index
    targ_size_t		 SDoffset;	// starting offset for data
    Outbuffer		*SDbuf;		// buffer to hold data
    Outbuffer		*SDrel;		// buffer to hold relocation info
#if ELFOBJ
    IDXSYM		 SDsymidx;	// each section is in the symbol table
    IDXSEC		 SDrelidx;	// section header for relocation info
    targ_size_t		 SDrelmaxoff;	// maximum offset encountered
    int			 SDrelindex;	// maximum offset encountered
    int			 SDrelcnt;	// number of relocations added
    IDXSEC		 SDshtidxout;	// final section header table index
    Symbol		*SDsym;		// if !=NULL, comdat symbol
#endif

    unsigned		SDaranges_offset;	// if !=0, offset in .debug_aranges

    unsigned		 SDlinnum_count;
    unsigned		 SDlinnum_max;
    linnum_data		*SDlinnum_data;	// array of line number / offset data

    int isCode();
};

#define Coffset SegData[cseg]->SDoffset

#endif

extern seg_data **SegData;
#define Offset(seg) SegData[seg]->SDoffset
#define Doffset SegData[DATA]->SDoffset
#define CDoffset SegData[CDATA]->SDoffset
#define UDoffset SegData[UDATA]->SDoffset

#if __cplusplus && TX86
}
#endif

