/*
 * Copyright (C) 2007, 2008. PathScale, LLC. All Rights Reserved.
 */

/*
 * Copyright (C) 2009 Advanced Micro Devices, Inc.  All Rights Reserved.
 */

/*
 * Copyright (C) 2007. QLogic Corporation. All Rights Reserved.
 */

/*
 * Copyright 2003, 2004, 2005, 2006 PathScale, Inc.  All Rights Reserved.
 */

/*

  Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.

   Path64 is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   Path64 is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   License for more details.

   You should have received a copy of the GNU General Public License
   along with Path64; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

   Special thanks goes to SGI for their continued support to open source

*/


/* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */

#ifndef symtab_defs_INCLUDED
#define symtab_defs_INCLUDED

#include <map>
#include <vector>

// Note:
//
// The comments in this file are intentionally brief.  For detail description,
// please refer to the "WHIRL Symbol Table Specification", which is the only
// document actively maintained.
//
// KEY: Any change in this file (and friends) about change in struct size
// or ordering of struct fields may need to be reflected elsewhere in the
// compiler, at least one known place of which is ipa/common/ipc_ty_hash.cxx
// and friends.
// Last notable change: changing STR_IDX from UINT32 to UINT64.


enum ST_CLASS
{
    CLASS_UNK	= 0,
    CLASS_VAR	= 1,			// data variable
    CLASS_FUNC	= 2,			// addrress of a function.
    CLASS_CONST	= 3,			// constant value
    CLASS_PREG	= 4,			// pseudo register
    CLASS_BLOCK	= 5,			// base to a block of data
    CLASS_NAME  = 6,			// just hold an ST name
    CLASS_COUNT = 7			// total number of classes
}; // ST_CLASS


enum ST_SCLASS
{
    // the values should not overlap with those in ST_CLASS for error checking
    SCLASS_UNKNOWN	= 0,
    SCLASS_AUTO		= 1,		// stack variable
    SCLASS_FORMAL	= 2,		// formal parameter
    SCLASS_FORMAL_REF	= 3,		// reference parameter
    SCLASS_PSTATIC	= 4,		// PU scope static data
    SCLASS_FSTATIC	= 5,		// file scope static data
    SCLASS_COMMON	= 6,		// common block (linker allocated)
    SCLASS_EXTERN	= 7,		// unallocated external data or text
    SCLASS_UGLOBAL	= 8,		// uninitialized global data
    SCLASS_DGLOBAL	= 9,		// initialized global data
    SCLASS_TEXT		= 10,		// executable code
    SCLASS_REG		= 11,		// register variable
    SCLASS_CPLINIT	= 12,		// cplinit
    SCLASS_EH_REGION	= 13,		// eh region
    SCLASS_EH_REGION_SUPP = 14,		// eh region supp
    SCLASS_DISTR_ARRAY	= 15,		// distributed array
    SCLASS_COMMENT	= 16,		// comment section
    SCLASS_THREAD_PRIVATE_FUNCS	= 17, // thread-private constr/destr funcs
    SCLASS_COUNT	= 18		// total number of classes

}; // ST_SCLASS


enum ST_EXPORT
{
    EXPORT_LOCAL	= 0,		// Not exported, e.g. C static
    EXPORT_LOCAL_INTERNAL = 1,		// Statics that do not have address
					// passed outside of a.out/DSO. 
    EXPORT_INTERNAL	= 2,		// Exported, only visible and used
					// within the containing
					// DSO/executable, i.e. not even
					// passed outside using a pointer.  
    EXPORT_HIDDEN	= 3,		// Exported, but name is hidden
					// within the containing
					// DSO/executable.  However, the
					// address may be exported from the
					// DSO via a pointer.  
    EXPORT_PROTECTED	= 4,		// Exported from DSO, but
					// non-preemptible. 
    EXPORT_PREEMPTIBLE	= 5,		// Exported and preemptible.
    EXPORT_OPTIONAL	= 6,		// STO_OPTIONAL case in "sys/elf.h"
    EXPORT_COUNT	= 7		// Must be last for consistency
					// checking 
}; // ST_EXPORT


