// Copyright (C) 1985-1996 by Symantec
// Copyright (C) 2000-2011 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

enum // #defining R12-R15 interfere with setjmps' _JUMP_BUFFER members
{
    R8       = 8,
    R9       = 9,
    R10      = 10,
    R11      = 11,
    R12      = 12,
    R13      = 13,
    R14      = 14,
    R15      = 15,
};

#define XMM0    16
#define XMM1    17
#define XMM2    18
#define XMM3    19
#define XMM4    20
#define XMM5    21
#define XMM6    22
#define XMM7    23
/* There are also XMM8..XMM14 */
#define XMM15   31


#define ES      24
#define PSW     25
#define STACK   26      // top of stack
#define ST0     27      // 8087 top of stack register
#define ST01    28      // top two 8087 registers; for complex types

#define NOREG   29     // 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 mR8     (1 << R8)
#define mR9     (1 << R9)
#define mR10    (1 << R10)
#define mR11    (1 << R11)
#define mR12    (1 << R12)
#define mR13    (1 << R13)
#define mR14    (1 << R14)
#define mR15    (1 << R15)

#define mXMM0   (1 << XMM0)
#define mXMM1   (1 << XMM1)
#define mXMM2   (1 << XMM2)
#define mXMM3   (1 << XMM3)
#define mXMM4   (1 << XMM4)
#define mXMM5   (1 << XMM5)
#define mXMM6   (1 << XMM6)
#define mXMM7   (1 << XMM7)
#define XMMREGS  (mXMM0 |mXMM1 |mXMM2 |mXMM3 |mXMM4 |mXMM5 |mXMM6 |mXMM7)

#define mES     (1 << ES)       // 0x1000000
#define mPSW    (1 << PSW)      // 0x2000000

#define mSTACK  (1 << STACK)    // 0x4000000

#define mST0    (1 << ST0)      // 0x20000000
#define mST01   (1 << ST01)     // 0x40000000

// Flags for getlvalue (must fit in regm_t)
#define RMload  (1 << 30)
#define RMstore (1 << 31)

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || 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_64    mAX
#define FLOATREGS2_64   mDX
#define DOUBLEREGS_64   mAX
#define DOUBLEREGS2_64  mDX

#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 a 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) (I64 || ((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 CALL    0xE8
#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 << 8)       // line number information
    #define ESCctor     (2 << 8)       // object is constructed
    #define ESCdtor     (3 << 8)       // object is destructed
    #define ESCmark     (4 << 8)       // mark eh stack
    #define ESCrelease  (5 << 8)       // release eh stack
    #define ESCoffset   (6 << 8)       // set code offset for eh
    #define ESCadjesp   (7 << 8)       // adjust ESP by IEV2.Vint
    #define ESCmark2    (8 << 8)       // mark eh stack
    #define ESCrelease2 (9 << 8)       // release eh stack
    #define ESCframeptr (10 << 8)      // replace with load of frame pointer
    #define ESCdctor    (11 << 8)      // D object is constructed
    #define ESCddtor    (12 << 8)      // D object is destructed
    #define ESCadjfpu   (13 << 8)      // adjust fpustackused by IEV2.Vint

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

/*********************************
 * Macros to ease generating code
 * modregrm:    generate mod reg r/m field
 * modregxrm:   reg could be R8..R15
 * modregrmx:   rm could be R8..R15
 * modregxrmx:  reg or rm could be R8..R15
 * NEWREG:      change reg field of x to r
 * genorreg:    OR  t,f
 */

#define modregrm(m,r,rm)        (((m)<<6)|((r)<<3)|(rm))
#define modregxrm(m,r,rm)       ((((r)&8)<<15)|modregrm((m),(r)&7,rm))
#define modregrmx(m,r,rm)       ((((rm)&8)<<13)|modregrm((m),r,(rm)&7))
#define modregxrmx(m,r,rm)      ((((r)&8)<<15)|(((rm)&8)<<13)|modregrm((m),(r)&7,(rm)&7))

