/* $Header:opt.h 12.0$ */
/* $ACIS:opt.h 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/c2_ca/RCS/opt.h,v $ */

#if !defined(lint) && !defined(LOCORE)  && defined(RCS_HDRS)
static char *rcsidopt = "$Header:opt.h 12.0$";
#endif

/* Define Data for ibm032 UNIX C Compiler Optimizer

   Copyright (c) 1985 by IBM
*/

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

#ifndef NULL
#define NULL 0
#endif


/* define the system we are on
   (Currently only used here and in ROPT.C)
*/
#define CMS    1
#define UNIX   2
#define PC     3
#define SYSTEM UNIX


/* defines for validating pointers; see ValidNode() in NODES.C */

#if SYSTEM == CMS
#define MINPTR (char*)0x20000       /* for CMS */
#define MAXPTR (char*)(4*1048576)   /* for CMS */
#endif

#if SYSTEM == UNIX
#define MINPTR (char*)10000000      /* for ibm032 */
#define MAXPTR (char*)0x1FFFFFFF    /* for ibm032 */
#endif

#if SYSTEM == PC
#define MINPTR (char*)0             /* for PC */
#define MAXPTR (char*)(640*1024)    /* for PC */
#endif

#define ValidPointer(p)  ( (p)==NULL ? TRUE : CHECKPRANGE((char*)(p)) )
#define CHECKPRANGE(p)   ( (p)>=MINPTR && (p)<=MAXPTR ? TRUE : FALSE )


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

struct snode {
       struct snode *next;    /* next sequential statement  */
       struct snode *last;    /* last sequential statement  */
       short lineno;          /* number of input line       */
       short seqno;           /* sequence number of line    */
       long  type;            /* the type of the statement  */
       short fregs;           /* free regs (_fregs only)    */
       char ldstype;          /* load/store type            */
       char mods;             /* changes made to this node  */
       int  modby;            /* who changed made by        */
       struct label *lablock; /* pointer to label block     */
       struct snode *labsame; /* next ref to same label     */
       char *labels;          /* string with labels         */
       struct opStat *opcode; /* pointer to opStat entry    */
       char *op1;             /* operand 1                  */
       char *op2a;            /* part of operand 2          */
       char *op2b;            /* sub-part of operand 2      */
       char *op3a;            /* part of operand 3          */
       char *op3b;            /* sub-part of operand 3      */
       char *rest;            /* the rest of the statement  */
             };

/* opcode types */
#define type_unimportant   1 /* unimportant statement            */
#define type_cbranch       4 /* conditional branch               */
#define type_ucbranch      8 /* unconditional branch             */
#define type_branch     0x0C /* branch (any kind)                */
#define type_load       0x10 /* load memory to register          */
#define type_store      0x20 /* store op1 reg into op2 location  */
                             /* (if op2=reg then it's a reg move)*/
#define type_optpseudo  0x40 /* optimizer pseudo op (_freg ...)  */
#define type_pseudo     0x80 /* all pseudo ops (.data ...)       */
#define type_unknown   0x100 /* don't know;  assume worst        */

/* opcode type modifiers */
#define type_ccset    0x1000 /* sets cc                          */
#define type_setreg   0x2000 /* set op1 register                 */
#define type_ccref    0x4000 /* refers to cc                     */
#define type_haslabel 0x8000 /* has a label                      */
#define type_bal     0x10000 /* branch is Branch & Link          */
#define type_execute 0x20000 /* Execute form of branch           */
#define type_btlab   0x40000 /* might have branch target label   */
                             /* as an operand (1st or 2nd only)  */