enum ST_FLAGS
{
    ST_IS_WEAK_SYMBOL	= 0x00000001,	// Weak external name
    ST_IS_SPLIT_COMMON	= 0x00000002,	// part of a splitted common
    ST_IS_NOT_USED	= 0x00000004,	// Symbol is not referenced
    ST_IS_INITIALIZED	= 0x00000008,	// Symbol is initialized
    ST_IS_RETURN_VAR	= 0x00000010,	// CLASS_VAR: Return value
    ST_IS_VALUE_PARM	= 0x00000020,	// CLASS_VAR: Value parm
    ST_PROMOTE_PARM	= 0x00000040,	// CLASS_VAR: Promote C formal
    ST_KEEP_NAME_W2F	= 0x00000080,	// CLASS_VAR: don't mangle name
    ST_IS_DATAPOOL	= 0x00000100,	// CLASS_VAR: represents datapool
    ST_IS_RESHAPED	= 0x00000200,	// lno may reshape the ST
    ST_EMIT_SYMBOL	= 0x00000400,	// emit the empty dummy symbol
    ST_HAS_NESTED_REF	= 0x00000800,	// has ref in nested pu
    ST_INIT_VALUE_ZERO	= 0x00001000,	// has initial value of zero
    ST_GPREL		= 0x00002000,	// force object to be gp-rel
    ST_NOT_GPREL	= 0x00004000,	// force object to not be gp-rel
    ST_IS_NAMELIST	= 0x00008000,	// namelist table
    ST_IS_F90_TARGET	= 0x00010000,	// F90 target
    ST_DECLARED_STATIC	= 0x00020000,	// VMS formals declared static
    ST_IS_EQUIVALENCED	= 0x00040000,	// is part of an equivalence
    ST_IS_FILL_ALIGN	= 0x00080000,	// has fill/align pragma.
    ST_IS_OPTIONAL_ARGUMENT = 0x00100000, // F90 OPTIONAL arguments
    ST_PT_TO_UNIQUE_MEM	= 0x00200000,	// a pointer that is not aliased
    ST_IS_TEMP_VAR	= 0x00400000,	// compiler generated temp. variable
    ST_IS_CONST_VAR	= 0x00800000,	// read-only variable
    ST_ADDR_SAVED	= 0x01000000,	// address saved
    ST_ADDR_PASSED	= 0x02000000,	// address passed
    ST_IS_THREAD_PRIVATE = 0x04000000,	// Symbol is allocated in XLOCAL
					// data segment
    ST_PT_TO_COMPILER_GENERATED_MEM = 0x08000000,   // a pointer to compiler-
                                        // allocated memory space
    ST_IS_SHARED_AUTO = 0x10000000,     // SCLASS_AUTO and accessed with
                                        // SHARED scope in an MP region
    ST_ASSIGNED_TO_DEDICATED_PREG = 0x20000000,	// assigned to dedicated preg
						// specified in offset
    ST_ASM_FUNCTION_ST  = 0x40000000,	// ST is CLASS_NAME asm string with
                                        // file scope.
    ST_HAS_NAMED_SECTION = 0x80000000	// has named section attribute
    // new flags must go into flags_ext field.
}; // ST_FLAGS
   
enum ST_FLAGS_EXT
{
#ifdef KEY
    ST_ONE_PER_PU = 0x01,		// Only 1 instance per pu
    ST_COPY_CONSTRUCTOR_ST =   0x02,	// ST is copy constructor function
    ST_INITV_IN_OTHER_ST   =   0x04,	// ST is being used as an initianliation
					// offset by other symbol
    ST_IS_PURE_VFUNC    = 0x40,         // ST is pure virtual function

    ST_IS_THREAD_LOCAL     =   0x08,	// ST is thread-local (GCC __thread)
#endif
        /* (cbr) vague linkage support */
    ST_IS_COMDAT = 0x8000,        //  C++ PU need will be generated by any
                                      // translation unit than needs it
    ST_HAS_ALIAS = 0x10000,        // symbol is base of aliases
    ST_ALIAS_USED= 0x20000,        // symbol is an alias and is referenced
    ST_IS_USED =   0x40000,        // symbol has used attribute
    ST_IS_NOT_SIZED =   0x80000,       // symbol has not its size for the moment
}; // ST_FLAGS_EXT

// symbol table element
class ST
{
public:
    mUINT64 offset;			// offset from base

    ST_IDX base_idx;			// base of the allocated block

    ST_IDX st_idx;			// my own st_idx

    union {
	STR_IDX name_idx;		// index to the name string
	TCON_IDX tcon;			// constant value
    } u1;

    union {
	TY_IDX type;			// idx to high-level type
	PU_IDX pu;			// idx to program unit table
	BLK_IDX blk;			// idx to block table
    } u2;

    mUINT32 flags;			// misc. attributes

    mUINT8 flags_ext;			// more attributes

    ST_CLASS sym_class : 8;		// class info
    ST_SCLASS storage_class : 8;	// storage info
    ST_EXPORT export_class : 8;		// export class of the symbol

    // operations
    
    ST ()  {Fail_FmtAssertion("ST default constructor must not be called.");}

    void Verify(UINT level) const;
    
    void Print(FILE *f, BOOL verbose = TRUE) const;

}; // ST

// Now verify that ST has no gaps. IPA does memcmp on it and needs it tightly packed.
#ifdef _WIN32
// ??? FIXME: the code below doesn't work for some reason
#else
typedef int CTAssert_ST_has_gaps[(sizeof(ST) == sizeof(((ST *)NULL)->offset) +
    sizeof(((ST *)NULL)->base_idx) +sizeof(((ST *)NULL)->st_idx) + 
    sizeof(((ST *)NULL)->u1) + sizeof(((ST *)NULL)->u2) + sizeof(((ST *)NULL)->flags) +
    sizeof(((ST *)NULL)->flags_ext) + 3) ? 1 : -1]; 
#endif

// Give information about a field in a struct.  The TY of the struct type
// points to the FLD entry for the first field.  The remaining fields
// follow in consecutive FLD entries, until a flag indicates it is the last
// field.