#define NEWREXR(x,r)            ((x)=((x)&~REX_R)|(((r)&8)>>1))
#define NEWREG(x,r)             ((x)=((x)&~(7<<3))|((r)<<3))
#define code_newreg(c,r)        (NEWREG((c)->Irm,(r)&7),NEWREXR((c)->Irex,(r)))

#define genorreg(c,t,f)         genregs((c),0x09,(f),(t))

#define REX     0x40            // REX prefix byte, OR'd with the following bits:
#define REX_W   8               // 0 = default operand size, 1 = 64 bit operand size
#define REX_R   4               // high bit of reg field of modregrm
#define REX_X   2               // high bit of sib index reg
#define REX_B   1               // high bit of rm field, sib base reg, or opcode reg

#define VEX2_B1(ivex)                           \
    (                                           \
        ivex.r    << 7 |                        \
        ivex.vvvv << 3 |                        \
        ivex.l    << 2 |                        \
        ivex.pp                                 \
    )

#define VEX3_B1(ivex)                           \
    (                                           \
        ivex.r    << 7 |                        \
        ivex.x    << 6 |                        \
        ivex.b    << 5 |                        \
        ivex.mmmm                               \
    )

#define VEX3_B2(ivex)                           \
    (                                           \
        ivex.w    << 7 |                        \
        ivex.vvvv << 3 |                        \
        ivex.l    << 2 |                        \
        ivex.pp                                 \
    )

/**********************
 * 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;
    targ_llong  Vllong;
    targ_size_t Vsize_t;
    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
    {   size_t 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 CFoffset64  0x40000     // offset is 64 bits
#define CFpc32      0x80000     // I64: PC relative 32 bit fixup

#define CFvex       0x100000    // vex prefix
#define CFvex3      0x200000    // 3 byte vex prefix

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

    union {
        unsigned _Iop;
        struct {
#pragma pack(1)
            unsigned char  op;
            unsigned short   pp : 2;
            unsigned short    l : 1;
            unsigned short vvvv : 4;
            unsigned short    w : 1;
            unsigned short mmmm : 5;
            unsigned short    b : 1;
            unsigned short    x : 1;
            unsigned short    r : 1;
            unsigned char pfx; // always 0xC4
#pragma pack()
        } _Ivex;
    } _OP;

    /* The _EA is the "effective address" for the instruction, and consists of the modregrm byte,
     * the sib byte, and the REX prefix byte. The 16 bit code generator just used the modregrm,
     * the 32 bit x86 added the sib, and the 64 bit one added the rex.
     */
    union
    {   unsigned _Iea;
        struct
        {
            unsigned char _Irm;          // reg/mode
            unsigned char _Isib;         // SIB byte
            unsigned char _Irex;         // REX prefix
        } _ea;
    } _EA;

#define Iop  _OP._Iop
#define Ivex _OP._Ivex
#define Iea  _EA._Iea
#define Irm  _EA._ea._Irm
#define Isib _EA._ea._Isib
#define Irex _EA._ea._Irex


    /* IFL1 and IEV1 are the first operand, which usually winds up being the offset to the Effective
     * Address. IFL1 is the tag saying which variant type is in IEV1. IFL2 and IEV2 is the second
     * operand, usually for immediate instructions.
     */

    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
      #define IEVllong2   IEV2.Vllong
    void print();               // pretty-printer

    code() { next = NULL; Iflags = 0; Iop = 0; Iea = 0; IFL1 = 0; IFL2 = 0; }      // constructor

    void orReg(unsigned reg)
    {   if (reg & 8)
            Irex |= REX_R;
        Irm |= modregrm(0, reg & 7, 0);
    }

    void setReg(unsigned reg)
    {
        Irex &= ~REX_R;
        Irm &= ~modregrm(0, 7, 0);
        orReg(reg);
    }

    bool isJumpOP() { return Iop == JMP || Iop == JMPS; }
};

// !=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)
};

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

#if TX86
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];
#endif

/************************************
 * Register save state.
 */

extern "C++"
{
struct REGSAVE
{
    targ_size_t off;            // offset on stack
    unsigned top;               // high water mark
    unsigned idx;               // current number in use
    int alignment;              // 8 or 16

    void reset() { off = 0; top = 0; idx = 0; alignment = REGSIZE; }
    code *save(code *c, int reg, unsigned *pidx);
    code *restore(code *c, int reg, unsigned idx);
};
}
extern REGSAVE regsave;

