/* Language-independent node constructors for parse phase of GNU compiler. | |

Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, | |

1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. | |

This file is part of GCC. | |

GCC is free software; you can redistribute it and/or modify it under | |

the terms of the GNU General Public License as published by the Free | |

Software Foundation; either version 2, or (at your option) any later | |

version. | |

GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |

WARRANTY; without even the implied warranty of MERCHANTABILITY or | |

FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |

for more details. | |

You should have received a copy of the GNU General Public License | |

along with GCC; see the file COPYING. If not, write to the Free | |

Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |

02111-1307, USA. */ | |

/* This file contains the low level primitives for operating on tree nodes, | |

including allocation, list operations, interning of identifiers, | |

construction of data type nodes and statement nodes, | |

and construction of type conversion nodes. It also contains | |

tables index by tree code that describe how to take apart | |

nodes of that code. | |

It is intended to be language-independent, but occasionally | |

calls language-dependent routines defined (for C) in typecheck.c. */ | |

#include "config.h" | |

#include "system.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" | |

/* obstack.[ch] explicitly declined to prototype this. */ | |

extern int _obstack_allocated_p PARAMS ((struct obstack *h, PTR obj)); | |

#ifdef GATHER_STATISTICS | |

/* Statistics-gathering stuff. */ | |

typedef enum | |

{ | |

d_kind, | |

t_kind, | |

b_kind, | |

s_kind, | |

r_kind, | |

e_kind, | |

c_kind, | |

id_kind, | |

perm_list_kind, | |

temp_list_kind, | |

vec_kind, | |

x_kind, | |

lang_decl, | |

lang_type, | |

all_kinds | |

} tree_node_kind; | |

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", | |

"random kinds", | |

"lang_decl kinds", | |

"lang_type kinds" | |

}; | |

#endif /* GATHER_STATISTICS */ | |

/* Unique id for next decl created. */ | |

static int next_decl_uid; | |

/* Unique id for next type created. */ | |

static int next_type_uid = 1; | |

/* Since we cannot rehash a type after it is in the table, we have to | |

keep the hash code. */ | |

struct type_hash GTY(()) | |

{ | |

unsigned long hash; | |

tree type; | |

}; | |

/* Initial size of the hash table (rounded to next prime). */ | |

#define TYPE_HASH_INITIAL_SIZE 1000 | |

/* Now here is the hash table. When recording a type, it is added to | |

the slot whose index is the hash code. Note that the hash table is | |

used for several kinds of types (function types, array types and | |

array index range types, for now). While all these live in the | |

same table, they are completely independent, and the hash code is | |

computed differently for each of these. */ | |

static GTY ((if_marked ("type_hash_marked_p"), param_is (struct type_hash))) | |

htab_t type_hash_table; | |

static void set_type_quals PARAMS ((tree, int)); | |

static void append_random_chars PARAMS ((char *)); | |

static int type_hash_eq PARAMS ((const void *, const void *)); | |

static hashval_t type_hash_hash PARAMS ((const void *)); | |

static void print_type_hash_statistics PARAMS((void)); | |

static void finish_vector_type PARAMS((tree)); | |

static tree make_vector PARAMS ((enum machine_mode, tree, int)); | |

static int type_hash_marked_p PARAMS ((const void *)); | |

tree global_trees[TI_MAX]; | |

tree integer_types[itk_none]; | |

/* Init tree.c. */ | |

void | |

init_ttree () | |

{ | |

/* Initialize the hash table of types. */ | |

type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash, | |

type_hash_eq, 0); | |

} | |

/* The name of the object as the assembler will see it (but before any | |

translations made by ASM_OUTPUT_LABELREF). Often this is the same | |

as DECL_NAME. It is an IDENTIFIER_NODE. */ | |

tree | |

decl_assembler_name (decl) | |

tree decl; | |

{ | |

if (!DECL_ASSEMBLER_NAME_SET_P (decl)) | |

(*lang_hooks.set_decl_assembler_name) (decl); | |

return DECL_CHECK (decl)->decl.assembler_name; | |

} | |

/* Compute the number of bytes occupied by 'node'. This routine only | |

looks at TREE_CODE and, if the code is TREE_VEC, TREE_VEC_LENGTH. */ | |

size_t | |

tree_size (node) | |

tree node; | |

{ | |

enum tree_code code = TREE_CODE (node); | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'd': /* A decl node */ | |

return sizeof (struct tree_decl); | |

case 't': /* a type node */ | |

return sizeof (struct tree_type); | |

case 'b': /* a lexical block node */ | |

return sizeof (struct tree_block); | |

case 'r': /* a reference */ | |

case 'e': /* an expression */ | |

case 's': /* an expression with side effects */ | |

case '<': /* a comparison expression */ | |

case '1': /* a unary arithmetic expression */ | |

case '2': /* a binary arithmetic expression */ | |

return (sizeof (struct tree_exp) | |

+ TREE_CODE_LENGTH (code) * sizeof (char *) - sizeof (char *)); | |

case 'c': /* a constant */ | |

/* We can't use TREE_CODE_LENGTH for INTEGER_CST, since the number of | |

words is machine-dependent due to varying length of HOST_WIDE_INT, | |

which might be wider than a pointer (e.g., long long). Similarly | |

for REAL_CST, since the number of words is machine-dependent due | |

to varying size and alignment of `double'. */ | |

if (code == INTEGER_CST) | |

return sizeof (struct tree_int_cst); | |

else if (code == REAL_CST) | |

return sizeof (struct tree_real_cst); | |

else | |

return (sizeof (struct tree_common) | |

+ TREE_CODE_LENGTH (code) * sizeof (char *)); | |

case 'x': /* something random, like an identifier. */ | |

{ | |

size_t length; | |

length = (sizeof (struct tree_common) | |

+ TREE_CODE_LENGTH (code) * sizeof (char *)); | |

if (code == TREE_VEC) | |

length += TREE_VEC_LENGTH (node) * sizeof (char *) - sizeof (char *); | |

return length; | |

} | |

default: | |

abort (); | |

} | |

} | |

/* Return a newly allocated node of code CODE. | |

For decl and type nodes, some other fields are initialized. | |

The rest of the node is initialized to zero. | |

Achoo! I got a code in the node. */ | |

tree | |

make_node (code) | |

enum tree_code code; | |

{ | |

tree t; | |

int type = TREE_CODE_CLASS (code); | |

size_t length; | |

#ifdef GATHER_STATISTICS | |

tree_node_kind kind; | |

#endif | |

struct tree_common ttmp; | |

/* We can't allocate a TREE_VEC without knowing how many elements | |

it will have. */ | |

if (code == TREE_VEC) | |

abort (); | |

TREE_SET_CODE ((tree)&ttmp, code); | |

length = tree_size ((tree)&ttmp); | |

#ifdef GATHER_STATISTICS | |

switch (type) | |

{ | |

case 'd': /* A decl node */ | |

kind = d_kind; | |

break; | |

case 't': /* a type node */ | |

kind = t_kind; | |

break; | |

case 'b': /* a lexical block */ | |

kind = b_kind; | |

break; | |

case 's': /* an expression with side effects */ | |

kind = s_kind; | |

break; | |

case 'r': /* a reference */ | |

kind = r_kind; | |

break; | |

case 'e': /* an expression */ | |

case '<': /* a comparison expression */ | |

case '1': /* a unary arithmetic expression */ | |

case '2': /* a binary arithmetic expression */ | |

kind = e_kind; | |

break; | |

case 'c': /* a constant */ | |

kind = c_kind; | |

break; | |

case 'x': /* something random, like an identifier. */ | |

if (code == IDENTIFIER_NODE) | |

kind = id_kind; | |

else if (code == TREE_VEC) | |

kind = vec_kind; | |

else | |

kind = x_kind; | |

break; | |

default: | |

abort (); | |

} | |

tree_node_counts[(int) kind]++; | |

tree_node_sizes[(int) kind] += length; | |

#endif | |

t = ggc_alloc_tree (length); | |

memset ((PTR) t, 0, length); | |

TREE_SET_CODE (t, code); | |

switch (type) | |

{ | |

case 's': | |

TREE_SIDE_EFFECTS (t) = 1; | |

TREE_TYPE (t) = void_type_node; | |

break; | |

case 'd': | |

if (code != FUNCTION_DECL) | |

DECL_ALIGN (t) = 1; | |

DECL_USER_ALIGN (t) = 0; | |

DECL_IN_SYSTEM_HEADER (t) = in_system_header; | |

DECL_SOURCE_LINE (t) = lineno; | |

DECL_SOURCE_FILE (t) = | |

(input_filename) ? input_filename : "<built-in>"; | |

DECL_UID (t) = next_decl_uid++; | |

/* We have not yet computed the alias set for this declaration. */ | |

DECL_POINTER_ALIAS_SET (t) = -1; | |

break; | |

case 't': | |

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; | |

/* Default to no attributes for type, but let target change that. */ | |

TYPE_ATTRIBUTES (t) = NULL_TREE; | |

(*targetm.set_default_type_attributes) (t); | |

/* We have not yet computed the alias set for this type. */ | |

TYPE_ALIAS_SET (t) = -1; | |

break; | |

case 'c': | |

TREE_CONSTANT (t) = 1; | |

break; | |

case 'e': | |

switch (code) | |

{ | |

case INIT_EXPR: | |

case MODIFY_EXPR: | |

case VA_ARG_EXPR: | |

case RTL_EXPR: | |

case PREDECREMENT_EXPR: | |

case PREINCREMENT_EXPR: | |

case POSTDECREMENT_EXPR: | |

case POSTINCREMENT_EXPR: | |

/* All of these have side-effects, no matter what their | |

operands are. */ | |

TREE_SIDE_EFFECTS (t) = 1; | |

break; | |

default: | |

break; | |

} | |

break; | |

} | |

return t; | |

} | |