enum FLD_FLAGS
{
    FLD_LAST_FIELD	= 0x0001,	// last field in a struct
    FLD_EQUIVALENCE	= 0x0002,	// fortran equivalence
    FLD_BEGIN_UNION	= 0x0004,      	// begin a union
    FLD_END_UNION	= 0x0008,	// end a union
    FLD_BEGIN_MAP	= 0x0010,	// begin a map (fortran)
    FLD_END_MAP		= 0x0020,	// end a map
    FLD_IS_BIT_FIELD	= 0x0040,	// is bit field
    FLD_IS_ANONYMOUS    = 0x0080,       // is anonymous field
    FLD_IS_BASE_CLASS   = 0x0100,       // is a field of base class type
};

struct FLD
{
    STR_IDX name_idx;

    mUINT64 ofst;			// offset within the struct in bytes

    ST_IDX st;				// used if an st exists for this fld

    TY_IDX type;

    mUINT8 bsize;			// bit field size in bits
    mUINT8 bofst;			// bit field offset starting at
					// byte specified by ofst
    mUINT16 flags;			// misc. attributes
    mUINT32 unused;                     // padding

    // operations

    FLD ();

    void Verify (UINT64 record_size) const;

    void Print (FILE *f) const;

}; // FLD


typedef TY_IDX TYLIST;			// for now, it's just a list of TY_IDX


// Give information about a dimension of an array.  The TY of the array type
// points to the ARB entry for the first dimension.  The remaining dimensions
// follow in consecutive ARB entries until a flag indicates it is the last
// dimension.
enum ARB_FLAGS
{
    ARB_CONST_LBND	= 0x0001,	// constant lower bound
    ARB_CONST_UBND	= 0x0002,	// constant upper bound
    ARB_CONST_STRIDE	= 0x0004,	// constant stride
    ARB_FIRST_DIMEN	= 0x0008,	// first dimension
    ARB_LAST_DIMEN	= 0x0010	// last dimension
};

struct ARB
{
    mUINT16 flags;			// misc. attributes
    mUINT16 dimension;			// number of dimensions

    mUINT32 unused;			// must be zero'ed

    union {
	mINT64 lbnd_val;		// constant lower bound value
	struct {
	    ST_IDX lbnd_var;		// variable that stores the
					// non-constant lower bound
#ifndef _LP64
	    mINT32 unused;		// filler, must be zero'ed
#endif // !_LP64
	} var;
    } u1;

    union {
	mINT64 ubnd_val;		// constant upper bound value
	struct {
	    ST_IDX ubnd_var;		// variable that stores the
					// non-constant upper bound
#ifndef _LP64
	    mINT32 unused;		// filler, must be zero'ed
#endif // !_LP64
	} var;
    } u2;

    union {
	mINT64 stride_val;		// constant stride
	struct {
	    ST_IDX stride_var;		// variable that stores the
					// non-constant stride
#ifndef _LP64
	    mINT32 unused;		// filler, must be zero'ed
#endif // !_LP64
	} var;
    } u3;

    // access functions
    INT64 Lbnd_val () const		{ return u1.lbnd_val; }
    void Set_lbnd_val (INT64 val)	{ u1.lbnd_val = val; }

    ST_IDX Lbnd_var () const		{ return u1.var.lbnd_var; }
    void Set_lbnd_var (ST_IDX st) {
	u1.var.lbnd_var = st;
#ifndef _LP64
	u1.var.unused = 0;
#endif // !_LP64
    }
    
    INT64 Ubnd_val () const		{ return u2.ubnd_val; }
    void Set_ubnd_val (INT64 val)	{ u2.ubnd_val = val; }

    ST_IDX Ubnd_var () const		{ return u2.var.ubnd_var; }
    void Set_ubnd_var (ST_IDX st) {
	u2.var.ubnd_var = st;
#ifndef _LP64
	u2.var.unused = 0;
#endif // !_LP64
    }
    
    INT64 Stride_val () const		{ return u3.stride_val; }
    void Set_stride_val (INT64 val)	{ u3.stride_val = val; }

    ST_IDX Stride_var () const		{ return u3.var.stride_var; }
    void Set_stride_var (ST_IDX st) {
	u3.var.stride_var = st;
#ifndef _LP64
	u3.var.unused = 0;
#endif // _LP64
    }
    
	
    // operations

    ARB () { memset (this, 0, sizeof(ARB)); }

    void Verify (mUINT16 dim) const;
    
    void Print (FILE *f) const;

}; // ARB


enum LABEL_KIND
{
    LKIND_DEFAULT		= 0,
    LKIND_ASSIGNED		= 1,	// in ASSIGNED statement
    LKIND_BEGIN_EH_RANGE	= 2,
    LKIND_END_EH_RANGE		= 3,
    LKIND_BEGIN_HANDLER		= 4,
    LKIND_END_HANDLER		= 5,
    LKIND_TAG			= 6	// symbolic address, never branched to
};

enum LABEL_FLAGS
{
    LABEL_TARGET_OF_GOTO_OUTER_BLOCK	= 1,
    LABEL_ADDR_SAVED			= 2,
    LABEL_ADDR_PASSED			= 4,
    LABEL_ADDR_INLINE_SAVED     = 8
};

struct LABEL
{
    STR_IDX    name_idx;
    mUINT32    flags:24;
    LABEL_KIND kind:8;