/*******************************
 * 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;
extern  int STACKALIGN;
#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 );
#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);
bool cse_simple(code *c, elem *e);
code* gen_testcse(code *c, unsigned sz, targ_uns i);
code* gen_loadcse(code *c, unsigned reg, targ_uns i);
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 );
code *scodelem (elem *e , regm_t *pretregs , regm_t keepmsk , bool constflag );
const char *regm_str(regm_t rm);
int numbitsset(regm_t);

/* 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);
unsigned buildModregrm(int mod, int reg, int rm);
void andregcon (con_t *pregconsave);
void genEEcode();
code *docommas (elem **pe );
void gensaverestore(regm_t, code **, code **);
void gensaverestore2(regm_t regm,code **csave,code **crestore);
code *genstackclean(code *c,unsigned numpara,regm_t keepmsk);
code *logexp (elem *e , int jcond , unsigned fltarg , code *targ );
code *loadea (elem *e , code *cs , unsigned op , unsigned reg , targ_size_t offset , regm_t keepmsk , regm_t desmsk );
unsigned getaddrmode (regm_t idxregs );
void setaddrmode(code *c, regm_t idxregs);
void getlvalue_msw(code *);
void getlvalue_lsw(code *);
code *getlvalue (code *pcs , elem *e , regm_t keepmsk );
code *fltregs (code *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 */
int movOnly(elem *e);
regm_t idxregm(code *c);
#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_OPENBSD || 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 cddctor;
cd_t cdddtor;
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_initregs();
void cod3_setdefault();
void cod3_set32 (void );
void cod3_set64 (void );
void cod3_align_bytes (size_t nbytes);
void cod3_align (void );
code* cod3_stackadj(code* c, int nbytes);
regm_t regmask(tym_t tym, tym_t tyf);
void cgreg_dst_regs(unsigned *dst_integer_reg, unsigned *dst_float_reg);
void cgreg_set_priorities(tym_t ty, char **pseq, char **pseqmsw);
void outblkexitcode(block *bl, code*& c, int& anyspill, const char* sflsave, symbol** retsym, const regm_t mfuncregsave );
void doswitch (block *b );
void outjmptab (block *b );
void outswitab (block *b );
int jmpopcode (elem *e );
void cod3_ptrchk(code **pc,code *pcs,regm_t keepmsk);
code *genregs (code *c , unsigned op , unsigned dstreg , unsigned srcreg );
code *gentstreg (code *c , unsigned reg );
code *genpush (code *c , unsigned reg );
code *genpop (code *c , unsigned reg );
code* gensavereg(unsigned& reg, targ_uns slot);
code *genmovreg (code *c , unsigned to , unsigned from );
code *genmulimm(code *c,unsigned r1,unsigned r2,targ_int imm);
code *genshift(code *);
code *movregconst (code *c , unsigned reg , targ_size_t value , regm_t flags );
code *genjmp (code *c , unsigned op , unsigned fltarg , block *targ );
code *prolog (void );
void epilog (block *b);
code *gen_spill_reg(Symbol *s, bool toreg);
cd_t cdframeptr;
cd_t cdgot;
code *load_localgot();
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 simplify_code(code *c);
void jmpaddr (code *c );
int code_match(code *c1,code *c2);
unsigned calcblksize (code *c);
unsigned calccodsize(code *c);
unsigned 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);

extern int hasframe;            /* !=0 if this function has a stack frame */
extern targ_size_t spoff;
extern targ_size_t Foff;        // BP offset of floating register
extern targ_size_t CSoff;       // offset of common sub expressions
extern targ_size_t NDPoff;      // offset of saved 8087 registers
extern int BPoff;                      // offset from BP
extern int EBPtoESP;            // add to EBP offset to get ESP offset
extern int AAoff;               // offset of alloca temporary