#define BRANCH(x)       ( ((x)->type & type_branch)      != 0 )
#define UCBRANCH(x)     ( ((x)->type & type_ucbranch)    != 0 )
#define CBRANCH(x)      ( ((x)->type & type_cbranch)     != 0 )
#define FREGS(x)        ( (x)->opcode->opnumber == i_freg  )
#define LOAD(x)         ( ((x)->type & type_load)        != 0 )
#define STORE(x)        ( ((x)->type & type_store)       != 0 )
#define UNKNOWN(x)      ( ((x)->type & type_unknown)     != 0 )
#define UNIMPORTANT(x)  ( ((x)->type & type_unimportant) != 0 )
#define SETCC(x)        ( ((x)->type & type_ccset)       != 0 )
#define REFCC(x)        ( ((x)->type & type_ccref)       != 0 )
#define SETREG(x)       ( ((x)->type & type_setreg)      != 0 )
#define HASLABEL(x)     ( ((x)->type & type_haslabel)    != 0 )
#define EXFORM(x)       ( ((x)->type & type_execute)     != 0 )
#define BTLAB(x)        ( ((x)->type & type_btlab)       != 0 )
#define OPTPSEUDO(x)    ( ((x)->type & type_optpseudo)   != 0 )
#define PSEUDO(x)       ( ((x)->type & type_pseudo)      != 0 )
#define BAL(x)          ( ((x)->type & type_bal)         != 0 )

#define CAS(x)          ( (x)->opcode->opnumber == i_cas)
#define MR(x)           ( CAS(x) && (RegNumber( (x)->op3a ) == 0) )


/* change information */
#define mod_deleted  0x01     /* deleted this statement   */
#define mod_changed  0x02     /* statement changed        */
#define mod_new      0x04     /* statement added          */
#define mod_moved    0x08     /* statement moved          */

#define DELETED(x)    ( ((x)->mods & mod_deleted) != 0)
#define CHANGED(x)    ( ((x)->mods & mod_changed) != 0)
#define NEW(x)        ( ((x)->mods & mod_new)     != 0)
#define MOVED(x)      ( ((x)->mods & mod_moved)   != 0)


/* Who Is Currently Running */
#define who_nobody       0   /* Nobody running now           */
#define who_balr      0x001   /* Running now: balr->balrs opt */
#define who_1load     0x002   /* Running now: load opt pass 1 */
#define who_2load     0x004   /* Running now: load opt pass 2 */
#define who_1jump     0x008   /* Running now: jump opt pass 1 */
#define who_2jump     0x100   /* Running now: jump opt pass 2 */
#define who_regvar    0x010   /* Running now: reg var opt     */
#define who_1mr       0x020   /* Running now: mr opt pass 1   */
#define who_2mr       0x040   /* Running now: mr opt pass 2   */
#define who_misc      0x080   /* Running now: misc opt        */
#define who_long      0x200   /* Running now: long to short   */

#define MODSBYBALR(x)       ( ((x)->modby & who_balr)   != 0)
#define MODSBY1LOAD(x)      ( ((x)->modby & who_1load)  != 0)
#define MODSBY2LOAD(x)      ( ((x)->modby & who_2load)  != 0)
#define MODSBY1JUMP(x)      ( ((x)->modby & who_1jump)  != 0)
#define MODSBY2JUMP(x)      ( ((x)->modby & who_2jump)  != 0)
#define MODSBYREGVAR(x)     ( ((x)->modby & who_regvar) != 0)
#define MODSBY1MR(x)        ( ((x)->modby & who_1mr)    != 0)
#define MODSBY2MR(x)        ( ((x)->modby & who_2mr)    != 0)
#define MODSBYMISC(x)       ( ((x)->modby & who_misc)   != 0)
#define MODSBYLONG(x)       ( ((x)->modby & who_long)   != 0)


/* load and store types */
#define lds_full     'f'    /* References one full word        */
#define lds_half     'h'    /* References a half word          */
#define lds_ahalf    'a'    /* References a half word; signed  */
#define lds_char     'c'    /* References a character          */
#define lds_immed    'i'    /* Immediate load                  */

#define REFFULL(x)     ((x)->ldstype == lds_full)
#define REFHALF(x)     ((x)->ldstype == lds_half)
#define REFHALFA(x)    ((x)->ldstype == lds_ahalf)
#define REFCHAR(x)     ((x)->ldstype == lds_char)
#define REFIMMED(x)    ((x)->ldstype == lds_immed)
#define REFTYPE(x)     ((x)->ldstype != 0)