    // operations
    
    LABEL () {Fail_FmtAssertion("LABEL default constructor must not be called.");}

    LABEL (STR_IDX idx, LABEL_KIND k) : name_idx (idx), kind (k) {}

    void Verify(UINT level) const;

    void Print (FILE *f) const;
}; // LABEL


struct PREG
{
    STR_IDX  name_idx;

    // operations
    PREG(void)
      {
	Fail_FmtAssertion("PREG default constructor must not be called.");
      }

    PREG (STR_IDX idx) : name_idx (idx) { }

    void Verify(UINT level) const;

    void Print (FILE *f) const;

}; // PREG


// misc. ST attributes
enum ST_ATTR_KIND
{
    ST_ATTR_UNKNOWN		= 0,
    ST_ATTR_DEDICATED_REGISTER	= 1,	// physical register number
    ST_ATTR_SECTION_NAME	= 2	// name of sections where defined.
};

class ST_ATTR
{
    public:
    ST_IDX st_idx;
    ST_ATTR_KIND kind;
    private:
    union {
	mUINT32 value;			// generic 32-bit value
	mPREG_NUM reg_id;
	STR_IDX section_name;
    } u;

    public:
    // operations
    ST_ATTR () {
	Fail_FmtAssertion("ST_ATTR default constructor must not be called.");
    }

    ST_ATTR (ST_IDX idx, ST_ATTR_KIND akind, UINT64 val) :
	st_idx (idx), kind (akind) {
	u.section_name = val;
    }

    // Access the union value
    void Set_u (UINT64 val) {
        u.section_name = val;
    }

    // Access reg_id
    void Set_reg_id (mPREG_NUM r) {
        u.reg_id = r;
    }

    mPREG_NUM Get_reg_id (void) const {
        return u.reg_id;
    }

    // Access section_name
    void Set_section_name (STR_IDX i) {
        u.section_name = i;
    }

    STR_IDX Get_section_name (void) const {
        return u.section_name;
    }
	    

    void Verify (UINT level) const;

    void Print (FILE* f) const;
}; // ST_ATTR


/* Kinds of types: */
enum TY_KIND
{
    KIND_INVALID	= 0,		// Invalid
    KIND_SCALAR		= 1,		// integer/floating point
    KIND_ARRAY		= 2,		// array
    KIND_STRUCT		= 3,		// struct/union
    KIND_POINTER	= 4,		// pointer
    KIND_FUNCTION	= 5,		// function/procedure
    KIND_VOID		= 6,		// C void type
    KIND_LAST		= 8
};


enum TY_FLAGS
{
    TY_IS_CHARACTER	= 0x0001,	/* type is a character (fortran) */
    TY_IS_LOGICAL	= 0x0002,	/* Type is logical (fortran) */
    TY_IS_UNION		= 0x0004,	/* Struct or class type is union */
    TY_IS_PACKED	= 0x0008,	/* Struct or class type is packed */
    TY_PTR_AS_ARRAY	= 0x0010,	/* Treat pointer as array */
    TY_ANONYMOUS	= 0x0020,	/* Anonymous structs/classes/unions */
    TY_SPLIT		= 0x0040,	/* Split from a larger common block
					 * equivalence (block_split) */
    TY_IS_F90_POINTER	= 0x0080,	/* If the type is an F90 pointer */
    TY_NOT_IN_UNION	= 0x0100,	/* If the type cannot be part of a union */
    TY_NO_ANSI_ALIAS	= 0x0200,	// ANSI alias rules don't applied
    TY_IS_NON_POD	= 0x0400,	// type is non pod (for C++ classes)
#ifdef KEY
    TY_RETURN_IN_MEM	= 0x0800,	// Functions must return objects of this
					// type in memory.
    TY_CONTENT_SEEN	= 0x1000,	// for differentiating between a 0-sized
    					// struct and its forward declaration;
					// used by wgen
    TY_IS_INCOMPLETE	= 0x2000,	// Type is incomplete, used by wgen to
					// mark VLA types when used as function
					// arguments.
    TY_NO_SPLIT         = 0x4000,       // May be used by any phase after
                                        // front-end for TY that should not
                                        // be split.
#endif

    TY_COMPLETE_STRUCT_RELAYOUT_CANDIDATE = 0x0001, // it's OK to share this
      // with TY_IS_CHARACTER above for now, since this has to be a struct
};


// TY flags that are valid only for KIND_FUNCTION
enum TY_PU_FLAGS
{
    TY_RETURN_TO_PARAM	= 0x00000001,	// return value through first param
    TY_IS_VARARGS	= 0x00000002,	// variable number of arguments
    TY_HAS_PROTOTYPE	= 0x00000004,	// has ansi-style prototype
#ifdef TARG_X8664
    TY_HAS_SSEREG_PARM	= 0x00000008,	// SSE register parameters under i386
    TY_HAS_1_REG_PARM	= 0x00000010,	// 1 register parameter under i386
    TY_HAS_2_REG_PARM	= 0x00000020,	// 2 register parameters under i386
    TY_HAS_3_REG_PARM	= 0x00000030	// 3 register parameters under i386
#endif
};

class TY
{
public:
    mUINT64 size;			// size of the type in bytes