/* Return a new node with the same contents as NODE except that its | |

TREE_CHAIN is zero and it has a fresh uid. */ | |

tree | |

copy_node (node) | |

tree node; | |

{ | |

tree t; | |

enum tree_code code = TREE_CODE (node); | |

size_t length; | |

length = tree_size (node); | |

t = ggc_alloc_tree (length); | |

memcpy (t, node, length); | |

TREE_CHAIN (t) = 0; | |

TREE_ASM_WRITTEN (t) = 0; | |

if (TREE_CODE_CLASS (code) == 'd') | |

DECL_UID (t) = next_decl_uid++; | |

else if (TREE_CODE_CLASS (code) == 't') | |

{ | |

TYPE_UID (t) = next_type_uid++; | |

/* The following is so that the debug code for | |

the copy is different from the original type. | |

The two statements usually duplicate each other | |

(because they clear fields of the same union), | |

but the optimizer should catch that. */ | |

TYPE_SYMTAB_POINTER (t) = 0; | |

TYPE_SYMTAB_ADDRESS (t) = 0; | |

} | |

return t; | |

} | |

/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field. | |

For example, this can copy a list made of TREE_LIST nodes. */ | |

tree | |

copy_list (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; | |

} | |

/* Return a newly constructed INTEGER_CST node whose constant value | |

is specified by the two ints LOW and HI. | |

The TREE_TYPE is set to `int'. | |

This function should be used via the `build_int_2' macro. */ | |

tree | |

build_int_2_wide (low, hi) | |

unsigned HOST_WIDE_INT low; | |

HOST_WIDE_INT hi; | |

{ | |

tree t = make_node (INTEGER_CST); | |

TREE_INT_CST_LOW (t) = low; | |

TREE_INT_CST_HIGH (t) = hi; | |

TREE_TYPE (t) = integer_type_node; | |

return t; | |

} | |

/* Return a new VECTOR_CST node whose type is TYPE and whose values | |

are in a list pointed by VALS. */ | |

tree | |

build_vector (type, vals) | |

tree type, vals; | |

{ | |

tree v = make_node (VECTOR_CST); | |

int over1 = 0, over2 = 0; | |

tree link; | |

TREE_VECTOR_CST_ELTS (v) = vals; | |

TREE_TYPE (v) = type; | |

/* Iterate through elements and check for overflow. */ | |

for (link = vals; link; link = TREE_CHAIN (link)) | |

{ | |

tree value = TREE_VALUE (link); | |

over1 |= TREE_OVERFLOW (value); | |

over2 |= TREE_CONSTANT_OVERFLOW (value); | |

} | |

TREE_OVERFLOW (v) = over1; | |

TREE_CONSTANT_OVERFLOW (v) = over2; | |

return v; | |

} | |

/* Return a new REAL_CST node whose type is TYPE and value is D. */ | |

tree | |

build_real (type, d) | |

tree type; | |

REAL_VALUE_TYPE d; | |

{ | |

tree v; | |

REAL_VALUE_TYPE *dp; | |

int overflow = 0; | |

/* ??? Used to check for overflow here via CHECK_FLOAT_TYPE. | |

Consider doing it via real_convert now. */ | |

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; | |

} | |

/* Return a new REAL_CST node whose type is TYPE | |

and whose value is the integer value of the INTEGER_CST node I. */ | |

REAL_VALUE_TYPE | |

real_value_from_int_cst (type, i) | |

tree type ATTRIBUTE_UNUSED, i; | |

{ | |

REAL_VALUE_TYPE d; | |

/* Clear all bits of the real value type so that we can later do | |

bitwise comparisons to see if two values are the same. */ | |

memset ((char *) &d, 0, sizeof d); | |

if (! TREE_UNSIGNED (TREE_TYPE (i))) | |

REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i), | |

TYPE_MODE (type)); | |

else | |

REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i), | |

TREE_INT_CST_HIGH (i), TYPE_MODE (type)); | |

return d; | |

} | |

/* Given a tree representing an integer constant I, return a tree | |

representing the same value as a floating-point constant of type TYPE. */ | |

tree | |

build_real_from_int_cst (type, i) | |

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; | |

} | |

/* Return a newly constructed STRING_CST node whose value is | |

the LEN characters at STR. | |

The TREE_TYPE is not initialized. */ | |

tree | |

build_string (len, str) | |

int len; | |

const char *str; | |

{ | |

tree s = make_node (STRING_CST); | |

TREE_STRING_LENGTH (s) = len; | |

TREE_STRING_POINTER (s) = ggc_alloc_string (str, len); | |

return s; | |

} | |

/* Return a newly constructed COMPLEX_CST node whose value is | |

specified by the real and imaginary parts REAL and IMAG. | |

Both REAL and IMAG should be constant nodes. TYPE, if specified, | |

will be the type of the COMPLEX_CST; otherwise a new type will be made. */ | |

tree | |

build_complex (type, real, imag) | |

tree type; | |

tree real, 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; | |

} | |

/* Build a newly constructed TREE_VEC node of length LEN. */ | |

tree | |

make_tree_vec (len) | |

int len; | |

{ | |

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_tree (length); | |

memset ((PTR) t, 0, length); | |

TREE_SET_CODE (t, TREE_VEC); | |

TREE_VEC_LENGTH (t) = len; | |

return t; | |

} | |

/* Return 1 if EXPR is the integer constant zero or a complex constant | |

of zero. */ | |

int | |

integer_zerop (expr) | |

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)))); | |

} | |

/* Return 1 if EXPR is the integer constant one or the corresponding | |

complex constant. */ | |

int | |

integer_onep (expr) | |

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)))); | |

} | |

/* Return 1 if EXPR is an integer containing all 1's in as much precision as | |

it contains. Likewise for the corresponding complex constant. */ | |

int | |

integer_all_onesp (expr) | |

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 = TREE_UNSIGNED (TREE_TYPE (expr)); | |

if (!uns) | |

return (TREE_INT_CST_LOW (expr) == ~(unsigned HOST_WIDE_INT) 0 | |

&& TREE_INT_CST_HIGH (expr) == -1); | |

/* Note that using TYPE_PRECISION here is wrong. We care about the | |

actual bits, not the (arbitrary) range of the type. */ | |

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; | |

if (shift_amount > HOST_BITS_PER_WIDE_INT) | |

/* Can not handle precisions greater than twice the host int size. */ | |

abort (); | |

else if (shift_amount == HOST_BITS_PER_WIDE_INT) | |

/* Shifting by the host word size is undefined according to the ANSI | |

standard, so we must handle this as a special case. */ | |

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; | |

} | |

/* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only | |

one bit on). */ | |

int | |

integer_pow2p (expr) | |

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); | |

/* First clear all bits that are beyond the type's precision in case | |

we've been sign extended. */ | |

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)); | |

} | |

/* Return 1 if EXPR is an integer constant other than zero or a | |

complex constant other than zero. */ | |

int | |

integer_nonzerop (expr) | |

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))))); | |

} | |

/* Return the power of two represented by a tree node known to be a | |

power of two. */ | |

int | |

tree_log2 (expr) | |

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); | |

/* First clear all bits that are beyond the type's precision in case | |

we've been sign extended. */ | |

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)); | |

} | |

/* Similar, but return the largest integer Y such that 2 ** Y is less | |

than or equal to EXPR. */ | |

int | |

tree_floor_log2 (expr) | |

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); | |

/* First clear all bits that are beyond the type's precision in case | |

we've been sign extended. Ignore if type's precision hasn't been set | |

since what we are doing is setting it. */ | |

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)); | |

} | |

/* Return 1 if EXPR is the real constant zero. */ | |

int | |

real_zerop (expr) | |

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)))); | |

} | |

/* Return 1 if EXPR is the real constant one in real or complex form. */ | |

int | |

real_onep (expr) | |

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)))); | |

} | |

/* Return 1 if EXPR is the real constant two. */ | |

int | |

real_twop (expr) | |

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)))); | |

} | |

/* Return 1 if EXPR is the real constant minus one. */ | |

int | |

real_minus_onep (expr) | |

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)))); | |

} | |

/* Nonzero if EXP is a constant or a cast of a constant. */ | |

int | |

really_constant_p (exp) | |

tree exp; | |

{ | |

/* This is not quite the same as STRIP_NOPS. It does more. */ | |

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); | |

} | |

/* Return first list element whose TREE_VALUE is ELEM. | |

Return 0 if ELEM is not in LIST. */ | |

tree | |

value_member (elem, list) | |

tree elem, list; | |

{ | |

while (list) | |

{ | |

if (elem == TREE_VALUE (list)) | |

return list; | |

list = TREE_CHAIN (list); | |

} | |

return NULL_TREE; | |

} | |

/* Return first list element whose TREE_PURPOSE is ELEM. | |

Return 0 if ELEM is not in LIST. */ | |

tree | |

purpose_member (elem, list) | |

tree elem, list; | |

{ | |

while (list) | |

{ | |

if (elem == TREE_PURPOSE (list)) | |

return list; | |

list = TREE_CHAIN (list); | |

} | |

return NULL_TREE; | |

} | |

