X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree.c;h=12aa391d8e8eb46e6141fc55a2753fd7e580e91d;hb=74ca0dd9c18166183e5181020d21e17db185904f;hp=791cc221349f73c3dabc7ac1251c8d08a3cc3881;hpb=1acf029802710ffdf59be2af26c8ae49247c394e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree.c b/gcc/tree.c index 791cc221349..12aa391d8e8 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -48,6 +48,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree-iterator.h" #include "basic-block.h" #include "tree-flow.h" +#include "params.h" /* obstack.[ch] explicitly declined to prototype this. */ extern int _obstack_allocated_p (struct obstack *h, void *obj); @@ -71,6 +72,7 @@ static const char * const tree_node_kind_names[] = { "perm_tree_lists", "temp_tree_lists", "vecs", + "binfos", "phi_nodes", "ssa names", "random kinds", @@ -110,7 +112,7 @@ 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 void finish_vector_type (tree); +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); @@ -192,18 +194,11 @@ tree_size (tree node) + (PHI_ARG_CAPACITY (node) - 1) * sizeof (struct phi_arg_d)); - case EPHI_NODE: return (sizeof (struct tree_ephi_node) - + (EPHI_ARG_CAPACITY (node) - 1) * - sizeof (struct ephi_arg_d)); - case SSA_NAME: return sizeof (struct tree_ssa_name); - case EUSE_NODE: return sizeof (struct tree_euse_node); - - case EKILL_NODE: - case EEXIT_NODE: return sizeof (struct tree_eref_common); 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); @@ -231,9 +226,9 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) #endif struct tree_common ttmp; - /* We can't allocate a TREE_VEC, PHI_NODE, EPHI_NODE or STRING_CST + /* We can't allocate a TREE_VEC, PHI_NODE, or STRING_CST without knowing how many elements it will have. */ - if (code == TREE_VEC || code == PHI_NODE || code == EPHI_NODE) + if (code == TREE_VEC || code == PHI_NODE) abort (); TREE_SET_CODE ((tree)&ttmp, code); @@ -274,6 +269,8 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) kind = id_kind; else if (code == TREE_VEC) kind = vec_kind; + else if (code == TREE_BINFO) + kind = binfo_kind; else if (code == PHI_NODE) kind = phi_kind; else if (code == SSA_NAME) @@ -341,7 +338,6 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) case INIT_EXPR: case MODIFY_EXPR: case VA_ARG_EXPR: - case RTL_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: @@ -396,6 +392,13 @@ copy_node_stat (tree node MEM_STAT_DECL) but the optimizer should catch that. */ TYPE_SYMTAB_POINTER (t) = 0; TYPE_SYMTAB_ADDRESS (t) = 0; + + /* Do not copy the values cache. */ + if (TYPE_CACHED_VALUES_P(t)) + { + TYPE_CACHED_VALUES_P (t) = 0; + TYPE_CACHED_VALUES (t) = NULL_TREE; + } } return t; @@ -425,20 +428,91 @@ copy_list (tree list) } -/* 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. */ +/* Create an INT_CST node of TYPE and value HI:LOW. If TYPE is NULL, + integer_type_node is used. */ tree -build_int_2_wide (unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi) +build_int_cst (tree type, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi) { - tree t = make_node (INTEGER_CST); + tree t; + int ix = -1; + int limit = 0; + + if (!type) + type = integer_type_node; + + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + /* Cache NULL pointer. */ + if (!hi && !low) + { + limit = 1; + ix = 0; + } + break; + + case BOOLEAN_TYPE: + /* Cache false or true. */ + limit = 2; + if (!hi && low < 2) + ix = low; + break; + + case INTEGER_TYPE: + case CHAR_TYPE: + case OFFSET_TYPE: + if (TYPE_UNSIGNED (type)) + { + /* Cache 0..N */ + limit = INTEGER_SHARE_LIMIT; + if (!hi && low < (unsigned HOST_WIDE_INT)INTEGER_SHARE_LIMIT) + ix = low; + } + else + { + /* Cache -1..N */ + 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) + { + /* Make sure no one is clobbering the shared constant. */ + if (TREE_TYPE (t) != type) + abort (); + if (TREE_INT_CST_LOW (t) != low || TREE_INT_CST_HIGH (t) != hi) + abort (); + return t; + } + } + + t = make_node (INTEGER_CST); TREE_INT_CST_LOW (t) = low; TREE_INT_CST_HIGH (t) = hi; - TREE_TYPE (t) = integer_type_node; + TREE_TYPE (t) = type; + + if (ix >= 0) + TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t; + return t; } @@ -581,6 +655,32 @@ build_complex (tree type, tree real, tree imag) return t; } +/* Build a BINFO with LEN language slots. */ + +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; +} + + /* Build a newly constructed TREE_VEC node of length LEN. */ tree @@ -932,21 +1032,6 @@ purpose_member (tree elem, tree list) return NULL_TREE; } -/* Return first list element whose BINFO_TYPE is ELEM. - Return 0 if ELEM is not in LIST. */ - -tree -binfo_member (tree elem, tree 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 @@ -1126,7 +1211,7 @@ size_in_bytes (tree type) } if (TREE_CODE (t) == INTEGER_CST) - force_fit_type (t, 0); + t = force_fit_type (t, 0, false, false); return t; } @@ -1213,7 +1298,7 @@ expr_align (tree t) case SAVE_EXPR: case COMPOUND_EXPR: case MODIFY_EXPR: case INIT_EXPR: case TARGET_EXPR: case WITH_CLEANUP_EXPR: - case CLEANUP_POINT_EXPR: case UNSAVE_EXPR: + case CLEANUP_POINT_EXPR: /* These don't change the alignment of an object. */ return expr_align (TREE_OPERAND (t, 0)); @@ -1260,13 +1345,13 @@ array_type_nelts (tree type) return (integer_zerop (min) ? max - : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min))); + : fold (build2 (MINUS_EXPR, TREE_TYPE (max), max, min))); } -/* Return nonzero if arg is static -- a reference to an object in +/* Return true if arg is static -- a reference to an object in static storage. This is not the same as the C meaning of `static'. */ -int +bool staticp (tree arg) { switch (TREE_CODE (arg)) @@ -1287,10 +1372,10 @@ staticp (tree arg) case LABEL_DECL: case STRING_CST: - return 1; + return true; case COMPONENT_REF: - /* If the thing being referenced is not a field, then it is + /* If the thing being referenced is not a field, then it is something language specific. */ if (TREE_CODE (TREE_OPERAND (arg, 1)) != FIELD_DECL) return (*lang_hooks.staticp) (arg); @@ -1298,12 +1383,12 @@ staticp (tree arg) /* If we are referencing a bitfield, we can't evaluate an ADDR_EXPR at compile time and so it isn't a constant. */ if (DECL_BIT_FIELD (TREE_OPERAND (arg, 1))) - return 0; + return false; return staticp (TREE_OPERAND (arg, 0)); case BIT_FIELD_REF: - return 0; + return false; #if 0 /* This case is technically correct, but results in setting @@ -1319,14 +1404,14 @@ staticp (tree arg) && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST) return staticp (TREE_OPERAND (arg, 0)); else - return 0; + return false; default: if ((unsigned int) TREE_CODE (arg) >= (unsigned int) LAST_AND_UNUSED_TREE_CODE) return lang_hooks.staticp (arg); else - return 0; + return false; } } @@ -1383,7 +1468,7 @@ save_expr (tree expr) if (contains_placeholder_p (inner)) return t; - t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE); + t = build1 (SAVE_EXPR, TREE_TYPE (expr), t); /* 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 @@ -1432,33 +1517,6 @@ skip_simple_arithmetic (tree expr) return inner; } -/* Return TRUE if EXPR is a SAVE_EXPR or wraps simple arithmetic around a - SAVE_EXPR. Return FALSE otherwise. */ - -bool -saved_expr_p (tree expr) -{ - return TREE_CODE (skip_simple_arithmetic (expr)) == SAVE_EXPR; -} - -/* 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 (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. */ @@ -1467,13 +1525,6 @@ first_rtl_op (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; default: return TREE_CODE_LENGTH (code); } @@ -1509,159 +1560,17 @@ tree_node_structure (tree t) case TREE_LIST: return TS_LIST; case TREE_VEC: return TS_VEC; case PHI_NODE: return TS_PHI_NODE; - case EPHI_NODE: return TS_EPHI_NODE; - case EUSE_NODE: return TS_EUSE_NODE; - case EKILL_NODE: return TS_EREF_NODE; - case EEXIT_NODE: return TS_EREF_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: abort (); } } - -/* Perform any modifications to EXPR required when it is unsaved. Does - not recurse into EXPR's subtrees. */ - -void -unsave_expr_1 (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; - } -} - -/* 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 (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; - - /* A label can only be emitted once. */ - case LABEL_EXPR: - return 1; - - case BIND_EXPR: - unsafeness = 1; - break; - - 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 */ - 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. */ @@ -1670,7 +1579,6 @@ bool contains_placeholder_p (tree exp) { enum tree_code code; - int result; if (!exp) return 0; @@ -1708,19 +1616,6 @@ contains_placeholder_p (tree exp) || 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; - default: break; } @@ -1858,7 +1753,6 @@ has_cleanups (tree exp) switch (TREE_CODE (exp)) { case TARGET_EXPR: - case GOTO_SUBROUTINE_EXPR: case WITH_CLEANUP_EXPR: return 1; @@ -1874,6 +1768,10 @@ has_cleanups (tree exp) } return 0; + case DECL_EXPR: + return (DECL_INITIAL (DECL_EXPR_DECL (exp)) + && has_cleanups (DECL_INITIAL (DECL_EXPR_DECL (exp)))); + default: break; } @@ -1938,8 +1836,7 @@ substitute_in_expr (tree exp, tree f, tree r) && TREE_OPERAND (exp, 1) == f) return r; - /* If this expression hasn't been completed let, leave it - alone. */ + /* If this expression hasn't been completed let, leave it alone. */ if (TREE_CODE (inner) == PLACEHOLDER_EXPR && TREE_TYPE (inner) == 0) return exp; @@ -1947,7 +1844,8 @@ substitute_in_expr (tree exp, tree f, tree r) if (op0 == TREE_OPERAND (exp, 0)) return exp; - new = fold (build (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1))); + new = fold (build3 (COMPONENT_REF, TREE_TYPE (exp), + op0, TREE_OPERAND (exp, 1), NULL_TREE)); } else switch (TREE_CODE_CLASS (code)) @@ -2177,7 +2075,7 @@ stabilize_reference (tree ref) case COMPONENT_REF: result = build_nt (COMPONENT_REF, stabilize_reference (TREE_OPERAND (ref, 0)), - TREE_OPERAND (ref, 1)); + TREE_OPERAND (ref, 1), NULL_TREE); break; case BIT_FIELD_REF: @@ -2190,13 +2088,15 @@ stabilize_reference (tree ref) case ARRAY_REF: result = build_nt (ARRAY_REF, stabilize_reference (TREE_OPERAND (ref, 0)), - stabilize_reference_1 (TREE_OPERAND (ref, 1))); + 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))); + stabilize_reference_1 (TREE_OPERAND (ref, 1)), + TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3)); break; case COMPOUND_EXPR: @@ -2205,13 +2105,6 @@ stabilize_reference (tree ref) 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: @@ -2312,41 +2205,81 @@ stabilize_reference_1 (tree e) /* Low-level constructors for expressions. */ -/* A helper function for build1 and constant folders. - Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR. */ +/* A helper function for build1 and constant folders. Set TREE_CONSTANT, + TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR. */ void recompute_tree_invarant_for_addr_expr (tree t) { - tree node = TREE_OPERAND (t, 0); - bool tc = false, ti = false; + tree node; + bool tc = true, ti = true, se = false; - /* Addresses of constants and static variables are constant; - all other decl addresses are invariant. */ - if (staticp (node)) - tc = ti = true; - else + /* We started out assuming this address is both invariant and constant, but + does not have side effects. Now go down any handled components and see if + any of them involve offsets that are either non-constant or non-invariant. + Also check for side-effects. + + ??? Note that this code makes no attempt to deal with the case where + taking the address of something causes a copy due to misalignment. */ + +#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)) { - /* Step past constant offsets. */ - while (1) + /* If the first operand doesn't have an ARRAY_TYPE, this is a bogus + array reference (probably made temporarily by the G++ front end), + so ignore all the operands. */ + if ((TREE_CODE (node) == ARRAY_REF + || TREE_CODE (node) == ARRAY_RANGE_REF) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE) { - if (TREE_CODE (node) == COMPONENT_REF - && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL - && ! DECL_BIT_FIELD (TREE_OPERAND (node, 1))) - ; - else if (TREE_CODE (node) == ARRAY_REF - && TREE_CONSTANT (TREE_OPERAND (node, 1))) - ; - else - break; - node = TREE_OPERAND (node, 0); + UPDATE_TITCSE (TREE_OPERAND (node, 1)); + UPDATE_TITCSE (array_ref_low_bound (node)); + UPDATE_TITCSE (array_ref_element_size (node)); } - if (DECL_P (node)) - ti = true; + /* Likewise, just because this is a COMPONENT_REF doesn't mean we have a + FIELD_DECL, apparently. The G++ front end can put something else + there, at least temporarily. */ + else if (TREE_CODE (node) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL) + UPDATE_TITCSE (component_ref_field_offset (node)); + else if (TREE_CODE (node) == BIT_FIELD_REF) + UPDATE_TITCSE (TREE_OPERAND (node, 2)); + } + + /* Now see what's inside. If it's an INDIRECT_REF, copy our properties from + it. If it's a decl, it's invariant and constant if the decl is static. + It's also invariant if it's a decl in the current function. (Taking the + address of a volatile variable is not volatile.) If it's a constant, + the address is both invariant and constant. Otherwise it's neither. */ + if (TREE_CODE (node) == INDIRECT_REF) + 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 (TREE_CODE_CLASS (TREE_CODE (node)) == 'c') + ; + 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 } /* Build an expression of code CODE, data type TYPE, and operands as @@ -2354,7 +2287,7 @@ recompute_tree_invarant_for_addr_expr (tree t) Constants, decls, types and misc nodes cannot be. We define 5 non-variadic functions, from 0 to 4 arguments. This is - enough for all extant tree codes. These functions can be called + enough for all extant tree codes. These functions can be called directly (preferably!), but can also be obtained via GCC preprocessor magic within the build macro. */ @@ -2413,7 +2346,11 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) 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; @@ -2430,7 +2367,6 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) case INIT_EXPR: case MODIFY_EXPR: case VA_ARG_EXPR: - case RTL_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: @@ -2449,27 +2385,7 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) case ADDR_EXPR: if (node) - { - recompute_tree_invarant_for_addr_expr (t); - - /* The address of a volatile decl or reference does not have - side-effects. But be careful not to ignore side-effects from - other sources deeper in the expression--if node is a _REF and - one of its operands has side-effects, so do we. */ - if (TREE_THIS_VOLATILE (node)) - { - TREE_SIDE_EFFECTS (t) = 0; - if (!DECL_P (node)) - { - int i = first_rtl_op (TREE_CODE (node)) - 1; - for (; i >= 0; --i) - { - if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i))) - TREE_SIDE_EFFECTS (t) = 1; - } - } - } - } + recompute_tree_invarant_for_addr_expr (t); break; default: @@ -2478,6 +2394,8 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) TREE_CONSTANT (t) = 1; if (TREE_CODE_CLASS (code) == '1' && node && TREE_INVARIANT (node)) TREE_INVARIANT (t) = 1; + if (TREE_CODE_CLASS (code) == 'r' && node && TREE_THIS_VOLATILE (node)) + TREE_THIS_VOLATILE (t) = 1; break; } @@ -2535,7 +2453,9 @@ build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL) TREE_READONLY (t) = read_only; TREE_CONSTANT (t) = constant; TREE_INVARIANT (t) = invariant; - TREE_SIDE_EFFECTS (t) = side_effects; + TREE_SIDE_EFFECTS (t) = side_effects; + TREE_THIS_VOLATILE (t) + = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0); return t; } @@ -2584,7 +2504,9 @@ build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1, } } - TREE_SIDE_EFFECTS (t) = side_effects; + TREE_SIDE_EFFECTS (t) = side_effects; + TREE_THIS_VOLATILE (t) + = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0); return t; } @@ -2614,7 +2536,9 @@ build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1, PROCESS_ARG(2); PROCESS_ARG(3); - TREE_SIDE_EFFECTS (t) = side_effects; + TREE_SIDE_EFFECTS (t) = side_effects; + TREE_THIS_VOLATILE (t) + = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0); return t; } @@ -2715,6 +2639,11 @@ build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL) else if (code == FUNCTION_DECL) DECL_MODE (t) = FUNCTION_MODE; + /* Set default visibility to whatever the user supplied with + visibility_specified depending on #pragma GCC visibility. */ + DECL_VISIBILITY (t) = default_visibility; + DECL_VISIBILITY_SPECIFIED (t) = visibility_options.inpragma; + return t; } @@ -2735,7 +2664,29 @@ build_block (tree vars, tree tags ATTRIBUTE_UNUSED, tree subblocks, return block; } +#if 1 /* ! defined(USE_MAPPED_LOCATION) */ +/* ??? gengtype doesn't handle conditionals */ 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 /* Record the exact location where an expression or an identifier were encountered. */ @@ -2779,6 +2730,7 @@ annotate_with_locus (tree node, location_t locus) { annotate_with_file_line (node, locus.file, locus.line); } +#endif /* Return a declaration like DDECL except that its DECL_ATTRIBUTES is ATTRIBUTE. */ @@ -2991,7 +2943,7 @@ merge_decl_attributes (tree olddecl, tree newdecl) DECL_ATTRIBUTES (newdecl)); } -#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES +#if TARGET_DLLIMPORT_DECL_ATTRIBUTES /* Specialization of merge_decl_attributes for various Windows targets. @@ -3044,6 +2996,81 @@ merge_dllimport_decl_attributes (tree old, tree new) return a; } +/* Handle a "dllimport" or "dllexport" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_dll_attribute (tree * pnode, tree name, tree args, int flags, + bool *no_add_attrs) +{ + tree node = *pnode; + + /* These attributes may apply to structure and union types being created, + but otherwise should pass to the declaration involved. */ + 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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; + } + + /* Report error on dllimport ambiguities seen now before they cause + any damage. */ + if (is_attribute_p ("dllimport", name)) + { + /* Like MS, treat definition of dllimported variables and + non-inlined functions on declaration as syntax errors. We + allow the attribute for function definitions if declared + inline. */ + if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node) + && !DECL_DECLARED_INLINE_P (node)) + { + error ("%Jfunction `%D' definition is marked dllimport.", node, node); + *no_add_attrs = true; + } + + else if (TREE_CODE (node) == VAR_DECL) + { + if (DECL_INITIAL (node)) + { + error ("%Jvariable `%D' definition is marked dllimport.", + node, node); + *no_add_attrs = true; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + DECL_EXTERNAL (node) = 1; + /* Also, implicitly give dllimport'd variables declared within + a function global scope, unless declared static. */ + if (current_function_decl != NULL_TREE && !TREE_STATIC (node)) + TREE_PUBLIC (node) = 1; + } + } + + /* Report error if symbol is not accessible at global scope. */ + if (!TREE_PUBLIC (node) + && (TREE_CODE (node) == VAR_DECL + || TREE_CODE (node) == FUNCTION_DECL)) + { + error ("%Jexternal linkage required for symbol '%D' because of " + "'%s' attribute.", node, node, IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + #endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES */ /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask @@ -3106,29 +3133,45 @@ build_qualified_type (tree type, int type_quals) /* If not, build it. */ if (!t) { - t = build_type_copy (type); + t = build_variant_type_copy (type); set_type_quals (t, type_quals); } return t; } +/* Create a new distinct copy of TYPE. The new type is made its own + MAIN_VARIANT. */ + +tree +build_distinct_type_copy (tree type) +{ + tree t = copy_node (type); + + TYPE_POINTER_TO (t) = 0; + TYPE_REFERENCE_TO (t) = 0; + + /* Make it its own variant. */ + TYPE_MAIN_VARIANT (t) = t; + TYPE_NEXT_VARIANT (t) = 0; + + return t; +} + /* Create a new variant of TYPE, equivalent but distinct. This is so the caller can modify it. */ tree -build_type_copy (tree type) +build_variant_type_copy (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. */ + t = build_distinct_type_copy (type); + + /* Add the new type to the chain of variants of TYPE. */ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); TYPE_NEXT_VARIANT (m) = t; + TYPE_MAIN_VARIANT (t) = m; return t; } @@ -3201,7 +3244,7 @@ type_hash_eq (const void *va, const void *vb) || 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), + || tree_int_cst_equal (TYPE_MIN_VALUE (a->type), TYPE_MIN_VALUE (b->type)))); case OFFSET_TYPE: @@ -3216,7 +3259,7 @@ type_hash_eq (const void *va, const void *vb) && 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); @@ -3669,7 +3712,7 @@ simple_cst_equal (tree t1, tree t2) TREE_STRING_LENGTH (t1))); case CONSTRUCTOR: - return simple_cst_list_equal (CONSTRUCTOR_ELTS (t1), + return simple_cst_list_equal (CONSTRUCTOR_ELTS (t1), CONSTRUCTOR_ELTS (t2)); case SAVE_EXPR: @@ -3812,6 +3855,13 @@ commutative_tree_code (enum tree_code code) 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: @@ -3839,7 +3889,8 @@ iterative_hash_expr (tree t, hashval_t val) code = TREE_CODE (t); class = TREE_CODE_CLASS (code); - if (class == 'd') + if (class == 'd' + || TREE_CODE (t) == VALUE_HANDLE) { /* Decls we can just compare by pointer. */ val = iterative_hash_object (t, val); @@ -3854,8 +3905,11 @@ iterative_hash_expr (tree t, hashval_t val) val = iterative_hash_object (TREE_INT_CST_HIGH (t), val); } else if (code == REAL_CST) - val = iterative_hash (TREE_REAL_CST_PTR (t), - sizeof (REAL_VALUE_TYPE), val); + { + unsigned int val2 = real_hash (TREE_REAL_CST_PTR (t)); + + val = iterative_hash (&val2, sizeof (unsigned int), val); + } else if (code == STRING_CST) val = iterative_hash (TREE_STRING_POINTER (t), TREE_STRING_LENGTH (t), val); @@ -4082,6 +4136,28 @@ build_index_type (tree maxval) return itype; } +/* Builds a signed or unsigned integer type of precision PRECISION. + Used for C bitfields whose precision does not match that of + built-in target types. */ +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; +} + /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with low bound LOWVAL and high bound HIGHVAL. @@ -4278,7 +4354,7 @@ build_method_type (tree basetype, tree type) if (TREE_CODE (type) != FUNCTION_TYPE) abort (); - return build_method_type_directly (basetype, + return build_method_type_directly (basetype, TREE_TYPE (type), TYPE_ARG_TYPES (type)); } @@ -4467,8 +4543,8 @@ get_unwidened (tree op, tree for_type) && (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1))) && (! uns || final_prec <= innerprec || unsignedp)) { - win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0), - 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); } @@ -4488,6 +4564,7 @@ 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) { @@ -4524,6 +4601,10 @@ get_narrower (tree op, int *unsignedp_ptr) uns = TYPE_UNSIGNED (TREE_TYPE (op)); first = 0; op = TREE_OPERAND (op, 0); + /* Keep trying to narrow, but don't assign op to win if it + would turn an integral type into something else. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (op)) != integral_p) + continue; } win = op; @@ -4533,7 +4614,8 @@ get_narrower (tree op, int *unsignedp_ptr) /* Since type_for_size always gives an integer type. */ && TREE_CODE (TREE_TYPE (op)) != REAL_TYPE /* Ensure field is laid out already. */ - && DECL_SIZE (TREE_OPERAND (op, 1)) != 0) + && 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); @@ -4556,8 +4638,8 @@ get_narrower (tree op, int *unsignedp_ptr) { if (first) uns = DECL_UNSIGNED (TREE_OPERAND (op, 1)); - win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0), - 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); } @@ -4628,25 +4710,55 @@ int_fits_type_p (tree c, tree type) { c = copy_node (c); TREE_TYPE (c) = type; - return !force_fit_type (c, 0); + c = force_fit_type (c, -1, false, false); + return !TREE_OVERFLOW (c); } } +/* Subprogram of following function. Called by walk_tree. + + Return *TP if it is an automatic variable or parameter of the + function passed in as DATA. */ + +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; +} + /* Returns true if T is, contains, or refers to a type with variable - size. This concept is more general than that of C99 'variably - modified types': in C99, a struct type is never variably modified - because a VLA may not appear as a structure member. However, in - GNU C code like: + size. If FN is nonzero, only return true if a modifier of the type + or position of FN is a variable or parameter inside FN. + + This concept is more general than that of C99 'variably modified types': + in C99, a struct type is never variably modified because a VLA may not + appear as a structure member. However, in GNU C code like: struct S { int i[f()]; }; is valid, and other languages may define similar constructs. */ bool -variably_modified_type_p (tree type) +variably_modified_type_p (tree type, tree fn) { tree t; +/* Test if T is either variable (if FN is zero) or an expression containing + a variable in FN. */ +#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; @@ -4655,9 +4767,8 @@ variably_modified_type_p (tree type) We do not yet have a representation of the C99 '[*]' syntax. When a representation is chosen, this function should be modified to test for that case as well. */ - t = TYPE_SIZE (type); - if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) - return true; + RETURN_TRUE_IF_VAR (TYPE_SIZE (type)); + RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type)); switch (TREE_CODE (type)) { @@ -4666,7 +4777,7 @@ variably_modified_type_p (tree type) case ARRAY_TYPE: case SET_TYPE: case VECTOR_TYPE: - if (variably_modified_type_p (TREE_TYPE (type))) + if (variably_modified_type_p (TREE_TYPE (type), fn)) return true; break; @@ -4674,13 +4785,13 @@ variably_modified_type_p (tree type) case METHOD_TYPE: /* If TYPE is a function type, it is variably modified if any of the parameters or the return type are variably modified. */ - if (variably_modified_type_p (TREE_TYPE (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))) + if (variably_modified_type_p (TREE_VALUE (t), fn)) return true; break; @@ -4691,13 +4802,8 @@ variably_modified_type_p (tree type) case CHAR_TYPE: /* Scalar types are variably modified if their end points aren't constant. */ - t = TYPE_MIN_VALUE (type); - if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) - return true; - - t = TYPE_MAX_VALUE (type); - if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) - return true; + RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type)); + RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type)); break; case RECORD_TYPE: @@ -4710,14 +4816,12 @@ variably_modified_type_p (tree type) for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) if (TREE_CODE (t) == FIELD_DECL) { - tree t1 = DECL_FIELD_OFFSET (t); - - if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST) - return true; + RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t)); + RETURN_TRUE_IF_VAR (DECL_SIZE (t)); + RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t)); - t1 = DECL_SIZE (t); - if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST) - return true; + if (TREE_CODE (type) == QUAL_UNION_TYPE) + RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t)); } break; @@ -4727,7 +4831,9 @@ variably_modified_type_p (tree type) /* The current language may have other cases to check, but in general, all other types are not variably modified. */ - return lang_hooks.tree_inlining.var_mod_type_p (type); + return lang_hooks.tree_inlining.var_mod_type_p (type, fn); + +#undef RETURN_TRUE_IF_VAR } /* Given a DECL or TYPE, return the scope in which it was declared, or @@ -4750,9 +4856,6 @@ decl_function_context (tree decl) if (TREE_CODE (decl) == ERROR_MARK) return 0; - if (TREE_CODE (decl) == SAVE_EXPR) - context = SAVE_EXPR_CONTEXT (decl); - /* C++ virtual functions use DECL_CONTEXT for the class of the vtable where we look up the function at runtime. Such functions always take a first argument of type 'pointer to real context'. @@ -4797,16 +4900,16 @@ decl_type_context (tree decl) 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: abort (); } @@ -4845,7 +4948,7 @@ get_callee_fndecl (tree call) if (TREE_CODE (addr) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL) return TREE_OPERAND (addr, 0); - + /* We couldn't figure out what was being called. Maybe the front end has some idea. */ return lang_hooks.lang_get_callee_fndecl (call); @@ -4897,11 +5000,11 @@ crc32_string (unsigned chksum, const char *string) { unsigned value = *string << 24; unsigned ix; - + for (ix = 8; ix--; value <<= 1) { unsigned feedback; - + feedback = (value ^ chksum) & 0x80000000 ? 0x04c11db7 : 0; chksum <<= 1; chksum ^= feedback; @@ -5085,75 +5188,80 @@ get_set_constructor_bytes (tree init, unsigned char *buffer, int wd_size) #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) -/* Complain that the tree code of NODE does not match the expected CODE. - FILE, LINE, and FUNCTION are of the caller. */ +/* Complain that the tree code of NODE does not match the expected 0 + terminated list of trailing codes. FILE, LINE, and FUNCTION are of + the caller. */ void -tree_check_failed (const tree node, enum tree_code code, const char *file, - int line, const char *function) -{ +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", - tree_code_name[code], tree_code_name[TREE_CODE (node)], + buffer, tree_code_name[TREE_CODE (node)], function, trim_filename (file), line); } -/* Similar to above except that we allowed the code to be one of two - different codes. */ +/* Complain that the tree code of NODE does match the expected 0 + terminated list of trailing codes. FILE, LINE, and FUNCTION are of + the caller. */ void -tree_check2_failed (const tree node, enum tree_code code1, - enum tree_code code2, const char *file, - int line, const char *function) -{ - internal_error ("tree check: expected %s or %s, have %s in %s, at %s:%d", - tree_code_name[code1], tree_code_name[code2], - tree_code_name[TREE_CODE (node)], - function, trim_filename (file), line); -} - -/* Likewise for three different codes. */ +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); -void -tree_check3_failed (const tree node, enum tree_code code1, - enum tree_code code2, enum tree_code code3, - const char *file, int line, const char *function) -{ - internal_error ("tree check: expected %s, %s or %s; have %s in %s, at %s:%d", - tree_code_name[code1], tree_code_name[code2], - tree_code_name[code3], tree_code_name[TREE_CODE (node)], + 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); } -/* ... and for four different codes. */ - -void -tree_check4_failed (const tree node, enum tree_code code1, - enum tree_code code2, enum tree_code code3, - enum tree_code code4, const char *file, int line, - const char *function) -{ - internal_error - ("tree check: expected %s, %s, %s or %s; have %s in %s, at %s:%d", - tree_code_name[code1], tree_code_name[code2], tree_code_name[code3], - tree_code_name[code4], tree_code_name[TREE_CODE (node)], function, - trim_filename (file), line); -} - -/* ... and for five different codes. */ - -void -tree_check5_failed (const tree node, enum tree_code code1, - enum tree_code code2, enum tree_code code3, - enum tree_code code4, enum tree_code code5, - const char *file, int line, const char *function) -{ - internal_error - ("tree check: expected %s, %s, %s, %s or %s; have %s in %s, at %s:%d", - tree_code_name[code1], tree_code_name[code2], tree_code_name[code3], - tree_code_name[code4], tree_code_name[code5], - tree_code_name[TREE_CODE (node)], function, trim_filename (file), line); -} - /* Similar to tree_check_failed, except that we check for a class of tree code, given in CL. */ @@ -5179,18 +5287,6 @@ tree_vec_elt_check_failed (int idx, int len, const char *file, int line, idx + 1, len, function, trim_filename (file), line); } -/* Similar to above, except that the check is for the bounds of a EPHI_NODE's - (dynamically sized) vector. */ - -void -ephi_node_elt_check_failed (int idx, int len, const char *file, int line, - const char *function) -{ - internal_error - ("tree check: accessed elt %d of ephi_node with %d elts in %s, at %s:%d", - idx + 1, len, function, trim_filename (file), line); -} - /* Similar to above, except that the check is for the bounds of a PHI_NODE's (dynamically sized) vector. */ @@ -5217,18 +5313,23 @@ tree_operand_check_failed (int idx, enum tree_code code, const char *file, } #endif /* ENABLE_TREE_CHECKING */ -/* For a new vector type node T, build the information necessary for - debugging output. */ +/* Create a new vector type node holding SUBPARTS units of type INNERTYPE, + and mapped to the machine mode MODE. Initialize its fields and build + the information necessary for debugging output. */ -static void -finish_vector_type (tree t) +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_2 (TYPE_VECTOR_SUBPARTS (t) - 1, 0); - tree array = build_array_type (TREE_TYPE (t), - build_index_type (index)); + tree index = build_int_cst (NULL_TREE, nunits - 1, 0); + 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); @@ -5241,6 +5342,8 @@ finish_vector_type (tree t) numbers equal. */ TYPE_UID (rt) = TYPE_UID (t); } + + return t; } static tree @@ -5269,12 +5372,12 @@ make_or_reuse_type (unsigned size, int unsignedp) this function to select one of the types as sizetype. */ void -build_common_tree_nodes (int signed_char) +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 (); + initialize_sizetypes (signed_sizetype); /* Define both `signed char' and `unsigned char'. */ signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); @@ -5302,8 +5405,7 @@ build_common_tree_nodes (int signed_char) boolean_type_node before calling build_common_tree_nodes_2. */ 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_2 (1, 0); - TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node; + TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1, 0); TYPE_PRECISION (boolean_type_node) = 1; /* Fill in the rest of the sized types. Reuse existing type nodes @@ -5319,7 +5421,7 @@ build_common_tree_nodes (int signed_char) 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"); @@ -5332,9 +5434,9 @@ void build_common_tree_nodes_2 (int short_double) { /* Define these next since types below may used them. */ - integer_zero_node = build_int_2 (0, 0); - integer_one_node = build_int_2 (1, 0); - integer_minus_one_node = build_int_2 (-1, -1); + integer_zero_node = build_int_cst (NULL_TREE, 0, 0); + integer_one_node = build_int_cst (NULL_TREE, 1, 0); + integer_minus_one_node = build_int_cst (NULL_TREE, -1, -1); size_zero_node = size_int (0); size_one_node = size_int (1); @@ -5353,13 +5455,14 @@ build_common_tree_nodes_2 (int short_double) TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; TYPE_USER_ALIGN (void_type_node) = 0; - null_pointer_node = build_int_2 (0, 0); - TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + null_pointer_node = build_int_cst (build_pointer_type (void_type_node), + 0, 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; @@ -5406,7 +5509,7 @@ build_common_tree_nodes_2 (int short_double) don't copy record types and let c_common_nodes_and_builtins() declare the type to be __builtin_va_list. */ if (TREE_CODE (t) != RECORD_TYPE) - t = build_type_copy (t); + t = build_variant_type_copy (t); va_list_type_node = t; } @@ -5446,7 +5549,7 @@ reconstruct_complex_type (tree type, tree bottom) { inner = reconstruct_complex_type (TREE_TYPE (type), bottom); outer = build_method_type_directly (TYPE_METHOD_BASETYPE (type), - inner, + inner, TYPE_ARG_TYPES (type)); } else @@ -5458,36 +5561,39 @@ reconstruct_complex_type (tree type, tree bottom) return outer; } -/* Returns a vector tree node given a vector mode and inner type. */ +/* Returns a vector tree node given a mode (integer, vector, or BLKmode) and + the inner type. */ tree build_vector_type_for_mode (tree innertype, enum machine_mode mode) { - tree t; - t = make_node (VECTOR_TYPE); - TREE_TYPE (t) = innertype; - TYPE_MODE (t) = mode; - finish_vector_type (t); - return t; -} + int nunits; -/* Similarly, but takes inner type and units. */ + if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + nunits = GET_MODE_NUNITS (mode); -tree -build_vector_type (tree innertype, int nunits) -{ - enum machine_mode innermode = TYPE_MODE (innertype); - enum machine_mode mode; + else if (GET_MODE_CLASS (mode) == MODE_INT) + { + /* Check that there are no leftover bits. */ + if (GET_MODE_BITSIZE (mode) % TREE_INT_CST_LOW (TYPE_SIZE (innertype))) + abort (); - if (GET_MODE_CLASS (innermode) == MODE_FLOAT) - mode = MIN_MODE_VECTOR_FLOAT; + nunits = GET_MODE_BITSIZE (mode) + / TREE_INT_CST_LOW (TYPE_SIZE (innertype)); + } else - mode = MIN_MODE_VECTOR_INT; + abort (); - for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode)) - if (GET_MODE_NUNITS (mode) == nunits && GET_MODE_INNER (mode) == innermode) - return build_vector_type_for_mode (innertype, mode); + return make_vector_type (innertype, nunits, mode); +} - return NULL_TREE; +/* Similarly, but takes the inner type and number of units, which must be + a power of two. */ + +tree +build_vector_type (tree innertype, int nunits) +{ + return make_vector_type (innertype, nunits, VOIDmode); } /* Given an initializer INIT, return TRUE if INIT is zero or some @@ -5560,15 +5666,42 @@ build_empty_stmt (void) return build1 (NOP_EXPR, void_type_node, size_zero_node); } + +/* Returns true if it is possible to prove that the index of + an array access REF (an ARRAY_REF expression) falls into the + array bounds. */ + bool -is_essa_node (tree t) +in_array_bounds_p (tree ref) { - if (TREE_CODE (t) == EPHI_NODE || TREE_CODE (t) == EUSE_NODE - || TREE_CODE (t) == EEXIT_NODE || TREE_CODE (t) == EKILL_NODE) - return true; - return false; + 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; } +/* Return true if T (assumed to be a DECL) is a global variable. */ + +bool +is_global_var (tree t) +{ + return (TREE_STATIC (t) || DECL_EXTERNAL (t)); +} /* Return true if T (assumed to be a DECL) must be assigned a memory location. */ @@ -5576,13 +5709,116 @@ is_essa_node (tree t) bool needs_to_live_in_memory (tree t) { - return (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (t) - || TREE_STATIC (t) - || DECL_EXTERNAL (t) - || DECL_NONLOCAL (t) + return (TREE_ADDRESSABLE (t) + || is_global_var (t) || (TREE_CODE (t) == RESULT_DECL - && aggregate_value_p (t, current_function_decl)) - || decl_function_context (t) != current_function_decl); + && aggregate_value_p (t, current_function_decl))); +} + +/* There are situations in which a language considers record types + compatible which have different field lists. Decide if two fields + are compatible. It is assumed that the parent records are compatible. */ + +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; +} + +/* Locate within RECORD a field that is compatible with ORIG_FIELD. */ + +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; + + /* ??? Why isn't this on the main fields list? */ + f = TYPE_VFIELD (record); + if (f && TREE_CODE (f) == FIELD_DECL + && fields_compatible_p (f, orig_field)) + return f; + + /* ??? We should abort here, but Java appears to do Bad Things + with inherited fields. */ + return orig_field; +} + +/* Return value of a constant X. */ + +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; + + if (bits > HOST_BITS_PER_WIDE_INT) + abort (); + + if (negative) + val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1; + else + val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1); + + return val; +} + +/* Returns the greatest common divisor of A and B, which must be + INTEGER_CSTs. */ + +tree +tree_fold_gcd (tree a, tree b) +{ + tree a_mod_b; + tree type = TREE_TYPE (a); + +#if defined ENABLE_CHECKING + if (TREE_CODE (a) != INTEGER_CST + || TREE_CODE (b) != INTEGER_CST) + abort (); +#endif + + 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; + } } #include "gt-tree.h"