#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "flags.h"
#include "tree.h"
#include "real.h"
#include "tm_p.h"
#include "function.h"
#include "obstack.h"
#include "toplev.h"
#include "ggc.h"
#include "hashtab.h"
#include "output.h"
#include "target.h"
#include "langhooks.h"
#include "tree-iterator.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "params.h"
const char *const tree_code_class_strings[] =
{
"exceptional",
"constant",
"type",
"declaration",
"reference",
"comparison",
"unary",
"binary",
"statement",
"expression",
};
extern int _obstack_allocated_p (struct obstack *h, void *obj);
#ifdef GATHER_STATISTICS
int tree_node_counts[(int) all_kinds];
int tree_node_sizes[(int) all_kinds];
static const char * const tree_node_kind_names[] = {
"decls",
"types",
"blocks",
"stmts",
"refs",
"exprs",
"constants",
"identifiers",
"perm_tree_lists",
"temp_tree_lists",
"vecs",
"binfos",
"phi_nodes",
"ssa names",
"random kinds",
"lang_decl kinds",
"lang_type kinds"
};
#endif
static GTY(()) int next_decl_uid;
static GTY(()) int next_type_uid = 1;
struct type_hash GTY(())
{
unsigned long hash;
tree type;
};
#define TYPE_HASH_INITIAL_SIZE 4111
static GTY ((if_marked ("type_hash_marked_p"), param_is (struct type_hash)))
htab_t type_hash_table;
static void set_type_quals (tree, int);
static int type_hash_eq (const void *, const void *);
static hashval_t type_hash_hash (const void *);
static void print_type_hash_statistics (void);
static tree make_vector_type (tree, int, enum machine_mode);
static int type_hash_marked_p (const void *);
static unsigned int type_hash_list (tree, hashval_t);
static unsigned int attribute_hash_list (tree, hashval_t);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
void
init_ttree (void)
{
type_hash_table = htab_create_ggc (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
type_hash_eq, 0);
}
tree
decl_assembler_name (tree decl)
{
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
lang_hooks.set_decl_assembler_name (decl);
return DECL_CHECK (decl)->decl.assembler_name;
}
size_t
tree_code_size (enum tree_code code)
{
switch (TREE_CODE_CLASS (code))
{
case tcc_declaration:
return sizeof (struct tree_decl);
case tcc_type:
return sizeof (struct tree_type);
case tcc_reference:
case tcc_expression:
case tcc_statement:
case tcc_comparison:
case tcc_unary:
case tcc_binary:
return (sizeof (struct tree_exp)
+ (TREE_CODE_LENGTH (code) - 1) * sizeof (char *));
case tcc_constant:
switch (code)
{
case INTEGER_CST: return sizeof (struct tree_int_cst);
case REAL_CST: return sizeof (struct tree_real_cst);
case COMPLEX_CST: return sizeof (struct tree_complex);
case VECTOR_CST: return sizeof (struct tree_vector);
case STRING_CST: gcc_unreachable ();
default:
return lang_hooks.tree_size (code);
}
case tcc_exceptional:
switch (code)
{
case IDENTIFIER_NODE: return lang_hooks.identifier_size;
case TREE_LIST: return sizeof (struct tree_list);
case ERROR_MARK:
case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
case TREE_VEC:
case PHI_NODE: gcc_unreachable ();
case SSA_NAME: return sizeof (struct tree_ssa_name);
case STATEMENT_LIST: return sizeof (struct tree_statement_list);
case BLOCK: return sizeof (struct tree_block);
case VALUE_HANDLE: return sizeof (struct tree_value_handle);
default:
return lang_hooks.tree_size (code);
}
default:
gcc_unreachable ();
}
}
size_t
tree_size (tree node)
{
enum tree_code code = TREE_CODE (node);
switch (code)
{
case PHI_NODE:
return (sizeof (struct tree_phi_node)
+ (PHI_ARG_CAPACITY (node) - 1) * sizeof (struct phi_arg_d));
case TREE_VEC:
return (sizeof (struct tree_vec)
+ (TREE_VEC_LENGTH (node) - 1) * sizeof(char *));
case STRING_CST:
return sizeof (struct tree_string) + TREE_STRING_LENGTH (node) - 1;
default:
return tree_code_size (code);
}
}
tree
make_node_stat (enum tree_code code MEM_STAT_DECL)
{
tree t;
enum tree_code_class type = TREE_CODE_CLASS (code);
size_t length = tree_code_size (code);
#ifdef GATHER_STATISTICS
tree_node_kind kind;
switch (type)
{
case tcc_declaration:
kind = d_kind;
break;
case tcc_type:
kind = t_kind;
break;
case tcc_statement:
kind = s_kind;
break;
case tcc_reference:
kind = r_kind;
break;
case tcc_expression:
case tcc_comparison:
case tcc_unary:
case tcc_binary:
kind = e_kind;
break;
case tcc_constant:
kind = c_kind;
break;
case tcc_exceptional:
switch (code)
{
case IDENTIFIER_NODE:
kind = id_kind;
break;
case TREE_VEC:;
kind = vec_kind;
break;
case TREE_BINFO:
kind = binfo_kind;
break;
case PHI_NODE:
kind = phi_kind;
break;
case SSA_NAME:
kind = ssa_name_kind;
break;
case BLOCK:
kind = b_kind;
break;
default:
kind = x_kind;
break;
}
break;
default:
gcc_unreachable ();
}
tree_node_counts[(int) kind]++;
tree_node_sizes[(int) kind] += length;
#endif
t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, length);
TREE_SET_CODE (t, code);
switch (type)
{
case tcc_statement:
TREE_SIDE_EFFECTS (t) = 1;
break;
case tcc_declaration:
if (code != FUNCTION_DECL)
DECL_ALIGN (t) = 1;
DECL_USER_ALIGN (t) = 0;
DECL_IN_SYSTEM_HEADER (t) = in_system_header;
DECL_SOURCE_LOCATION (t) = input_location;
DECL_UID (t) = next_decl_uid++;
DECL_POINTER_ALIAS_SET (t) = -1;
break;
case tcc_type:
TYPE_UID (t) = next_type_uid++;
TYPE_ALIGN (t) = char_type_node ? TYPE_ALIGN (char_type_node) : 0;
TYPE_USER_ALIGN (t) = 0;
TYPE_MAIN_VARIANT (t) = t;
TYPE_ATTRIBUTES (t) = NULL_TREE;
targetm.set_default_type_attributes (t);
TYPE_ALIAS_SET (t) = -1;
break;
case tcc_constant:
TREE_CONSTANT (t) = 1;
TREE_INVARIANT (t) = 1;
break;
case tcc_expression:
switch (code)
{
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
TREE_SIDE_EFFECTS (t) = 1;
break;
default:
break;
}
break;
default:
break;
}
return t;
}
tree
copy_node_stat (tree node MEM_STAT_DECL)
{
tree t;
enum tree_code code = TREE_CODE (node);
size_t length;
gcc_assert (code != STATEMENT_LIST);
length = tree_size (node);
t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memcpy (t, node, length);
TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
TREE_VISITED (t) = 0;
t->common.ann = 0;
if (TREE_CODE_CLASS (code) == tcc_declaration)
DECL_UID (t) = next_decl_uid++;
else if (TREE_CODE_CLASS (code) == tcc_type)
{
TYPE_UID (t) = next_type_uid++;
TYPE_SYMTAB_POINTER (t) = 0;
TYPE_SYMTAB_ADDRESS (t) = 0;
if (TYPE_CACHED_VALUES_P(t))
{
TYPE_CACHED_VALUES_P (t) = 0;
TYPE_CACHED_VALUES (t) = NULL_TREE;
}
}
return t;
}
tree
copy_list (tree list)
{
tree head;
tree prev, next;
if (list == 0)
return 0;
head = prev = copy_node (list);
next = TREE_CHAIN (list);
while (next)
{
TREE_CHAIN (prev) = copy_node (next);
prev = TREE_CHAIN (prev);
next = TREE_CHAIN (next);
}
return head;
}
tree
build_int_cst (tree type, HOST_WIDE_INT low)
{
return build_int_cst_wide (type, low, low < 0 ? -1 : 0);
}
tree
build_int_cstu (tree type, unsigned HOST_WIDE_INT low)
{
return build_int_cst_wide (type, low, 0);
}
tree
build_int_cst_type (tree type, HOST_WIDE_INT low)
{
unsigned HOST_WIDE_INT val = (unsigned HOST_WIDE_INT) low;
unsigned bits;
bool signed_p;
bool negative;
tree ret;
if (!type)
type = integer_type_node;
bits = TYPE_PRECISION (type);
signed_p = !TYPE_UNSIGNED (type);
negative = ((val >> (bits - 1)) & 1) != 0;
if (signed_p && negative)
{
if (bits < HOST_BITS_PER_WIDE_INT)
val = val | ((~(unsigned HOST_WIDE_INT) 0) << bits);
ret = build_int_cst_wide (type, val, ~(unsigned HOST_WIDE_INT) 0);
}
else
{
if (bits < HOST_BITS_PER_WIDE_INT)
val = val & ~((~(unsigned HOST_WIDE_INT) 0) << bits);
ret = build_int_cst_wide (type, val, 0);
}
return ret;
}
tree
build_int_cst_wide (tree type, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi)
{
tree t;
int ix = -1;
int limit = 0;
if (!type)
type = integer_type_node;
switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
if (!hi && !low)
{
limit = 1;
ix = 0;
}
break;
case BOOLEAN_TYPE:
limit = 2;
if (!hi && low < 2)
ix = low;
break;
case INTEGER_TYPE:
case CHAR_TYPE:
case OFFSET_TYPE:
if (TYPE_UNSIGNED (type))
{
limit = INTEGER_SHARE_LIMIT;
if (!hi && low < (unsigned HOST_WIDE_INT)INTEGER_SHARE_LIMIT)
ix = low;
}
else
{
limit = INTEGER_SHARE_LIMIT + 1;
if (!hi && low < (unsigned HOST_WIDE_INT)INTEGER_SHARE_LIMIT)
ix = low + 1;
else if (hi == -1 && low == -(unsigned HOST_WIDE_INT)1)
ix = 0;
}
break;
default:
break;
}
if (ix >= 0)
{
if (!TYPE_CACHED_VALUES_P (type))
{
TYPE_CACHED_VALUES_P (type) = 1;
TYPE_CACHED_VALUES (type) = make_tree_vec (limit);
}
t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix);
if (t)
{
gcc_assert (TREE_TYPE (t) == type);
gcc_assert (TREE_INT_CST_LOW (t) == low);
gcc_assert (TREE_INT_CST_HIGH (t) == hi);
return t;
}
}
t = make_node (INTEGER_CST);
TREE_INT_CST_LOW (t) = low;
TREE_INT_CST_HIGH (t) = hi;
TREE_TYPE (t) = type;
if (ix >= 0)
TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t;
return t;
}
bool
cst_and_fits_in_hwi (tree x)
{
if (TREE_CODE (x) != INTEGER_CST)
return false;
if (TYPE_PRECISION (TREE_TYPE (x)) > HOST_BITS_PER_WIDE_INT)
return false;
return (TREE_INT_CST_HIGH (x) == 0
|| TREE_INT_CST_HIGH (x) == -1);
}
tree
build_vector (tree type, tree vals)
{
tree v = make_node (VECTOR_CST);
int over1 = 0, over2 = 0;
tree link;
TREE_VECTOR_CST_ELTS (v) = vals;
TREE_TYPE (v) = type;
for (link = vals; link; link = TREE_CHAIN (link))
{
tree value = TREE_VALUE (link);
TREE_VALUE (link) = fold (value);
over1 |= TREE_OVERFLOW (value);
over2 |= TREE_CONSTANT_OVERFLOW (value);
}
TREE_OVERFLOW (v) = over1;
TREE_CONSTANT_OVERFLOW (v) = over2;
return v;
}
tree
build_constructor (tree type, tree vals)
{
tree c = make_node (CONSTRUCTOR);
TREE_TYPE (c) = type;
CONSTRUCTOR_ELTS (c) = vals;
if (vals)
{
TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals);
TREE_READONLY (c) = TREE_READONLY (vals);
TREE_CONSTANT (c) = TREE_CONSTANT (vals);
TREE_INVARIANT (c) = TREE_INVARIANT (vals);
}
return c;
}
tree
build_real (tree type, REAL_VALUE_TYPE d)
{
tree v;
REAL_VALUE_TYPE *dp;
int overflow = 0;
v = make_node (REAL_CST);
dp = ggc_alloc (sizeof (REAL_VALUE_TYPE));
memcpy (dp, &d, sizeof (REAL_VALUE_TYPE));
TREE_TYPE (v) = type;
TREE_REAL_CST_PTR (v) = dp;
TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
return v;
}
REAL_VALUE_TYPE
real_value_from_int_cst (tree type, tree i)
{
REAL_VALUE_TYPE d;
memset (&d, 0, sizeof d);
real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode,
TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
TYPE_UNSIGNED (TREE_TYPE (i)));
return d;
}
tree
build_real_from_int_cst (tree type, tree i)
{
tree v;
int overflow = TREE_OVERFLOW (i);
v = build_real (type, real_value_from_int_cst (type, i));
TREE_OVERFLOW (v) |= overflow;
TREE_CONSTANT_OVERFLOW (v) |= overflow;
return v;
}
tree
build_string (int len, const char *str)
{
tree s;
size_t length;
length = len + sizeof (struct tree_string);
#ifdef GATHER_STATISTICS
tree_node_counts[(int) c_kind]++;
tree_node_sizes[(int) c_kind] += length;
#endif
s = ggc_alloc_tree (length);
memset (s, 0, sizeof (struct tree_common));
TREE_SET_CODE (s, STRING_CST);
TREE_STRING_LENGTH (s) = len;
memcpy ((char *) TREE_STRING_POINTER (s), str, len);
((char *) TREE_STRING_POINTER (s))[len] = '\0';
return s;
}
tree
build_complex (tree type, tree real, tree imag)
{
tree t = make_node (COMPLEX_CST);
TREE_REALPART (t) = real;
TREE_IMAGPART (t) = imag;
TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real));
TREE_OVERFLOW (t) = TREE_OVERFLOW (real) | TREE_OVERFLOW (imag);
TREE_CONSTANT_OVERFLOW (t)
= TREE_CONSTANT_OVERFLOW (real) | TREE_CONSTANT_OVERFLOW (imag);
return t;
}
tree
make_tree_binfo_stat (unsigned base_binfos MEM_STAT_DECL)
{
tree t;
size_t length = (offsetof (struct tree_binfo, base_binfos)
+ VEC_embedded_size (tree, base_binfos));
#ifdef GATHER_STATISTICS
tree_node_counts[(int) binfo_kind]++;
tree_node_sizes[(int) binfo_kind] += length;
#endif
t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, offsetof (struct tree_binfo, base_binfos));
TREE_SET_CODE (t, TREE_BINFO);
VEC_embedded_init (tree, BINFO_BASE_BINFOS (t), base_binfos);
return t;
}
tree
make_tree_vec_stat (int len MEM_STAT_DECL)
{
tree t;
int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
#ifdef GATHER_STATISTICS
tree_node_counts[(int) vec_kind]++;
tree_node_sizes[(int) vec_kind] += length;
#endif
t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, length);
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
return t;
}
int
integer_zerop (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == INTEGER_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& TREE_INT_CST_LOW (expr) == 0
&& TREE_INT_CST_HIGH (expr) == 0)
|| (TREE_CODE (expr) == COMPLEX_CST
&& integer_zerop (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr))));
}
int
integer_onep (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == INTEGER_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& TREE_INT_CST_LOW (expr) == 1
&& TREE_INT_CST_HIGH (expr) == 0)
|| (TREE_CODE (expr) == COMPLEX_CST
&& integer_onep (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr))));
}
int
integer_all_onesp (tree expr)
{
int prec;
int uns;
STRIP_NOPS (expr);
if (TREE_CODE (expr) == COMPLEX_CST
&& integer_all_onesp (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr)))
return 1;
else if (TREE_CODE (expr) != INTEGER_CST
|| TREE_CONSTANT_OVERFLOW (expr))
return 0;
uns = TYPE_UNSIGNED (TREE_TYPE (expr));
if (!uns)
return (TREE_INT_CST_LOW (expr) == ~(unsigned HOST_WIDE_INT) 0
&& TREE_INT_CST_HIGH (expr) == -1);
prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)));
if (prec >= HOST_BITS_PER_WIDE_INT)
{
HOST_WIDE_INT high_value;
int shift_amount;
shift_amount = prec - HOST_BITS_PER_WIDE_INT;
gcc_assert (shift_amount <= HOST_BITS_PER_WIDE_INT);
if (shift_amount == HOST_BITS_PER_WIDE_INT)
high_value = -1;
else
high_value = ((HOST_WIDE_INT) 1 << shift_amount) - 1;
return (TREE_INT_CST_LOW (expr) == ~(unsigned HOST_WIDE_INT) 0
&& TREE_INT_CST_HIGH (expr) == high_value);
}
else
return TREE_INT_CST_LOW (expr) == ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
}
int
integer_pow2p (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
STRIP_NOPS (expr);
if (TREE_CODE (expr) == COMPLEX_CST
&& integer_pow2p (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr)))
return 1;
if (TREE_CODE (expr) != INTEGER_CST || TREE_CONSTANT_OVERFLOW (expr))
return 0;
prec = (POINTER_TYPE_P (TREE_TYPE (expr))
? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
low = TREE_INT_CST_LOW (expr);
if (prec == 2 * HOST_BITS_PER_WIDE_INT)
;
else if (prec > HOST_BITS_PER_WIDE_INT)
high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
else
{
high = 0;
if (prec < HOST_BITS_PER_WIDE_INT)
low &= ~((HOST_WIDE_INT) (-1) << prec);
}
if (high == 0 && low == 0)
return 0;
return ((high == 0 && (low & (low - 1)) == 0)
|| (low == 0 && (high & (high - 1)) == 0));
}
int
integer_nonzerop (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == INTEGER_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& (TREE_INT_CST_LOW (expr) != 0
|| TREE_INT_CST_HIGH (expr) != 0))
|| (TREE_CODE (expr) == COMPLEX_CST
&& (integer_nonzerop (TREE_REALPART (expr))
|| integer_nonzerop (TREE_IMAGPART (expr)))));
}
int
tree_log2 (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
STRIP_NOPS (expr);
if (TREE_CODE (expr) == COMPLEX_CST)
return tree_log2 (TREE_REALPART (expr));
prec = (POINTER_TYPE_P (TREE_TYPE (expr))
? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
low = TREE_INT_CST_LOW (expr);
if (prec == 2 * HOST_BITS_PER_WIDE_INT)
;
else if (prec > HOST_BITS_PER_WIDE_INT)
high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
else
{
high = 0;
if (prec < HOST_BITS_PER_WIDE_INT)
low &= ~((HOST_WIDE_INT) (-1) << prec);
}
return (high != 0 ? HOST_BITS_PER_WIDE_INT + exact_log2 (high)
: exact_log2 (low));
}
int
tree_floor_log2 (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
STRIP_NOPS (expr);
if (TREE_CODE (expr) == COMPLEX_CST)
return tree_log2 (TREE_REALPART (expr));
prec = (POINTER_TYPE_P (TREE_TYPE (expr))
? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
low = TREE_INT_CST_LOW (expr);
if (prec == 2 * HOST_BITS_PER_WIDE_INT || prec == 0)
;
else if (prec > HOST_BITS_PER_WIDE_INT)
high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
else
{
high = 0;
if (prec < HOST_BITS_PER_WIDE_INT)
low &= ~((HOST_WIDE_INT) (-1) << prec);
}
return (high != 0 ? HOST_BITS_PER_WIDE_INT + floor_log2 (high)
: floor_log2 (low));
}
int
real_zerop (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_zerop (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
}
int
real_onep (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_onep (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
}
int
real_twop (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_twop (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
}
int
real_minus_onep (tree expr)
{
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_minus_onep (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
}
int
really_constant_p (tree exp)
{
while (TREE_CODE (exp) == NOP_EXPR
|| TREE_CODE (exp) == CONVERT_EXPR
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
return TREE_CONSTANT (exp);
}
tree
value_member (tree elem, tree list)
{
while (list)
{
if (elem == TREE_VALUE (list))
return list;
list = TREE_CHAIN (list);
}
return NULL_TREE;
}
tree
purpose_member (tree elem, tree list)
{
while (list)
{
if (elem == TREE_PURPOSE (list))
return list;
list = TREE_CHAIN (list);
}
return NULL_TREE;
}
int
chain_member (tree elem, tree chain)
{
while (chain)
{
if (elem == chain)
return 1;
chain = TREE_CHAIN (chain);
}
return 0;
}
int
list_length (tree t)
{
tree p = t;
#ifdef ENABLE_TREE_CHECKING
tree q = t;
#endif
int len = 0;
while (p)
{
p = TREE_CHAIN (p);
#ifdef ENABLE_TREE_CHECKING
if (len % 2)
q = TREE_CHAIN (q);
gcc_assert (p != q);
#endif
len++;
}
return len;
}
int
fields_length (tree type)
{
tree t = TYPE_FIELDS (type);
int count = 0;
for (; t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL)
++count;
return count;
}
tree
chainon (tree op1, tree op2)
{
tree t1;
if (!op1)
return op2;
if (!op2)
return op1;
for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
continue;
TREE_CHAIN (t1) = op2;
#ifdef ENABLE_TREE_CHECKING
{
tree t2;
for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
gcc_assert (t2 != t1);
}
#endif
return op1;
}
tree
tree_last (tree chain)
{
tree next;
if (chain)
while ((next = TREE_CHAIN (chain)))
chain = next;
return chain;
}
tree
nreverse (tree t)
{
tree prev = 0, decl, next;
for (decl = t; decl; decl = next)
{
next = TREE_CHAIN (decl);
TREE_CHAIN (decl) = prev;
prev = decl;
}
return prev;
}
tree
build_tree_list_stat (tree parm, tree value MEM_STAT_DECL)
{
tree t = make_node_stat (TREE_LIST PASS_MEM_STAT);
TREE_PURPOSE (t) = parm;
TREE_VALUE (t) = value;
return t;
}
tree
tree_cons_stat (tree purpose, tree value, tree chain MEM_STAT_DECL)
{
tree node;
node = ggc_alloc_zone_stat (sizeof (struct tree_list),
tree_zone PASS_MEM_STAT);
memset (node, 0, sizeof (struct tree_common));
#ifdef GATHER_STATISTICS
tree_node_counts[(int) x_kind]++;
tree_node_sizes[(int) x_kind] += sizeof (struct tree_list);
#endif
TREE_SET_CODE (node, TREE_LIST);
TREE_CHAIN (node) = chain;
TREE_PURPOSE (node) = purpose;
TREE_VALUE (node) = value;
return node;
}
tree
size_in_bytes (tree type)
{
tree t;
if (type == error_mark_node)
return integer_zero_node;
type = TYPE_MAIN_VARIANT (type);
t = TYPE_SIZE_UNIT (type);
if (t == 0)
{
lang_hooks.types.incomplete_type_error (NULL_TREE, type);
return size_zero_node;
}
if (TREE_CODE (t) == INTEGER_CST)
t = force_fit_type (t, 0, false, false);
return t;
}
HOST_WIDE_INT
int_size_in_bytes (tree type)
{
tree t;
if (type == error_mark_node)
return 0;
type = TYPE_MAIN_VARIANT (type);
t = TYPE_SIZE_UNIT (type);
if (t == 0
|| TREE_CODE (t) != INTEGER_CST
|| TREE_OVERFLOW (t)
|| TREE_INT_CST_HIGH (t) != 0
|| (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
return -1;
return TREE_INT_CST_LOW (t);
}
tree
bit_position (tree field)
{
return bit_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
}
HOST_WIDE_INT
int_bit_position (tree field)
{
return tree_low_cst (bit_position (field), 0);
}
tree
byte_position (tree field)
{
return byte_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
}
HOST_WIDE_INT
int_byte_position (tree field)
{
return tree_low_cst (byte_position (field), 0);
}
unsigned int
expr_align (tree t)
{
unsigned int align0, align1;
switch (TREE_CODE (t))
{
case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR:
align0 = expr_align (TREE_OPERAND (t, 0));
align1 = TYPE_ALIGN (TREE_TYPE (t));
return MAX (align0, align1);
case SAVE_EXPR: case COMPOUND_EXPR: case MODIFY_EXPR:
case INIT_EXPR: case TARGET_EXPR: case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
return expr_align (TREE_OPERAND (t, 0));
case COND_EXPR:
align0 = expr_align (TREE_OPERAND (t, 1));
align1 = expr_align (TREE_OPERAND (t, 2));
return MIN (align0, align1);
case LABEL_DECL: case CONST_DECL:
case VAR_DECL: case PARM_DECL: case RESULT_DECL:
if (DECL_ALIGN (t) != 0)
return DECL_ALIGN (t);
break;
case FUNCTION_DECL:
return FUNCTION_BOUNDARY;
default:
break;
}
return TYPE_ALIGN (TREE_TYPE (t));
}
tree
array_type_nelts (tree type)
{
tree index_type, min, max;
if (! TYPE_DOMAIN (type))
return error_mark_node;
index_type = TYPE_DOMAIN (type);
min = TYPE_MIN_VALUE (index_type);
max = TYPE_MAX_VALUE (index_type);
return (integer_zerop (min)
? max
: fold (build2 (MINUS_EXPR, TREE_TYPE (max), max, min)));
}
tree
staticp (tree arg)
{
switch (TREE_CODE (arg))
{
case FUNCTION_DECL:
return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
&& ! DECL_NON_ADDR_CONST_P (arg)
? arg : NULL);
case VAR_DECL:
return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
&& ! DECL_THREAD_LOCAL (arg)
&& ! DECL_NON_ADDR_CONST_P (arg)
? arg : NULL);
case CONST_DECL:
return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
? arg : NULL);
case CONSTRUCTOR:
return TREE_STATIC (arg) ? arg : NULL;
case LABEL_DECL:
case STRING_CST:
return arg;
case COMPONENT_REF:
if (TREE_CODE (TREE_OPERAND (arg, 1)) != FIELD_DECL)
return (*lang_hooks.staticp) (arg);
if (DECL_BIT_FIELD (TREE_OPERAND (arg, 1)))
return NULL;
return staticp (TREE_OPERAND (arg, 0));
case BIT_FIELD_REF:
return NULL;
case MISALIGNED_INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
return TREE_CONSTANT (TREE_OPERAND (arg, 0)) ? arg : NULL;
case ARRAY_REF:
case ARRAY_RANGE_REF:
if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST)
return staticp (TREE_OPERAND (arg, 0));
else
return false;
default:
if ((unsigned int) TREE_CODE (arg)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
return lang_hooks.staticp (arg);
else
return NULL;
}
}
tree
save_expr (tree expr)
{
tree t = fold (expr);
tree inner;
inner = skip_simple_arithmetic (t);
if (TREE_INVARIANT (inner)
|| (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
|| TREE_CODE (inner) == SAVE_EXPR
|| TREE_CODE (inner) == ERROR_MARK)
return t;
if (contains_placeholder_p (inner))
return t;
t = build1 (SAVE_EXPR, TREE_TYPE (expr), t);
TREE_SIDE_EFFECTS (t) = 1;
TREE_INVARIANT (t) = 1;
return t;
}
tree
skip_simple_arithmetic (tree expr)
{
tree inner;
while (TREE_CODE (expr) == NON_LVALUE_EXPR)
expr = TREE_OPERAND (expr, 0);
inner = expr;
while (1)
{
if (UNARY_CLASS_P (inner))
inner = TREE_OPERAND (inner, 0);
else if (BINARY_CLASS_P (inner))
{
if (TREE_INVARIANT (TREE_OPERAND (inner, 1)))
inner = TREE_OPERAND (inner, 0);
else if (TREE_INVARIANT (TREE_OPERAND (inner, 0)))
inner = TREE_OPERAND (inner, 1);
else
break;
}
else
break;
}
return inner;
}
int
first_rtl_op (enum tree_code code)
{
switch (code)
{
default:
return TREE_CODE_LENGTH (code);
}
}
enum tree_node_structure_enum
tree_node_structure (tree t)
{
enum tree_code code = TREE_CODE (t);
switch (TREE_CODE_CLASS (code))
{
case tcc_declaration:
return TS_DECL;
case tcc_type:
return TS_TYPE;
case tcc_reference:
case tcc_comparison:
case tcc_unary:
case tcc_binary:
case tcc_expression:
case tcc_statement:
return TS_EXP;
default:
break;
}
switch (code)
{
case INTEGER_CST: return TS_INT_CST;
case REAL_CST: return TS_REAL_CST;
case COMPLEX_CST: return TS_COMPLEX;
case VECTOR_CST: return TS_VECTOR;
case STRING_CST: return TS_STRING;
case ERROR_MARK: return TS_COMMON;
case IDENTIFIER_NODE: return TS_IDENTIFIER;
case TREE_LIST: return TS_LIST;
case TREE_VEC: return TS_VEC;
case PHI_NODE: return TS_PHI_NODE;
case SSA_NAME: return TS_SSA_NAME;
case PLACEHOLDER_EXPR: return TS_COMMON;
case STATEMENT_LIST: return TS_STATEMENT_LIST;
case BLOCK: return TS_BLOCK;
case TREE_BINFO: return TS_BINFO;
case VALUE_HANDLE: return TS_VALUE_HANDLE;
default:
gcc_unreachable ();
}
}
bool
contains_placeholder_p (tree exp)
{
enum tree_code code;
if (!exp)
return 0;
code = TREE_CODE (exp);
if (code == PLACEHOLDER_EXPR)
return 1;
switch (TREE_CODE_CLASS (code))
{
case tcc_reference:
return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
case tcc_exceptional:
if (code == TREE_LIST)
return (CONTAINS_PLACEHOLDER_P (TREE_VALUE (exp))
|| CONTAINS_PLACEHOLDER_P (TREE_CHAIN (exp)));
break;
case tcc_unary:
case tcc_binary:
case tcc_comparison:
case tcc_expression:
switch (code)
{
case COMPOUND_EXPR:
return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
case COND_EXPR:
return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
default:
break;
}
switch (first_rtl_op (code))
{
case 1:
return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
case 2:
return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1)));
default:
return 0;
}
default:
return 0;
}
return 0;
}
static bool
type_contains_placeholder_1 (tree type)
{
if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
|| CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
|| (TREE_TYPE (type) != 0
&& type_contains_placeholder_p (TREE_TYPE (type))))
return true;
switch (TREE_CODE (type))
{
case VOID_TYPE:
case COMPLEX_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
case POINTER_TYPE:
case OFFSET_TYPE:
case REFERENCE_TYPE:
case METHOD_TYPE:
case FILE_TYPE:
case FUNCTION_TYPE:
return false;
case INTEGER_TYPE:
case REAL_TYPE:
return (CONTAINS_PLACEHOLDER_P (TYPE_MIN_VALUE (type))
|| CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
case ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
return type_contains_placeholder_p (TYPE_DOMAIN (type));
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
{
tree field;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL
&& (CONTAINS_PLACEHOLDER_P (DECL_FIELD_OFFSET (field))
|| (TREE_CODE (type) == QUAL_UNION_TYPE
&& CONTAINS_PLACEHOLDER_P (DECL_QUALIFIER (field)))
|| type_contains_placeholder_p (TREE_TYPE (field))))
return true;
return false;
}
default:
gcc_unreachable ();
}
}
bool
type_contains_placeholder_p (tree type)
{
bool result;
if (TYPE_CONTAINS_PLACEHOLDER_INTERNAL (type) > 0)
return TYPE_CONTAINS_PLACEHOLDER_INTERNAL (type) - 1;
TYPE_CONTAINS_PLACEHOLDER_INTERNAL (type) = 1;
result = type_contains_placeholder_1 (type);
TYPE_CONTAINS_PLACEHOLDER_INTERNAL (type) = result + 1;
return result;
}
tree
substitute_in_expr (tree exp, tree f, tree r)
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2;
tree new;
tree inner;
if (code == TREE_LIST)
{
op0 = SUBSTITUTE_IN_EXPR (TREE_CHAIN (exp), f, r);
op1 = SUBSTITUTE_IN_EXPR (TREE_VALUE (exp), f, r);
if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
return exp;
return tree_cons (TREE_PURPOSE (exp), op1, op0);
}
else if (code == COMPONENT_REF)
{
for (inner = TREE_OPERAND (exp, 0);
REFERENCE_CLASS_P (inner);
inner = TREE_OPERAND (inner, 0))
;
if (TREE_CODE (inner) == PLACEHOLDER_EXPR
&& TREE_OPERAND (exp, 1) == f)
return r;
if (TREE_CODE (inner) == PLACEHOLDER_EXPR && TREE_TYPE (inner) == 0)
return exp;
op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
if (op0 == TREE_OPERAND (exp, 0))
return exp;
new = fold (build3 (COMPONENT_REF, TREE_TYPE (exp),
op0, TREE_OPERAND (exp, 1), NULL_TREE));
}
else
switch (TREE_CODE_CLASS (code))
{
case tcc_constant:
case tcc_declaration:
return exp;
case tcc_exceptional:
case tcc_unary:
case tcc_binary:
case tcc_comparison:
case tcc_expression:
case tcc_reference:
switch (first_rtl_op (code))
{
case 0:
return exp;
case 1:
op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
if (op0 == TREE_OPERAND (exp, 0))
return exp;
new = fold (build1 (code, TREE_TYPE (exp), op0));
break;
case 2:
op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
op1 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 1), f, r);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
return exp;
new = fold (build2 (code, TREE_TYPE (exp), op0, op1));
break;
case 3:
op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
op1 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 1), f, r);
op2 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 2), f, r);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
&& op2 == TREE_OPERAND (exp, 2))
return exp;
new = fold (build3 (code, TREE_TYPE (exp), op0, op1, op2));
break;
default:
gcc_unreachable ();
}
break;
default:
gcc_unreachable ();
}
TREE_READONLY (new) = TREE_READONLY (exp);
return new;
}
tree
substitute_placeholder_in_expr (tree exp, tree obj)
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2, op3;
if (code == PLACEHOLDER_EXPR)
{
tree need_type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
tree elt;
for (elt = obj; elt != 0;
elt = ((TREE_CODE (elt) == COMPOUND_EXPR
|| TREE_CODE (elt) == COND_EXPR)
? TREE_OPERAND (elt, 1)
: (REFERENCE_CLASS_P (elt)
|| UNARY_CLASS_P (elt)
|| BINARY_CLASS_P (elt)
|| EXPRESSION_CLASS_P (elt))
? TREE_OPERAND (elt, 0) : 0))
if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
return elt;
for (elt = obj; elt != 0;
elt = ((TREE_CODE (elt) == COMPOUND_EXPR
|| TREE_CODE (elt) == COND_EXPR)
? TREE_OPERAND (elt, 1)
: (REFERENCE_CLASS_P (elt)
|| UNARY_CLASS_P (elt)
|| BINARY_CLASS_P (elt)
|| EXPRESSION_CLASS_P (elt))
? TREE_OPERAND (elt, 0) : 0))
if (POINTER_TYPE_P (TREE_TYPE (elt))
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
== need_type))
return fold (build1 (INDIRECT_REF, need_type, elt));
return exp;
}
else if (code == TREE_LIST)
{
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_CHAIN (exp), obj);
op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_VALUE (exp), obj);
if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
return exp;
return tree_cons (TREE_PURPOSE (exp), op1, op0);
}
else
switch (TREE_CODE_CLASS (code))
{
case tcc_constant:
case tcc_declaration:
return exp;
case tcc_exceptional:
case tcc_unary:
case tcc_binary:
case tcc_comparison:
case tcc_expression:
case tcc_reference:
case tcc_statement:
switch (first_rtl_op (code))
{
case 0:
return exp;
case 1:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
if (op0 == TREE_OPERAND (exp, 0))
return exp;
else
return fold (build1 (code, TREE_TYPE (exp), op0));
case 2:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
return exp;
else
return fold (build2 (code, TREE_TYPE (exp), op0, op1));
case 3:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
op2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 2), obj);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
&& op2 == TREE_OPERAND (exp, 2))
return exp;
else
return fold (build3 (code, TREE_TYPE (exp), op0, op1, op2));
case 4:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
op2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 2), obj);
op3 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 3), obj);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
&& op2 == TREE_OPERAND (exp, 2)
&& op3 == TREE_OPERAND (exp, 3))
return exp;
else
return fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
default:
gcc_unreachable ();
}
break;
default:
gcc_unreachable ();
}
}
tree
stabilize_reference (tree ref)
{
tree result;
enum tree_code code = TREE_CODE (ref);
switch (code)
{
case VAR_DECL:
case PARM_DECL:
case RESULT_DECL:
return ref;
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
break;
case INDIRECT_REF:
result = build_nt (INDIRECT_REF,
stabilize_reference_1 (TREE_OPERAND (ref, 0)));
break;
case COMPONENT_REF:
result = build_nt (COMPONENT_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
TREE_OPERAND (ref, 1), NULL_TREE);
break;
case BIT_FIELD_REF:
result = build_nt (BIT_FIELD_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
stabilize_reference_1 (TREE_OPERAND (ref, 1)),
stabilize_reference_1 (TREE_OPERAND (ref, 2)));
break;
case ARRAY_REF:
result = build_nt (ARRAY_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
stabilize_reference_1 (TREE_OPERAND (ref, 1)),
TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case ARRAY_RANGE_REF:
result = build_nt (ARRAY_RANGE_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
stabilize_reference_1 (TREE_OPERAND (ref, 1)),
TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case COMPOUND_EXPR:
return stabilize_reference_1 (ref);
default:
return ref;
case ERROR_MARK:
return error_mark_node;
}
TREE_TYPE (result) = TREE_TYPE (ref);
TREE_READONLY (result) = TREE_READONLY (ref);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
return result;
}
tree
stabilize_reference_1 (tree e)
{
tree result;
enum tree_code code = TREE_CODE (e);
if (TREE_INVARIANT (e))
return e;
switch (TREE_CODE_CLASS (code))
{
case tcc_exceptional:
case tcc_type:
case tcc_declaration:
case tcc_comparison:
case tcc_statement:
case tcc_expression:
case tcc_reference:
if (TREE_SIDE_EFFECTS (e))
return save_expr (e);
return e;
case tcc_constant:
return e;
case tcc_binary:
if (code == TRUNC_DIV_EXPR || code == TRUNC_MOD_EXPR
|| code == FLOOR_DIV_EXPR || code == FLOOR_MOD_EXPR
|| code == CEIL_DIV_EXPR || code == CEIL_MOD_EXPR
|| code == ROUND_DIV_EXPR || code == ROUND_MOD_EXPR)
return save_expr (e);
result = build_nt (code, stabilize_reference_1 (TREE_OPERAND (e, 0)),
stabilize_reference_1 (TREE_OPERAND (e, 1)));
break;
case tcc_unary:
result = build_nt (code, stabilize_reference_1 (TREE_OPERAND (e, 0)));
break;
default:
gcc_unreachable ();
}
TREE_TYPE (result) = TREE_TYPE (e);
TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
TREE_INVARIANT (result) = 1;
return result;
}
void
recompute_tree_invarant_for_addr_expr (tree t)
{
tree node;
bool tc = true, ti = true, se = false;
#define UPDATE_TITCSE(NODE) \
do { tree _node = (NODE); \
if (_node && !TREE_INVARIANT (_node)) ti = false; \
if (_node && !TREE_CONSTANT (_node)) tc = false; \
if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
for (node = TREE_OPERAND (t, 0); handled_component_p (node);
node = TREE_OPERAND (node, 0))
{
if ((TREE_CODE (node) == ARRAY_REF
|| TREE_CODE (node) == ARRAY_RANGE_REF)
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
{
UPDATE_TITCSE (TREE_OPERAND (node, 1));
if (TREE_OPERAND (node, 2))
UPDATE_TITCSE (TREE_OPERAND (node, 2));
if (TREE_OPERAND (node, 3))
UPDATE_TITCSE (TREE_OPERAND (node, 3));
}
else if (TREE_CODE (node) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
{
if (TREE_OPERAND (node, 2))
UPDATE_TITCSE (TREE_OPERAND (node, 2));
}
else if (TREE_CODE (node) == BIT_FIELD_REF)
UPDATE_TITCSE (TREE_OPERAND (node, 2));
}
if (TREE_CODE (node) == INDIRECT_REF)
{
if (TREE_CODE (TREE_OPERAND (node, 0)) != INTEGER_CST)
UPDATE_TITCSE (node);
}
else if (DECL_P (node))
{
if (staticp (node))
;
else if (decl_function_context (node) == current_function_decl)
tc = false;
else
ti = tc = false;
}
else if (CONSTANT_CLASS_P (node))
;
else
{
ti = tc = false;
se |= TREE_SIDE_EFFECTS (node);
}
TREE_CONSTANT (t) = tc;
TREE_INVARIANT (t) = ti;
TREE_SIDE_EFFECTS (t) = se;
#undef UPDATE_TITCSE
}
tree
build0_stat (enum tree_code code, tree tt MEM_STAT_DECL)
{
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 0);
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
return t;
}
tree
build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL)
{
int length = sizeof (struct tree_exp);
#ifdef GATHER_STATISTICS
tree_node_kind kind;
#endif
tree t;
#ifdef GATHER_STATISTICS
switch (TREE_CODE_CLASS (code))
{
case tcc_statement:
kind = s_kind;
break;
case tcc_reference:
kind = r_kind;
break;
default:
kind = e_kind;
break;
}
tree_node_counts[(int) kind]++;
tree_node_sizes[(int) kind] += length;
#endif
gcc_assert (TREE_CODE_LENGTH (code) == 1);
t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, sizeof (struct tree_common));
TREE_SET_CODE (t, code);
TREE_TYPE (t) = type;
#ifdef USE_MAPPED_LOCATION
SET_EXPR_LOCATION (t, UNKNOWN_LOCATION);
#else
SET_EXPR_LOCUS (t, NULL);
#endif
TREE_COMPLEXITY (t) = 0;
TREE_OPERAND (t, 0) = node;
TREE_BLOCK (t) = NULL_TREE;
if (node && !TYPE_P (node) && first_rtl_op (code) != 0)
{
TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
TREE_READONLY (t) = TREE_READONLY (node);
}
if (TREE_CODE_CLASS (code) == tcc_statement)
TREE_SIDE_EFFECTS (t) = 1;
else switch (code)
{
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
TREE_SIDE_EFFECTS (t) = 1;
TREE_READONLY (t) = 0;
break;
case MISALIGNED_INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
TREE_READONLY (t) = 0;
break;
case ADDR_EXPR:
if (node)
recompute_tree_invarant_for_addr_expr (t);
break;
default:
if (TREE_CODE_CLASS (code) == tcc_unary
&& node && !TYPE_P (node)
&& TREE_CONSTANT (node))
TREE_CONSTANT (t) = 1;
if (TREE_CODE_CLASS (code) == tcc_unary
&& node && TREE_INVARIANT (node))
TREE_INVARIANT (t) = 1;
if (TREE_CODE_CLASS (code) == tcc_reference
&& node && TREE_THIS_VOLATILE (node))
TREE_THIS_VOLATILE (t) = 1;
break;
}
return t;
}
#define PROCESS_ARG(N) \
do { \
TREE_OPERAND (t, N) = arg##N; \
if (arg##N &&!TYPE_P (arg##N) && fro > N) \
{ \
if (TREE_SIDE_EFFECTS (arg##N)) \
side_effects = 1; \
if (!TREE_READONLY (arg##N)) \
read_only = 0; \
if (!TREE_CONSTANT (arg##N)) \
constant = 0; \
if (!TREE_INVARIANT (arg##N)) \
invariant = 0; \
} \
} while (0)
tree
build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
{
bool constant, read_only, side_effects, invariant;
tree t;
int fro;
gcc_assert (TREE_CODE_LENGTH (code) == 2);
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
fro = first_rtl_op (code);
constant = (TREE_CODE_CLASS (code) == tcc_comparison
|| TREE_CODE_CLASS (code) == tcc_expression
|| TREE_CODE_CLASS (code) == tcc_binary);
read_only = 1;
side_effects = TREE_SIDE_EFFECTS (t);
invariant = constant;
PROCESS_ARG(0);
PROCESS_ARG(1);
TREE_READONLY (t) = read_only;
TREE_CONSTANT (t) = constant;
TREE_INVARIANT (t) = invariant;
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
&& arg0 && TREE_THIS_VOLATILE (arg0));
return t;
}
tree
build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2 MEM_STAT_DECL)
{
bool constant, read_only, side_effects, invariant;
tree t;
int fro;
gcc_assert (TREE_CODE_LENGTH (code) == 3);
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
fro = first_rtl_op (code);
side_effects = TREE_SIDE_EFFECTS (t);
PROCESS_ARG(0);
PROCESS_ARG(1);
PROCESS_ARG(2);
if (code == CALL_EXPR && !side_effects)
{
tree node;
int i;
i = call_expr_flags (t);
if (!(i & (ECF_CONST | ECF_PURE)))
side_effects = 1;
else for (node = arg1; node; node = TREE_CHAIN (node))
if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
{
side_effects = 1;
break;
}
}
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
&& arg0 && TREE_THIS_VOLATILE (arg0));
return t;
}
tree
build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2, tree arg3 MEM_STAT_DECL)
{
bool constant, read_only, side_effects, invariant;
tree t;
int fro;
gcc_assert (TREE_CODE_LENGTH (code) == 4);
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
fro = first_rtl_op (code);
side_effects = TREE_SIDE_EFFECTS (t);
PROCESS_ARG(0);
PROCESS_ARG(1);
PROCESS_ARG(2);
PROCESS_ARG(3);
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
&& arg0 && TREE_THIS_VOLATILE (arg0));
return t;
}
tree
(build) (enum tree_code code, tree tt, ...)
{
tree t, arg0, arg1, arg2, arg3;
int length = TREE_CODE_LENGTH (code);
va_list p;
va_start (p, tt);
switch (length)
{
case 0:
t = build0 (code, tt);
break;
case 1:
arg0 = va_arg (p, tree);
t = build1 (code, tt, arg0);
break;
case 2:
arg0 = va_arg (p, tree);
arg1 = va_arg (p, tree);
t = build2 (code, tt, arg0, arg1);
break;
case 3:
arg0 = va_arg (p, tree);
arg1 = va_arg (p, tree);
arg2 = va_arg (p, tree);
t = build3 (code, tt, arg0, arg1, arg2);
break;
case 4:
arg0 = va_arg (p, tree);
arg1 = va_arg (p, tree);
arg2 = va_arg (p, tree);
arg3 = va_arg (p, tree);
t = build4 (code, tt, arg0, arg1, arg2, arg3);
break;
default:
gcc_unreachable ();
}
va_end (p);
return t;
}
tree
build_nt (enum tree_code code, ...)
{
tree t;
int length;
int i;
va_list p;
va_start (p, code);
t = make_node (code);
length = TREE_CODE_LENGTH (code);
for (i = 0; i < length; i++)
TREE_OPERAND (t, i) = va_arg (p, tree);
va_end (p);
return t;
}
tree
build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL)
{
tree t;
t = make_node_stat (code PASS_MEM_STAT);
DECL_NAME (t) = name;
TREE_TYPE (t) = type;
if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
layout_decl (t, 0);
else if (code == FUNCTION_DECL)
DECL_MODE (t) = FUNCTION_MODE;
DECL_VISIBILITY (t) = default_visibility;
DECL_VISIBILITY_SPECIFIED (t) = visibility_options.inpragma;
return t;
}
tree
build_block (tree vars, tree tags ATTRIBUTE_UNUSED, tree subblocks,
tree supercontext, tree chain)
{
tree block = make_node (BLOCK);
BLOCK_VARS (block) = vars;
BLOCK_SUBBLOCKS (block) = subblocks;
BLOCK_SUPERCONTEXT (block) = supercontext;
BLOCK_CHAIN (block) = chain;
return block;
}
#if 1
static GTY(()) tree last_annotated_node;
#endif
#ifdef USE_MAPPED_LOCATION
expanded_location
expand_location (source_location loc)
{
expanded_location xloc;
if (loc == 0) { xloc.file = NULL; xloc.line = 0; xloc.column = 0; }
else
{
const struct line_map *map = linemap_lookup (&line_table, loc);
xloc.file = map->to_file;
xloc.line = SOURCE_LINE (map, loc);
xloc.column = SOURCE_COLUMN (map, loc);
};
return xloc;
}
#else
void
annotate_with_file_line (tree node, const char *file, int line)
{
if (EXPR_LOCUS (node)
&& (EXPR_FILENAME (node) == file
|| ! strcmp (EXPR_FILENAME (node), file))
&& EXPR_LINENO (node) == line)
{
last_annotated_node = node;
return;
}
if (last_annotated_node
&& EXPR_LOCUS (last_annotated_node)
&& (EXPR_FILENAME (last_annotated_node) == file
|| ! strcmp (EXPR_FILENAME (last_annotated_node), file))
&& EXPR_LINENO (last_annotated_node) == line)
{
SET_EXPR_LOCUS (node, EXPR_LOCUS (last_annotated_node));
return;
}
SET_EXPR_LOCUS (node, ggc_alloc (sizeof (location_t)));
EXPR_LINENO (node) = line;
EXPR_FILENAME (node) = file;
last_annotated_node = node;
}
void
annotate_with_locus (tree node, location_t locus)
{
annotate_with_file_line (node, locus.file, locus.line);
}
#endif
tree
build_decl_attribute_variant (tree ddecl, tree attribute)
{
DECL_ATTRIBUTES (ddecl) = attribute;
return ddecl;
}
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<< 8); \
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
}
static inline hashval_t
iterative_hash_hashval_t (hashval_t val, hashval_t val2)
{
hashval_t a = 0x9e3779b9;
mix (a, val, val2);
return val2;
}
static inline hashval_t
iterative_hash_pointer (void *ptr, hashval_t val2)
{
if (sizeof (ptr) == sizeof (hashval_t))
return iterative_hash_hashval_t ((size_t) ptr, val2);
else
{
hashval_t a = (hashval_t) (size_t) ptr;
int zero = 0;
hashval_t b = (hashval_t) ((size_t) ptr >> (sizeof (hashval_t) * 8 + zero));
mix (a, b, val2);
return val2;
}
}
static inline hashval_t
iterative_hash_host_wide_int (HOST_WIDE_INT val, hashval_t val2)
{
if (sizeof (HOST_WIDE_INT) == sizeof (hashval_t))
return iterative_hash_hashval_t (val, val2);
else
{
hashval_t a = (hashval_t) val;
int zero = 0;
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 8 + zero));
mix (a, b, val2);
if (sizeof (HOST_WIDE_INT) > 2 * sizeof (hashval_t))
{
hashval_t a = (hashval_t) (val >> (sizeof (hashval_t) * 16 + zero));
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 24 + zero));
mix (a, b, val2);
}
return val2;
}
}
tree
build_type_attribute_variant (tree ttype, tree attribute)
{
if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
{
hashval_t hashcode = 0;
tree ntype;
enum tree_code code = TREE_CODE (ttype);
ntype = copy_node (ttype);
TYPE_POINTER_TO (ntype) = 0;
TYPE_REFERENCE_TO (ntype) = 0;
TYPE_ATTRIBUTES (ntype) = attribute;
TYPE_MAIN_VARIANT (ntype) = ntype;
TYPE_NEXT_VARIANT (ntype) = 0;
set_type_quals (ntype, TYPE_UNQUALIFIED);
hashcode = iterative_hash_object (code, hashcode);
if (TREE_TYPE (ntype))
hashcode = iterative_hash_object (TYPE_HASH (TREE_TYPE (ntype)),
hashcode);
hashcode = attribute_hash_list (attribute, hashcode);
switch (TREE_CODE (ntype))
{
case FUNCTION_TYPE:
hashcode = type_hash_list (TYPE_ARG_TYPES (ntype), hashcode);
break;
case ARRAY_TYPE:
hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (ntype)),
hashcode);
break;
case INTEGER_TYPE:
hashcode = iterative_hash_object
(TREE_INT_CST_LOW (TYPE_MAX_VALUE (ntype)), hashcode);
hashcode = iterative_hash_object
(TREE_INT_CST_HIGH (TYPE_MAX_VALUE (ntype)), hashcode);
break;
case REAL_TYPE:
{
unsigned int precision = TYPE_PRECISION (ntype);
hashcode = iterative_hash_object (precision, hashcode);
}
break;
default:
break;
}
ntype = type_hash_canon (hashcode, ntype);
ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
}
return ttype;
}
int
is_attribute_p (const char *attr, tree ident)
{
int ident_len, attr_len;
const char *p;
if (TREE_CODE (ident) != IDENTIFIER_NODE)
return 0;
if (strcmp (attr, IDENTIFIER_POINTER (ident)) == 0)
return 1;
p = IDENTIFIER_POINTER (ident);
ident_len = strlen (p);
attr_len = strlen (attr);
if (attr[0] == '_')
{
gcc_assert (attr[1] == '_');
gcc_assert (attr[attr_len - 2] == '_');
gcc_assert (attr[attr_len - 1] == '_');
gcc_assert (attr[1] == '_');
if (ident_len == attr_len - 4
&& strncmp (attr + 2, p, attr_len - 4) == 0)
return 1;
}
else
{
if (ident_len == attr_len + 4
&& p[0] == '_' && p[1] == '_'
&& p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
&& strncmp (attr, p + 2, attr_len) == 0)
return 1;
}
return 0;
}
tree
lookup_attribute (const char *attr_name, tree list)
{
tree l;
for (l = list; l; l = TREE_CHAIN (l))
{
gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
if (is_attribute_p (attr_name, TREE_PURPOSE (l)))
return l;
}
return NULL_TREE;
}
tree
merge_attributes (tree a1, tree a2)
{
tree attributes;
if ((attributes = a1) == 0)
attributes = a2;
else if (a2 != 0 && ! attribute_list_contained (a1, a2))
{
if (attribute_list_contained (a2, a1))
attributes = a2;
else
{
if (list_length (a1) < list_length (a2))
attributes = a2, a2 = a1;
for (; a2 != 0; a2 = TREE_CHAIN (a2))
{
tree a;
for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
attributes);
a != NULL_TREE;
a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
TREE_CHAIN (a)))
{
if (simple_cst_equal (TREE_VALUE (a), TREE_VALUE (a2)) == 1)
break;
}
if (a == NULL_TREE)
{
a1 = copy_node (a2);
TREE_CHAIN (a1) = attributes;
attributes = a1;
}
}
}
}
return attributes;
}
tree
merge_type_attributes (tree t1, tree t2)
{
return merge_attributes (TYPE_ATTRIBUTES (t1),
TYPE_ATTRIBUTES (t2));
}
tree
merge_decl_attributes (tree olddecl, tree newdecl)
{
return merge_attributes (DECL_ATTRIBUTES (olddecl),
DECL_ATTRIBUTES (newdecl));
}
#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
tree
merge_dllimport_decl_attributes (tree old, tree new)
{
tree a;
int delete_dllimport_p;
old = DECL_ATTRIBUTES (old);
new = DECL_ATTRIBUTES (new);
if (lookup_attribute ("dllimport", old) != NULL_TREE
&& lookup_attribute ("dllimport", new) == NULL_TREE)
delete_dllimport_p = 1;
else
delete_dllimport_p = 0;
a = merge_attributes (old, new);
if (delete_dllimport_p)
{
tree prev, t;
for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
{
if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
{
if (prev == NULL_TREE)
a = TREE_CHAIN (a);
else
TREE_CHAIN (prev) = TREE_CHAIN (t);
break;
}
}
}
return a;
}
tree
handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
bool *no_add_attrs)
{
tree node = *pnode;
if (!DECL_P (node))
{
if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
| (int) ATTR_FLAG_ARRAY_NEXT))
{
*no_add_attrs = true;
return tree_cons (name, args, NULL_TREE);
}
if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
{
warning ("%qs attribute ignored", IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
if (is_attribute_p ("dllimport", name))
{
if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node)
&& !DECL_DECLARED_INLINE_P (node))
{
error ("%Jfunction %qD definition is marked dllimport.", node, node);
*no_add_attrs = true;
}
else if (TREE_CODE (node) == VAR_DECL)
{
if (DECL_INITIAL (node))
{
error ("%Jvariable %qD definition is marked dllimport.",
node, node);
*no_add_attrs = true;
}
DECL_EXTERNAL (node) = 1;
if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
TREE_PUBLIC (node) = 1;
}
}
if (!TREE_PUBLIC (node)
&& (TREE_CODE (node) == VAR_DECL
|| TREE_CODE (node) == FUNCTION_DECL))
{
error ("%Jexternal linkage required for symbol %qD because of "
"%qs attribute.", node, node, IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
#endif
static void
set_type_quals (tree type, int type_quals)
{
TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
}
bool
check_qualified_type (tree cand, tree base, int type_quals)
{
return (TYPE_QUALS (cand) == type_quals
&& TYPE_NAME (cand) == TYPE_NAME (base)
&& TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
&& attribute_list_equal (TYPE_ATTRIBUTES (cand),
TYPE_ATTRIBUTES (base)));
}
tree
get_qualified_type (tree type, int type_quals)
{
tree t;
if (TYPE_QUALS (type) == type_quals)
return type;
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
if (check_qualified_type (t, type, type_quals))
return t;
return NULL_TREE;
}
tree
build_qualified_type (tree type, int type_quals)
{
tree t;
t = get_qualified_type (type, type_quals);
if (!t)
{
t = build_variant_type_copy (type);
set_type_quals (t, type_quals);
}
return t;
}
tree
build_distinct_type_copy (tree type)
{
tree t = copy_node (type);
TYPE_POINTER_TO (t) = 0;
TYPE_REFERENCE_TO (t) = 0;
TYPE_MAIN_VARIANT (t) = t;
TYPE_NEXT_VARIANT (t) = 0;
return t;
}
tree
build_variant_type_copy (tree type)
{
tree t, m = TYPE_MAIN_VARIANT (type);
t = build_distinct_type_copy (type);
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
TYPE_NEXT_VARIANT (m) = t;
TYPE_MAIN_VARIANT (t) = m;
return t;
}
unsigned int
type_hash_list (tree list, hashval_t hashcode)
{
tree tail;
for (tail = list; tail; tail = TREE_CHAIN (tail))
if (TREE_VALUE (tail) != error_mark_node)
hashcode = iterative_hash_object (TYPE_HASH (TREE_VALUE (tail)),
hashcode);
return hashcode;
}
static int
type_hash_eq (const void *va, const void *vb)
{
const struct type_hash *a = va, *b = vb;
if (a->hash != b->hash
|| TREE_CODE (a->type) != TREE_CODE (b->type)
|| TREE_TYPE (a->type) != TREE_TYPE (b->type)
|| !attribute_list_equal (TYPE_ATTRIBUTES (a->type),
TYPE_ATTRIBUTES (b->type))
|| TYPE_ALIGN (a->type) != TYPE_ALIGN (b->type)
|| TYPE_MODE (a->type) != TYPE_MODE (b->type))
return 0;
switch (TREE_CODE (a->type))
{
case VOID_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
return 1;
case ENUMERAL_TYPE:
if (TYPE_VALUES (a->type) != TYPE_VALUES (b->type)
&& !(TYPE_VALUES (a->type)
&& TREE_CODE (TYPE_VALUES (a->type)) == TREE_LIST
&& TYPE_VALUES (b->type)
&& TREE_CODE (TYPE_VALUES (b->type)) == TREE_LIST
&& type_list_equal (TYPE_VALUES (a->type),
TYPE_VALUES (b->type))))
return 0;
case INTEGER_TYPE:
case REAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
return ((TYPE_MAX_VALUE (a->type) == TYPE_MAX_VALUE (b->type)
|| tree_int_cst_equal (TYPE_MAX_VALUE (a->type),
TYPE_MAX_VALUE (b->type)))
&& (TYPE_MIN_VALUE (a->type) == TYPE_MIN_VALUE (b->type)
|| tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
TYPE_MIN_VALUE (b->type))));
case OFFSET_TYPE:
return TYPE_OFFSET_BASETYPE (a->type) == TYPE_OFFSET_BASETYPE (b->type);
case METHOD_TYPE:
return (TYPE_METHOD_BASETYPE (a->type) == TYPE_METHOD_BASETYPE (b->type)
&& (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
|| (TYPE_ARG_TYPES (a->type)
&& TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
&& TYPE_ARG_TYPES (b->type)
&& TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST
&& type_list_equal (TYPE_ARG_TYPES (a->type),
TYPE_ARG_TYPES (b->type)))));
case ARRAY_TYPE:
case SET_TYPE:
return TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type);
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
return (TYPE_FIELDS (a->type) == TYPE_FIELDS (b->type)
|| (TYPE_FIELDS (a->type)
&& TREE_CODE (TYPE_FIELDS (a->type)) == TREE_LIST
&& TYPE_FIELDS (b->type)
&& TREE_CODE (TYPE_FIELDS (b->type)) == TREE_LIST
&& type_list_equal (TYPE_FIELDS (a->type),
TYPE_FIELDS (b->type))));
case FUNCTION_TYPE:
return (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
|| (TYPE_ARG_TYPES (a->type)
&& TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
&& TYPE_ARG_TYPES (b->type)
&& TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST
&& type_list_equal (TYPE_ARG_TYPES (a->type),
TYPE_ARG_TYPES (b->type))));
default:
return 0;
}
}
static hashval_t
type_hash_hash (const void *item)
{
return ((const struct type_hash *) item)->hash;
}
tree
type_hash_lookup (hashval_t hashcode, tree type)
{
struct type_hash *h, in;
layout_type (type);
in.hash = hashcode;
in.type = type;
h = htab_find_with_hash (type_hash_table, &in, hashcode);
if (h)
return h->type;
return NULL_TREE;
}
void
type_hash_add (hashval_t hashcode, tree type)
{
struct type_hash *h;
void **loc;
h = ggc_alloc (sizeof (struct type_hash));
h->hash = hashcode;
h->type = type;
loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
*(struct type_hash **) loc = h;
}
tree
type_hash_canon (unsigned int hashcode, tree type)
{
tree t1;
gcc_assert (TYPE_MAIN_VARIANT (type) == type);
if (!lang_hooks.types.hash_types)
return type;
t1 = type_hash_lookup (hashcode, type);
if (t1 != 0)
{
#ifdef GATHER_STATISTICS
tree_node_counts[(int) t_kind]--;
tree_node_sizes[(int) t_kind] -= sizeof (struct tree_type);
#endif
return t1;
}
else
{
type_hash_add (hashcode, type);
return type;
}
}
static int
type_hash_marked_p (const void *p)
{
tree type = ((struct type_hash *) p)->type;
return ggc_marked_p (type) || TYPE_SYMTAB_POINTER (type);
}
static void
print_type_hash_statistics (void)
{
fprintf (stderr, "Type hash: size %ld, %ld elements, %f collisions\n",
(long) htab_size (type_hash_table),
(long) htab_elements (type_hash_table),
htab_collisions (type_hash_table));
}
unsigned int
attribute_hash_list (tree list, hashval_t hashcode)
{
tree tail;
for (tail = list; tail; tail = TREE_CHAIN (tail))
hashcode = iterative_hash_object
(IDENTIFIER_HASH_VALUE (TREE_PURPOSE (tail)), hashcode);
return hashcode;
}
int
attribute_list_equal (tree l1, tree l2)
{
return attribute_list_contained (l1, l2)
&& attribute_list_contained (l2, l1);
}
int
attribute_list_contained (tree l1, tree l2)
{
tree t1, t2;
if (l1 == l2)
return 1;
for (t1 = l1, t2 = l2;
t1 != 0 && t2 != 0
&& TREE_PURPOSE (t1) == TREE_PURPOSE (t2)
&& TREE_VALUE (t1) == TREE_VALUE (t2);
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2));
if (t1 == 0 && t2 == 0)
return 1;
for (; t2 != 0; t2 = TREE_CHAIN (t2))
{
tree attr;
for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
attr != NULL_TREE;
attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
TREE_CHAIN (attr)))
{
if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) == 1)
break;
}
if (attr == 0)
return 0;
if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) != 1)
return 0;
}
return 1;
}
int
type_list_equal (tree l1, tree l2)
{
tree t1, t2;
for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
if (TREE_VALUE (t1) != TREE_VALUE (t2)
|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
&& ! (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))
&& (TREE_TYPE (TREE_PURPOSE (t1))
== TREE_TYPE (TREE_PURPOSE (t2))))))
return 0;
return t1 == t2;
}
int
type_num_arguments (tree type)
{
int i = 0;
tree t;
for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
if (VOID_TYPE_P (TREE_VALUE (t)))
break;
else
++i;
return i;
}
int
tree_int_cst_equal (tree t1, tree t2)
{
if (t1 == t2)
return 1;
if (t1 == 0 || t2 == 0)
return 0;
if (TREE_CODE (t1) == INTEGER_CST
&& TREE_CODE (t2) == INTEGER_CST
&& TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2))
return 1;
return 0;
}
int
tree_int_cst_lt (tree t1, tree t2)
{
if (t1 == t2)
return 0;
if (TYPE_UNSIGNED (TREE_TYPE (t1)) != TYPE_UNSIGNED (TREE_TYPE (t2)))
{
int t1_sgn = tree_int_cst_sgn (t1);
int t2_sgn = tree_int_cst_sgn (t2);
if (t1_sgn < t2_sgn)
return 1;
else if (t1_sgn > t2_sgn)
return 0;
}
else if (!TYPE_UNSIGNED (TREE_TYPE (t1)))
return INT_CST_LT (t1, t2);
return INT_CST_LT_UNSIGNED (t1, t2);
}
int
tree_int_cst_compare (tree t1, tree t2)
{
if (tree_int_cst_lt (t1, t2))
return -1;
else if (tree_int_cst_lt (t2, t1))
return 1;
else
return 0;
}
int
host_integerp (tree t, int pos)
{
return (TREE_CODE (t) == INTEGER_CST
&& ! TREE_OVERFLOW (t)
&& ((TREE_INT_CST_HIGH (t) == 0
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0)
|| (! pos && TREE_INT_CST_HIGH (t) == -1
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0
&& !TYPE_UNSIGNED (TREE_TYPE (t)))
|| (pos && TREE_INT_CST_HIGH (t) == 0)));
}
HOST_WIDE_INT
tree_low_cst (tree t, int pos)
{
gcc_assert (host_integerp (t, pos));
return TREE_INT_CST_LOW (t);
}
int
tree_int_cst_msb (tree t)
{
int prec;
HOST_WIDE_INT h;
unsigned HOST_WIDE_INT l;
prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (t))) - 1;
rshift_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t), prec,
2 * HOST_BITS_PER_WIDE_INT, &l, &h, 0);
return (l & 1) == 1;
}
int
tree_int_cst_sgn (tree t)
{
if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0)
return 0;
else if (TYPE_UNSIGNED (TREE_TYPE (t)))
return 1;
else if (TREE_INT_CST_HIGH (t) < 0)
return -1;
else
return 1;
}
int
simple_cst_list_equal (tree l1, tree l2)
{
while (l1 != NULL_TREE && l2 != NULL_TREE)
{
if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
return 0;
l1 = TREE_CHAIN (l1);
l2 = TREE_CHAIN (l2);
}
return l1 == l2;
}
int
simple_cst_equal (tree t1, tree t2)
{
enum tree_code code1, code2;
int cmp;
int i;
if (t1 == t2)
return 1;
if (t1 == 0 || t2 == 0)
return 0;
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
{
if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
|| code2 == NON_LVALUE_EXPR)
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
else
return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
}
else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
|| code2 == NON_LVALUE_EXPR)
return simple_cst_equal (t1, TREE_OPERAND (t2, 0));
if (code1 != code2)
return 0;
switch (code1)
{
case INTEGER_CST:
return (TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2));
case REAL_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
case STRING_CST:
return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
&& ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
TREE_STRING_LENGTH (t1)));
case CONSTRUCTOR:
return simple_cst_list_equal (CONSTRUCTOR_ELTS (t1),
CONSTRUCTOR_ELTS (t2));
case SAVE_EXPR:
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
case CALL_EXPR:
cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return
simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case TARGET_EXPR:
if ((TREE_CODE (TREE_OPERAND (t1, 0)) == VAR_DECL
&& DECL_NAME (TREE_OPERAND (t1, 0)) == NULL_TREE
&& !DECL_RTL_SET_P (TREE_OPERAND (t1, 0)))
|| (TREE_CODE (TREE_OPERAND (t2, 0)) == VAR_DECL
&& DECL_NAME (TREE_OPERAND (t2, 0)) == NULL_TREE
&& !DECL_RTL_SET_P (TREE_OPERAND (t2, 0))))
cmp = 1;
else
cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case WITH_CLEANUP_EXPR:
cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
if (cmp <= 0)
return cmp;
return simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
case COMPONENT_REF:
if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
return 0;
case VAR_DECL:
case PARM_DECL:
case CONST_DECL:
case FUNCTION_DECL:
return 0;
default:
break;
}
if ((int) code1 >= (int) LAST_AND_UNUSED_TREE_CODE)
return -1;
switch (TREE_CODE_CLASS (code1))
{
case tcc_unary:
case tcc_binary:
case tcc_comparison:
case tcc_expression:
case tcc_reference:
case tcc_statement:
cmp = 1;
for (i = 0; i < TREE_CODE_LENGTH (code1); i++)
{
cmp = simple_cst_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
if (cmp <= 0)
return cmp;
}
return cmp;
default:
return -1;
}
}
int
compare_tree_int (tree t, unsigned HOST_WIDE_INT u)
{
if (tree_int_cst_sgn (t) < 0)
return -1;
else if (TREE_INT_CST_HIGH (t) != 0)
return 1;
else if (TREE_INT_CST_LOW (t) == u)
return 0;
else if (TREE_INT_CST_LOW (t) < u)
return -1;
else
return 1;
}
bool
associative_tree_code (enum tree_code code)
{
switch (code)
{
case BIT_IOR_EXPR:
case BIT_AND_EXPR:
case BIT_XOR_EXPR:
case PLUS_EXPR:
case MULT_EXPR:
case MIN_EXPR:
case MAX_EXPR:
return true;
default:
break;
}
return false;
}
bool
commutative_tree_code (enum tree_code code)
{
switch (code)
{
case PLUS_EXPR:
case MULT_EXPR:
case MIN_EXPR:
case MAX_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
case NE_EXPR:
case EQ_EXPR:
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNEQ_EXPR:
case LTGT_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_XOR_EXPR:
case TRUTH_OR_EXPR:
return true;
default:
break;
}
return false;
}
hashval_t
iterative_hash_expr (tree t, hashval_t val)
{
int i;
enum tree_code code;
char class;
if (t == NULL_TREE)
return iterative_hash_pointer (t, val);
code = TREE_CODE (t);
switch (code)
{
case INTEGER_CST:
val = iterative_hash_host_wide_int (TREE_INT_CST_LOW (t), val);
return iterative_hash_host_wide_int (TREE_INT_CST_HIGH (t), val);
case REAL_CST:
{
unsigned int val2 = real_hash (TREE_REAL_CST_PTR (t));
return iterative_hash_hashval_t (val2, val);
}
case STRING_CST:
return iterative_hash (TREE_STRING_POINTER (t),
TREE_STRING_LENGTH (t), val);
case COMPLEX_CST:
val = iterative_hash_expr (TREE_REALPART (t), val);
return iterative_hash_expr (TREE_IMAGPART (t), val);
case VECTOR_CST:
return iterative_hash_expr (TREE_VECTOR_CST_ELTS (t), val);
case SSA_NAME:
case VALUE_HANDLE:
return iterative_hash_pointer (t, val);
case TREE_LIST:
for (; t; t = TREE_CHAIN (t))
val = iterative_hash_expr (TREE_VALUE (t), val);
return val;
default:
class = TREE_CODE_CLASS (code);
if (class == tcc_declaration)
{
val = iterative_hash_pointer (t, val);
}
else
{
gcc_assert (IS_EXPR_CODE_CLASS (class));
val = iterative_hash_object (code, val);
if (code == NOP_EXPR
|| code == CONVERT_EXPR
|| code == NON_LVALUE_EXPR)
{
val += TYPE_UNSIGNED (TREE_TYPE (t));
val = iterative_hash_expr (TREE_OPERAND (t, 0), val);
}
else if (commutative_tree_code (code))
{
hashval_t one = iterative_hash_expr (TREE_OPERAND (t, 0), 0);
hashval_t two = iterative_hash_expr (TREE_OPERAND (t, 1), 0);
hashval_t t;
if (one > two)
t = one, one = two, two = t;
val = iterative_hash_hashval_t (one, val);
val = iterative_hash_hashval_t (two, val);
}
else
for (i = first_rtl_op (code) - 1; i >= 0; --i)
val = iterative_hash_expr (TREE_OPERAND (t, i), val);
}
return val;
break;
}
}
tree
build_pointer_type_for_mode (tree to_type, enum machine_mode mode,
bool can_alias_all)
{
tree t;
if (TYPE_POINTER_TO (to_type) != 0
&& TREE_CODE (TYPE_POINTER_TO (to_type)) != POINTER_TYPE)
return TYPE_POINTER_TO (to_type);
for (t = TYPE_POINTER_TO (to_type); t; t = TYPE_NEXT_PTR_TO (t))
if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all)
return t;
t = make_node (POINTER_TYPE);
TREE_TYPE (t) = to_type;
TYPE_MODE (t) = mode;
TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all;
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
TYPE_POINTER_TO (to_type) = t;
layout_type (t);
return t;
}
tree
build_pointer_type (tree to_type)
{
return build_pointer_type_for_mode (to_type, ptr_mode, false);
}
tree
build_reference_type_for_mode (tree to_type, enum machine_mode mode,
bool can_alias_all)
{
tree t;
if (TYPE_REFERENCE_TO (to_type) != 0
&& TREE_CODE (TYPE_REFERENCE_TO (to_type)) != REFERENCE_TYPE)
return TYPE_REFERENCE_TO (to_type);
for (t = TYPE_REFERENCE_TO (to_type); t; t = TYPE_NEXT_REF_TO (t))
if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all)
return t;
t = make_node (REFERENCE_TYPE);
TREE_TYPE (t) = to_type;
TYPE_MODE (t) = mode;
TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all;
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
TYPE_REFERENCE_TO (to_type) = t;
layout_type (t);
return t;
}
tree
build_reference_type (tree to_type)
{
return build_reference_type_for_mode (to_type, ptr_mode, false);
}
tree
build_type_no_quals (tree t)
{
switch (TREE_CODE (t))
{
case POINTER_TYPE:
return build_pointer_type_for_mode (build_type_no_quals (TREE_TYPE (t)),
TYPE_MODE (t),
TYPE_REF_CAN_ALIAS_ALL (t));
case REFERENCE_TYPE:
return
build_reference_type_for_mode (build_type_no_quals (TREE_TYPE (t)),
TYPE_MODE (t),
TYPE_REF_CAN_ALIAS_ALL (t));
default:
return TYPE_MAIN_VARIANT (t);
}
}
tree
build_index_type (tree maxval)
{
tree itype = make_node (INTEGER_TYPE);
TREE_TYPE (itype) = sizetype;
TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
TYPE_MIN_VALUE (itype) = size_zero_node;
TYPE_MAX_VALUE (itype) = fold_convert (sizetype, maxval);
TYPE_MODE (itype) = TYPE_MODE (sizetype);
TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (sizetype);
if (host_integerp (maxval, 1))
return type_hash_canon (tree_low_cst (maxval, 1), itype);
else
return itype;
}
tree
build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision,
int unsignedp)
{
tree itype = make_node (INTEGER_TYPE);
TYPE_PRECISION (itype) = precision;
if (unsignedp)
fixup_unsigned_type (itype);
else
fixup_signed_type (itype);
if (host_integerp (TYPE_MAX_VALUE (itype), 1))
return type_hash_canon (tree_low_cst (TYPE_MAX_VALUE (itype), 1), itype);
return itype;
}
tree
build_range_type (tree type, tree lowval, tree highval)
{
tree itype = make_node (INTEGER_TYPE);
TREE_TYPE (itype) = type;
if (type == NULL_TREE)
type = sizetype;
TYPE_MIN_VALUE (itype) = convert (type, lowval);
TYPE_MAX_VALUE (itype) = highval ? convert (type, highval) : NULL;
TYPE_PRECISION (itype) = TYPE_PRECISION (type);
TYPE_MODE (itype) = TYPE_MODE (type);
TYPE_SIZE (itype) = TYPE_SIZE (type);
TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
TYPE_ALIGN (itype) = TYPE_ALIGN (type);
TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (type);
if (host_integerp (lowval, 0) && highval != 0 && host_integerp (highval, 0))
return type_hash_canon (tree_low_cst (highval, 0)
- tree_low_cst (lowval, 0),
itype);
else
return itype;
}
tree
build_index_2_type (tree lowval, tree highval)
{
return build_range_type (sizetype, lowval, highval);
}
tree
build_array_type (tree elt_type, tree index_type)
{
tree t;
hashval_t hashcode = 0;
if (TREE_CODE (elt_type) == FUNCTION_TYPE)
{
error ("arrays of functions are not meaningful");
elt_type = integer_type_node;
}
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
if (index_type == 0)
return t;
hashcode = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
return t;
}
tree
get_inner_array_type (tree array)
{
tree type = TREE_TYPE (array);
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
return type;
}
tree
build_function_type (tree value_type, tree arg_types)
{
tree t;
hashval_t hashcode = 0;
if (TREE_CODE (value_type) == FUNCTION_TYPE)
{
error ("function return type cannot be function");
value_type = integer_type_node;
}
t = make_node (FUNCTION_TYPE);
TREE_TYPE (t) = value_type;
TYPE_ARG_TYPES (t) = arg_types;
hashcode = iterative_hash_object (TYPE_HASH (value_type), hashcode);
hashcode = type_hash_list (arg_types, hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
return t;
}
tree
build_function_type_list (tree return_type, ...)
{
tree t, args, last;
va_list p;
va_start (p, return_type);
t = va_arg (p, tree);
for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree))
args = tree_cons (NULL_TREE, t, args);
last = args;
args = nreverse (args);
TREE_CHAIN (last) = void_list_node;
args = build_function_type (return_type, args);
va_end (p);
return args;
}
tree
build_method_type_directly (tree basetype,
tree rettype,
tree argtypes)
{
tree t;
tree ptype;
int hashcode = 0;
t = make_node (METHOD_TYPE);
TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
TREE_TYPE (t) = rettype;
ptype = build_pointer_type (basetype);
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (rettype), hashcode);
hashcode = type_hash_list (argtypes, hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
return t;
}
tree
build_method_type (tree basetype, tree type)
{
gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
return build_method_type_directly (basetype,
TREE_TYPE (type),
TYPE_ARG_TYPES (type));
}
tree
build_offset_type (tree basetype, tree type)
{
tree t;
hashval_t hashcode = 0;
t = make_node (OFFSET_TYPE);
TYPE_OFFSET_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
TREE_TYPE (t) = type;
hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (type), hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
return t;
}
tree
build_complex_type (tree component_type)
{
tree t;
hashval_t hashcode;
t = make_node (COMPLEX_TYPE);
TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
hashcode = iterative_hash_object (TYPE_HASH (component_type), 0);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
if ((write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
&& ! TYPE_NAME (t))
{
const char *name;
if (component_type == char_type_node)
name = "complex char";
else if (component_type == signed_char_type_node)
name = "complex signed char";
else if (component_type == unsigned_char_type_node)
name = "complex unsigned char";
else if (component_type == short_integer_type_node)
name = "complex short int";
else if (component_type == short_unsigned_type_node)
name = "complex short unsigned int";
else if (component_type == integer_type_node)
name = "complex int";
else if (component_type == unsigned_type_node)
name = "complex unsigned int";
else if (component_type == long_integer_type_node)
name = "complex long int";
else if (component_type == long_unsigned_type_node)
name = "complex long unsigned int";
else if (component_type == long_long_integer_type_node)
name = "complex long long int";
else if (component_type == long_long_unsigned_type_node)
name = "complex long long unsigned int";
else
name = 0;
if (name != 0)
TYPE_NAME (t) = get_identifier (name);
}
return build_qualified_type (t, TYPE_QUALS (component_type));
}
tree
get_unwidened (tree op, tree for_type)
{
tree type = TREE_TYPE (op);
unsigned final_prec
= TYPE_PRECISION (for_type != 0 ? for_type : type);
int uns
= (for_type != 0 && for_type != type
&& final_prec > TYPE_PRECISION (type)
&& TYPE_UNSIGNED (type));
tree win = op;
while (TREE_CODE (op) == NOP_EXPR)
{
int bitschange
= TYPE_PRECISION (TREE_TYPE (op))
- TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0)));
if (bitschange < 0
&& final_prec > TYPE_PRECISION (TREE_TYPE (op)))
break;
op = TREE_OPERAND (op, 0);
if (bitschange > 0)
{
if (! uns || final_prec <= TYPE_PRECISION (TREE_TYPE (op)))
win = op;
if ((uns || TREE_CODE (op) == NOP_EXPR)
&& TYPE_UNSIGNED (TREE_TYPE (op)))
{
uns = 1;
win = op;
}
}
}
if (TREE_CODE (op) == COMPONENT_REF
&& TREE_CODE (type) != REAL_TYPE
&& DECL_SIZE (TREE_OPERAND (op, 1)) != 0
&& host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
{
unsigned int innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
int unsignedp = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
|| TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
type = lang_hooks.types.type_for_size (innerprec, unsignedp);
if (type != 0
&& INT_CST_LT_UNSIGNED (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (op)))
&& (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
&& (! uns || final_prec <= innerprec || unsignedp))
{
win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
}
return win;
}
tree
get_narrower (tree op, int *unsignedp_ptr)
{
int uns = 0;
int first = 1;
tree win = op;
bool integral_p = INTEGRAL_TYPE_P (TREE_TYPE (op));
while (TREE_CODE (op) == NOP_EXPR)
{
int bitschange
= (TYPE_PRECISION (TREE_TYPE (op))
- TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0))));
if (bitschange < 0)
break;
if (bitschange > 0)
{
op = TREE_OPERAND (op, 0);
if (first)
uns = TYPE_UNSIGNED (TREE_TYPE (op));
else if (uns != TYPE_UNSIGNED (TREE_TYPE (op)))
break;
first = 0;
}
else
{
if (first)
uns = TYPE_UNSIGNED (TREE_TYPE (op));
first = 0;
op = TREE_OPERAND (op, 0);
if (INTEGRAL_TYPE_P (TREE_TYPE (op)) != integral_p)
continue;
}
win = op;
}
if (TREE_CODE (op) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (op)) != REAL_TYPE
&& DECL_SIZE (TREE_OPERAND (op, 1)) != 0
&& host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
{
unsigned HOST_WIDE_INT innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
int unsignedp = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
|| TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
tree type = lang_hooks.types.type_for_size (innerprec, unsignedp);
if (innerprec < TYPE_PRECISION (TREE_TYPE (op))
&& ! DECL_BIT_FIELD (TREE_OPERAND (op, 1))
&& (first || uns == DECL_UNSIGNED (TREE_OPERAND (op, 1)))
&& type != 0)
{
if (first)
uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
}
*unsignedp_ptr = uns;
return win;
}
int
int_fits_type_p (tree c, tree type)
{
tree type_low_bound = TYPE_MIN_VALUE (type);
tree type_high_bound = TYPE_MAX_VALUE (type);
int ok_for_low_bound, ok_for_high_bound;
if ((TYPE_UNSIGNED (type) && tree_int_cst_sgn (c) < 0)
|| (! TYPE_UNSIGNED (type)
&& TYPE_UNSIGNED (TREE_TYPE (c)) && tree_int_cst_msb (c)))
return 0;
ok_for_low_bound = -1;
ok_for_high_bound = -1;
if (type_low_bound && TREE_CODE (type_low_bound) == INTEGER_CST)
{
ok_for_low_bound = ! tree_int_cst_lt (c, type_low_bound);
if (! ok_for_low_bound)
return 0;
}
if (type_high_bound && TREE_CODE (type_high_bound) == INTEGER_CST)
{
ok_for_high_bound = ! tree_int_cst_lt (type_high_bound, c);
if (! ok_for_high_bound)
return 0;
}
if (ok_for_low_bound == 1 && ok_for_high_bound == 1)
return 1;
else if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != 0)
return int_fits_type_p (c, TREE_TYPE (type));
else
{
c = copy_node (c);
TREE_TYPE (c) = type;
c = force_fit_type (c, -1, false, false);
return !TREE_OVERFLOW (c);
}
}
static tree
find_var_from_fn (tree *tp, int *walk_subtrees, void *data)
{
tree fn = (tree) data;
if (TYPE_P (*tp))
*walk_subtrees = 0;
else if (DECL_P (*tp)
&& lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
return *tp;
return NULL_TREE;
}
bool
variably_modified_type_p (tree type, tree fn)
{
tree t;
#define RETURN_TRUE_IF_VAR(T) \
do { tree _t = (T); \
if (_t && _t != error_mark_node && TREE_CODE (_t) != INTEGER_CST \
&& (!fn || walk_tree (&_t, find_var_from_fn, fn, NULL))) \
return true; } while (0)
if (type == error_mark_node)
return false;
RETURN_TRUE_IF_VAR (TYPE_SIZE (type));
RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type));
switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
case ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
if (variably_modified_type_p (TREE_TYPE (type), fn))
return true;
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
if (variably_modified_type_p (TREE_TYPE (type), fn))
return true;
for (t = TYPE_ARG_TYPES (type);
t && t != void_list_node;
t = TREE_CHAIN (t))
if (variably_modified_type_p (TREE_VALUE (t), fn))
return true;
break;
case INTEGER_TYPE:
case REAL_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL)
{
RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
RETURN_TRUE_IF_VAR (DECL_SIZE (t));
RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
if (TREE_CODE (type) == QUAL_UNION_TYPE)
RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
}
break;
default:
break;
}
return lang_hooks.tree_inlining.var_mod_type_p (type, fn);
#undef RETURN_TRUE_IF_VAR
}
tree
get_containing_scope (tree t)
{
return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
}
tree
decl_function_context (tree decl)
{
tree context;
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
context
= TYPE_MAIN_VARIANT
(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
else
context = DECL_CONTEXT (decl);
while (context && TREE_CODE (context) != FUNCTION_DECL)
{
if (TREE_CODE (context) == BLOCK)
context = BLOCK_SUPERCONTEXT (context);
else
context = get_containing_scope (context);
}
return context;
}
tree
decl_type_context (tree decl)
{
tree context = DECL_CONTEXT (decl);
while (context)
switch (TREE_CODE (context))
{
case NAMESPACE_DECL:
case TRANSLATION_UNIT_DECL:
return NULL_TREE;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
return context;
case TYPE_DECL:
case FUNCTION_DECL:
context = DECL_CONTEXT (context);
break;
case BLOCK:
context = BLOCK_SUPERCONTEXT (context);
break;
default:
gcc_unreachable ();
}
return NULL_TREE;
}
tree
get_callee_fndecl (tree call)
{
tree addr;
gcc_assert (TREE_CODE (call) == CALL_EXPR);
addr = TREE_OPERAND (call, 0);
STRIP_NOPS (addr);
if (DECL_P (addr) && TREE_CODE (addr) != FUNCTION_DECL
&& TREE_READONLY (addr) && ! TREE_THIS_VOLATILE (addr)
&& DECL_INITIAL (addr))
addr = DECL_INITIAL (addr);
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
return TREE_OPERAND (addr, 0);
return lang_hooks.lang_get_callee_fndecl (call);
}
void
dump_tree_statistics (void)
{
#ifdef GATHER_STATISTICS
int i;
int total_nodes, total_bytes;
#endif
fprintf (stderr, "\n??? tree nodes created\n\n");
#ifdef GATHER_STATISTICS
fprintf (stderr, "Kind Nodes Bytes\n");
fprintf (stderr, "---------------------------------------\n");
total_nodes = total_bytes = 0;
for (i = 0; i < (int) all_kinds; i++)
{
fprintf (stderr, "%-20s %7d %10d\n", tree_node_kind_names[i],
tree_node_counts[i], tree_node_sizes[i]);
total_nodes += tree_node_counts[i];
total_bytes += tree_node_sizes[i];
}
fprintf (stderr, "---------------------------------------\n");
fprintf (stderr, "%-20s %7d %10d\n", "Total", total_nodes, total_bytes);
fprintf (stderr, "---------------------------------------\n");
ssanames_print_statistics ();
phinodes_print_statistics ();
#else
fprintf (stderr, "(No per-node statistics)\n");
#endif
print_type_hash_statistics ();
lang_hooks.print_statistics ();
}
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
unsigned
crc32_string (unsigned chksum, const char *string)
{
do
{
unsigned value = *string << 24;
unsigned ix;
for (ix = 8; ix--; value <<= 1)
{
unsigned feedback;
feedback = (value ^ chksum) & 0x80000000 ? 0x04c11db7 : 0;
chksum <<= 1;
chksum ^= feedback;
}
}
while (*string++);
return chksum;
}
void
clean_symbol_name (char *p)
{
for (; *p; p++)
if (! (ISALNUM (*p)
#ifndef NO_DOLLAR_IN_LABEL
|| *p == '$'
#endif
#ifndef NO_DOT_IN_LABEL
|| *p == '.'
#endif
))
*p = '_';
}
tree
get_file_function_name_long (const char *type)
{
char *buf;
const char *p;
char *q;
if (first_global_object_name)
p = first_global_object_name;
else
{
unsigned len;
const char *name = weak_global_object_name;
const char *file = main_input_filename;
if (! name)
name = "";
if (! file)
file = input_filename;
len = strlen (file);
q = alloca (9 * 2 + len + 1);
memcpy (q, file, len + 1);
clean_symbol_name (q);
sprintf (q + len, "_%08X_%08X", crc32_string (0, name),
crc32_string (0, flag_random_seed));
p = q;
}
buf = alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p) + strlen (type));
sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
return get_identifier (buf);
}
tree
get_file_function_name (int kind)
{
char p[2];
p[0] = kind;
p[1] = 0;
return get_file_function_name_long (p);
}
tree
get_set_constructor_bits (tree init, char *buffer, int bit_size)
{
int i;
tree vals;
HOST_WIDE_INT domain_min
= tree_low_cst (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (init))), 0);
tree non_const_bits = NULL_TREE;
for (i = 0; i < bit_size; i++)
buffer[i] = 0;
for (vals = TREE_OPERAND (init, 1);
vals != NULL_TREE; vals = TREE_CHAIN (vals))
{
if (!host_integerp (TREE_VALUE (vals), 0)
|| (TREE_PURPOSE (vals) != NULL_TREE
&& !host_integerp (TREE_PURPOSE (vals), 0)))
non_const_bits
= tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
else if (TREE_PURPOSE (vals) != NULL_TREE)
{
HOST_WIDE_INT lo_index
= tree_low_cst (TREE_PURPOSE (vals), 0) - domain_min;
HOST_WIDE_INT hi_index
= tree_low_cst (TREE_VALUE (vals), 0) - domain_min;
gcc_assert (lo_index >= 0);
gcc_assert (lo_index < bit_size);
gcc_assert (hi_index >= 0);
gcc_assert (hi_index < bit_size);
for (; lo_index <= hi_index; lo_index++)
buffer[lo_index] = 1;
}
else
{
HOST_WIDE_INT index
= tree_low_cst (TREE_VALUE (vals), 0) - domain_min;
if (index < 0 || index >= bit_size)
{
error ("invalid initializer for bit string");
return NULL_TREE;
}
buffer[index] = 1;
}
}
return non_const_bits;
}
tree
get_set_constructor_bytes (tree init, unsigned char *buffer, int wd_size)
{
int i;
int set_word_size = BITS_PER_UNIT;
int bit_size = wd_size * set_word_size;
int bit_pos = 0;
unsigned char *bytep = buffer;
char *bit_buffer = alloca (bit_size);
tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
for (i = 0; i < wd_size; i++)
buffer[i] = 0;
for (i = 0; i < bit_size; i++)
{
if (bit_buffer[i])
{
if (BYTES_BIG_ENDIAN)
*bytep |= (1 << (set_word_size - 1 - bit_pos));
else
*bytep |= 1 << bit_pos;
}
bit_pos++;
if (bit_pos >= set_word_size)
bit_pos = 0, bytep++;
}
return non_const_bits;
}
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
void
tree_check_failed (const tree node, const char *file,
int line, const char *function, ...)
{
va_list args;
char *buffer;
unsigned length = 0;
int code;
va_start (args, function);
while ((code = va_arg (args, int)))
length += 4 + strlen (tree_code_name[code]);
va_end (args);
va_start (args, function);
buffer = alloca (length);
length = 0;
while ((code = va_arg (args, int)))
{
if (length)
{
strcpy (buffer + length, " or ");
length += 4;
}
strcpy (buffer + length, tree_code_name[code]);
length += strlen (tree_code_name[code]);
}
va_end (args);
internal_error ("tree check: expected %s, have %s in %s, at %s:%d",
buffer, tree_code_name[TREE_CODE (node)],
function, trim_filename (file), line);
}
void
tree_not_check_failed (const tree node, const char *file,
int line, const char *function, ...)
{
va_list args;
char *buffer;
unsigned length = 0;
int code;
va_start (args, function);
while ((code = va_arg (args, int)))
length += 4 + strlen (tree_code_name[code]);
va_end (args);
va_start (args, function);
buffer = alloca (length);
length = 0;
while ((code = va_arg (args, int)))
{
if (length)
{
strcpy (buffer + length, " or ");
length += 4;
}
strcpy (buffer + length, tree_code_name[code]);
length += strlen (tree_code_name[code]);
}
va_end (args);
internal_error ("tree check: expected none of %s, have %s in %s, at %s:%d",
buffer, tree_code_name[TREE_CODE (node)],
function, trim_filename (file), line);
}
void
tree_class_check_failed (const tree node, const enum tree_code_class cl,
const char *file, int line, const char *function)
{
internal_error
("tree check: expected class %qs, have %qs (%s) in %s, at %s:%d",
TREE_CODE_CLASS_STRING (cl),
TREE_CODE_CLASS_STRING (TREE_CODE_CLASS (TREE_CODE (node))),
tree_code_name[TREE_CODE (node)], function, trim_filename (file), line);
}
void
tree_vec_elt_check_failed (int idx, int len, const char *file, int line,
const char *function)
{
internal_error
("tree check: accessed elt %d of tree_vec with %d elts in %s, at %s:%d",
idx + 1, len, function, trim_filename (file), line);
}
void
phi_node_elt_check_failed (int idx, int len, const char *file, int line,
const char *function)
{
internal_error
("tree check: accessed elt %d of phi_node with %d elts in %s, at %s:%d",
idx + 1, len, function, trim_filename (file), line);
}
void
tree_operand_check_failed (int idx, enum tree_code code, const char *file,
int line, const char *function)
{
internal_error
("tree check: accessed operand %d of %s with %d operands in %s, at %s:%d",
idx + 1, tree_code_name[code], TREE_CODE_LENGTH (code),
function, trim_filename (file), line);
}
#endif
static tree
make_vector_type (tree innertype, int nunits, enum machine_mode mode)
{
tree t = make_node (VECTOR_TYPE);
TREE_TYPE (t) = innertype;
TYPE_VECTOR_SUBPARTS (t) = nunits;
TYPE_MODE (t) = mode;
layout_type (t);
{
tree index = build_int_cst (NULL_TREE, nunits - 1);
tree array = build_array_type (innertype, build_index_type (index));
tree rt = make_node (RECORD_TYPE);
TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
layout_type (rt);
TYPE_DEBUG_REPRESENTATION_TYPE (t) = rt;
TYPE_UID (rt) = TYPE_UID (t);
}
return t;
}
static tree
make_or_reuse_type (unsigned size, int unsignedp)
{
if (size == INT_TYPE_SIZE)
return unsignedp ? unsigned_type_node : integer_type_node;
if (size == CHAR_TYPE_SIZE)
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (size == SHORT_TYPE_SIZE)
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
if (size == LONG_TYPE_SIZE)
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
if (size == LONG_LONG_TYPE_SIZE)
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
if (unsignedp)
return make_unsigned_type (size);
else
return make_signed_type (size);
}
void
build_common_tree_nodes (bool signed_char, bool signed_sizetype)
{
error_mark_node = make_node (ERROR_MARK);
TREE_TYPE (error_mark_node) = error_mark_node;
initialize_sizetypes (signed_sizetype);
signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
char_type_node
= (signed_char
? make_signed_type (CHAR_TYPE_SIZE)
: make_unsigned_type (CHAR_TYPE_SIZE));
short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
integer_type_node = make_signed_type (INT_TYPE_SIZE);
unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1);
TYPE_PRECISION (boolean_type_node) = 1;
intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 0);
intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 0);
intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 0);
intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 0);
intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 0);
unsigned_intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 1);
unsigned_intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 1);
unsigned_intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 1);
unsigned_intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 1);
unsigned_intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 1);
access_public_node = get_identifier ("public");
access_protected_node = get_identifier ("protected");
access_private_node = get_identifier ("private");
}
void
build_common_tree_nodes_2 (int short_double)
{
integer_zero_node = build_int_cst (NULL_TREE, 0);
integer_one_node = build_int_cst (NULL_TREE, 1);
integer_minus_one_node = build_int_cst (NULL_TREE, -1);
size_zero_node = size_int (0);
size_one_node = size_int (1);
bitsize_zero_node = bitsize_int (0);
bitsize_one_node = bitsize_int (1);
bitsize_unit_node = bitsize_int (BITS_PER_UNIT);
boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
void_type_node = make_node (VOID_TYPE);
layout_type (void_type_node);
TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
TYPE_USER_ALIGN (void_type_node) = 0;
null_pointer_node = build_int_cst (build_pointer_type (void_type_node), 0);
layout_type (TREE_TYPE (null_pointer_node));
ptr_type_node = build_pointer_type (void_type_node);
const_ptr_type_node
= build_pointer_type (build_type_variant (void_type_node, 1, 0));
fileptr_type_node = ptr_type_node;
float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
layout_type (float_type_node);
double_type_node = make_node (REAL_TYPE);
if (short_double)
TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
else
TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
layout_type (double_type_node);
long_double_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
layout_type (long_double_type_node);
float_ptr_type_node = build_pointer_type (float_type_node);
double_ptr_type_node = build_pointer_type (double_type_node);
long_double_ptr_type_node = build_pointer_type (long_double_type_node);
integer_ptr_type_node = build_pointer_type (integer_type_node);
complex_integer_type_node = make_node (COMPLEX_TYPE);
TREE_TYPE (complex_integer_type_node) = integer_type_node;
layout_type (complex_integer_type_node);
complex_float_type_node = make_node (COMPLEX_TYPE);
TREE_TYPE (complex_float_type_node) = float_type_node;
layout_type (complex_float_type_node);
complex_double_type_node = make_node (COMPLEX_TYPE);
TREE_TYPE (complex_double_type_node) = double_type_node;
layout_type (complex_double_type_node);
complex_long_double_type_node = make_node (COMPLEX_TYPE);
TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
layout_type (complex_long_double_type_node);
{
tree t = targetm.build_builtin_va_list ();
if (TREE_CODE (t) != RECORD_TYPE)
t = build_variant_type_copy (t);
va_list_type_node = t;
}
}
tree
reconstruct_complex_type (tree type, tree bottom)
{
tree inner, outer;
if (POINTER_TYPE_P (type))
{
inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
outer = build_pointer_type (inner);
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
outer = build_array_type (inner, TYPE_DOMAIN (type));
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
outer = build_function_type (inner, TYPE_ARG_TYPES (type));
}
else if (TREE_CODE (type) == METHOD_TYPE)
{
tree argtypes;
inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
argtypes = TYPE_ARG_TYPES (type);
outer = build_method_type_directly (TYPE_METHOD_BASETYPE (type),
inner,
TYPE_ARG_TYPES (type));
TYPE_ARG_TYPES (outer) = argtypes;
}
else
return bottom;
TYPE_READONLY (outer) = TYPE_READONLY (type);
TYPE_VOLATILE (outer) = TYPE_VOLATILE (type);
return outer;
}
tree
build_vector_type_for_mode (tree innertype, enum machine_mode mode)
{
int nunits;
switch (GET_MODE_CLASS (mode))
{
case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT:
nunits = GET_MODE_NUNITS (mode);
break;
case MODE_INT:
gcc_assert (GET_MODE_BITSIZE (mode)
% TREE_INT_CST_LOW (TYPE_SIZE (innertype)) == 0);
nunits = GET_MODE_BITSIZE (mode)
/ TREE_INT_CST_LOW (TYPE_SIZE (innertype));
break;
default:
gcc_unreachable ();
}
return make_vector_type (innertype, nunits, mode);
}
tree
build_vector_type (tree innertype, int nunits)
{
return make_vector_type (innertype, nunits, VOIDmode);
}
bool
initializer_zerop (tree init)
{
tree elt;
STRIP_NOPS (init);
switch (TREE_CODE (init))
{
case INTEGER_CST:
return integer_zerop (init);
case REAL_CST:
return real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
case COMPLEX_CST:
return integer_zerop (init)
|| (real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
case VECTOR_CST:
for (elt = TREE_VECTOR_CST_ELTS (init); elt; elt = TREE_CHAIN (elt))
if (!initializer_zerop (TREE_VALUE (elt)))
return false;
return true;
case CONSTRUCTOR:
elt = CONSTRUCTOR_ELTS (init);
if (elt == NULL_TREE)
return true;
if (TREE_CODE (TREE_TYPE (init)) == SET_TYPE)
return false;
for (; elt ; elt = TREE_CHAIN (elt))
if (! initializer_zerop (TREE_VALUE (elt)))
return false;
return true;
default:
return false;
}
}
void
add_var_to_bind_expr (tree bind_expr, tree var)
{
BIND_EXPR_VARS (bind_expr)
= chainon (BIND_EXPR_VARS (bind_expr), var);
if (BIND_EXPR_BLOCK (bind_expr))
BLOCK_VARS (BIND_EXPR_BLOCK (bind_expr))
= BIND_EXPR_VARS (bind_expr);
}
tree
build_empty_stmt (void)
{
return build1 (NOP_EXPR, void_type_node, size_zero_node);
}
bool
in_array_bounds_p (tree ref)
{
tree idx = TREE_OPERAND (ref, 1);
tree min, max;
if (TREE_CODE (idx) != INTEGER_CST)
return false;
min = array_ref_low_bound (ref);
max = array_ref_up_bound (ref);
if (!min
|| !max
|| TREE_CODE (min) != INTEGER_CST
|| TREE_CODE (max) != INTEGER_CST)
return false;
if (tree_int_cst_lt (idx, min)
|| tree_int_cst_lt (max, idx))
return false;
return true;
}
bool
is_global_var (tree t)
{
return (TREE_STATIC (t) || DECL_EXTERNAL (t));
}
bool
needs_to_live_in_memory (tree t)
{
return (TREE_ADDRESSABLE (t)
|| is_global_var (t)
|| (TREE_CODE (t) == RESULT_DECL
&& aggregate_value_p (t, current_function_decl)));
}
bool
fields_compatible_p (tree f1, tree f2)
{
if (!operand_equal_p (DECL_FIELD_BIT_OFFSET (f1),
DECL_FIELD_BIT_OFFSET (f2), OEP_ONLY_CONST))
return false;
if (!operand_equal_p (DECL_FIELD_OFFSET (f1),
DECL_FIELD_OFFSET (f2), OEP_ONLY_CONST))
return false;
if (!lang_hooks.types_compatible_p (TREE_TYPE (f1), TREE_TYPE (f2)))
return false;
return true;
}
tree
find_compatible_field (tree record, tree orig_field)
{
tree f;
for (f = TYPE_FIELDS (record); f ; f = TREE_CHAIN (f))
if (TREE_CODE (f) == FIELD_DECL
&& fields_compatible_p (f, orig_field))
return f;
f = TYPE_VFIELD (record);
if (f && TREE_CODE (f) == FIELD_DECL
&& fields_compatible_p (f, orig_field))
return f;
return orig_field;
}
HOST_WIDE_INT
int_cst_value (tree x)
{
unsigned bits = TYPE_PRECISION (TREE_TYPE (x));
unsigned HOST_WIDE_INT val = TREE_INT_CST_LOW (x);
bool negative = ((val >> (bits - 1)) & 1) != 0;
gcc_assert (bits <= HOST_BITS_PER_WIDE_INT);
if (negative)
val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1;
else
val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1);
return val;
}
tree
tree_fold_gcd (tree a, tree b)
{
tree a_mod_b;
tree type = TREE_TYPE (a);
gcc_assert (TREE_CODE (a) == INTEGER_CST);
gcc_assert (TREE_CODE (b) == INTEGER_CST);
if (integer_zerop (a))
return b;
if (integer_zerop (b))
return a;
if (tree_int_cst_sgn (a) == -1)
a = fold (build2 (MULT_EXPR, type, a,
convert (type, integer_minus_one_node)));
if (tree_int_cst_sgn (b) == -1)
b = fold (build2 (MULT_EXPR, type, b,
convert (type, integer_minus_one_node)));
while (1)
{
a_mod_b = fold (build2 (CEIL_MOD_EXPR, type, a, b));
if (!TREE_INT_CST_LOW (a_mod_b)
&& !TREE_INT_CST_HIGH (a_mod_b))
return b;
a = b;
b = a_mod_b;
}
}
tree
unsigned_type_for (tree type)
{
return lang_hooks.types.unsigned_type (type);
}
tree
signed_type_for (tree type)
{
return lang_hooks.types.signed_type (type);
}
#include "gt-tree.h"