/* Return first list element whose BINFO_TYPE is ELEM. | |

Return 0 if ELEM is not in LIST. */ | |

tree | |

binfo_member (elem, list) | |

tree elem, list; | |

{ | |

while (list) | |

{ | |

if (elem == BINFO_TYPE (list)) | |

return list; | |

list = TREE_CHAIN (list); | |

} | |

return NULL_TREE; | |

} | |

/* Return nonzero if ELEM is part of the chain CHAIN. */ | |

int | |

chain_member (elem, chain) | |

tree elem, chain; | |

{ | |

while (chain) | |

{ | |

if (elem == chain) | |

return 1; | |

chain = TREE_CHAIN (chain); | |

} | |

return 0; | |

} | |

/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of | |

chain CHAIN. This and the next function are currently unused, but | |

are retained for completeness. */ | |

int | |

chain_member_value (elem, chain) | |

tree elem, chain; | |

{ | |

while (chain) | |

{ | |

if (elem == TREE_VALUE (chain)) | |

return 1; | |

chain = TREE_CHAIN (chain); | |

} | |

return 0; | |

} | |

/* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN) | |

for any piece of chain CHAIN. */ | |

int | |

chain_member_purpose (elem, chain) | |

tree elem, chain; | |

{ | |

while (chain) | |

{ | |

if (elem == TREE_PURPOSE (chain)) | |

return 1; | |

chain = TREE_CHAIN (chain); | |

} | |

return 0; | |

} | |

/* Return the length of a chain of nodes chained through TREE_CHAIN. | |

We expect a null pointer to mark the end of the chain. | |

This is the Lisp primitive `length'. */ | |

int | |

list_length (t) | |

tree t; | |

{ | |

tree tail; | |

int len = 0; | |

for (tail = t; tail; tail = TREE_CHAIN (tail)) | |

len++; | |

return len; | |

} | |

/* Returns the number of FIELD_DECLs in TYPE. */ | |

int | |

fields_length (type) | |

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; | |

} | |

/* Concatenate two chains of nodes (chained through TREE_CHAIN) | |

by modifying the last node in chain 1 to point to chain 2. | |

This is the Lisp primitive `nconc'. */ | |

tree | |

chainon (op1, op2) | |

tree op1, op2; | |

{ | |

if (op1) | |

{ | |

tree t1; | |

#ifdef ENABLE_TREE_CHECKING | |

tree t2; | |

#endif | |

for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1)) | |

; | |

TREE_CHAIN (t1) = op2; | |

#ifdef ENABLE_TREE_CHECKING | |

for (t2 = op2; t2; t2 = TREE_CHAIN (t2)) | |

if (t2 == t1) | |

abort (); /* Circularity created. */ | |

#endif | |

return op1; | |

} | |

else | |

return op2; | |

} | |

/* Return the last node in a chain of nodes (chained through TREE_CHAIN). */ | |

tree | |

tree_last (chain) | |

tree chain; | |

{ | |

tree next; | |

if (chain) | |

while ((next = TREE_CHAIN (chain))) | |

chain = next; | |

return chain; | |

} | |

/* Reverse the order of elements in the chain T, | |

and return the new head of the chain (old last element). */ | |

tree | |

nreverse (t) | |

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; | |

} | |

/* Given a chain CHAIN of tree nodes, | |

construct and return a list of those nodes. */ | |

tree | |

listify (chain) | |

tree chain; | |

{ | |

tree result = NULL_TREE; | |

tree in_tail = chain; | |

tree out_tail = NULL_TREE; | |

while (in_tail) | |

{ | |

tree next = tree_cons (NULL_TREE, in_tail, NULL_TREE); | |

if (out_tail) | |

TREE_CHAIN (out_tail) = next; | |

else | |

result = next; | |

out_tail = next; | |

in_tail = TREE_CHAIN (in_tail); | |

} | |

return result; | |

} | |

/* Return a newly created TREE_LIST node whose | |

purpose and value fields are PARM and VALUE. */ | |

tree | |

build_tree_list (parm, value) | |

tree parm, value; | |

{ | |

tree t = make_node (TREE_LIST); | |

TREE_PURPOSE (t) = parm; | |

TREE_VALUE (t) = value; | |

return t; | |

} | |

/* Return a newly created TREE_LIST node whose | |

purpose and value fields are PARM and VALUE | |

and whose TREE_CHAIN is CHAIN. */ | |

tree | |

tree_cons (purpose, value, chain) | |

tree purpose, value, chain; | |

{ | |

tree node; | |

node = ggc_alloc_tree (sizeof (struct tree_list)); | |

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; | |

} | |

/* Return the size nominally occupied by an object of type TYPE | |

when it resides in memory. The value is measured in units of bytes, | |

and its data type is that normally used for type sizes | |

(which is the first type created by make_signed_type or | |

make_unsigned_type). */ | |

tree | |

size_in_bytes (type) | |

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) | |

force_fit_type (t, 0); | |

return t; | |

} | |

/* Return the size of TYPE (in bytes) as a wide integer | |

or return -1 if the size can vary or is larger than an integer. */ | |

HOST_WIDE_INT | |

int_size_in_bytes (type) | |

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 | |

/* If the result would appear negative, it's too big to represent. */ | |

|| (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0) | |

return -1; | |

return TREE_INT_CST_LOW (t); | |

} | |

/* Return the bit position of FIELD, in bits from the start of the record. | |

This is a tree of type bitsizetype. */ | |

tree | |

bit_position (field) | |

tree field; | |

{ | |

return bit_from_pos (DECL_FIELD_OFFSET (field), | |

DECL_FIELD_BIT_OFFSET (field)); | |

} | |

/* Likewise, but return as an integer. Abort if it cannot be represented | |

in that way (since it could be a signed value, we don't have the option | |

of returning -1 like int_size_in_byte can. */ | |

HOST_WIDE_INT | |

int_bit_position (field) | |

tree field; | |

{ | |

return tree_low_cst (bit_position (field), 0); | |

} | |

/* Return the byte position of FIELD, in bytes from the start of the record. | |

This is a tree of type sizetype. */ | |

tree | |

byte_position (field) | |

tree field; | |

{ | |

return byte_from_pos (DECL_FIELD_OFFSET (field), | |

DECL_FIELD_BIT_OFFSET (field)); | |

} | |

/* Likewise, but return as an integer. Abort if it cannot be represented | |

in that way (since it could be a signed value, we don't have the option | |

of returning -1 like int_size_in_byte can. */ | |

HOST_WIDE_INT | |

int_byte_position (field) | |

tree field; | |

{ | |

return tree_low_cst (byte_position (field), 0); | |

} | |

/* Return the strictest alignment, in bits, that T is known to have. */ | |

unsigned int | |

expr_align (t) | |

tree t; | |

{ | |

unsigned int align0, align1; | |

switch (TREE_CODE (t)) | |

{ | |

case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR: | |

/* If we have conversions, we know that the alignment of the | |

object must meet each of the alignments of the types. */ | |

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 WITH_RECORD_EXPR: case CLEANUP_POINT_EXPR: case UNSAVE_EXPR: | |

/* These don't change the alignment of an object. */ | |

return expr_align (TREE_OPERAND (t, 0)); | |

case COND_EXPR: | |

/* The best we can do is say that the alignment is the least aligned | |

of the two arms. */ | |

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; | |

} | |

/* Otherwise take the alignment from that of the type. */ | |

return TYPE_ALIGN (TREE_TYPE (t)); | |

} | |

/* Return, as a tree node, the number of elements for TYPE (which is an | |

ARRAY_TYPE) minus one. This counts only elements of the top array. */ | |

tree | |

array_type_nelts (type) | |

tree type; | |

{ | |

tree index_type, min, max; | |

/* If they did it with unspecified bounds, then we should have already | |

given an error about it before we got here. */ | |

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 (build (MINUS_EXPR, TREE_TYPE (max), max, min))); | |

} | |

/* Return nonzero if arg is static -- a reference to an object in | |

static storage. This is not the same as the C meaning of `static'. */ | |

int | |

staticp (arg) | |

tree arg; | |

{ | |

switch (TREE_CODE (arg)) | |

{ | |

case FUNCTION_DECL: | |

/* Nested functions aren't static, since taking their address | |

involves a trampoline. */ | |

return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg)) | |

&& ! DECL_NON_ADDR_CONST_P (arg)); | |

case VAR_DECL: | |

return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg)) | |

&& ! DECL_THREAD_LOCAL (arg) | |

&& ! DECL_NON_ADDR_CONST_P (arg)); | |

case CONSTRUCTOR: | |

return TREE_STATIC (arg); | |

case LABEL_DECL: | |

case STRING_CST: | |

return 1; | |

/* If we are referencing a bitfield, we can't evaluate an | |

ADDR_EXPR at compile time and so it isn't a constant. */ | |

case COMPONENT_REF: | |

return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1)) | |

&& staticp (TREE_OPERAND (arg, 0))); | |

case BIT_FIELD_REF: | |

return 0; | |

#if 0 | |

/* This case is technically correct, but results in setting | |

TREE_CONSTANT on ADDR_EXPRs that cannot be evaluated at | |

compile time. */ | |

case INDIRECT_REF: | |

return TREE_CONSTANT (TREE_OPERAND (arg, 0)); | |

#endif | |

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)); | |

default: | |

if ((unsigned int) TREE_CODE (arg) | |

>= (unsigned int) LAST_AND_UNUSED_TREE_CODE) | |

return (*lang_hooks.staticp) (arg); | |

else | |