    TY_KIND kind : 8;			// kind of type
    mTYPE_ID mtype : 8;			// WHIRL data type
    mUINT16 flags;			// misc. attributes

    union {
	FLD_IDX fld;
	TYLIST_IDX tylist;
	ARB_IDX arb;
    } u1;				// idx to FLD_TAB, TYLIST_TAB, etc.

    STR_IDX name_idx;			// name 

    union {
	TY_IDX etype;			// type of array element (array only)
	TY_IDX pointed;			// pointed-to type (pointers only)
        struct {
	    mUINT32 pu_flags;		// attributes for KIND_FUNCTION
#ifdef _LP64
            mUINT32 unused;             // padding
#endif // _LP64
        } flags;
#ifdef KEY
	ST_IDX copy_constructor;	// copy constructor X(X&) (record only)
#endif
    } u2;

    // access function for unions

    FLD_IDX Fld () const		{ return u1.fld; }
    void Set_fld (FLD_IDX idx)		{ u1.fld = idx; }
    
    TYLIST_IDX Tylist () const		{ return u1.tylist; }
    void Set_tylist (TYLIST_IDX idx)	{ u1.tylist = idx; }
    
    ARB_IDX Arb () const		{ return u1.arb; }
    void Set_arb (ARB_IDX idx)		{ u1.arb = idx; }

    TY_IDX Etype () const
      {
	Is_True(kind == KIND_ARRAY,
		("non-KIND_ARRAY type has no element type"));
	return u2.etype;
      }
    void Set_etype (TY_IDX idx)		{ u2.etype = idx; }
    
    TY_IDX Pointed () const
      {
	Is_True(kind == KIND_POINTER,
		("non-KIND_POINTER type doesn't point"));
	return u2.pointed;
      }
    void Set_pointed (TY_IDX idx)	{ u2.pointed = idx; }

#ifdef KEY
    ST_IDX Copy_constructor () const
      {
	Is_True(kind == KIND_STRUCT,
		("non-KIND_STRUCT type has no copy constructor"));
	return u2.copy_constructor;
      }
    void Set_copy_constructor (ST_IDX idx)	{ u2.copy_constructor = idx; }
#endif	// KEY

    PU_IDX Pu_flags () const		{ return u2.flags.pu_flags; }

    void Set_pu_flag (TY_PU_FLAGS f)
      {
        u2.flags.pu_flags |= f;
#ifdef _LP64
        u2.flags.unused = 0;
#endif // _LP64
      }

    void Clear_pu_flag (TY_PU_FLAGS f)
      {
        u2.flags.pu_flags &= ~f;
#ifndef _LP64
        u2.flags.unused = 0;
#endif // _LP64
      }

    // operations

    TY ();

    void Verify(UINT level) const;

    void Print (FILE *f) const;

}; // TY


// PU_FLAGS: cannot use enum as some of the the values are > max unsigned int

#define	PU_IS_PURE		0x00000001	// pure function
#define	PU_NO_SIDE_EFFECTS	0x00000002	// no side effect
#define	PU_IS_INLINE_FUNCTION	0x00000004	// inline keyword specified
#define	PU_NO_INLINE		0x00000008	// noinline pragma specified
#define	PU_MUST_INLINE		0x00000010	// must inline
#define	PU_NO_DELETE		0x00000020	// nodelete pragma specified
#define	PU_HAS_EXC_SCOPES	0x00000040	// has eh regions, or would have
						// if exceptions were enabled
#define	PU_IS_NESTED_FUNC	0x00000080	// is a nested function
#define	PU_HAS_NON_MANGLED_CALL	0x00000100	// PU has a call in which no
					 	// reshaped arrays are passed
#define	PU_ARGS_ALIASED		0x00000200	// f77 arguments are aliased
#define	PU_NEEDS_FILL_ALIGN_LOWERING 0x00000400	// needs fill/align lowering
#define	PU_NEEDS_T9		0x00000800	// needs T9
#define	PU_HAS_VERY_HIGH_WHIRL	0x00001000	// PU has very high whirl in it
#define	PU_HAS_ALTENTRY		0x00002000	// PU has alternate entries
#define	PU_RECURSIVE		0x00004000	// in recursive path
#define	PU_IS_MAINPU		0x00008000	// is entry point of program
#define	PU_UPLEVEL		0x00010000	// Other PU nested in this one
#define	PU_MP_NEEDS_LNO		0x00020000	// PU needs LNO processing
#define	PU_HAS_ALLOCA		0x00040000	// PU has alloca in it
#define	PU_IN_ELF_SECTION	0x00080000	// PU is in its own Elf section
#define	PU_HAS_MP		0x00100000	// Symtab has MP region/do within it
#define	PU_MP			0x00200000	// PU is an MP region/do
#define	PU_HAS_NAMELIST		0x00400000	// PU has namelist
#define	PU_HAS_RETURN_ADDRESS	0x00800000	// __return_address was used
#define	PU_HAS_REGION		0x01000000	// PU has regions in it
#define	PU_HAS_INLINES		0x02000000	// PU has inlined code in it
#define	PU_CALLS_SETJMP		0x04000000	// PU has calls to setjmp(2)
#define	PU_CALLS_LONGJMP	0x08000000	// PU has calls to longjmp(2)
#define PU_IPA_ADDR_ANALYSIS    0x10000000      // IPA has done address analysis
#define PU_SMART_ADDR_ANALYSIS  0x20000000      // Unnecessary addr flags are reset