/* other references */
#define LONGINSTR(x)    ( (x)->opcode!=NULL ? (x)->opcode->inslen == 4 : FALSE )
#define SHORTINSTR(x)   ( (x)->opcode!=NULL ? (x)->opcode->inslen == 2 : FALSE )
#define INSTRLEN(x)     ( (x)->opcode!=NULL ? (int)(x)->opcode->inslen : 0 )
#define OPNUMBER(x)     ( (x)->opcode!=NULL ? (x)->opcode->opnumber : -1 )
#define REGFREE(sp,n)   ( (0x8000>>n) & (sp)->fregs )
#define INSTRTIMING(x)  ( (x)->opcode!=NULL ? (int)(x)->opcode->timing : 0 )
#define FASTINSTR(x)    ( INSTRTIMING(x) == 1 )
#define SLOWINSTR(x)    ( INSTRTIMING(x) >  1 )

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


extern struct snode *Root;         /* the start of it all */
extern struct snode *Tail;         /* the end of the chain */

extern struct snode *FunctLoc;     /* pointer to _funct node */
extern struct snode *EFunctLoc;    /* pointer to _efunct node */

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

struct label {
       struct label *lnext; /* pointer to the next label     */
       char *lname;         /* the labels name               */
       int refcount;        /* count of references to label  */
       struct snode *ldef;  /* pointer to where defined      */
       struct snode *lchain;/* pointer to first of chain of  */
                            /*  references to this label     */
       };

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

/* Flags */

extern int DoBALR;      /* TRUE to optimize BALRs               */
extern int DoLoad;      /* TRUE to optimize Loads               */
extern int DoJumps;     /* TRUE to optimize branches            */
extern int DoRegVar;    /* TRUE to introduce register variables */
extern int DoMR;        /* TRUE to remove MR instructions       */
extern int DoMisc;      /* TRUE to do misc. optimizations       */

extern int Debug;       /* Output debug info;
                           0=none; DBGLEV1=some; DBGLEV2=more   */
extern int Running;
extern int WhoRunning;  /* holds who_xxx for current phase      */
extern int ReadLineno;  /* line number of line in input file    */
extern int ShowMods;
extern int Trace;
extern int MoreToRead;  /* TRUE when not all input as been read */
extern int SeqnoWrong;  /* some change has make sequence
                           numbers invalid                      */

#define DBGLEV1  0x01
#define DBGLEV2  0x03
#define DEBUG1   (Debug &  DBGLEV1)
#define DEBUG2   (Debug == DBGLEV2)


/* file information */

extern char OptName[];     /* Name of optimized output file */
extern char SourceName[];  /* Name of input file as given on command */


/* layout of opcode table  (in opcodtab.c)  */

struct opStat {
       char *opname;      /* the name of the opcode              */
       char  inslen;      /* instruction length                  */
       char  timing;      /* the instruction timing              */
       short opnumber;    /* The opcode (machine ops are < 256)  */
       short opldstype;   /* Characteristics of loads and stores */
       long  optype;      /* Characteristics of the opcode       */
};


/* statistics about optimization */
extern struct  stats {

    /* starting statistics */
    long functions;       /* The number of functions processed    */
    long storage;         /* Total storage allocated (in bytes)   */
    long subpools;        /* Number of subpools obtained (malloc) */
    long inststart;       /* Number instructions before optimization */
    long instend;         /* Number instructions after optimization */

    long loads;
    long stores;
    long balrs;
    long branches;

    long balrmoves;
    long balrmrgen;

    long loadchanges;     /* Loads deleted                       */
    long loadmrchanges;   /* MRs deleted                         */
    long loadgenmr;       /* MRs generated                       */
    long loadpostskip;    /* Post increments/decrements skipped  */
    long redunstore;      /* Redundant stores found              */
    long loadideletes;    /* immed loads deleted                 */

    long jumpdeletes;
    long unreflab;
    long jumptojumps;
    long jumptolabels;
    long deadinst;
    long deadblocks;
    long jumpmoves;
    long jumpunwinds;

    long regvarmr;        /* MRs generated */
    long regvarloads;     /* loads deleted & replaced with MR  */
    long regvarstores;    /* stores deleted & replaced with MR */
    long regvars;         /* number of reg vars created        */

    long mrs;             /* MRs present when MrOpt() starts   */
    long mrdeletes;       /* MRs deleted by MrOpt()            */

    long miscnoops;
    long miscsp;

    } c;