return 0; | |

} | |

} | |

/* Wrap a SAVE_EXPR around EXPR, if appropriate. | |

Do this to any expression which may be used in more than one place, | |

but must be evaluated only once. | |

Normally, expand_expr would reevaluate the expression each time. | |

Calling save_expr produces something that is evaluated and recorded | |

the first time expand_expr is called on it. Subsequent calls to | |

expand_expr just reuse the recorded value. | |

The call to expand_expr that generates code that actually computes | |

the value is the first call *at compile time*. Subsequent calls | |

*at compile time* generate code to use the saved value. | |

This produces correct result provided that *at run time* control | |

always flows through the insns made by the first expand_expr | |

before reaching the other places where the save_expr was evaluated. | |

You, the caller of save_expr, must make sure this is so. | |

Constants, and certain read-only nodes, are returned with no | |

SAVE_EXPR because that is safe. Expressions containing placeholders | |

are not touched; see tree.def for an explanation of what these | |

are used for. */ | |

tree | |

save_expr (expr) | |

tree expr; | |

{ | |

tree t = fold (expr); | |

tree inner; | |

/* We don't care about whether this can be used as an lvalue in this | |

context. */ | |

while (TREE_CODE (t) == NON_LVALUE_EXPR) | |

t = TREE_OPERAND (t, 0); | |

/* If we have simple operations applied to a SAVE_EXPR or to a SAVE_EXPR and | |

a constant, it will be more efficient to not make another SAVE_EXPR since | |

it will allow better simplification and GCSE will be able to merge the | |

computations if they actualy occur. */ | |

for (inner = t; | |

(TREE_CODE_CLASS (TREE_CODE (inner)) == '1' | |

|| (TREE_CODE_CLASS (TREE_CODE (inner)) == '2' | |

&& TREE_CONSTANT (TREE_OPERAND (inner, 1)))); | |

inner = TREE_OPERAND (inner, 0)) | |

; | |

/* If the tree evaluates to a constant, then we don't want to hide that | |

fact (i.e. this allows further folding, and direct checks for constants). | |

However, a read-only object that has side effects cannot be bypassed. | |

Since it is no problem to reevaluate literals, we just return the | |

literal node. */ | |

if (TREE_CONSTANT (inner) | |

|| (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner)) | |

|| TREE_CODE (inner) == SAVE_EXPR || TREE_CODE (inner) == ERROR_MARK) | |

return t; | |

/* If T contains a PLACEHOLDER_EXPR, we must evaluate it each time, since | |

it means that the size or offset of some field of an object depends on | |

the value within another field. | |

Note that it must not be the case that T contains both a PLACEHOLDER_EXPR | |

and some variable since it would then need to be both evaluated once and | |

evaluated more than once. Front-ends must assure this case cannot | |

happen by surrounding any such subexpressions in their own SAVE_EXPR | |

and forcing evaluation at the proper time. */ | |

if (contains_placeholder_p (t)) | |

return t; | |

t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE); | |

/* This expression might be placed ahead of a jump to ensure that the | |

value was computed on both sides of the jump. So make sure it isn't | |

eliminated as dead. */ | |

TREE_SIDE_EFFECTS (t) = 1; | |

TREE_READONLY (t) = 1; | |

return t; | |

} | |

/* Arrange for an expression to be expanded multiple independent | |

times. This is useful for cleanup actions, as the backend can | |

expand them multiple times in different places. */ | |

tree | |

unsave_expr (expr) | |

tree expr; | |

{ | |

tree t; | |

/* If this is already protected, no sense in protecting it again. */ | |

if (TREE_CODE (expr) == UNSAVE_EXPR) | |

return expr; | |

t = build1 (UNSAVE_EXPR, TREE_TYPE (expr), expr); | |

TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr); | |

return t; | |

} | |

/* Returns the index of the first non-tree operand for CODE, or the number | |

of operands if all are trees. */ | |

int | |

first_rtl_op (code) | |

enum tree_code code; | |

{ | |

switch (code) | |

{ | |

case SAVE_EXPR: | |

return 2; | |

case GOTO_SUBROUTINE_EXPR: | |

case RTL_EXPR: | |

return 0; | |

case WITH_CLEANUP_EXPR: | |

return 2; | |

case METHOD_CALL_EXPR: | |

return 3; | |

default: | |

return TREE_CODE_LENGTH (code); | |

} | |

} | |

/* Return which tree structure is used by T. */ | |

enum tree_node_structure_enum | |

tree_node_structure (t) | |

tree t; | |

{ | |

enum tree_code code = TREE_CODE (t); | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'd': return TS_DECL; | |

case 't': return TS_TYPE; | |

case 'b': return TS_BLOCK; | |

case 'r': case '<': case '1': case '2': case 'e': case 's': | |

return TS_EXP; | |

default: /* 'c' and 'x' */ | |

break; | |

} | |

switch (code) | |

{ | |

/* 'c' cases. */ | |

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; | |

/* 'x' cases. */ | |

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 PLACEHOLDER_EXPR: return TS_COMMON; | |

default: | |

abort (); | |

} | |

} | |

/* Perform any modifications to EXPR required when it is unsaved. Does | |

not recurse into EXPR's subtrees. */ | |

void | |

unsave_expr_1 (expr) | |

tree expr; | |

{ | |

switch (TREE_CODE (expr)) | |

{ | |

case SAVE_EXPR: | |

if (! SAVE_EXPR_PERSISTENT_P (expr)) | |

SAVE_EXPR_RTL (expr) = 0; | |

break; | |

case TARGET_EXPR: | |

/* Don't mess with a TARGET_EXPR that hasn't been expanded. | |

It's OK for this to happen if it was part of a subtree that | |

isn't immediately expanded, such as operand 2 of another | |

TARGET_EXPR. */ | |

if (TREE_OPERAND (expr, 1)) | |

break; | |

TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3); | |

TREE_OPERAND (expr, 3) = NULL_TREE; | |

break; | |

case RTL_EXPR: | |

/* I don't yet know how to emit a sequence multiple times. */ | |

if (RTL_EXPR_SEQUENCE (expr) != 0) | |

abort (); | |

break; | |

default: | |

break; | |

} | |

} | |

/* Default lang hook for "unsave_expr_now". */ | |

tree | |

lhd_unsave_expr_now (expr) | |

tree expr; | |

{ | |

enum tree_code code; | |

/* There's nothing to do for NULL_TREE. */ | |

if (expr == 0) | |

return expr; | |

unsave_expr_1 (expr); | |

code = TREE_CODE (expr); | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'c': /* a constant */ | |

case 't': /* a type node */ | |

case 'd': /* A decl node */ | |

case 'b': /* A block node */ | |

break; | |

case 'x': /* miscellaneous: e.g., identifier, TREE_LIST or ERROR_MARK. */ | |

if (code == TREE_LIST) | |

{ | |

lhd_unsave_expr_now (TREE_VALUE (expr)); | |

lhd_unsave_expr_now (TREE_CHAIN (expr)); | |

} | |

break; | |

case 'e': /* an expression */ | |

case 'r': /* a reference */ | |

case 's': /* an expression with side effects */ | |

case '<': /* a comparison expression */ | |

case '2': /* a binary arithmetic expression */ | |

case '1': /* a unary arithmetic expression */ | |

{ | |

int i; | |

for (i = first_rtl_op (code) - 1; i >= 0; i--) | |

lhd_unsave_expr_now (TREE_OPERAND (expr, i)); | |

} | |

break; | |

default: | |

abort (); | |

} | |

return expr; | |

} | |

/* Return 0 if it is safe to evaluate EXPR multiple times, | |

return 1 if it is safe if EXPR is unsaved afterward, or | |

return 2 if it is completely unsafe. | |

This assumes that CALL_EXPRs and TARGET_EXPRs are never replicated in | |

an expression tree, so that it safe to unsave them and the surrounding | |

context will be correct. | |

SAVE_EXPRs basically *only* appear replicated in an expression tree, | |

occasionally across the whole of a function. It is therefore only | |

safe to unsave a SAVE_EXPR if you know that all occurrences appear | |

below the UNSAVE_EXPR. | |

RTL_EXPRs consume their rtl during evaluation. It is therefore | |

never possible to unsave them. */ | |

int | |

unsafe_for_reeval (expr) | |

tree expr; | |