code* prolog_ifunc(tym_t* tyf);
code* prolog_ifunc2(tym_t tyf, tym_t tym, bool pushds);
code* prolog_16bit_windows_farfunc(tym_t* tyf, bool* pushds);
code* prolog_frame(unsigned farfunc, unsigned* xlocalsize, bool* enter);
code* prolog_frameadj(tym_t tyf, unsigned xlocalsize, bool enter, bool* pushalloc);
code* prolog_frameadj2(tym_t tyf, unsigned xlocalsize, bool* pushalloc);
code* prolog_setupalloca();
code* prolog_trace(bool farfunc, unsigned* regsaved);
code* prolog_genvarargs(symbol* sv, regm_t* namedargs);
code* prolog_loadparams(tym_t tyf, bool pushalloc, regm_t* namedargs);

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

int doinreg(symbol *s, elem *e);
code *modEA(code *c);
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();

/* cgxmm.c */
code *movxmmconst(unsigned reg, unsigned sz, targ_size_t value, regm_t flags);
code *orthxmm(elem *e, regm_t *pretregs);
code *xmmeq(elem *e, regm_t *pretregs);
code *xmmcnvt(elem *e,regm_t *pretregs);
code *xmmopass(elem *e, regm_t *pretregs);
code *xmmneg(elem *e, regm_t *pretregs);
unsigned xmmload(tym_t tym);
unsigned xmmstore(tym_t tym);
code *cdvector(elem *e, regm_t *pretregs);

/* 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);
void gensaverestore87(regm_t, code **, code **);
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);
#if TX86
extern int stackused;
#endif
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_filltables(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);
code *nteh_patchindex(code* c, int index);

// cgen.c
code *code_last(code *c);
void code_orflag(code *c,unsigned flag);
void code_orrex(code *c,unsigned rex);
code *setOpcode(code *c, code *cs, unsigned op);
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 *genasm (code *c , char *s , unsigned slen );
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_size_t EV2 );
code *genc1 (code *c , unsigned op , unsigned rm , unsigned FL1 , targ_size_t EV1 );
code *genc (code *c , unsigned op , unsigned rm , unsigned FL1 , targ_size_t EV1 , unsigned FL2 , targ_size_t EV2 );
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 *genadjfpu(code *c, int offset);
code *gennop(code *);
code *gencodelem(code *c,elem *e,regm_t *pretregs,bool constflag);
bool reghasvalue (regm_t regm , targ_size_t value , unsigned *preg );
code *regwithvalue (code *c , regm_t regm , targ_size_t 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_block(block *b);

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

struct Ledatarec;               // OMF
struct linnum_data;             // Elf, Mach


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

struct seg_data
{
    int                  SDseg;         // index into SegData[]
    targ_size_t          SDoffset;      // starting offset for data
    int                  SDalignment;   // power of 2

#if OMFOBJ
    bool isfarseg;
    int segidx;                         // internal object file 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
    Ledatarec *ledata;                  // current one we're filling in
#endif

#if 1 //ELFOBJ || MACHOBJ
    IDXSEC               SDshtidx;      // section header table index
    Outbuffer           *SDbuf;         // buffer to hold data
    Outbuffer           *SDrel;         // buffer to hold relocation info
#if 1 //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();
#endif
};



#if 1 //ELFOBJ || MACHOBJ

struct linnum_data
{
    const 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
};

#endif

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

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

/* Allocate registers to function parameters
 */

struct FuncParamRegs
{
    FuncParamRegs(tym_t tyf);

    int alloc(type *t, tym_t ty, unsigned char *reg1, unsigned char *reg2);

  private:
    tym_t tyf;                  // type of function
    int i;                      // ith parameter
    int regcnt;                 // how many general purpose registers are allocated
    int xmmcnt;                 // how many fp registers are allocated
    size_t numintegerregs;      // number of gp registers that can be allocated
    size_t numfloatregs;        // number of fp registers that can be allocated
    const unsigned char* argregs;       // map to gp register
    const unsigned char* floatregs;     // map to fp register
};

extern "C++" { extern const unsigned mask[32]; }

inline regm_t Symbol::Spregm()
{
    /*assert(Sclass == SCfastpar);*/
    return mask[Spreg] | (Spreg2 == NOREG ? 0 : mask[Spreg2]);
}


#if __cplusplus && TX86
}
#endif