/* FUNCTION DECLARATIONS */

#define  VOID int

/* node manipulation */
struct snode *NewNode();
struct snode *CopyNode();
struct snode *InstNode();
struct snode *NextImportant();
VOID GenRR();
VOID GenRS();
VOID InsertNode( );
VOID MoveAfter( );
VOID PrintNode( );
VOID PrintShortNode( );
char *Myalloc();

struct label *LookupLab();
int Labcmp();
struct opStat *OpcodeEval();
struct snode *ScanFor();

#define UNWINDLIMIT 20  /* max instr. in block
                           to be unwound by jumpopt */

/* values of registers referred to symbolically */
#define SPREG   1
/*#define BPREG  13 */
#define FPREG  13
#define DPREG  14


/* register uses */
#define SCRATCH_REG  0x01
#define REGVAR_REG   0x02
#define SPECIAL_REG  0x04

/* where we remember the register type */
extern int RegType[16];

/* what types the registers have */
#define REGTYP0   SPECIAL_REG
#define REGTYP1   SPECIAL_REG
#define REGTYP2   SCRATCH_REG
#define REGTYP3   SCRATCH_REG
#define REGTYP4   SCRATCH_REG
#define REGTYP5   SCRATCH_REG
#define REGTYP6   REGVAR_REG
#define REGTYP7   REGVAR_REG
#define REGTYP8   REGVAR_REG
#define REGTYP9   REGVAR_REG
#define REGTYP10  REGVAR_REG
#define REGTYP11  REGVAR_REG
#define REGTYP12  SCRATCH_REG
#define REGTYP13  SPECIAL_REG
#define REGTYP14  SPECIAL_REG
#define REGTYP15  SCRATCH_REG

/* how we ask about register types */
#define REGVARREG(n)   ( RegType[n] & REGVAR_REG )
#define SCRATCHREG(n)  ( RegType[n] & SCRATCH_REG )
#define SPECIALREG(n)  ( RegType[n] & SPECIAL_REG )

/* which registers are used by RUCC as scratch and how it
   knows them internally. (from mac2defs.h, a part of RUCC).
   The flags output on the _FREG op use RUCC internal numbering */
/* define R0  0  */
/* define R2  1  */
/* define R3  2  */
/* define R4  3  */
/* define R5  4  */
/* define R15 5  */

/* definition of bits in _FREG operand.  If "FREG_Rn" is nonzero
   then the position of the 1 bit matches the position
   in the operand of a _fregs for that register.
   Note that R0 is considered by RUCC as a scratch register
   but is NOT so considered by ROPT  */
#define FREG_R0    0x0000   /* scratch but we ignore it */
#define FREG_R1    0x0000
#define FREG_R2    0x0004
#define FREG_R3    0x0008
#define FREG_R4    0x0010
#define FREG_R5    0x0020
#define FREG_R6    0x0040
#define FREG_R7    0x0080
#define FREG_R8    0x0100
#define FREG_R9    0x0200
#define FREG_R10   0x0400
#define FREG_R11   0x0800
#define FREG_R12   0x1000
#define FREG_R13   0x0000
#define FREG_R14   0x0000
#define FREG_R15   0x8000

#define ALL_FREE  "0xFFFF" /* _fregs opnd that means all regs free */

/* macros for testing characters
   (so we don't depend on erratic portability
   of isdigit, isupper, etc.)
   Names changed to protect the guilty.       */
#define inrange(n,a,b)   ((n)>=(a) && (n)<=(b))
#define isdig(n)    (inrange(n,'0','9'))
#define isxdig(n)  ((inrange(n,'0','9') \
                  || inrange(n,'a','f') \
                  || inrange(n,'A','F')))
#define isupc(c)    (inrange(c,'A','Z'))
#define islowc(c)   (inrange(c,'a','z'))
#define islet(c)    (isupc(c) || islowc(c))
#define isalpha(c)  (isupc(c) || islowc(c))