{ | |

int unsafeness = 0; | |

enum tree_code code; | |

int i, tmp, tmp2; | |

tree exp; | |

int first_rtl; | |

if (expr == NULL_TREE) | |

return 1; | |

code = TREE_CODE (expr); | |

first_rtl = first_rtl_op (code); | |

switch (code) | |

{ | |

case SAVE_EXPR: | |

case RTL_EXPR: | |

return 2; | |

case TREE_LIST: | |

for (exp = expr; exp != 0; exp = TREE_CHAIN (exp)) | |

{ | |

tmp = unsafe_for_reeval (TREE_VALUE (exp)); | |

unsafeness = MAX (tmp, unsafeness); | |

} | |

return unsafeness; | |

case CALL_EXPR: | |

tmp2 = unsafe_for_reeval (TREE_OPERAND (expr, 0)); | |

tmp = unsafe_for_reeval (TREE_OPERAND (expr, 1)); | |

return MAX (MAX (tmp, 1), tmp2); | |

case TARGET_EXPR: | |

unsafeness = 1; | |

break; | |

case EXIT_BLOCK_EXPR: | |

/* EXIT_BLOCK_LABELED_BLOCK, a.k.a. TREE_OPERAND (expr, 0), holds | |

a reference to an ancestor LABELED_BLOCK, so we need to avoid | |

unbounded recursion in the 'e' traversal code below. */ | |

exp = EXIT_BLOCK_RETURN (expr); | |

return exp ? unsafe_for_reeval (exp) : 0; | |

default: | |

tmp = (*lang_hooks.unsafe_for_reeval) (expr); | |

if (tmp >= 0) | |

return tmp; | |

break; | |

} | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'c': /* a constant */ | |

case 't': /* a type node */ | |

case 'x': /* something random, like an identifier or an ERROR_MARK. */ | |

case 'd': /* A decl node */ | |

case 'b': /* A block node */ | |

return 0; | |

case 'e': /* an expression */ | |

case 'r': /* a reference */ | |

case 's': /* an expression with side effects */ | |

case '<': /* a comparison expression */ | |

case '2': /* a binary arithmetic expression */ | |

case '1': /* a unary arithmetic expression */ | |

for (i = first_rtl - 1; i >= 0; i--) | |

{ | |

tmp = unsafe_for_reeval (TREE_OPERAND (expr, i)); | |

unsafeness = MAX (tmp, unsafeness); | |

} | |

return unsafeness; | |

default: | |

return 2; | |

} | |

} | |

/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size | |

or offset that depends on a field within a record. */ | |

int | |

contains_placeholder_p (exp) | |

tree exp; | |

{ | |

enum tree_code code; | |

int result; | |

if (!exp) | |

return 0; | |

/* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR | |

in it since it is supplying a value for it. */ | |

code = TREE_CODE (exp); | |

if (code == WITH_RECORD_EXPR) | |

return 0; | |

else if (code == PLACEHOLDER_EXPR) | |

return 1; | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'r': | |

/* Don't look at any PLACEHOLDER_EXPRs that might be in index or bit | |

position computations since they will be converted into a | |

WITH_RECORD_EXPR involving the reference, which will assume | |

here will be valid. */ | |

return contains_placeholder_p (TREE_OPERAND (exp, 0)); | |

case 'x': | |

if (code == TREE_LIST) | |

return (contains_placeholder_p (TREE_VALUE (exp)) | |

|| (TREE_CHAIN (exp) != 0 | |

&& contains_placeholder_p (TREE_CHAIN (exp)))); | |

break; | |

case '1': | |

case '2': case '<': | |

case 'e': | |

switch (code) | |

{ | |

case COMPOUND_EXPR: | |

/* Ignoring the first operand isn't quite right, but works best. */ | |

return contains_placeholder_p (TREE_OPERAND (exp, 1)); | |

case RTL_EXPR: | |

case CONSTRUCTOR: | |

return 0; | |

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))); | |

case SAVE_EXPR: | |

/* If we already know this doesn't have a placeholder, don't | |

check again. */ | |

if (SAVE_EXPR_NOPLACEHOLDER (exp) || SAVE_EXPR_RTL (exp) != 0) | |

return 0; | |

SAVE_EXPR_NOPLACEHOLDER (exp) = 1; | |

result = contains_placeholder_p (TREE_OPERAND (exp, 0)); | |

if (result) | |

SAVE_EXPR_NOPLACEHOLDER (exp) = 0; | |

return result; | |

case CALL_EXPR: | |

return (TREE_OPERAND (exp, 1) != 0 | |

&& contains_placeholder_p (TREE_OPERAND (exp, 1))); | |

default: | |

break; | |

} | |

switch (TREE_CODE_LENGTH (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; | |

} | |

/* Return 1 if EXP contains any expressions that produce cleanups for an | |

outer scope to deal with. Used by fold. */ | |

int | |

has_cleanups (exp) | |

tree exp; | |

{ | |

int i, nops, cmp; | |

if (! TREE_SIDE_EFFECTS (exp)) | |

return 0; | |

switch (TREE_CODE (exp)) | |

{ | |

case TARGET_EXPR: | |

case GOTO_SUBROUTINE_EXPR: | |

case WITH_CLEANUP_EXPR: | |

return 1; | |

case CLEANUP_POINT_EXPR: | |

return 0; | |

case CALL_EXPR: | |

for (exp = TREE_OPERAND (exp, 1); exp; exp = TREE_CHAIN (exp)) | |

{ | |

cmp = has_cleanups (TREE_VALUE (exp)); | |

if (cmp) | |

return cmp; | |

} | |

return 0; | |

default: | |

break; | |

} | |

/* This general rule works for most tree codes. All exceptions should be | |

handled above. If this is a language-specific tree code, we can't | |

trust what might be in the operand, so say we don't know | |

the situation. */ | |

if ((int) TREE_CODE (exp) >= (int) LAST_AND_UNUSED_TREE_CODE) | |

return -1; | |

nops = first_rtl_op (TREE_CODE (exp)); | |

for (i = 0; i < nops; i++) | |

if (TREE_OPERAND (exp, i) != 0) | |

{ | |

int type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i))); | |

if (type == 'e' || type == '<' || type == '1' || type == '2' | |

|| type == 'r' || type == 's') | |

{ | |

cmp = has_cleanups (TREE_OPERAND (exp, i)); | |

if (cmp) | |

return cmp; | |

} | |

} | |

return 0; | |

} | |

/* Given a tree EXP, a FIELD_DECL F, and a replacement value R, | |

return a tree with all occurrences of references to F in a | |

PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP | |

contains only arithmetic expressions or a CALL_EXPR with a | |

PLACEHOLDER_EXPR occurring only in its arglist. */ | |

tree | |

substitute_in_expr (exp, f, r) | |

tree exp; | |

tree f; | |

tree r; | |

{ | |

enum tree_code code = TREE_CODE (exp); | |

tree op0, op1, op2; | |

tree new; | |

tree inner; | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'c': | |

case 'd': | |

return exp; | |

case 'x': | |

if (code == PLACEHOLDER_EXPR) | |

return exp; | |

else if (code == TREE_LIST) | |

{ | |

op0 = (TREE_CHAIN (exp) == 0 | |

? 0 : 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); | |

} | |

abort (); | |

case '1': | |

case '2': | |

case '<': | |

case 'e': | |

switch (TREE_CODE_LENGTH (code)) | |

{ | |

case 1: | |

op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r); | |

if (op0 == TREE_OPERAND (exp, 0)) | |

return exp; | |

if (code == NON_LVALUE_EXPR) | |

return op0; | |

new = fold (build1 (code, TREE_TYPE (exp), op0)); | |

break; | |

case 2: | |

/* An RTL_EXPR cannot contain a PLACEHOLDER_EXPR; a CONSTRUCTOR | |

could, but we don't support it. */ | |

if (code == RTL_EXPR) | |

return exp; | |

else if (code == CONSTRUCTOR) | |

abort (); | |

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 (build (code, TREE_TYPE (exp), op0, op1)); | |

break; | |

case 3: | |

/* It cannot be that anything inside a SAVE_EXPR contains a | |

PLACEHOLDER_EXPR. */ | |

if (code == SAVE_EXPR) | |

return exp; | |

else if (code == CALL_EXPR) | |

{ | |

op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r); | |

if (op1 == TREE_OPERAND (exp, 1)) | |

return exp; | |

return build (code, TREE_TYPE (exp), | |

TREE_OPERAND (exp, 0), op1, NULL_TREE); | |

} | |

else if (code != COND_EXPR) | |

abort (); | |

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 (build (code, TREE_TYPE (exp), op0, op1, op2)); | |

break; | |

default: | |

abort (); | |

} | |

break; | |

case 'r': | |

switch (code) | |

{ | |

case COMPONENT_REF: | |

/* If this expression is getting a value from a PLACEHOLDER_EXPR | |

and it is the right field, replace it with R. */ | |

for (inner = TREE_OPERAND (exp, 0); | |

TREE_CODE_CLASS (TREE_CODE (inner)) == 'r'; | |

inner = TREE_OPERAND (inner, 0)) | |

; | |

if (TREE_CODE (inner) == PLACEHOLDER_EXPR | |

&& TREE_OPERAND (exp, 1) == f) | |

return r; | |

/* If this expression hasn't been completed let, leave it | |

alone. */ | |

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 (build (code, TREE_TYPE (exp), op0, | |

TREE_OPERAND (exp, 1))); | |

break; | |

case BIT_FIELD_REF: | |

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 (build (code, TREE_TYPE (exp), op0, op1, op2)); | |

break; | |

case INDIRECT_REF: | |

case BUFFER_REF: | |

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; | |

default: | |

abort (); | |

} | |

break; | |

default: | |

abort (); | |

} | |

TREE_READONLY (new) = TREE_READONLY (exp); | |

return new; | |

} | |

/* Stabilize a reference so that we can use it any number of times | |

without causing its operands to be evaluated more than once. | |

Returns the stabilized reference. This works by means of save_expr, | |

so see the caveats in the comments about save_expr. | |

Also allows conversion expressions whose operands are references. | |

Any other kind of expression is returned unchanged. */ | |

tree | |

stabilize_reference (ref) | |

tree ref; | |

{ | |

tree result; | |

enum tree_code code = TREE_CODE (ref); | |

switch (code) | |

{ | |

case VAR_DECL: | |

case PARM_DECL: | |

case RESULT_DECL: | |

/* No action is needed in this case. */ | |

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)); | |

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))); | |

break; | |

case ARRAY_RANGE_REF: | |

result = build_nt (ARRAY_RANGE_REF, | |

stabilize_reference (TREE_OPERAND (ref, 0)), | |

stabilize_reference_1 (TREE_OPERAND (ref, 1))); | |