#define	PU_HAS_SYSCALL_LINKAGE	0x40000000	// preserve input regs
#define PU_HAS_GLOBAL_PRAGMAS	0x80000000	// PU is a dummy pu with global
						//   pragmas
#define	PU_HAS_USER_ALLOCA	0x0000000100000000LL
						// PU has user alloca in it
#define	PU_HAS_UNKNOWN_CONTROL_FLOW	0x0000000200000000LL
						// PU has unknown control flow
						//  which disables tail call 
						// optimization
#define PU_IS_THUNK		0x0000000400000000LL // pu is a C++ thunk

#ifdef KEY
#define PU_NEEDS_MANUAL_UNWINDING	0x0000000800000000LL // PU has cleanups in outermost scope and hence needs to call _Unwind_Resume itself
#endif
#ifdef TARG_X8664
#define PU_FF2C_ABI		0x0000001000000000LL // PU use g77 linkage convention for returns of complex and float
#endif
#ifdef KEY
#define PU_IS_EXTERN_INLINE	0x0000002000000000LL // PU is marked extern _inline_ in C
#define PU_MP_LOWER_GENERATED	0x0000004000000000LL // PU generated by mp-lowerer
#define PU_IS_MARKED_INLINE	0x0000008000000000LL
                                           // C/C++: inline keyword used. Note
                                           // PU_IS_INLINE_FUNCTION just
                                           // indicates GNU inlining decision.
#define PU_NO_INSTRUMENT	0x0000010000000000LL // -finstrument-functions will skip PU
#define PU_NEED_TRAMPOLINE	0x0000020000000000LL // a nested function whose address is taken
#define PU_HAS_NONLOCAL_GOTO_LABEL	0x0000040000000000LL // has a label jumped to directly from a nested function
#define PU_HAS_GOTO_OUTER_BLOCK	0x0000080000000000LL // has GOTO_OUTER_BLOCK stmt
#endif

enum PU_SRC_LANG_FLAGS
{
    PU_UNKNOWN_LANG	= 0x00,	// UNKNOWN 
    PU_MIXED_LANG	= 0x01,	// MIXED
    PU_C_LANG		= 0x02,	// C
    PU_CXX_LANG		= 0x04,	// C++
    PU_F77_LANG		= 0x08,	// F77
    PU_F90_LANG		= 0x10,	// F90
    PU_JAVA_LANG	= 0x20	// JAVA
};

struct PU
{
    TARGET_INFO_IDX target_idx;		// idx to table for target-specific 
					// information

    TY_IDX prototype;			// function prototype
    SYMTAB_IDX lexical_level;		// lexical level (of nested proc).
    INITO_IDX misc;		        // store misc such EH related TYPE/TYPE_SPEC info. 32bits
    mUINT8 gp_group;			// gp_group id
    mUINT8 src_lang;			// source language
    mUINT8 unused;		        // for alignment for flags
    mUINT64 flags;			// misc. attributes about this func.

    // operations

    PU ();

    void Verify(UINT level) const;

    void Print (FILE *f) const;

    typedef std::vector<ST*> eh_spec_vector;
    typedef std::map<ST*, int> type_info_table;

    // Fills EH spec for PU
    void Get_eh_spec(eh_spec_vector &) const;

    // Filles type info table for PU
    void Get_type_info_table(type_info_table &) const;
}; // PU


// BLK only exists for CLASS_BLOCK.
// It is used for data layout in be.
// Only reason it is not local to be is that
// the IPA global symbol table will need the info.
class BLK
{
private:

	mUINT64 size;		// size of the block
	mUINT16 align;		// alignment of the block: 1,2,4,8
	mUINT16 flags;		// block flags
	mUINT16 section_idx;	// section index (0 if not a section)
	mUINT16 scninfo_idx;	// scninfo_idx (0 if not a section)

public:

	BLK () : size (0), section_idx(0), scninfo_idx(0), flags (0) {}

	void Init (void)	{ memset (this, 0, sizeof(BLK)); }

public:

    // access functions

    UINT64 Size () const	{ return size; }
    void Set_size (UINT64 s)	{ size = s; }

    UINT16 Align () const	{ return align; }
    void Set_align (UINT16 s)	{ align = s; }

    UINT16 Section_idx () const	{ return section_idx; }
    void Set_section_idx (UINT16 s)	{ section_idx = s; }
    UINT16 Scninfo_idx () const	{ return scninfo_idx; }
    void Set_scninfo_idx (UINT16 s)	{ scninfo_idx = s; }

    UINT16 Flags () const		{ return flags; }
    BOOL Is_set (UINT16 f) const	{ return flags & f; }
    void Set_flags (UINT16 f)		{ flags |= f; }
    void Clear_flags (UINT16 f)		{ flags &= ~f; }
    void Clear_all_flags ()		{ flags = 0; }

    void Print (FILE *f) const;
}; // BLK

