/* 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, 2005, 2006, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
#include "output.h"
#include "target.h"
#include "langhooks.h"
+#include "tree-inline.h"
#include "tree-iterator.h"
#include "basic-block.h"
#include "tree-flow.h"
/* Since we cannot rehash a type after it is in the table, we have to
keep the hash code. */
-struct type_hash GTY(())
-{
+struct GTY(()) type_hash {
unsigned long hash;
tree type;
};
param_is (struct tree_priority_map)))
htab_t init_priority_for_decl;
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
- htab_t restrict_base_for_decl;
-
static void set_type_quals (tree, int);
static int type_hash_eq (const void *, const void *);
static hashval_t type_hash_hash (const void *);
"collapse",
"untied"
};
-\f
+
+
+/* Return the tree node structure used by tree code CODE. */
+
+static inline enum tree_node_structure_enum
+tree_node_structure_for_code (enum tree_code code)
+{
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_declaration:
+ {
+ switch (code)
+ {
+ case FIELD_DECL:
+ return TS_FIELD_DECL;
+ case PARM_DECL:
+ return TS_PARM_DECL;
+ case VAR_DECL:
+ return TS_VAR_DECL;
+ case LABEL_DECL:
+ return TS_LABEL_DECL;
+ case RESULT_DECL:
+ return TS_RESULT_DECL;
+ case CONST_DECL:
+ return TS_CONST_DECL;
+ case TYPE_DECL:
+ return TS_TYPE_DECL;
+ case FUNCTION_DECL:
+ return TS_FUNCTION_DECL;
+ default:
+ return TS_DECL_NON_COMMON;
+ }
+ }
+ case tcc_type:
+ return TS_TYPE;
+ case tcc_reference:
+ case tcc_comparison:
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_expression:
+ case tcc_statement:
+ case tcc_vl_exp:
+ return TS_EXP;
+ default: /* tcc_constant and tcc_exceptional */
+ break;
+ }
+ switch (code)
+ {
+ /* tcc_constant cases. */
+ case INTEGER_CST: return TS_INT_CST;
+ case REAL_CST: return TS_REAL_CST;
+ case FIXED_CST: return TS_FIXED_CST;
+ case COMPLEX_CST: return TS_COMPLEX;
+ case VECTOR_CST: return TS_VECTOR;
+ case STRING_CST: return TS_STRING;
+ /* tcc_exceptional 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 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 CONSTRUCTOR: return TS_CONSTRUCTOR;
+ case TREE_BINFO: return TS_BINFO;
+ case OMP_CLAUSE: return TS_OMP_CLAUSE;
+ case OPTIMIZATION_NODE: return TS_OPTIMIZATION;
+ case TARGET_OPTION_NODE: return TS_TARGET_OPTION;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+
+/* Initialize tree_contains_struct to describe the hierarchy of tree
+ nodes. */
+
+static void
+initialize_tree_contains_struct (void)
+{
+ unsigned i;
+
+#define MARK_TS_BASE(C) \
+ do { \
+ tree_contains_struct[C][TS_BASE] = 1; \
+ } while (0)
+
+#define MARK_TS_COMMON(C) \
+ do { \
+ MARK_TS_BASE (C); \
+ tree_contains_struct[C][TS_COMMON] = 1; \
+ } while (0)
+
+#define MARK_TS_DECL_MINIMAL(C) \
+ do { \
+ MARK_TS_COMMON (C); \
+ tree_contains_struct[C][TS_DECL_MINIMAL] = 1; \
+ } while (0)
+
+#define MARK_TS_DECL_COMMON(C) \
+ do { \
+ MARK_TS_DECL_MINIMAL (C); \
+ tree_contains_struct[C][TS_DECL_COMMON] = 1; \
+ } while (0)
+
+#define MARK_TS_DECL_WRTL(C) \
+ do { \
+ MARK_TS_DECL_COMMON (C); \
+ tree_contains_struct[C][TS_DECL_WRTL] = 1; \
+ } while (0)
+
+#define MARK_TS_DECL_WITH_VIS(C) \
+ do { \
+ MARK_TS_DECL_WRTL (C); \
+ tree_contains_struct[C][TS_DECL_WITH_VIS] = 1; \
+ } while (0)
+
+#define MARK_TS_DECL_NON_COMMON(C) \
+ do { \
+ MARK_TS_DECL_WITH_VIS (C); \
+ tree_contains_struct[C][TS_DECL_NON_COMMON] = 1; \
+ } while (0)
+
+ for (i = ERROR_MARK; i < LAST_AND_UNUSED_TREE_CODE; i++)
+ {
+ enum tree_code code;
+ enum tree_node_structure_enum ts_code;
+
+ code = (enum tree_code) i;
+ ts_code = tree_node_structure_for_code (code);
+
+ /* Mark the TS structure itself. */
+ tree_contains_struct[code][ts_code] = 1;
+
+ /* Mark all the structures that TS is derived from. */
+ switch (ts_code)
+ {
+ case TS_COMMON:
+ MARK_TS_BASE (code);
+ break;
+
+ case TS_INT_CST:
+ case TS_REAL_CST:
+ case TS_FIXED_CST:
+ case TS_VECTOR:
+ case TS_STRING:
+ case TS_COMPLEX:
+ case TS_IDENTIFIER:
+ case TS_DECL_MINIMAL:
+ case TS_TYPE:
+ case TS_LIST:
+ case TS_VEC:
+ case TS_EXP:
+ case TS_SSA_NAME:
+ case TS_BLOCK:
+ case TS_BINFO:
+ case TS_STATEMENT_LIST:
+ case TS_CONSTRUCTOR:
+ case TS_OMP_CLAUSE:
+ case TS_OPTIMIZATION:
+ case TS_TARGET_OPTION:
+ MARK_TS_COMMON (code);
+ break;
+
+ case TS_DECL_COMMON:
+ MARK_TS_DECL_MINIMAL (code);
+ break;
+
+ case TS_DECL_WRTL:
+ MARK_TS_DECL_COMMON (code);
+ break;
+
+ case TS_DECL_NON_COMMON:
+ MARK_TS_DECL_WITH_VIS (code);
+ break;
+
+ case TS_DECL_WITH_VIS:
+ case TS_PARM_DECL:
+ case TS_LABEL_DECL:
+ case TS_RESULT_DECL:
+ case TS_CONST_DECL:
+ MARK_TS_DECL_WRTL (code);
+ break;
+
+ case TS_FIELD_DECL:
+ MARK_TS_DECL_COMMON (code);
+ break;
+
+ case TS_VAR_DECL:
+ MARK_TS_DECL_WITH_VIS (code);
+ break;
+
+ case TS_TYPE_DECL:
+ case TS_FUNCTION_DECL:
+ MARK_TS_DECL_NON_COMMON (code);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ /* Basic consistency checks for attributes used in fold. */
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_NON_COMMON]);
+ gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_NON_COMMON]);
+ gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_NON_COMMON]);
+ gcc_assert (tree_contains_struct[CONST_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[PARM_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[RESULT_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[LABEL_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[FIELD_DECL][TS_DECL_COMMON]);
+ gcc_assert (tree_contains_struct[CONST_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[PARM_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[RESULT_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[LABEL_DECL][TS_DECL_WRTL]);
+ gcc_assert (tree_contains_struct[CONST_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[PARM_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[RESULT_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS]);
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS]);
+ gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS]);
+ gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_WITH_VIS]);
+ gcc_assert (tree_contains_struct[VAR_DECL][TS_VAR_DECL]);
+ gcc_assert (tree_contains_struct[FIELD_DECL][TS_FIELD_DECL]);
+ gcc_assert (tree_contains_struct[PARM_DECL][TS_PARM_DECL]);
+ gcc_assert (tree_contains_struct[LABEL_DECL][TS_LABEL_DECL]);
+ gcc_assert (tree_contains_struct[RESULT_DECL][TS_RESULT_DECL]);
+ gcc_assert (tree_contains_struct[CONST_DECL][TS_CONST_DECL]);
+ gcc_assert (tree_contains_struct[TYPE_DECL][TS_TYPE_DECL]);
+ gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL]);
+ gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL]);
+ gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON]);
+
+#undef MARK_TS_BASE
+#undef MARK_TS_COMMON
+#undef MARK_TS_DECL_MINIMAL
+#undef MARK_TS_DECL_COMMON
+#undef MARK_TS_DECL_WRTL
+#undef MARK_TS_DECL_WITH_VIS
+#undef MARK_TS_DECL_NON_COMMON
+}
+
+
/* Init tree.c. */
void
tree_map_eq, 0);
init_priority_for_decl = htab_create_ggc (512, tree_priority_map_hash,
tree_priority_map_eq, 0);
- restrict_base_for_decl = htab_create_ggc (256, tree_map_hash,
- tree_map_eq, 0);
int_cst_hash_table = htab_create_ggc (1024, int_cst_hash_hash,
int_cst_hash_eq, NULL);
cl_optimization_node = make_node (OPTIMIZATION_NODE);
cl_target_option_node = make_node (TARGET_OPTION_NODE);
- tree_contains_struct[FUNCTION_DECL][TS_DECL_NON_COMMON] = 1;
- tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_NON_COMMON] = 1;
- tree_contains_struct[TYPE_DECL][TS_DECL_NON_COMMON] = 1;
-
-
- tree_contains_struct[CONST_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[VAR_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[PARM_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[RESULT_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[FUNCTION_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[TYPE_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[LABEL_DECL][TS_DECL_COMMON] = 1;
- tree_contains_struct[FIELD_DECL][TS_DECL_COMMON] = 1;
-
-
- tree_contains_struct[CONST_DECL][TS_DECL_WRTL] = 1;
- tree_contains_struct[VAR_DECL][TS_DECL_WRTL] = 1;
- tree_contains_struct[PARM_DECL][TS_DECL_WRTL] = 1;
- tree_contains_struct[RESULT_DECL][TS_DECL_WRTL] = 1;
- tree_contains_struct[FUNCTION_DECL][TS_DECL_WRTL] = 1;
- tree_contains_struct[LABEL_DECL][TS_DECL_WRTL] = 1;
-
- tree_contains_struct[CONST_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[VAR_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[PARM_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[RESULT_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[FUNCTION_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[TYPE_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[NAME_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[SYMBOL_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_DECL_MINIMAL] = 1;
-
- tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[SYMBOL_MEMORY_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_TAG] = 1;
-
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_PARTITION_TAG] = 1;
-
- tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
- tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1;
- tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS] = 1;
- tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_WITH_VIS] = 1;
-
- tree_contains_struct[VAR_DECL][TS_VAR_DECL] = 1;
- tree_contains_struct[FIELD_DECL][TS_FIELD_DECL] = 1;
- tree_contains_struct[PARM_DECL][TS_PARM_DECL] = 1;
- tree_contains_struct[LABEL_DECL][TS_LABEL_DECL] = 1;
- tree_contains_struct[RESULT_DECL][TS_RESULT_DECL] = 1;
- tree_contains_struct[CONST_DECL][TS_CONST_DECL] = 1;
- tree_contains_struct[TYPE_DECL][TS_TYPE_DECL] = 1;
- tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL] = 1;
- tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON] = 1;
-
+ /* Initialize the tree_contains_struct array. */
+ initialize_tree_contains_struct ();
lang_hooks.init_ts ();
}
return sizeof (struct tree_type_decl);
case FUNCTION_DECL:
return sizeof (struct tree_function_decl);
- case NAME_MEMORY_TAG:
- case SYMBOL_MEMORY_TAG:
- return sizeof (struct tree_memory_tag);
- case MEMORY_PARTITION_TAG:
- return sizeof (struct tree_memory_partition_tag);
default:
return sizeof (struct tree_decl_non_common);
}
}
else
DECL_ALIGN (t) = 1;
- /* We have not yet computed the alias set for this declaration. */
- DECL_POINTER_ALIAS_SET (t) = -1;
}
DECL_SOURCE_LOCATION (t) = input_location;
DECL_UID (t) = next_decl_uid++;
+ if (TREE_CODE (t) == LABEL_DECL)
+ LABEL_DECL_UID (t) = -1;
break;
SET_DECL_INIT_PRIORITY (t, DECL_INIT_PRIORITY (node));
DECL_HAS_INIT_PRIORITY_P (t) = 1;
}
- if (TREE_CODE (node) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (node))
- {
- SET_DECL_RESTRICT_BASE (t, DECL_GET_RESTRICT_BASE (node));
- DECL_BASED_ON_RESTRICT_P (t) = 1;
- }
}
else if (TREE_CODE_CLASS (code) == tcc_type)
{
: floor_log2 (low));
}
-/* Return 1 if EXPR is the real constant zero. */
+/* Return 1 if EXPR is the real constant zero. Trailing zeroes matter for
+ decimal float constants, so don't return 1 for them. */
int
real_zerop (const_tree expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
- && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0))
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0)
+ && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
|| (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. */
+/* Return 1 if EXPR is the real constant one in real or complex form.
+ Trailing zeroes matter for decimal float constants, so don't return
+ 1 for them. */
int
real_onep (const_tree expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
- && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1))
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1)
+ && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_onep (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
}
-/* Return 1 if EXPR is the real constant two. */
+/* Return 1 if EXPR is the real constant two. Trailing zeroes matter
+ for decimal float constants, so don't return 1 for them. */
int
real_twop (const_tree expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
- && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2))
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2)
+ && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
|| (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. */
+/* Return 1 if EXPR is the real constant minus one. Trailing zeroes
+ matter for decimal float constants, so don't return 1 for them. */
int
real_minus_onep (const_tree expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
- && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1))
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1)
+ && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_minus_onep (TREE_REALPART (expr))
&& real_zerop (TREE_IMAGPART (expr))));
return chain;
}
+/* Return the node in a chain of nodes whose value is x, NULL if not found. */
+
+tree
+tree_find_value (tree chain, tree x)
+{
+ tree list;
+ for (list = chain; list; list = TREE_CHAIN (list))
+ if (TREE_VALUE (list) == x)
+ return list;
+ return NULL;
+}
+
/* Reverse the order of elements in the chain T,
and return the new head of the chain (old last element). */
return t;
}
+/* Build a chain of TREE_LIST nodes from a vector. */
+
+tree
+build_tree_list_vec_stat (const VEC(tree,gc) *vec MEM_STAT_DECL)
+{
+ tree ret = NULL_TREE;
+ tree *pp = &ret;
+ unsigned int i;
+ tree t;
+ for (i = 0; VEC_iterate (tree, vec, i, t); ++i)
+ {
+ *pp = build_tree_list_stat (NULL, t PASS_MEM_STAT);
+ pp = &TREE_CHAIN (*pp);
+ }
+ return ret;
+}
+
/* Return a newly created TREE_LIST node whose
purpose and value fields are PURPOSE and VALUE
and whose TREE_CHAIN is CHAIN. */
return list;
}
+
+/* Return the values of the elements of a CONSTRUCTOR as a vector of
+ trees. */
+
+VEC(tree,gc) *
+ctor_to_vec (tree ctor)
+{
+ VEC(tree, gc) *vec = VEC_alloc (tree, gc, CONSTRUCTOR_NELTS (ctor));
+ unsigned int ix;
+ tree val;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), ix, val)
+ VEC_quick_push (tree, vec, val);
+
+ return vec;
+}
\f
/* Return the size nominally occupied by an object of type TYPE
when it resides in memory. The value is measured in units of bytes,
case COMPONENT_REF:
/* 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);
+ gcc_assert (TREE_CODE (TREE_OPERAND (arg, 1)) == FIELD_DECL);
/* If we are referencing a bitfield, we can't evaluate an
ADDR_EXPR at compile time and so it isn't a constant. */
&& TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST)
return staticp (TREE_OPERAND (arg, 0));
else
- return false;
+ return NULL;
+
+ case COMPOUND_LITERAL_EXPR:
+ return TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (arg)) ? arg : NULL;
default:
- if ((unsigned int) TREE_CODE (arg)
- >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
- return lang_hooks.staticp (arg);
- else
- return NULL;
+ return NULL;
}
}
return t;
t = build1 (SAVE_EXPR, TREE_TYPE (expr), t);
+ SET_EXPR_LOCATION (t, EXPR_LOCATION (expr));
/* 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
return inner;
}
+
/* Return which tree structure is used by T. */
enum tree_node_structure_enum
tree_node_structure (const_tree t)
{
const enum tree_code code = TREE_CODE (t);
+ return tree_node_structure_for_code (code);
+}
- switch (TREE_CODE_CLASS (code))
- {
- case tcc_declaration:
+/* Set various status flags when building a CALL_EXPR object T. */
+
+static void
+process_call_operands (tree t)
+{
+ bool side_effects = TREE_SIDE_EFFECTS (t);
+ bool read_only = false;
+ int i = call_expr_flags (t);
+
+ /* Calls have side-effects, except those to const or pure functions. */
+ if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
+ side_effects = true;
+ /* Propagate TREE_READONLY of arguments for const functions. */
+ if (i & ECF_CONST)
+ read_only = true;
+
+ if (!side_effects || read_only)
+ for (i = 1; i < TREE_OPERAND_LENGTH (t); i++)
{
- switch (code)
- {
- case FIELD_DECL:
- return TS_FIELD_DECL;
- case PARM_DECL:
- return TS_PARM_DECL;
- case VAR_DECL:
- return TS_VAR_DECL;
- case LABEL_DECL:
- return TS_LABEL_DECL;
- case RESULT_DECL:
- return TS_RESULT_DECL;
- case CONST_DECL:
- return TS_CONST_DECL;
- case TYPE_DECL:
- return TS_TYPE_DECL;
- case FUNCTION_DECL:
- return TS_FUNCTION_DECL;
- case SYMBOL_MEMORY_TAG:
- case NAME_MEMORY_TAG:
- case MEMORY_PARTITION_TAG:
- return TS_MEMORY_TAG;
- default:
- return TS_DECL_NON_COMMON;
- }
+ tree op = TREE_OPERAND (t, i);
+ if (op && TREE_SIDE_EFFECTS (op))
+ side_effects = true;
+ if (op && !TREE_READONLY (op) && !CONSTANT_CLASS_P (op))
+ read_only = false;
}
- case tcc_type:
- return TS_TYPE;
- case tcc_reference:
- case tcc_comparison:
- case tcc_unary:
- case tcc_binary:
- case tcc_expression:
- case tcc_statement:
- case tcc_vl_exp:
- return TS_EXP;
- default: /* tcc_constant and tcc_exceptional */
- break;
- }
- switch (code)
- {
- /* tcc_constant cases. */
- case INTEGER_CST: return TS_INT_CST;
- case REAL_CST: return TS_REAL_CST;
- case FIXED_CST: return TS_FIXED_CST;
- case COMPLEX_CST: return TS_COMPLEX;
- case VECTOR_CST: return TS_VECTOR;
- case STRING_CST: return TS_STRING;
- /* tcc_exceptional 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 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 CONSTRUCTOR: return TS_CONSTRUCTOR;
- case TREE_BINFO: return TS_BINFO;
- case OMP_CLAUSE: return TS_OMP_CLAUSE;
- case OPTIMIZATION_NODE: return TS_OPTIMIZATION;
- case TARGET_OPTION_NODE: return TS_TARGET_OPTION;
- default:
- gcc_unreachable ();
- }
+ TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_READONLY (t) = read_only;
}
\f
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
return result;
}
\f
+/* Push tree EXP onto vector QUEUE if it is not already present. */
+
+static void
+push_without_duplicates (tree exp, VEC (tree, heap) **queue)
+{
+ unsigned int i;
+ tree iter;
+
+ for (i = 0; VEC_iterate (tree, *queue, i, iter); i++)
+ if (simple_cst_equal (iter, exp) == 1)
+ break;
+
+ if (!iter)
+ VEC_safe_push (tree, heap, *queue, exp);
+}
+
+/* Given a tree EXP, find all occurences of references to fields
+ in a PLACEHOLDER_EXPR and place them in vector REFS without
+ duplicates. Also record VAR_DECLs and CONST_DECLs. Note that
+ we assume here that EXP contains only arithmetic expressions
+ or CALL_EXPRs with PLACEHOLDER_EXPRs occurring only in their
+ argument list. */
+
+void
+find_placeholder_in_expr (tree exp, VEC (tree, heap) **refs)
+{
+ enum tree_code code = TREE_CODE (exp);
+ tree inner;
+ int i;
+
+ /* We handle TREE_LIST and COMPONENT_REF separately. */
+ if (code == TREE_LIST)
+ {
+ FIND_PLACEHOLDER_IN_EXPR (TREE_CHAIN (exp), refs);
+ FIND_PLACEHOLDER_IN_EXPR (TREE_VALUE (exp), refs);
+ }
+ else if (code == COMPONENT_REF)
+ {
+ for (inner = TREE_OPERAND (exp, 0);
+ REFERENCE_CLASS_P (inner);
+ inner = TREE_OPERAND (inner, 0))
+ ;
+
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
+ push_without_duplicates (exp, refs);
+ else
+ FIND_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), refs);
+ }
+ else
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_constant:
+ break;
+
+ case tcc_declaration:
+ /* Variables allocated to static storage can stay. */
+ if (!TREE_STATIC (exp))
+ push_without_duplicates (exp, refs);
+ break;
+
+ case tcc_expression:
+ /* This is the pattern built in ada/make_aligning_type. */
+ if (code == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == PLACEHOLDER_EXPR)
+ {
+ push_without_duplicates (exp, refs);
+ break;
+ }
+
+ /* Fall through... */
+
+ case tcc_exceptional:
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_reference:
+ for (i = 0; i < TREE_CODE_LENGTH (code); i++)
+ FIND_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, i), refs);
+ break;
+
+ case tcc_vl_exp:
+ for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
+ FIND_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, i), refs);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* 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. */
+ PLACEHOLDER_EXPR replaced by R. Also handle VAR_DECLs and
+ CONST_DECLs. Note that we assume here that EXP contains only
+ arithmetic expressions or CALL_EXPRs with PLACEHOLDER_EXPRs
+ occurring only in their argument list. */
tree
substitute_in_expr (tree exp, tree f, tree r)
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2, op3;
- tree new_tree, inner;
+ tree new_tree;
/* We handle TREE_LIST and COMPONENT_REF separately. */
if (code == TREE_LIST)
return tree_cons (TREE_PURPOSE (exp), op1, op0);
}
else if (code == 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);
- REFERENCE_CLASS_P (inner);
- 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_tree = fold_build3 (COMPONENT_REF, TREE_TYPE (exp),
- op0, TREE_OPERAND (exp, 1), NULL_TREE);
+ {
+ tree inner;
+
+ /* 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);
+ REFERENCE_CLASS_P (inner);
+ inner = TREE_OPERAND (inner, 0))
+ ;
+
+ /* The field. */
+ op1 = TREE_OPERAND (exp, 1);
+
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR && op1 == f)
+ return r;
+
+ /* If this expression hasn't been completed let, leave it alone. */
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR && !TREE_TYPE (inner))
+ return exp;
+
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+
+ new_tree
+ = fold_build3 (COMPONENT_REF, TREE_TYPE (exp), op0, op1, NULL_TREE);
}
else
switch (TREE_CODE_CLASS (code))
{
case tcc_constant:
- case tcc_declaration:
return exp;
+ case tcc_declaration:
+ if (exp == f)
+ return r;
+ else
+ return exp;
+
+ case tcc_expression:
+ if (exp == f)
+ return r;
+
+ /* Fall through... */
+
case tcc_exceptional:
case tcc_unary:
case tcc_binary:
case tcc_comparison:
- case tcc_expression:
case tcc_reference:
switch (TREE_CODE_LENGTH (code))
{
&& op3 == TREE_OPERAND (exp, 3))
return exp;
- new_tree = fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
+ new_tree
+ = fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
break;
default:
case tcc_vl_exp:
{
- tree copy = NULL_TREE;
int i;
+ new_tree = NULL_TREE;
+
+ /* If we are trying to replace F with a constant, inline back
+ functions which do nothing else than computing a value from
+ the arguments they are passed. This makes it possible to
+ fold partially or entirely the replacement expression. */
+ if (CONSTANT_CLASS_P (r) && code == CALL_EXPR)
+ {
+ tree t = maybe_inline_call_in_expr (exp);
+ if (t)
+ return SUBSTITUTE_IN_EXPR (t, f, r);
+ }
+
for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
tree new_op = SUBSTITUTE_IN_EXPR (op, f, r);
if (new_op != op)
{
- if (!copy)
- copy = copy_node (exp);
- TREE_OPERAND (copy, i) = new_op;
+ if (!new_tree)
+ new_tree = copy_node (exp);
+ TREE_OPERAND (new_tree, i) = new_op;
}
}
- if (copy)
- new_tree = fold (copy);
+ if (new_tree)
+ {
+ new_tree = fold (new_tree);
+ if (TREE_CODE (new_tree) == CALL_EXPR)
+ process_call_operands (new_tree);
+ }
else
return exp;
}
gcc_unreachable ();
}
- TREE_READONLY (new_tree) = TREE_READONLY (exp);
+ TREE_READONLY (new_tree) |= TREE_READONLY (exp);
return new_tree;
}
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2, op3;
+ tree new_tree;
/* If this is a PLACEHOLDER_EXPR, see if we find a corresponding type
in the chain of OBJ. */
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
if (op0 == TREE_OPERAND (exp, 0))
return exp;
- else
- return fold_build1 (code, TREE_TYPE (exp), op0);
+
+ new_tree = fold_build1 (code, TREE_TYPE (exp), op0);
+ break;
case 2:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
return exp;
- else
- return fold_build2 (code, TREE_TYPE (exp), op0, op1);
+
+ new_tree = fold_build2 (code, TREE_TYPE (exp), op0, op1);
+ break;
case 3:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
&& op2 == TREE_OPERAND (exp, 2))
return exp;
- else
- return fold_build3 (code, TREE_TYPE (exp), op0, op1, op2);
+
+ new_tree = fold_build3 (code, TREE_TYPE (exp), op0, op1, op2);
+ break;
case 4:
op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
&& op2 == TREE_OPERAND (exp, 2)
&& op3 == TREE_OPERAND (exp, 3))
return exp;
- else
- return fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
+
+ new_tree
+ = fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
+ break;
default:
gcc_unreachable ();
case tcc_vl_exp:
{
- tree copy = NULL_TREE;
int i;
+ new_tree = NULL_TREE;
+
for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
tree new_op = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
if (new_op != op)
{
- if (!copy)
- copy = copy_node (exp);
- TREE_OPERAND (copy, i) = new_op;
+ if (!new_tree)
+ new_tree = copy_node (exp);
+ TREE_OPERAND (new_tree, i) = new_op;
}
}
- if (copy)
- return fold (copy);
+ if (new_tree)
+ {
+ new_tree = fold (new_tree);
+ if (TREE_CODE (new_tree) == CALL_EXPR)
+ process_call_operands (new_tree);
+ }
else
return exp;
}
+ break;
default:
gcc_unreachable ();
}
+
+ TREE_READONLY (new_tree) |= TREE_READONLY (exp);
+ return new_tree;
}
\f
/* Stabilize a reference so that we can use it any number of times
return t;
}
-#define PROCESS_ARG(N) \
- do { \
- TREE_OPERAND (t, N) = arg##N; \
- if (arg##N &&!TYPE_P (arg##N)) \
- { \
- if (TREE_SIDE_EFFECTS (arg##N)) \
- side_effects = 1; \
- if (!TREE_READONLY (arg##N)) \
- read_only = 0; \
- if (!TREE_CONSTANT (arg##N)) \
- constant = 0; \
- } \
+#define PROCESS_ARG(N) \
+ do { \
+ TREE_OPERAND (t, N) = arg##N; \
+ if (arg##N &&!TYPE_P (arg##N)) \
+ { \
+ if (TREE_SIDE_EFFECTS (arg##N)) \
+ side_effects = 1; \
+ if (!TREE_READONLY (arg##N) \
+ && !CONSTANT_CLASS_P (arg##N)) \
+ read_only = 0; \
+ if (!TREE_CONSTANT (arg##N)) \
+ constant = 0; \
+ } \
} while (0)
tree
gcc_assert (TREE_CODE_LENGTH (code) == 2);
if ((code == MINUS_EXPR || code == PLUS_EXPR || code == MULT_EXPR)
- && arg0 && arg1 && tt && POINTER_TYPE_P (tt))
- gcc_assert (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST);
+ && arg0 && arg1 && tt && POINTER_TYPE_P (tt)
+ /* When sizetype precision doesn't match that of pointers
+ we need to be able to build explicit extensions or truncations
+ of the offset argument. */
+ && TYPE_PRECISION (sizetype) == TYPE_PRECISION (tt))
+ gcc_assert (TREE_CODE (arg0) == INTEGER_CST
+ && TREE_CODE (arg1) == INTEGER_CST);
if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
+ read_only = 1;
+
/* As a special exception, if COND_EXPR has NULL branches, we
assume that it is a gimple statement and always consider
it to have side effects. */
PROCESS_ARG(1);
PROCESS_ARG(2);
+ if (code == COND_EXPR)
+ TREE_READONLY (t) = read_only;
+
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
}
tree
-build7_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
- tree arg2, tree arg3, tree arg4, tree arg5,
- tree arg6 MEM_STAT_DECL)
+build6_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ tree arg2, tree arg3, tree arg4, tree arg5 MEM_STAT_DECL)
{
bool constant, read_only, side_effects;
tree t;
PROCESS_ARG(3);
PROCESS_ARG(4);
PROCESS_ARG(5);
- PROCESS_ARG(6);
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t) = 0;
CALL_EXPR_ARG (t, i) = TREE_VALUE (arglist);
return t;
}
+
+/* Similar to build_nt, but for creating a CALL_EXPR object with a
+ tree VEC. */
+
+tree
+build_nt_call_vec (tree fn, VEC(tree,gc) *args)
+{
+ tree ret, t;
+ unsigned int ix;
+
+ ret = build_vl_exp (CALL_EXPR, VEC_length (tree, args) + 3);
+ CALL_EXPR_FN (ret) = fn;
+ CALL_EXPR_STATIC_CHAIN (ret) = NULL_TREE;
+ for (ix = 0; VEC_iterate (tree, args, ix, t); ++ix)
+ CALL_EXPR_ARG (ret, ix) = t;
+ return ret;
+}
\f
/* 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.
+ LOC is the location of the decl.
+
layout_decl is used to set up the decl's storage layout.
Other slots are initialized to 0 or null pointers. */
tree
-build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL)
+build_decl_stat (location_t loc, enum tree_code code, tree name,
+ tree type MEM_STAT_DECL)
{
tree t;
t = make_node_stat (code PASS_MEM_STAT);
+ DECL_SOURCE_LOCATION (t) = loc;
/* if (type == error_mark_node)
type = integer_type_node; */
build_fn_decl (const char *name, tree type)
{
tree id = get_identifier (name);
- tree decl = build_decl (FUNCTION_DECL, id, type);
+ tree decl = build_decl (input_location, FUNCTION_DECL, id, type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
}
\f
-/* Source location accessor functions. */
-
-
-void
-set_expr_locus (tree node, source_location *loc)
-{
- if (loc == NULL)
- EXPR_CHECK (node)->exp.locus = UNKNOWN_LOCATION;
- else
- EXPR_CHECK (node)->exp.locus = *loc;
-}
-
/* Like SET_EXPR_LOCATION, but make sure the tree can have a location.
LOC is the location to use in tree T. */
-void protected_set_expr_location (tree t, location_t loc)
+void
+protected_set_expr_location (tree t, location_t loc)
{
if (t && CAN_HAVE_LOCATION_P (t))
SET_EXPR_LOCATION (t, loc);
return val2;
}
-/* Produce good hash value combining PTR and VAL2. */
-static inline hashval_t
-iterative_hash_pointer (const void *ptr, hashval_t val2)
-{
- if (sizeof (ptr) == sizeof (hashval_t))
- return iterative_hash_hashval_t ((size_t) ptr, val2);
- else
- {
- hashval_t a = (hashval_t) (size_t) ptr;
- /* Avoid warnings about shifting of more than the width of the type on
- hosts that won't execute this path. */
- int zero = 0;
- hashval_t b = (hashval_t) ((size_t) ptr >> (sizeof (hashval_t) * 8 + zero));
- mix (a, b, val2);
- return val2;
- }
-}
-
/* Produce good hash value combining VAL and VAL2. */
static inline hashval_t
iterative_hash_host_wide_int (HOST_WIDE_INT val, hashval_t val2)
bool *no_add_attrs)
{
tree node = *pnode;
+ bool is_dllimport;
/* These attributes may apply to structure and union types being created,
but otherwise should pass to the declaration involved. */
}
else
{
- warning (OPT_Wattributes, "%qs attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored",
+ name);
*no_add_attrs = true;
return NULL_TREE;
}
&& TREE_CODE (node) != TYPE_DECL)
{
*no_add_attrs = true;
- warning (OPT_Wattributes, "%qs attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored",
+ name);
return NULL_TREE;
}
&& TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
{
*no_add_attrs = true;
- warning (OPT_Wattributes, "%qs attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored",
+ name);
return NULL_TREE;
}
+ is_dllimport = is_attribute_p ("dllimport", name);
+
/* Report error on dllimport ambiguities seen now before they cause
any damage. */
- else if (is_attribute_p ("dllimport", name))
+ if (is_dllimport)
{
/* Honor any target-specific overrides. */
if (!targetm.valid_dllimport_attribute_p (node))
if (*no_add_attrs == false)
DECL_DLLIMPORT_P (node) = 1;
}
+ else if (TREE_CODE (node) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (node))
+ /* An exported function, even if inline, must be emitted. */
+ DECL_EXTERNAL (node) = 0;
/* Report error if symbol is not accessible at global scope. */
if (!TREE_PUBLIC (node)
|| TREE_CODE (node) == FUNCTION_DECL))
{
error ("external linkage required for symbol %q+D because of "
- "%qs attribute", node, IDENTIFIER_POINTER (name));
+ "%qE attribute", node, name);
*no_add_attrs = true;
}
{
if (DECL_VISIBILITY_SPECIFIED (node)
&& DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
- error ("%qs implies default visibility, but %qD has already "
+ error ("%qE implies default visibility, but %qD has already "
"been declared with a different visibility",
- IDENTIFIER_POINTER (name), node);
+ name, node);
DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
DECL_VISIBILITY_SPECIFIED (node) = 1;
}
h->fini = priority;
}
-/* Look up a restrict qualified base decl for FROM. */
-
-tree
-decl_restrict_base_lookup (tree from)
-{
- struct tree_map *h;
- struct tree_map in;
-
- in.base.from = from;
- h = (struct tree_map *) htab_find_with_hash (restrict_base_for_decl, &in,
- htab_hash_pointer (from));
- return h ? h->to : NULL_TREE;
-}
-
-/* Record the restrict qualified base TO for FROM. */
-
-void
-decl_restrict_base_insert (tree from, tree to)
-{
- struct tree_map *h;
- void **loc;
-
- h = GGC_NEW (struct tree_map);
- h->hash = htab_hash_pointer (from);
- h->base.from = from;
- h->to = to;
- loc = htab_find_slot_with_hash (restrict_base_for_decl, h, h->hash, INSERT);
- *(struct tree_map **) loc = h;
-}
-
/* Print out the statistics for the DECL_DEBUG_EXPR hash table. */
static void
htab_collisions (value_expr_for_decl));
}
-/* Print out statistics for the RESTRICT_BASE_FOR_DECL hash table, but
- don't print anything if the table is empty. */
-
-static void
-print_restrict_base_statistics (void)
-{
- if (htab_elements (restrict_base_for_decl) != 0)
- fprintf (stderr,
- "RESTRICT_BASE hash: size %ld, %ld elements, %f collisions\n",
- (long) htab_size (restrict_base_for_decl),
- (long) htab_elements (restrict_base_for_decl),
- htab_collisions (restrict_base_for_decl));
-}
-
/* Lookup a debug expression for FROM, and return it if we find one. */
tree
return 1;
}
+/* Return the minimum number of bits needed to represent VALUE in a
+ signed or unsigned type, UNSIGNEDP says which. */
+
+unsigned int
+tree_int_cst_min_precision (tree value, bool unsignedp)
+{
+ int log;
+
+ /* If the value is negative, compute its negative minus 1. The latter
+ adjustment is because the absolute value of the largest negative value
+ is one larger than the largest positive value. This is equivalent to
+ a bit-wise negation, so use that operation instead. */
+
+ if (tree_int_cst_sgn (value) < 0)
+ value = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (value), value);
+
+ /* Return the number of bits needed, taking into account the fact
+ that we need one more bit for a signed than unsigned type. */
+
+ if (integer_zerop (value))
+ log = 0;
+ else
+ log = tree_floor_log2 (value);
+
+ return log + 1 + !unsignedp;
+}
+
/* Compare two constructor-element-type constants. Return 1 if the lists
are known to be equal; otherwise return 0. */
char tclass;
if (t == NULL_TREE)
- return iterative_hash_pointer (t, val);
+ return iterative_hash_hashval_t (0, val);
code = TREE_CODE (t);
case SSA_NAME:
/* we can just compare by pointer. */
- return iterative_hash_pointer (t, val);
+ return iterative_hash_host_wide_int (SSA_NAME_VERSION (t), val);
case TREE_LIST:
/* A list of expressions, for a CALL_EXPR or as the elements of a
return val;
}
case FUNCTION_DECL:
- /* When referring to a built-in FUNCTION_DECL, use the
- __builtin__ form. Otherwise nodes that compare equal
- according to operand_equal_p might get different
- hash codes. */
- if (DECL_BUILT_IN (t))
+ /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
+ Otherwise nodes that compare equal according to operand_equal_p might
+ get different hash codes. However, don't do this for machine specific
+ or front end builtins, since the function code is overloaded in those
+ cases. */
+ if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+ && built_in_decls[DECL_FUNCTION_CODE (t)])
{
- val = iterative_hash_pointer (built_in_decls[DECL_FUNCTION_CODE (t)],
- val);
- return val;
+ t = built_in_decls[DECL_FUNCTION_CODE (t)];
+ code = TREE_CODE (t);
}
- /* else FALL THROUGH */
+ /* FALL THROUGH */
default:
tclass = TREE_CODE_CLASS (code);
t = make_node (POINTER_TYPE);
TREE_TYPE (t) = to_type;
- TYPE_MODE (t) = mode;
+ SET_TYPE_MODE (t, mode);
TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all;
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
TYPE_POINTER_TO (to_type) = t;
t = make_node (REFERENCE_TYPE);
TREE_TYPE (t) = to_type;
- TYPE_MODE (t) = mode;
+ SET_TYPE_MODE (t, mode);
TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all;
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
TYPE_REFERENCE_TO (to_type) = t;
TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
TYPE_MIN_VALUE (itype) = size_zero_node;
TYPE_MAX_VALUE (itype) = fold_convert (sizetype, maxval);
- TYPE_MODE (itype) = TYPE_MODE (sizetype);
+ SET_TYPE_MODE (itype, TYPE_MODE (sizetype));
TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
TYPE_MAX_VALUE (itype) = highval ? fold_convert (type, highval) : NULL;
TYPE_PRECISION (itype) = TYPE_PRECISION (type);
- TYPE_MODE (itype) = TYPE_MODE (type);
+ SET_TYPE_MODE (itype, TYPE_MODE (type));
TYPE_SIZE (itype) = TYPE_SIZE (type);
TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
TYPE_ALIGN (itype) = TYPE_ALIGN (type);
return itype;
}
+/* Return true if the debug information for TYPE, a subtype, should be emitted
+ as a subrange type. If so, set LOWVAL to the low bound and HIGHVAL to the
+ high bound, respectively. Sometimes doing so unnecessarily obfuscates the
+ debug info and doesn't reflect the source code. */
+
+bool
+subrange_type_for_debug_p (const_tree type, tree *lowval, tree *highval)
+{
+ tree base_type = TREE_TYPE (type), low, high;
+
+ /* Subrange types have a base type which is an integral type. */
+ if (!INTEGRAL_TYPE_P (base_type))
+ return false;
+
+ /* Get the real bounds of the subtype. */
+ if (lang_hooks.types.get_subrange_bounds)
+ lang_hooks.types.get_subrange_bounds (type, &low, &high);
+ else
+ {
+ low = TYPE_MIN_VALUE (type);
+ high = TYPE_MAX_VALUE (type);
+ }
+
+ /* If the type and its base type have the same representation and the same
+ name, then the type is not a subrange but a copy of the base type. */
+ if ((TREE_CODE (base_type) == INTEGER_TYPE
+ || TREE_CODE (base_type) == BOOLEAN_TYPE)
+ && int_size_in_bytes (type) == int_size_in_bytes (base_type)
+ && tree_int_cst_equal (low, TYPE_MIN_VALUE (base_type))
+ && tree_int_cst_equal (high, TYPE_MAX_VALUE (base_type)))
+ {
+ tree type_name = TYPE_NAME (type);
+ tree base_type_name = TYPE_NAME (base_type);
+
+ if (type_name && TREE_CODE (type_name) == TYPE_DECL)
+ type_name = DECL_NAME (type_name);
+
+ if (base_type_name && TREE_CODE (base_type_name) == TYPE_DECL)
+ base_type_name = DECL_NAME (base_type_name);
+
+ if (type_name == base_type_name)
+ return false;
+ }
+
+ if (lowval)
+ *lowval = low;
+ if (highval)
+ *highval = high;
+ return true;
+}
+
/* Just like build_index_type, but takes lowval and highval instead
of just highval (maxval). */
else
new_reversed = void_list_node;
}
- gcc_assert (new_reversed);
/* Use copy_node to preserve as much as possible from original type
(debug info, attribute lists etc.)
name = 0;
if (name != 0)
- TYPE_NAME (t) = build_decl (TYPE_DECL, get_identifier (name), t);
+ TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL,
+ get_identifier (name), t);
}
return build_qualified_type (t, TYPE_QUALS (component_type));
}
+
+/* If TYPE is a real or complex floating-point type and the target
+ does not directly support arithmetic on TYPE then return the wider
+ type to be used for arithmetic on TYPE. Otherwise, return
+ NULL_TREE. */
+
+tree
+excess_precision_type (tree type)
+{
+ if (flag_excess_precision != EXCESS_PRECISION_FAST)
+ {
+ int flt_eval_method = TARGET_FLT_EVAL_METHOD;
+ switch (TREE_CODE (type))
+ {
+ case REAL_TYPE:
+ switch (flt_eval_method)
+ {
+ case 1:
+ if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
+ return double_type_node;
+ break;
+ case 2:
+ if (TYPE_MODE (type) == TYPE_MODE (float_type_node)
+ || TYPE_MODE (type) == TYPE_MODE (double_type_node))
+ return long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case COMPLEX_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
+ return NULL_TREE;
+ switch (flt_eval_method)
+ {
+ case 1:
+ if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node))
+ return complex_double_type_node;
+ break;
+ case 2:
+ if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node)
+ || (TYPE_MODE (TREE_TYPE (type))
+ == TYPE_MODE (double_type_node)))
+ return complex_long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return NULL_TREE;
+}
\f
/* Return OP, stripped of any conversions to wider types as much as is safe.
Converting the value back to OP's type makes a value equivalent to OP.
print_type_hash_statistics ();
print_debug_expr_statistics ();
print_value_expr_statistics ();
- print_restrict_base_statistics ();
lang_hooks.print_statistics ();
}
\f
{
char *buffer;
unsigned length = 0;
- enum tree_code c;
+ unsigned int c;
for (c = c1; c <= c2; ++c)
length += 4 + strlen (tree_code_name[c]);
{
char *buffer;
unsigned length = 0;
- enum omp_clause_code c;
+ unsigned int c;
for (c = c1; c <= c2; ++c)
length += 4 + strlen (omp_clause_code_name[c]);
t = make_node (VECTOR_TYPE);
TREE_TYPE (t) = TYPE_MAIN_VARIANT (innertype);
SET_TYPE_VECTOR_SUBPARTS (t, nunits);
- TYPE_MODE (t) = mode;
+ SET_TYPE_MODE (t, mode);
TYPE_READONLY (t) = TYPE_READONLY (innertype);
TYPE_VOLATILE (t) = TYPE_VOLATILE (innertype);
{
tree index = build_int_cst (NULL_TREE, nunits - 1);
- tree array = build_array_type (innertype, build_index_type (index));
+ tree array = build_array_type (TYPE_MAIN_VARIANT (innertype),
+ build_index_type (index));
tree rt = make_node (RECORD_TYPE);
- TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
+ TYPE_FIELDS (rt) = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+ get_identifier ("f"), array);
DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
layout_type (rt);
TYPE_DEBUG_REPRESENTATION_TYPE (t) = rt;
dfloat32_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
layout_type (dfloat32_type_node);
- TYPE_MODE (dfloat32_type_node) = SDmode;
+ SET_TYPE_MODE (dfloat32_type_node, SDmode);
dfloat32_ptr_type_node = build_pointer_type (dfloat32_type_node);
dfloat64_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
layout_type (dfloat64_type_node);
- TYPE_MODE (dfloat64_type_node) = DDmode;
+ SET_TYPE_MODE (dfloat64_type_node, DDmode);
dfloat64_ptr_type_node = build_pointer_type (dfloat64_type_node);
dfloat128_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
layout_type (dfloat128_type_node);
- TYPE_MODE (dfloat128_type_node) = TDmode;
+ SET_TYPE_MODE (dfloat128_type_node, TDmode);
dfloat128_ptr_type_node = build_pointer_type (dfloat128_type_node);
complex_integer_type_node = build_complex_type (integer_type_node);
complex. Further, we can do slightly better with folding these
beasties if the real and complex parts of the arguments are separate. */
{
- enum machine_mode mode;
+ int mode;
for (mode = MIN_MODE_COMPLEX_FLOAT; mode <= MAX_MODE_COMPLEX_FLOAT; ++mode)
{
enum built_in_function mcode, dcode;
tree type, inner_type;
- type = lang_hooks.types.type_for_mode (mode, 0);
+ type = lang_hooks.types.type_for_mode ((enum machine_mode) mode, 0);
if (type == NULL)
continue;
inner_type = TREE_TYPE (type);
tmp = tree_cons (NULL_TREE, inner_type, tmp);
ftype = build_function_type (type, tmp);
- mcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
- dcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+ mcode = ((enum built_in_function)
+ (BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT));
+ dcode = ((enum built_in_function)
+ (BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT));
for (p = GET_MODE_NAME (mode), q = mode_name_buf; *p; p++, q++)
*q = TOLOWER (*p);
return make_vector_type (innertype, nunits, VOIDmode);
}
+/* Similarly, but takes the inner type and number of units, which must be
+ a power of two. */
+
+tree
+build_opaque_vector_type (tree innertype, int nunits)
+{
+ tree t;
+ innertype = build_distinct_type_copy (innertype);
+ t = make_vector_type (innertype, nunits, VOIDmode);
+ TYPE_VECTOR_OPAQUE (t) = true;
+ return t;
+}
+
/* Build RESX_EXPR with given REGION_NUMBER. */
tree
}
}
-/* Build an empty statement. */
+/* Build an empty statement at location LOC. */
tree
-build_empty_stmt (void)
+build_empty_stmt (location_t loc)
{
- return build1 (NOP_EXPR, void_type_node, size_zero_node);
+ tree t = build1 (NOP_EXPR, void_type_node, size_zero_node);
+ SET_EXPR_LOCATION (t, loc);
+ return t;
}
-/* Build an OpenMP clause with code CODE. */
+/* Build an OpenMP clause with code CODE. LOC is the location of the
+ clause. */
tree
-build_omp_clause (enum omp_clause_code code)
+build_omp_clause (location_t loc, enum omp_clause_code code)
{
tree t;
int size, length;
memset (t, 0, size);
TREE_SET_CODE (t, OMP_CLAUSE);
OMP_CLAUSE_SET_CODE (t, code);
+ OMP_CLAUSE_LOCATION (t) = loc;
#ifdef GATHER_STATISTICS
tree_node_counts[(int) omp_clause_kind]++;
return t;
}
-/* Set various status flags when building a CALL_EXPR object T. */
-
-static void
-process_call_operands (tree t)
-{
- bool side_effects;
-
- side_effects = TREE_SIDE_EFFECTS (t);
- if (!side_effects)
- {
- int i, n;
- n = TREE_OPERAND_LENGTH (t);
- for (i = 1; i < n; i++)
- {
- tree op = TREE_OPERAND (t, i);
- if (op && TREE_SIDE_EFFECTS (op))
- {
- side_effects = 1;
- break;
- }
- }
- }
- if (!side_effects)
- {
- int i;
-
- /* Calls have side-effects, except those to const or
- pure functions. */
- i = call_expr_flags (t);
- if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
- side_effects = 1;
- }
- TREE_SIDE_EFFECTS (t) = side_effects;
-}
-
/* Build a tcc_vl_exp object with code CODE and room for LEN operands. LEN
includes the implicit operand count in TREE_OPERAND 0, and so must be >= 1.
Except for the CODE and operand count field, other storage for the
which are specified as a tree array ARGS. */
tree
-build_call_array (tree return_type, tree fn, int nargs, tree *args)
+build_call_array_loc (location_t loc, tree return_type, tree fn,
+ int nargs, const tree *args)
{
tree t;
int i;
for (i = 0; i < nargs; i++)
CALL_EXPR_ARG (t, i) = args[i];
process_call_operands (t);
+ SET_EXPR_LOCATION (t, loc);
return t;
}
+/* Like build_call_array, but takes a VEC. */
+
+tree
+build_call_vec (tree return_type, tree fn, VEC(tree,gc) *args)
+{
+ tree ret, t;
+ unsigned int ix;
+
+ ret = build_vl_exp (CALL_EXPR, VEC_length (tree, args) + 3);
+ TREE_TYPE (ret) = return_type;
+ CALL_EXPR_FN (ret) = fn;
+ CALL_EXPR_STATIC_CHAIN (ret) = NULL_TREE;
+ for (ix = 0; VEC_iterate (tree, args, ix, t); ++ix)
+ CALL_EXPR_ARG (ret, ix) = t;
+ process_call_operands (ret);
+ return ret;
+}
+
/* Returns true if it is possible to prove that the index of
an array access REF (an ARRAY_REF expression) falls into the
return val;
}
+/* Return value of a constant X and sign-extend it. */
+
+HOST_WIDEST_INT
+widest_int_cst_value (const_tree x)
+{
+ unsigned bits = TYPE_PRECISION (TREE_TYPE (x));
+ unsigned HOST_WIDEST_INT val = TREE_INT_CST_LOW (x);
+
+#if HOST_BITS_PER_WIDEST_INT > HOST_BITS_PER_WIDE_INT
+ gcc_assert (HOST_BITS_PER_WIDEST_INT >= 2 * HOST_BITS_PER_WIDE_INT);
+ val |= (((unsigned HOST_WIDEST_INT) TREE_INT_CST_HIGH (x))
+ << HOST_BITS_PER_WIDE_INT);
+#else
+ /* Make sure the sign-extended value will fit in a HOST_WIDE_INT. */
+ gcc_assert (TREE_INT_CST_HIGH (x) == 0
+ || TREE_INT_CST_HIGH (x) == -1);
+#endif
+
+ if (bits < HOST_BITS_PER_WIDEST_INT)
+ {
+ bool negative = ((val >> (bits - 1)) & 1) != 0;
+ if (negative)
+ val |= (~(unsigned HOST_WIDEST_INT) 0) << (bits - 1) << 1;
+ else
+ val &= ~((~(unsigned HOST_WIDEST_INT) 0) << (bits - 1) << 1);
+ }
+
+ return val;
+}
+
/* If TYPE is an integral type, return an equivalent type which is
unsigned iff UNSIGNEDP is true. If TYPE is not an integral type,
return TYPE itself. */
WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len));
}
- case CHANGE_DYNAMIC_TYPE_EXPR:
- WALK_SUBTREE (CHANGE_DYNAMIC_TYPE_NEW_TYPE (*tp));
- WALK_SUBTREE_TAIL (CHANGE_DYNAMIC_TYPE_LOCATION (*tp));
-
case DECL_EXPR:
/* If this is a TYPE_DECL, walk into the fields of the type that it's
defining. We only want to walk into these fields of a type in this
}
-/* Create a nameless artificial label and put it in the current function
- context. Returns the newly created label. */
+/* Create a nameless artificial label and put it in the current
+ function context. The label has a location of LOC. Returns the
+ newly created label. */
tree
-create_artificial_label (void)
+create_artificial_label (location_t loc)
{
- tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
+ tree lab = build_decl (loc,
+ LABEL_DECL, NULL_TREE, void_type_node);
DECL_ARTIFICIAL (lab) = 1;
DECL_IGNORED_P (lab) = 1;
return (t != NULL_TREE);
}
-/* Return the number of arguments that a function has. */
-
-int
-function_args_count (tree fntype)
-{
- function_args_iterator args_iter;
- tree t;
- int num = 0;
-
- if (fntype)
- {
- FOREACH_FUNCTION_ARGS(fntype, t, args_iter)
- {
- num++;
- }
- }
-
- return num;
-}
-
/* If BLOCK is inlined from an __attribute__((__artificial__))
routine, return pointer to location from where it has been
called. */
return ret;
}
+
+/* If EXP is inlined from an __attribute__((__artificial__))
+ function, return the location of the original call expression. */
+
+location_t
+tree_nonartificial_location (tree exp)
+{
+ location_t *loc = block_nonartificial_location (TREE_BLOCK (exp));
+
+ if (loc)
+ return *loc;
+ else
+ return EXPR_LOCATION (exp);
+}
+
+
/* These are the hash table functions for the hash table of OPTIMIZATION_NODEq
nodes. */
return t;
}
+/* Determine the "ultimate origin" of a block. The block may be an inlined
+ instance of an inlined instance of a block which is local to an inline
+ function, so we have to trace all of the way back through the origin chain
+ to find out what sort of node actually served as the original seed for the
+ given block. */
+
+tree
+block_ultimate_origin (const_tree block)
+{
+ tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+
+ /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
+ nodes in the function to point to themselves; ignore that if
+ we're trying to output the abstract instance of this function. */
+ if (BLOCK_ABSTRACT (block) && immediate_origin == block)
+ return NULL_TREE;
+
+ if (immediate_origin == NULL_TREE)
+ return NULL_TREE;
+ else
+ {
+ tree ret_val;
+ tree lookahead = immediate_origin;
+
+ do
+ {
+ ret_val = lookahead;
+ lookahead = (TREE_CODE (ret_val) == BLOCK
+ ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
+ }
+ while (lookahead != NULL && lookahead != ret_val);
+
+ /* The block's abstract origin chain may not be the *ultimate* origin of
+ the block. It could lead to a DECL that has an abstract origin set.
+ If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
+ will give us if it has one). Note that DECL's abstract origins are
+ supposed to be the most distant ancestor (or so decl_ultimate_origin
+ claims), so we don't need to loop following the DECL origins. */
+ if (DECL_P (ret_val))
+ return DECL_ORIGIN (ret_val);
+
+ return ret_val;
+ }
+}
+
+/* Return true if T1 and T2 are equivalent lists. */
+
+bool
+list_equal_p (const_tree t1, const_tree t2)
+{
+ for (; t1 && t2; t1 = TREE_CHAIN (t1) , t2 = TREE_CHAIN (t2))
+ if (TREE_VALUE (t1) != TREE_VALUE (t2))
+ return false;
+ return !t1 && !t2;
+}
+
+/* Return true iff conversion in EXP generates no instruction. Mark
+ it inline so that we fully inline into the stripping functions even
+ though we have two uses of this function. */
+
+static inline bool
+tree_nop_conversion (const_tree exp)
+{
+ tree outer_type, inner_type;
+
+ if (!CONVERT_EXPR_P (exp)
+ && TREE_CODE (exp) != NON_LVALUE_EXPR)
+ return false;
+ if (TREE_OPERAND (exp, 0) == error_mark_node)
+ return false;
+
+ outer_type = TREE_TYPE (exp);
+ inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+ /* Use precision rather then machine mode when we can, which gives
+ the correct answer even for submode (bit-field) types. */
+ if ((INTEGRAL_TYPE_P (outer_type)
+ || POINTER_TYPE_P (outer_type)
+ || TREE_CODE (outer_type) == OFFSET_TYPE)
+ && (INTEGRAL_TYPE_P (inner_type)
+ || POINTER_TYPE_P (inner_type)
+ || TREE_CODE (inner_type) == OFFSET_TYPE))
+ return TYPE_PRECISION (outer_type) == TYPE_PRECISION (inner_type);
+
+ /* Otherwise fall back on comparing machine modes (e.g. for
+ aggregate types, floats). */
+ return TYPE_MODE (outer_type) == TYPE_MODE (inner_type);
+}
+
+/* Return true iff conversion in EXP generates no instruction. Don't
+ consider conversions changing the signedness. */
+
+static bool
+tree_sign_nop_conversion (const_tree exp)
+{
+ tree outer_type, inner_type;
+
+ if (!tree_nop_conversion (exp))
+ return false;
+
+ outer_type = TREE_TYPE (exp);
+ inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+ return (TYPE_UNSIGNED (outer_type) == TYPE_UNSIGNED (inner_type)
+ && POINTER_TYPE_P (outer_type) == POINTER_TYPE_P (inner_type));
+}
+
+/* Strip conversions from EXP according to tree_nop_conversion and
+ return the resulting expression. */
+
+tree
+tree_strip_nop_conversions (tree exp)
+{
+ while (tree_nop_conversion (exp))
+ exp = TREE_OPERAND (exp, 0);
+ return exp;
+}
+
+/* Strip conversions from EXP according to tree_sign_nop_conversion
+ and return the resulting expression. */
+
+tree
+tree_strip_sign_nop_conversions (tree exp)
+{
+ while (tree_sign_nop_conversion (exp))
+ exp = TREE_OPERAND (exp, 0);
+ return exp;
+}
+
+
#include "gt-tree.h"