break; | |

case COMPOUND_EXPR: | |

/* We cannot wrap the first expression in a SAVE_EXPR, as then | |

it wouldn't be ignored. This matters when dealing with | |

volatiles. */ | |

return stabilize_reference_1 (ref); | |

case RTL_EXPR: | |

result = build1 (INDIRECT_REF, TREE_TYPE (ref), | |

save_expr (build1 (ADDR_EXPR, | |

build_pointer_type (TREE_TYPE (ref)), | |

ref))); | |

break; | |

/* If arg isn't a kind of lvalue we recognize, make no change. | |

Caller should recognize the error for an invalid lvalue. */ | |

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; | |

} | |

/* Subroutine of stabilize_reference; this is called for subtrees of | |

references. Any expression with side-effects must be put in a SAVE_EXPR | |

to ensure that it is only evaluated once. | |

We don't put SAVE_EXPR nodes around everything, because assigning very | |

simple expressions to temporaries causes us to miss good opportunities | |

for optimizations. Among other things, the opportunity to fold in the | |

addition of a constant into an addressing mode often gets lost, e.g. | |

"y[i+1] += x;". In general, we take the approach that we should not make | |

an assignment unless we are forced into it - i.e., that any non-side effect | |

operator should be allowed, and that cse should take care of coalescing | |

multiple utterances of the same expression should that prove fruitful. */ | |

tree | |

stabilize_reference_1 (e) | |

tree e; | |

{ | |

tree result; | |

enum tree_code code = TREE_CODE (e); | |

/* We cannot ignore const expressions because it might be a reference | |

to a const array but whose index contains side-effects. But we can | |

ignore things that are actual constant or that already have been | |

handled by this function. */ | |

if (TREE_CONSTANT (e) || code == SAVE_EXPR) | |

return e; | |

switch (TREE_CODE_CLASS (code)) | |

{ | |

case 'x': | |

case 't': | |

case 'd': | |

case 'b': | |

case '<': | |

case 's': | |

case 'e': | |

case 'r': | |

/* If the expression has side-effects, then encase it in a SAVE_EXPR | |

so that it will only be evaluated once. */ | |

/* The reference (r) and comparison (<) classes could be handled as | |

below, but it is generally faster to only evaluate them once. */ | |

if (TREE_SIDE_EFFECTS (e)) | |

return save_expr (e); | |

return e; | |

case 'c': | |

/* Constants need no processing. In fact, we should never reach | |

here. */ | |

return e; | |

case '2': | |

/* Division is slow and tends to be compiled with jumps, | |

especially the division by powers of 2 that is often | |

found inside of an array reference. So do it just once. */ | |

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); | |

/* Recursively stabilize each operand. */ | |

result = build_nt (code, stabilize_reference_1 (TREE_OPERAND (e, 0)), | |

stabilize_reference_1 (TREE_OPERAND (e, 1))); | |

break; | |

case '1': | |

/* Recursively stabilize each operand. */ | |

result = build_nt (code, stabilize_reference_1 (TREE_OPERAND (e, 0))); | |

break; | |

default: | |

abort (); | |

} | |

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); | |

return result; | |

} | |

/* Low-level constructors for expressions. */ | |

/* Build an expression of code CODE, data type TYPE, | |

and operands as specified by the arguments ARG1 and following arguments. | |

Expressions and reference nodes can be created this way. | |

Constants, decls, types and misc nodes cannot be. */ | |

tree | |

build VPARAMS ((enum tree_code code, tree tt, ...)) | |

{ | |

tree t; | |

int length; | |

int i; | |

int fro; | |

int constant; | |

VA_OPEN (p, tt); | |

VA_FIXEDARG (p, enum tree_code, code); | |

VA_FIXEDARG (p, tree, tt); | |

t = make_node (code); | |

length = TREE_CODE_LENGTH (code); | |

TREE_TYPE (t) = tt; | |

/* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the | |

result based on those same flags for the arguments. But if the | |

arguments aren't really even `tree' expressions, we shouldn't be trying | |

to do this. */ | |

fro = first_rtl_op (code); | |

/* Expressions without side effects may be constant if their | |

arguments are as well. */ | |

constant = (TREE_CODE_CLASS (code) == '<' | |

|| TREE_CODE_CLASS (code) == '1' | |

|| TREE_CODE_CLASS (code) == '2' | |

|| TREE_CODE_CLASS (code) == 'c'); | |

if (length == 2) | |

{ | |

/* This is equivalent to the loop below, but faster. */ | |

tree arg0 = va_arg (p, tree); | |

tree arg1 = va_arg (p, tree); | |

TREE_OPERAND (t, 0) = arg0; | |

TREE_OPERAND (t, 1) = arg1; | |

TREE_READONLY (t) = 1; | |

if (arg0 && fro > 0) | |

{ | |

if (TREE_SIDE_EFFECTS (arg0)) | |

TREE_SIDE_EFFECTS (t) = 1; | |

if (!TREE_READONLY (arg0)) | |

TREE_READONLY (t) = 0; | |

if (!TREE_CONSTANT (arg0)) | |

constant = 0; | |

} | |

if (arg1 && fro > 1) | |

{ | |

if (TREE_SIDE_EFFECTS (arg1)) | |

TREE_SIDE_EFFECTS (t) = 1; | |

if (!TREE_READONLY (arg1)) | |

TREE_READONLY (t) = 0; | |

if (!TREE_CONSTANT (arg1)) | |

constant = 0; | |

} | |

} | |

else if (length == 1) | |

{ | |

tree arg0 = va_arg (p, tree); | |

/* The only one-operand cases we handle here are those with side-effects. | |

Others are handled with build1. So don't bother checked if the | |

arg has side-effects since we'll already have set it. | |

??? This really should use build1 too. */ | |

if (TREE_CODE_CLASS (code) != 's') | |

abort (); | |

TREE_OPERAND (t, 0) = arg0; | |

} | |

else | |

{ | |

for (i = 0; i < length; i++) | |

{ | |

tree operand = va_arg (p, tree); | |

TREE_OPERAND (t, i) = operand; | |

if (operand && fro > i) | |

{ | |

if (TREE_SIDE_EFFECTS (operand)) | |

TREE_SIDE_EFFECTS (t) = 1; | |

if (!TREE_CONSTANT (operand)) | |

constant = 0; | |

} | |

} | |

} | |

VA_CLOSE (p); | |

TREE_CONSTANT (t) = constant; | |

return t; | |

} | |

/* Same as above, but only builds for unary operators. | |

Saves lions share of calls to `build'; cuts down use | |

of varargs, which is expensive for RISC machines. */ | |

tree | |

build1 (code, type, node) | |

enum tree_code code; | |

tree type; | |

tree node; | |

{ | |

int length; | |

#ifdef GATHER_STATISTICS | |

tree_node_kind kind; | |

#endif | |

tree t; | |

#ifdef GATHER_STATISTICS | |

if (TREE_CODE_CLASS (code) == 'r') | |

kind = r_kind; | |

else | |

kind = e_kind; | |

#endif | |

#ifdef ENABLE_CHECKING | |

if (TREE_CODE_CLASS (code) == '2' | |

|| TREE_CODE_CLASS (code) == '<' | |

|| TREE_CODE_LENGTH (code) != 1) | |

abort (); | |

#endif /* ENABLE_CHECKING */ | |

length = sizeof (struct tree_exp); | |

t = ggc_alloc_tree (length); | |

memset ((PTR) t, 0, sizeof (struct tree_common)); | |

#ifdef GATHER_STATISTICS | |

tree_node_counts[(int) kind]++; | |

tree_node_sizes[(int) kind] += length; | |

#endif | |

TREE_SET_CODE (t, code); | |

TREE_TYPE (t) = type; | |

TREE_COMPLEXITY (t) = 0; | |

TREE_OPERAND (t, 0) = node; | |

if (node && first_rtl_op (code) != 0) | |

{ | |

TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node); | |

TREE_READONLY (t) = TREE_READONLY (node); | |

} | |

switch (code) | |

{ | |

case INIT_EXPR: | |

case MODIFY_EXPR: | |

case VA_ARG_EXPR: | |

case RTL_EXPR: | |

case PREDECREMENT_EXPR: | |

case PREINCREMENT_EXPR: | |

case POSTDECREMENT_EXPR: | |

case POSTINCREMENT_EXPR: | |

/* All of these have side-effects, no matter what their | |

operands are. */ | |

TREE_SIDE_EFFECTS (t) = 1; | |

TREE_READONLY (t) = 0; | |

break; | |

case INDIRECT_REF: | |

/* Whether a dereference is readonly has nothing to do with whether | |

its operand is readonly. */ | |

TREE_READONLY (t) = 0; | |

break; | |

default: | |

if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node)) | |

TREE_CONSTANT (t) = 1; | |

break; | |

} | |

return t; | |

} | |

/* Similar except don't specify the TREE_TYPE | |

and leave the TREE_SIDE_EFFECTS as 0. | |

It is permissible for arguments to be null, | |

or even garbage if their values do not matter. */ | |

tree | |

build_nt VPARAMS ((enum tree_code code, ...)) | |