// BLK flags
#define BLK_SECTION		0x0001 // block for elf section
#define BLK_ROOT_BASE		0x0002 // block should not be merged
#define BLK_IS_BASEREG		0x0004 // block that maps into reg
#define BLK_DECREMENT		0x0008 // grow block by decrementing
#define BLK_EXEC		0x0010 // (ELF) executable instructions
#define BLK_NOBITS		0x0020 // (ELF) occupies no space in file
#define BLK_MERGE		0x0040 // (ELF) merge duplicates in ld
#define BLK_COMPILER_LAYOUT	0x0080 // children symbols are not connected


// place holder for misc. file-level info

enum FILE_INFO_FLAGS
{
    FI_IPA		= 0x1,		// IPA generated file
    FI_NEEDS_LNO	= 0x2,		// needs to run LNO
    FI_HAS_INLINES	= 0x4,		// some PUs have PU_HAS_INLINES set
    FI_HAS_MP   	= 0x8		// need to process MP constructs
};

struct FILE_INFO
{
    mUINT32 flags;			// misc. attributes
    mUINT8 gp_group;			// gp group id
    mUINT32 unused : 24;		// filler, must be zero

    void Verify() const;
    void Print (FILE *f) const;
    FILE_INFO () : flags (0), gp_group (0), unused (0) {}

};


// Type definitions of the symbol tables

typedef SEGMENTED_ARRAY<PU>	PU_TAB;
typedef RELATED_SEGMENTED_ARRAY<ST>	ST_TAB;
typedef SEGMENTED_ARRAY<TY>	TY_TAB;
typedef SEGMENTED_ARRAY<FLD>	FLD_TAB;
typedef SEGMENTED_ARRAY<TYLIST>	TYLIST_TAB;
typedef SEGMENTED_ARRAY<ARB>	ARB_TAB;
typedef RELATED_SEGMENTED_ARRAY<LABEL>	LABEL_TAB;
typedef RELATED_SEGMENTED_ARRAY<PREG>	PREG_TAB;
typedef SEGMENTED_ARRAY<ST_ATTR>	ST_ATTR_TAB;
typedef SEGMENTED_ARRAY<BLK>	BLK_TAB;
typedef SEGMENTED_ARRAY<TCON,64> TCON_TAB;
typedef SEGMENTED_ARRAY<INITO>	INITO_TAB;
typedef SEGMENTED_ARRAY<INITV>	INITV_TAB;

typedef PU_TAB::iterator	PU_ITER;
typedef ST_TAB::iterator	ST_ITER;
typedef TY_TAB::iterator	TY_ITER;
typedef FLD_TAB::iterator	FLD_ITER;
typedef TYLIST_TAB::iterator	TYLIST_ITER;
typedef ARB_TAB::iterator	ARB_ITER;
typedef LABEL_TAB::iterator	LABEL_ITER;
typedef PREG_TAB::iterator	PREG_ITER;
typedef ST_ATTR_TAB::iterator	ST_ATTR_ITER;
typedef BLK_TAB::iterator	BLK_ITER;
typedef TCON_TAB::iterator	TCON_ITER;
typedef INITO_TAB::iterator	INITO_ITER;
typedef INITV_TAB::iterator	INITV_ITER;


struct SCOPE
{
    MEM_POOL *pool;			// mem pool for local tables
    ST* st;				// ST * for the current pu
    ST_TAB *st_tab;
    LABEL_TAB *label_tab;
    PREG_TAB *preg_tab;
    INITO_TAB *inito_tab;
    ST_ATTR_TAB *st_attr_tab;

    void Init (ST_TAB *s) {
	// for global symtab
	pool = NULL;
	st_tab = s;
	st = NULL;
	label_tab = NULL;
	preg_tab = NULL;
	inito_tab = NULL;
	st_attr_tab = NULL;
    }

    void Init (ST_TAB *s, LABEL_TAB *l, PREG_TAB *p, INITO_TAB *io,
	       ST_ATTR_TAB* d, MEM_POOL *mp = Malloc_Mem_Pool) {
	pool = mp;
	st = NULL;
	st_tab = s;
	label_tab = l;
	preg_tab = p;
	inito_tab = io;
	st_attr_tab = d;
	
    }
    

}; // SCOPE

// predefined Scope indices
#define GLOBAL_SYMTAB		(1)	// file scope global symtab
#define CURRENT_SYMTAB		(Current_scope)

struct SCOPE_TAB_SYMTAB_ACCESS {
  SCOPE_TAB_SYMTAB_ACCESS(void) { }

  ST_TAB *operator()(SCOPE **scope_tab, SYMTAB_IDX level)
    { return (*scope_tab)[level].st_tab; }
};

struct SCOPE_TAB_INITO_ACCESS {
  SCOPE_TAB_INITO_ACCESS(void) { }

  INITO_TAB *operator()(SCOPE **scope_tab, SYMTAB_IDX level)
    { return (*scope_tab)[level].inito_tab; }
};

struct SCOPE_TAB_LABEL_ACCESS {
  SCOPE_TAB_LABEL_ACCESS(void) { }

  LABEL_TAB *operator()(SCOPE **scope_tab, SYMTAB_IDX level)
    { return (*scope_tab)[level].label_tab; }
};