{ | |

tree t; | |

int length; | |

int i; | |

VA_OPEN (p, code); | |

VA_FIXEDARG (p, enum tree_code, 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_CLOSE (p); | |

return t; | |

} | |

/* Create a DECL_... node of code CODE, name NAME and data type TYPE. | |

We do NOT enter this node in any sort of symbol table. | |

layout_decl is used to set up the decl's storage layout. | |

Other slots are initialized to 0 or null pointers. */ | |

tree | |

build_decl (code, name, type) | |

enum tree_code code; | |

tree name, type; | |

{ | |

tree t; | |

t = make_node (code); | |

/* if (type == error_mark_node) | |

type = integer_type_node; */ | |

/* That is not done, deliberately, so that having error_mark_node | |

as the type can suppress useless errors in the use of this variable. */ | |

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; | |

return t; | |

} | |

/* BLOCK nodes are used to represent the structure of binding contours | |

and declarations, once those contours have been exited and their contents | |

compiled. This information is used for outputting debugging info. */ | |

tree | |

build_block (vars, tags, subblocks, supercontext, chain) | |

tree vars, tags ATTRIBUTE_UNUSED, subblocks, supercontext, chain; | |

{ | |

tree block = make_node (BLOCK); | |

BLOCK_VARS (block) = vars; | |

BLOCK_SUBBLOCKS (block) = subblocks; | |

BLOCK_SUPERCONTEXT (block) = supercontext; | |

BLOCK_CHAIN (block) = chain; | |

return block; | |

} | |

/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact | |

location where an expression or an identifier were encountered. It | |

is necessary for languages where the frontend parser will handle | |

recursively more than one file (Java is one of them). */ | |

tree | |

build_expr_wfl (node, file, line, col) | |

tree node; | |

const char *file; | |

int line, col; | |

{ | |

static const char *last_file = 0; | |

static tree last_filenode = NULL_TREE; | |

tree wfl = make_node (EXPR_WITH_FILE_LOCATION); | |

EXPR_WFL_NODE (wfl) = node; | |

EXPR_WFL_SET_LINECOL (wfl, line, col); | |

if (file != last_file) | |

{ | |

last_file = file; | |

last_filenode = file ? get_identifier (file) : NULL_TREE; | |

} | |

EXPR_WFL_FILENAME_NODE (wfl) = last_filenode; | |

if (node) | |

{ | |

TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node); | |

TREE_TYPE (wfl) = TREE_TYPE (node); | |

} | |

return wfl; | |

} | |

/* Return a declaration like DDECL except that its DECL_ATTRIBUTES | |

is ATTRIBUTE. */ | |

tree | |

build_decl_attribute_variant (ddecl, attribute) | |

tree ddecl, attribute; | |

{ | |

DECL_ATTRIBUTES (ddecl) = attribute; | |

return ddecl; | |

} | |

/* Return a type like TTYPE except that its TYPE_ATTRIBUTE | |

is ATTRIBUTE. | |

Record such modified types already made so we don't make duplicates. */ | |

tree | |

build_type_attribute_variant (ttype, attribute) | |

tree ttype, attribute; | |

{ | |

if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute)) | |

{ | |

unsigned int hashcode; | |

tree ntype; | |

ntype = copy_node (ttype); | |

TYPE_POINTER_TO (ntype) = 0; | |

TYPE_REFERENCE_TO (ntype) = 0; | |

TYPE_ATTRIBUTES (ntype) = attribute; | |

/* Create a new main variant of TYPE. */ | |

TYPE_MAIN_VARIANT (ntype) = ntype; | |

TYPE_NEXT_VARIANT (ntype) = 0; | |

set_type_quals (ntype, TYPE_UNQUALIFIED); | |

hashcode = (TYPE_HASH (TREE_CODE (ntype)) | |

+ TYPE_HASH (TREE_TYPE (ntype)) | |

+ attribute_hash_list (attribute)); | |

switch (TREE_CODE (ntype)) | |

{ | |

case FUNCTION_TYPE: | |

hashcode += TYPE_HASH (TYPE_ARG_TYPES (ntype)); | |

break; | |

case ARRAY_TYPE: | |

hashcode += TYPE_HASH (TYPE_DOMAIN (ntype)); | |

break; | |

case INTEGER_TYPE: | |

hashcode += TYPE_HASH (TYPE_MAX_VALUE (ntype)); | |

break; | |

case REAL_TYPE: | |

hashcode += TYPE_HASH (TYPE_PRECISION (ntype)); | |

break; | |

default: | |

break; | |

} | |

ntype = type_hash_canon (hashcode, ntype); | |

ttype = build_qualified_type (ntype, TYPE_QUALS (ttype)); | |

} | |

return ttype; | |

} | |

/* Return nonzero if IDENT is a valid name for attribute ATTR, | |

or zero if not. | |

We try both `text' and `__text__', ATTR may be either one. */ | |

/* ??? It might be a reasonable simplification to require ATTR to be only | |

`text'. One might then also require attribute lists to be stored in | |

their canonicalized form. */ | |

int | |

is_attribute_p (attr, ident) | |

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 is `__text__', IDENT must be `text'; and vice versa. */ | |

if (attr[0] == '_') | |

{ | |

if (attr[1] != '_' | |

|| attr[attr_len - 2] != '_' | |

|| attr[attr_len - 1] != '_') | |

abort (); | |

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; | |

} | |

/* Given an attribute name and a list of attributes, return a pointer to the | |

attribute's list element if the attribute is part of the list, or NULL_TREE | |

if not found. If the attribute appears more than once, this only | |

returns the first occurrence; the TREE_CHAIN of the return value should | |

be passed back in if further occurrences are wanted. */ | |

tree | |

lookup_attribute (attr_name, list) | |

const char *attr_name; | |

tree list; | |

{ | |

tree l; | |

for (l = list; l; l = TREE_CHAIN (l)) | |

{ | |

if (TREE_CODE (TREE_PURPOSE (l)) != IDENTIFIER_NODE) | |

abort (); | |

if (is_attribute_p (attr_name, TREE_PURPOSE (l))) | |

return l; | |

} | |

return NULL_TREE; | |

} | |

/* Return an attribute list that is the union of a1 and a2. */ | |

tree | |

merge_attributes (a1, a2) | |

tree a1, a2; | |

{ | |

tree attributes; | |

/* Either one unset? Take the set one. */ | |

if ((attributes = a1) == 0) | |

attributes = a2; | |

/* One that completely contains the other? Take it. */ | |

else if (a2 != 0 && ! attribute_list_contained (a1, a2)) | |

{ | |

if (attribute_list_contained (a2, a1)) | |

attributes = a2; | |

else | |

{ | |

/* Pick the longest list, and hang on the other list. */ | |

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; | |

} | |

/* Given types T1 and T2, merge their attributes and return | |

the result. */ | |

tree | |

merge_type_attributes (t1, t2) | |

tree t1, t2; | |

{ | |

return merge_attributes (TYPE_ATTRIBUTES (t1), | |

TYPE_ATTRIBUTES (t2)); | |

} | |

/* Given decls OLDDECL and NEWDECL, merge their attributes and return | |

the result. */ | |

tree | |

merge_decl_attributes (olddecl, newdecl) | |

tree olddecl, newdecl; | |

{ | |

return merge_attributes (DECL_ATTRIBUTES (olddecl), | |

DECL_ATTRIBUTES (newdecl)); | |

} | |

#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES | |

/* Specialization of merge_decl_attributes for various Windows targets. | |

This handles the following situation: | |

__declspec (dllimport) int foo; | |

int foo; | |

The second instance of `foo' nullifies the dllimport. */ | |

tree | |

merge_dllimport_decl_attributes (old, new) | |

tree old; | |

tree new; | |

{ | |

tree a; | |

int delete_dllimport_p; | |

old = DECL_ATTRIBUTES (old); | |

new = DECL_ATTRIBUTES (new); | |

/* What we need to do here is remove from `old' dllimport if it doesn't | |

appear in `new'. dllimport behaves like extern: if a declaration is | |

marked dllimport and a definition appears later, then the object | |

is not dllimport'd. */ | |

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; | |

/* Scan the list for dllimport and delete it. */ | |

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; | |

} | |

#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES */ | |

/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask | |

of the various TYPE_QUAL values. */ | |

static void | |

set_type_quals (type, 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; | |

} | |

/* Return a version of the TYPE, qualified as indicated by the | |

TYPE_QUALS, if one exists. If no qualified version exists yet, | |

return NULL_TREE. */ | |

tree | |

get_qualified_type (type, type_quals) | |

tree type; | |

int type_quals; | |

{ | |

tree t; | |

/* Search the chain of variants to see if there is already one there just | |

like the one we need to have. If so, use that existing one. We must | |

preserve the TYPE_NAME, since there is code that depends on this. */ | |

for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) | |

if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type) | |

&& TYPE_CONTEXT (t) == TYPE_CONTEXT (type)) | |

return t; | |

return NULL_TREE; | |

} | |

/* Like get_qualified_type, but creates the type if it does not | |

exist. This function never returns NULL_TREE. */ | |

tree | |

build_qualified_type (type, type_quals) | |

tree type; | |

int type_quals; | |

{ | |

tree t; | |

/* See if we already have the appropriate qualified variant. */ | |

t = get_qualified_type (type, type_quals); | |

/* If not, build it. */ | |

if (!t) | |

{ | |

t = build_type_copy (type); | |

set_type_quals (t, type_quals); | |

} | |

return t; | |

} | |

/* Create a new variant of TYPE, equivalent but distinct. | |

This is so the caller can modify it. */ | |

tree | |

build_type_copy (type) | |

tree type; | |