// The global scope table
extern SCOPE		*Scope_tab;

// One instance of the following class per compilation.
typedef TABLE_INDEXED_BY_LEVEL8_AND_INDEX24<ST, ST_IDX, SYMTAB_IDX,
                                            SCOPE *, &Scope_tab,
					    SCOPE_TAB_SYMTAB_ACCESS>
        SYMBOL_TABLE;

typedef TABLE_INDEXED_BY_LEVEL8_AND_INDEX24<INITO, INITO_IDX, SYMTAB_IDX,
                                            SCOPE *, &Scope_tab,
					    SCOPE_TAB_INITO_ACCESS>
        INITO_TABLE;
typedef TABLE_INDEXED_BY_LEVEL8_AND_INDEX24<LABEL, LABEL_IDX, SYMTAB_IDX,
                                            SCOPE *, &Scope_tab,
					    SCOPE_TAB_LABEL_ACCESS>
        LABEL_TABLE;

struct PREG_TABLE
{
  inline PREG& operator[] (PREG_IDX idx);
  inline PREG& operator() (SYMTAB_IDX level, PREG_IDX idx);
};

struct ST_ATTR_TABLE
{
  inline ST_ATTR& operator[] (ST_ATTR_IDX idx);
  inline ST_ATTR& operator() (SYMTAB_IDX level, ST_ATTR_IDX idx);
};

struct TYPE_TABLE
{
  inline TY& operator[] (TY_IDX idx);
  inline TY_TAB* operator& ();
};

// declaration of global tables
extern FILE_INFO	File_info;
extern PU_TAB		Pu_Table;
extern SYMBOL_TABLE	St_Table;
extern TY_TAB		Ty_tab;
extern TYPE_TABLE	Ty_Table;
extern FLD_TAB		Fld_Table;
extern TYLIST_TAB	Tylist_Table;
extern ARB_TAB		Arb_Table;
extern STRING_TABLE     Str_Table;
extern TCON_TAB		Tcon_Table;
extern INITV_TAB	Initv_Table;
extern INITO_TABLE	Inito_Table;
extern PREG_TABLE	Preg_Table;
extern ST_ATTR_TABLE	St_Attr_Table;
extern LABEL_TABLE	Label_Table;
// some BLK_TAB items are really local, but make global to ease management
extern BLK_TAB		Blk_Table;

// global variables

extern SYMTAB_IDX Current_scope;
extern PU* Current_pu;




// headers that describe the layout of the symtab structures in files
// changing any of these requires incrementing the WHIRL revision number

// symbol table header types
enum SHDR_TYPE
{
    SHDR_UNK	= 0,			// uninitialized
    SHDR_FILE	= 1,
    SHDR_ST	= 2,
    SHDR_TY	= 3,
    SHDR_PU	= 4,
    SHDR_FLD	= 5,
    SHDR_ARB	= 6,
    SHDR_TYLIST	= 7,
    SHDR_TCON	= 8,
    SHDR_STR	= 9,
    SHDR_LABEL	= 10,
    SHDR_PREG	= 11,
    SHDR_INITO	= 12,
    SHDR_INITV	= 13,
    SHDR_BLK 	= 14,
    SHDR_ST_ATTR= 15
}; // SHDR_TYPE


struct SYMTAB_HEADER
{
    mUINT64 offset;			// offset from beginning of section
    mUINT64 size;			// size in bytes
    mUINT32 entsize;			// size of each entry if fixed
					// zero if entry size variable
    mUINT16 align;			// alignment
    mUINT16 type;			// type of table

    void Init (UINT64 _offset, UINT64 _size, UINT32 _entsize,
	       UINT16 _align, SHDR_TYPE _type) {
	offset = _offset;
	size = _size;
	entsize = _entsize;
	align = _align;
	type = _type;
    }
    
}; // SYMTAB_HEADER


#define GLOBAL_SYMTAB_TABLES	(13)	// # of tables in global symtab:
					// FILE_INFO, ST, TY, PU, FLD, ARB,
					// TYLIST, TCON, STR, INITO, INITV,
					// BLK, and ST_ATTR
#define LOCAL_SYMTAB_TABLES	(5)	// # of tables in local symtab:
					// ST, LABEL, PREG, INITO, and ST_ATTR

template <UINT table_size>
struct SYMTAB_HEADER_TABLE
{
    mUINT32 size;			// size of myself in bytes
    mUINT32 entries;			// number of SYMTAB_HEADER entries

    SYMTAB_HEADER header[table_size];

    typedef SYMTAB_HEADER_TABLE<table_size> self;

    SYMTAB_HEADER_TABLE () {
	size = sizeof(self);
	entries = table_size;
	memset (header, 0, sizeof(header));
    }

}; // SYMTAB_HEADER_TABLE

typedef SYMTAB_HEADER_TABLE<GLOBAL_SYMTAB_TABLES> GLOBAL_SYMTAB_HEADER_TABLE;
typedef SYMTAB_HEADER_TABLE<LOCAL_SYMTAB_TABLES> LOCAL_SYMTAB_HEADER_TABLE;

#endif /* symtab_defs_INCLUDED */