{ | |

tree t, m = TYPE_MAIN_VARIANT (type); | |

t = copy_node (type); | |

TYPE_POINTER_TO (t) = 0; | |

TYPE_REFERENCE_TO (t) = 0; | |

/* Add this type to the chain of variants of TYPE. */ | |

TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); | |

TYPE_NEXT_VARIANT (m) = t; | |

return t; | |

} | |

/* Hashing of types so that we don't make duplicates. | |

The entry point is `type_hash_canon'. */ | |

/* Compute a hash code for a list of types (chain of TREE_LIST nodes | |

with types in the TREE_VALUE slots), by adding the hash codes | |

of the individual types. */ | |

unsigned int | |

type_hash_list (list) | |

tree list; | |

{ | |

unsigned int hashcode; | |

tree tail; | |

for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail)) | |

hashcode += TYPE_HASH (TREE_VALUE (tail)); | |

return hashcode; | |

} | |

/* These are the Hashtable callback functions. */ | |

/* Returns true if the types are equal. */ | |

static int | |

type_hash_eq (va, vb) | |

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_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))) | |

/* Note that TYPE_DOMAIN is TYPE_ARG_TYPES for FUNCTION_TYPE. */ | |

&& (TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type) | |

|| (TYPE_DOMAIN (a->type) | |

&& TREE_CODE (TYPE_DOMAIN (a->type)) == TREE_LIST | |

&& TYPE_DOMAIN (b->type) | |

&& TREE_CODE (TYPE_DOMAIN (b->type)) == TREE_LIST | |

&& type_list_equal (TYPE_DOMAIN (a->type), | |

TYPE_DOMAIN (b->type))))) | |

return 1; | |

return 0; | |

} | |

/* Return the cached hash value. */ | |

static hashval_t | |

type_hash_hash (item) | |

const void *item; | |

{ | |

return ((const struct type_hash *) item)->hash; | |

} | |

/* Look in the type hash table for a type isomorphic to TYPE. | |

If one is found, return it. Otherwise return 0. */ | |

tree | |

type_hash_lookup (hashcode, type) | |

unsigned int hashcode; | |

tree type; | |

{ | |

struct type_hash *h, in; | |

/* The TYPE_ALIGN field of a type is set by layout_type(), so we | |

must call that routine before comparing TYPE_ALIGNs. */ | |

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; | |

} | |

/* Add an entry to the type-hash-table | |

for a type TYPE whose hash code is HASHCODE. */ | |

void | |

type_hash_add (hashcode, type) | |

unsigned int hashcode; | |

tree type; | |

{ | |

struct type_hash *h; | |

void **loc; | |

h = (struct type_hash *) 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; | |

} | |

/* Given TYPE, and HASHCODE its hash code, return the canonical | |

object for an identical type if one already exists. | |

Otherwise, return TYPE, and record it as the canonical object | |

if it is a permanent object. | |

To use this function, first create a type of the sort you want. | |

Then compute its hash code from the fields of the type that | |

make it different from other similar types. | |

Then call this function and use the value. | |

This function frees the type you pass in if it is a duplicate. */ | |

/* Set to 1 to debug without canonicalization. Never set by program. */ | |

int debug_no_type_hash = 0; | |

tree | |

type_hash_canon (hashcode, type) | |

unsigned int hashcode; | |

tree type; | |

{ | |

tree t1; | |

if (debug_no_type_hash) | |

return type; | |

/* See if the type is in the hash table already. If so, return it. | |

Otherwise, add the 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; | |

} | |

} | |

/* See if the data pointed to by the type hash table is marked. We consider | |

it marked if the type is marked or if a debug type number or symbol | |

table entry has been made for the type. This reduces the amount of | |

debugging output and eliminates that dependency of the debug output on | |

the number of garbage collections. */ | |

static int | |

type_hash_marked_p (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 () | |

{ | |

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)); | |

} | |

/* Compute a hash code for a list of attributes (chain of TREE_LIST nodes | |

with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots), | |

by adding the hash codes of the individual attributes. */ | |

unsigned int | |

attribute_hash_list (list) | |

tree list; | |

{ | |

unsigned int hashcode; | |

tree tail; | |

for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail)) | |

/* ??? Do we want to add in TREE_VALUE too? */ | |

hashcode += TYPE_HASH (TREE_PURPOSE (tail)); | |

return hashcode; | |

} | |

/* Given two lists of attributes, return true if list l2 is | |

equivalent to l1. */ | |

int | |

attribute_list_equal (l1, l2) | |

tree l1, l2; | |

{ | |

return attribute_list_contained (l1, l2) | |

&& attribute_list_contained (l2, l1); | |

} | |

/* Given two lists of attributes, return true if list L2 is | |

completely contained within L1. */ | |

/* ??? This would be faster if attribute names were stored in a canonicalized | |

form. Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method | |

must be used to show these elements are equivalent (which they are). */ | |

/* ??? It's not clear that attributes with arguments will always be handled | |

correctly. */ | |

int | |

attribute_list_contained (l1, l2) | |

tree l1, l2; | |

{ | |

tree t1, t2; | |

/* First check the obvious, maybe the lists are identical. */ | |

if (l1 == l2) | |

return 1; | |

/* Maybe the lists are similar. */ | |

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)); | |

/* Maybe the lists are equal. */ | |

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; | |

} | |

/* Given two lists of types | |

(chains of TREE_LIST nodes with types in the TREE_VALUE slots) | |

return 1 if the lists contain the same types in the same order. | |

Also, the TREE_PURPOSEs must match. */ | |

int | |

type_list_equal (l1, l2) | |

tree l1, 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; | |

} | |

/* Returns the number of arguments to the FUNCTION_TYPE or METHOD_TYPE | |

given by TYPE. If the argument list accepts variable arguments, | |

then this function counts only the ordinary arguments. */ | |

int | |

type_num_arguments (type) | |

tree type; | |

{ | |

int i = 0; | |

tree t; | |

for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t)) | |

/* If the function does not take a variable number of arguments, | |

the last element in the list will have type `void'. */ | |

if (VOID_TYPE_P (TREE_VALUE (t))) | |

break; | |

else | |

++i; | |

return i; | |

} | |

/* Nonzero if integer constants T1 and T2 | |

represent the same constant value. */ | |

int | |

tree_int_cst_equal (t1, t2) | |

tree t1, 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; | |

} | |

/* Nonzero if integer constants T1 and T2 represent values that satisfy <. | |

The precise way of comparison depends on their data type. */ | |

int | |

tree_int_cst_lt (t1, t2) | |

tree t1, t2; | |

{ | |

if (t1 == t2) | |

return 0; | |

if (TREE_UNSIGNED (TREE_TYPE (t1)) != TREE_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; | |

/* Otherwise, both are non-negative, so we compare them as | |

unsigned just in case one of them would overflow a signed | |

type. */ | |

} | |

else if (! TREE_UNSIGNED (TREE_TYPE (t1))) | |

return INT_CST_LT (t1, t2); | |

return INT_CST_LT_UNSIGNED (t1, t2); | |

} | |

/* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2. */ | |

int | |

tree_int_cst_compare (t1, t2) | |

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; | |

} | |

/* Return 1 if T is an INTEGER_CST that can be manipulated efficiently on | |

the host. If POS is zero, the value can be represented in a single | |

HOST_WIDE_INT. If POS is nonzero, the value must be positive and can | |

be represented in a single unsigned HOST_WIDE_INT. */ | |

int | |

host_integerp (t, pos) | |

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 | |

&& ! TREE_UNSIGNED (TREE_TYPE (t))) | |

|| (pos && TREE_INT_CST_HIGH (t) == 0))); | |

} | |

/* Return the HOST_WIDE_INT least significant bits of T if it is an | |

INTEGER_CST and there is no overflow. POS is nonzero if the result must | |

be positive. Abort if we cannot satisfy the above conditions. */ | |

HOST_WIDE_INT | |

tree_low_cst (t, pos) | |

tree t; | |

int pos; | |

{ | |

if (host_integerp (t, pos)) | |

return TREE_INT_CST_LOW (t); | |

else | |

abort (); | |

} | |

/* Return the most significant bit of the integer constant T. */ | |

int | |

tree_int_cst_msb (t) | |

tree t; | |

{ | |

int prec; | |

HOST_WIDE_INT h; | |

unsigned HOST_WIDE_INT l; | |

/* Note that using TYPE_PRECISION here is wrong. We care about the | |

actual bits, not the (arbitrary) range of the type. */ | |

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; | |

} | |

/* Return an indication of the sign of the integer constant T. | |

The return value is -1 if T < 0, 0 if T == 0, and 1 if T > 0. | |

Note that -1 will never be returned it T's type is unsigned. */ | |

int | |

tree_int_cst_sgn (t) | |

tree t; | |

{ | |

if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0) | |

return 0; | |

else if (TREE_UNSIGNED (TREE_TYPE (t))) | |

return 1; | |

else if (TREE_INT_CST_HIGH (t) < 0) | |

return -1; | |

else | |

return 1; | |

} | |

/* Compare two constructor-element-type constants. Return 1 if the lists | |

are known to be equal; otherwise return 0. */ | |

int | |

simple_cst_list_equal (l1, l2) | |

tree l1, 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; | |

} | |

/* Return truthvalue of whether T1 is the same tree structure as T2. | |

Return 1 if they are the same. | |

Return 0 if they are understandably different. | |

Return -1 if either contains tree structure not understood by | |

this function. */ | |

int | |

simple_cst_equal (t1, t2) | |

tree t1, t2; | |

{ | |

enum tree_code code1, code2; | |

int cmp; | |