/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010 Free Software Foundation, Inc.
This file is part of GCC.
static GTY(()) section *unnamed_sections;
/* Return a nonzero value if DECL has a section attribute. */
-#ifndef IN_NAMED_SECTION
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
-#endif
/* Hash table of named sections. */
static GTY((param_is (section))) htab_t section_htab;
unsigned plen = strlen (prefix);
unsigned nlen = strlen (IDENTIFIER_POINTER (name));
char *toname = (char *) alloca (plen + nlen + 1);
-
+
memcpy (toname, prefix, plen);
memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
{
tree word_type_node, field, next_field;
-
+
field = build_decl (UNKNOWN_LOCATION,
FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
DECL_CONTEXT (field) = type;
next_field = field;
-
+
field = build_decl (UNKNOWN_LOCATION,
FIELD_DECL, get_identifier ("__offset"),
ptr_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
next_field = field;
-
+
word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
field = build_decl (UNKNOWN_LOCATION,
FIELD_DECL, get_identifier ("__align"),
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
next_field = field;
-
+
field = build_decl (UNKNOWN_LOCATION,
FIELD_DECL, get_identifier ("__size"), word_type_node);
DECL_CONTEXT (field) = type;
get_emutls_init_templ_addr (tree decl)
{
tree name, to;
-
+
if (targetm.emutls.register_common && !DECL_INITIAL (decl)
&& !DECL_SECTION_NAME (decl))
return null_pointer_node;
DECL_IGNORED_P (to) = 1;
DECL_CONTEXT (to) = DECL_CONTEXT (decl);
DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
-
+
DECL_WEAK (to) = DECL_WEAK (decl);
if (DECL_ONE_ONLY (decl))
{
htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
if (body == NULL_TREE)
return;
-
+
cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
}
}
static section *
get_variable_section (tree decl, bool prefer_noswitch_p)
{
+ addr_space_t as = ADDR_SPACE_GENERIC;
int reloc;
- /* If the decl has been given an explicit section name, then it
- isn't common, and shouldn't be handled as such. */
- if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
+ if (TREE_TYPE (decl) != error_mark_node)
+ as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
+
+ if (DECL_COMMON (decl))
{
+ /* If the decl has been given an explicit section name, or it resides
+ in a non-generic address space, then it isn't common, and shouldn't
+ be handled as such. */
+ gcc_assert (DECL_SECTION_NAME (decl) == NULL
+ && ADDR_SPACE_GENERIC_P (as));
if (DECL_THREAD_LOCAL_P (decl))
return tls_comm_section;
/* This cannot be common bss for an emulated TLS object without
if (IN_NAMED_SECTION (decl))
return get_named_section (decl, NULL, reloc);
- if (!DECL_THREAD_LOCAL_P (decl)
+ if (ADDR_SPACE_GENERIC_P (as)
+ && !DECL_THREAD_LOCAL_P (decl)
&& !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
&& bss_initializer_p (decl))
{
return;
}
+ /* If this variable belongs to the global constant pool, retrieve the
+ pre-computed RTL or recompute it in LTO mode. */
+ if (TREE_CODE (decl) == VAR_DECL && DECL_IN_CONSTANT_POOL (decl))
+ {
+ SET_DECL_RTL (decl, output_constant_def (DECL_INITIAL (decl), 1));
+ return;
+ }
+
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
/* Specifying a section attribute on a variable forces it into a
non-.bss section, and thus it cannot be common. */
+ /* FIXME: In general this code should not be necessary because
+ visibility pass is doing the same work. But notice_global_symbol
+ is called early and it needs to make DECL_RTL to get the name.
+ we take care of recomputing the DECL_RTL after visibility is changed. */
if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
&& DECL_INITIAL (decl) == NULL_TREE
if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
x = create_block_symbol (name, get_block_for_decl (decl), -1);
else
- x = gen_rtx_SYMBOL_REF (Pmode, name);
+ {
+ enum machine_mode address_mode = Pmode;
+ if (TREE_TYPE (decl) != error_mark_node)
+ {
+ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
+ address_mode = targetm.addr_space.address_mode (as);
+ }
+ x = gen_rtx_SYMBOL_REF (address_mode, name);
+ }
SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
SET_SYMBOL_REF_DECL (x, decl);
if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
mudflap_enqueue_decl (decl);
}
+
+/* Like make_decl_rtl, but inhibit creation of new alias sets when
+ calling make_decl_rtl. Also, reset DECL_RTL before returning the
+ rtl. */
+
+rtx
+make_decl_rtl_for_debug (tree decl)
+{
+ unsigned int save_aliasing_flag, save_mudflap_flag;
+ rtx rtl;
+
+ if (DECL_RTL_SET_P (decl))
+ return DECL_RTL (decl);
+
+ /* Kludge alert! Somewhere down the call chain, make_decl_rtl will
+ call new_alias_set. If running with -fcompare-debug, sometimes
+ we do not want to create alias sets that will throw the alias
+ numbers off in the comparison dumps. So... clearing
+ flag_strict_aliasing will keep new_alias_set() from creating a
+ new set. It is undesirable to register decl with mudflap
+ in this case as well. */
+ save_aliasing_flag = flag_strict_aliasing;
+ flag_strict_aliasing = 0;
+ save_mudflap_flag = flag_mudflap;
+ flag_mudflap = 0;
+
+ rtl = DECL_RTL (decl);
+ /* Reset DECL_RTL back, as various parts of the compiler expects
+ DECL_RTL set meaning it is actually going to be output. */
+ SET_DECL_RTL (decl, NULL);
+
+ flag_strict_aliasing = save_aliasing_flag;
+ flag_mudflap = save_mudflap_flag;
+
+ return rtl;
+}
\f
/* Output a string of literal assembler code
for an `asm' keyword used between functions. */
}
/* Write the address of the entity given by SYMBOL to SEC. */
-void
+void
assemble_addr_to_section (rtx symbol, section *sec)
{
switch_to_section (sec);
section *sec;
if (priority != DEFAULT_INIT_PRIORITY)
- sec = get_cdtor_priority_section (priority,
+ sec = get_cdtor_priority_section (priority,
/*constructor_p=*/false);
else
sec = get_section (".dtors", SECTION_WRITE, NULL);
section *sec;
if (priority != DEFAULT_INIT_PRIORITY)
- sec = get_cdtor_priority_section (priority,
+ sec = get_cdtor_priority_section (priority,
/*constructor_p=*/true);
else
sec = get_section (".ctors", SECTION_WRITE, NULL);
constructor_elt *elt;
tree type = TREE_TYPE (to);
tree field = TYPE_FIELDS (type);
-
+
elt = VEC_quick_push (constructor_elt, v, NULL);
elt->index = field;
elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
+
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = build_int_cst (TREE_TYPE (field),
DECL_ALIGN_UNIT (decl));
-
+
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = null_pointer_node;
-
+
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = proxy;
-
+
return build_constructor (type, v);
}
Without this, if the variable is placed in a
section-anchored block, the template will only be marked
when it's too late. */
- record_references_in_initializer (to);
+ record_references_in_initializer (to, false);
}
decl = to;
if (flag_syntax_only)
return;
- app_disable ();
-
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
gcc_assert (MEM_P (decl_rtl));
gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
symbol = XEXP (decl_rtl, 0);
+
+ /* If this symbol belongs to the tree constant pool, output the constant
+ if it hasn't already been written. */
+ if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ tree decl = SYMBOL_REF_DECL (symbol);
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
+ output_constant_def_contents (symbol);
+ return;
+ }
+
+ app_disable ();
+
name = XSTR (symbol, 0);
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
notice_global_symbol (decl);
/* We want to output annotation for weak and external symbols at
very last to check if they are references or not. */
- if (SUPPORTS_WEAK && DECL_WEAK (decl)
+ if (SUPPORTS_WEAK
+ && DECL_WEAK (decl)
/* TREE_STATIC is a weird and abused creature which is not
generally the right test for whether an entity has been
locally emitted, inlined or otherwise not-really-extern, but
for declarations that can be weak, it happens to be
match. */
&& !TREE_STATIC (decl)
+ && lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
&& value_member (decl, weak_decls) == NULL_TREE)
weak_decls = tree_cons (NULL, decl, weak_decls);
{
if (TREE_CODE (target) == COMPONENT_REF
&& host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
-
{
offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
* tree_low_cst (TREE_OPERAND (target, 1), 0));
target = TREE_OPERAND (target, 0);
}
+ else if (TREE_CODE (target) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (target, 0)) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (target, 0), 0))
+ == ADDR_EXPR)
+ target = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (target, 0), 0), 0);
else
break;
}
static GTY((param_is (struct constant_descriptor_tree)))
htab_t const_desc_htab;
-static struct constant_descriptor_tree * build_constant_desc (tree);
static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
/* Constant pool accessor function. */
-htab_t
+htab_t
constant_pool_htab (void)
{
return const_desc_htab;
return (const_hash_1 (TREE_REALPART (exp)) * 5
+ const_hash_1 (TREE_IMAGPART (exp)));
+ case VECTOR_CST:
+ {
+ tree link;
+
+ hi = 7 + TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp));
+
+ for (link = TREE_VECTOR_CST_ELTS (exp); link; link = TREE_CHAIN (link))
+ hi = hi * 563 + const_hash_1 (TREE_VALUE (link));
+
+ return hi;
+ }
+
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT idx;
return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
&& compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
+ case VECTOR_CST:
+ {
+ tree link1, link2;
+
+ if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2)))
+ return 0;
+
+ link2 = TREE_VECTOR_CST_ELTS (t2);
+ for (link1 = TREE_VECTOR_CST_ELTS (t1);
+ link1;
+ link1 = TREE_CHAIN (link1))
+ {
+ if (!compare_constant (TREE_VALUE (link1), TREE_VALUE (link2)))
+ return 0;
+ link2 = TREE_CHAIN (link2);
+ }
+
+ return 1;
+ }
+
case CONSTRUCTOR:
{
VEC(constructor_elt, gc) *v1, *v2;
case FDESC_EXPR:
{
struct addr_const value1, value2;
+ enum rtx_code code;
+ int ret;
decode_addr_const (t1, &value1);
decode_addr_const (t2, &value2);
- return (value1.offset == value2.offset
- && strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+
+ if (value1.offset != value2.offset)
+ return 0;
+
+ code = GET_CODE (value1.base);
+ if (code != GET_CODE (value2.base))
+ return 0;
+
+ switch (code)
+ {
+ case SYMBOL_REF:
+ ret = (strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+ break;
+
+ case LABEL_REF:
+ ret = (CODE_LABEL_NUMBER (XEXP (value1.base, 0))
+ == CODE_LABEL_NUMBER (XEXP (value2.base, 0)));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return ret;
}
case PLUS_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
+ case VECTOR_CST:
+ return build_vector (TREE_TYPE (exp),
+ copy_list (TREE_VECTOR_CST_ELTS (exp)));
+
case CONSTRUCTOR:
{
tree copy = copy_node (exp);
}
}
\f
-/* Return the alignment of constant EXP in bits. */
-
-static unsigned int
-get_constant_alignment (tree exp)
-{
- unsigned int align;
-
- align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
- align = CONSTANT_ALIGNMENT (exp, align);
-#endif
- return align;
-}
-
/* Return the section into which constant EXP should be placed. */
static section *
-get_constant_section (tree exp)
+get_constant_section (tree exp, unsigned int align)
{
- if (IN_NAMED_SECTION (exp))
- return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
- else
- return targetm.asm_out.select_section (exp,
- compute_reloc_for_constant (exp),
- get_constant_alignment (exp));
+ return targetm.asm_out.select_section (exp,
+ compute_reloc_for_constant (exp),
+ align);
}
/* Return the size of constant EXP in bytes. */
static struct constant_descriptor_tree *
build_constant_desc (tree exp)
{
- rtx symbol;
- rtx rtl;
+ struct constant_descriptor_tree *desc;
+ rtx symbol, rtl;
char label[256];
int labelno;
- struct constant_descriptor_tree *desc;
+ tree decl;
desc = GGC_NEW (struct constant_descriptor_tree);
desc->value = copy_constant (exp);
labelno = const_labelno++;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
- /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
+ /* Construct the VAR_DECL associated with the constant. */
+ decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label),
+ TREE_TYPE (exp));
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_ADDRESSABLE (decl) = 1;
+ /* We don't set the RTL yet as this would cause varpool to assume that the
+ variable is referenced. Moreover, it would just be dropped in LTO mode.
+ Instead we set the flag that will be recognized in make_decl_rtl. */
+ DECL_IN_CONSTANT_POOL (decl) = 1;
+ DECL_INITIAL (decl) = desc->value;
+ /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most
+ architectures so use DATA_ALIGNMENT as well, except for strings. */
+ if (TREE_CODE (exp) == STRING_CST)
+ {
+#ifdef CONSTANT_ALIGNMENT
+ DECL_ALIGN (decl) = CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl));
+#endif
+ }
+ else
+ align_variable (decl, 0);
+
+ /* Now construct the SYMBOL_REF and the MEM. */
if (use_object_blocks_p ())
{
- section *sect = get_constant_section (exp);
+ section *sect = get_constant_section (exp, DECL_ALIGN (decl));
symbol = create_block_symbol (ggc_strdup (label),
get_block_for_section (sect), -1);
}
else
symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
- SET_SYMBOL_REF_DECL (symbol, desc->value);
+ SET_SYMBOL_REF_DECL (symbol, decl);
TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
ASM_OUTPUT_LABELREF will have to know how to strip this
information. This call might invalidate our local variable
SYMBOL; we can't use it afterward. */
-
targetm.encode_section_info (exp, rtl, true);
desc->rtl = rtl;
static void
output_constant_def_contents (rtx symbol)
{
- tree exp = SYMBOL_REF_DECL (symbol);
+ tree decl = SYMBOL_REF_DECL (symbol);
+ tree exp = DECL_INITIAL (decl);
unsigned int align;
/* Make sure any other constants whose addresses appear in EXP
place_block_symbol (symbol);
else
{
- switch_to_section (get_constant_section (exp));
- align = get_constant_alignment (exp);
+ align = DECL_ALIGN (decl);
+ switch_to_section (get_constant_section (exp, align));
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_constant_contents (exp, XSTR (symbol, 0), align);
return (desc ? desc->rtl : NULL_RTX);
}
+
+/* Return a tree representing a reference to constant data in memory
+ for the constant expression EXP.
+
+ This is the counterpart of output_constant_def at the Tree level. */
+
+tree
+tree_output_constant_def (tree exp)
+{
+ struct constant_descriptor_tree *desc, key;
+ void **loc;
+ tree decl;
+
+ /* Look up EXP in the table of constant descriptors. If we didn't find
+ it, create a new one. */
+ key.value = exp;
+ key.hash = const_hash_1 (exp);
+ loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
+
+ desc = (struct constant_descriptor_tree *) *loc;
+ if (desc == 0)
+ {
+ desc = build_constant_desc (exp);
+ desc->hash = key.hash;
+ *loc = desc;
+ }
+
+ decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
+ varpool_finalize_decl (decl);
+ return decl;
+}
\f
/* Used in the hash tables to avoid outputting the same constant
twice. Unlike 'struct constant_descriptor_tree', RTX constants
}
else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
{
- tree exp = SYMBOL_REF_DECL (x);
- if (!TREE_ASM_WRITTEN (exp))
+ tree decl = SYMBOL_REF_DECL (x);
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
{
n_deferred_constants--;
output_constant_def_contents (x);
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
}
+static tree initializer_constant_valid_p_1 (tree value, tree endtype,
+ tree *cache);
+
/* A subroutine of initializer_constant_valid_p. VALUE is a MINUS_EXPR,
PLUS_EXPR or POINTER_PLUS_EXPR. This looks for cases of VALUE
which are valid when ENDTYPE is an integer of any size; in
returns NULL. */
static tree
-narrowing_initializer_constant_valid_p (tree value, tree endtype)
+narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache)
{
tree op0, op1;
op1 = inner;
}
- op0 = initializer_constant_valid_p (op0, endtype);
- op1 = initializer_constant_valid_p (op1, endtype);
+ op0 = initializer_constant_valid_p_1 (op0, endtype, cache);
+ if (!op0)
+ return NULL_TREE;
+ op1 = initializer_constant_valid_p_1 (op1, endtype,
+ cache ? cache + 2 : NULL);
/* Both initializers must be known. */
- if (op0 && op1)
+ if (op1)
{
if (op0 == op1
&& (op0 == null_pointer_node
return NULL_TREE;
}
-/* Return nonzero if VALUE is a valid constant-valued expression
+/* Helper function of initializer_constant_valid_p.
+ Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
if it is relocatable, return the variable that determines the relocation.
We assume that VALUE has been folded as much as possible;
therefore, we do not need to check for such things as
- arithmetic-combinations of integers. */
+ arithmetic-combinations of integers.
-tree
-initializer_constant_valid_p (tree value, tree endtype)
+ Use CACHE (pointer to 2 tree values) for caching if non-NULL. */
+
+static tree
+initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
{
tree ret;
tree elt;
bool absolute = true;
+ if (cache && cache[0] == value)
+ return cache[1];
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
{
tree reloc;
- reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
+ reloc = initializer_constant_valid_p_1 (elt, TREE_TYPE (elt),
+ NULL);
if (!reloc)
- return NULL_TREE;
+ {
+ if (cache)
+ {
+ cache[0] = value;
+ cache[1] = NULL_TREE;
+ }
+ return NULL_TREE;
+ }
if (reloc != null_pointer_node)
absolute = false;
}
/* For a non-absolute relocation, there is no single
variable that can be "the variable that determines the
relocation." */
+ if (cache)
+ {
+ cache[0] = value;
+ cache[1] = absolute ? null_pointer_node : error_mark_node;
+ }
return absolute ? null_pointer_node : error_mark_node;
}
}
case NON_LVALUE_EXPR:
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+ return initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+ endtype, cache);
case VIEW_CONVERT_EXPR:
{
if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type))
{
if (TYPE_MODE (endtype) == TYPE_MODE (dest_type))
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
else
return NULL_TREE;
}
/* Allow all other kinds of view-conversion. */
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
}
CASE_CONVERT:
|| (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
|| (TREE_CODE (dest_type) == OFFSET_TYPE
&& TREE_CODE (src_type) == OFFSET_TYPE))
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
/* Allow length-preserving conversions between integer types. */
if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
&& (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
/* Allow conversions between other integer types only if
explicit value. */
if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
{
- tree inner = initializer_constant_valid_p (src, endtype);
+ tree inner = initializer_constant_valid_p_1 (src, endtype, cache);
if (inner == null_pointer_node)
return null_pointer_node;
break;
/* Allow (int) &foo provided int is as wide as a pointer. */
if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
&& (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
/* Likewise conversions from int to pointers, but also allow
conversions from 0. */
if (integer_zerop (src))
return null_pointer_node;
else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
}
/* Allow conversions to struct or union types if the value
inside is okay. */
if (TREE_CODE (dest_type) == RECORD_TYPE
|| TREE_CODE (dest_type) == UNION_TYPE)
- return initializer_constant_valid_p (src, endtype);
+ return initializer_constant_valid_p_1 (src, endtype, cache);
}
break;
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
+ /* Any valid floating-point constants will have been folded by now;
+ with -frounding-math we hit this with addition of two constants. */
+ if (TREE_CODE (endtype) == REAL_TYPE)
+ return NULL_TREE;
+ if (cache && cache[0] == value)
+ return cache[1];
if (! INTEGRAL_TYPE_P (endtype)
- || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value)))
{
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
+ tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+ tree valid0
+ = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+ endtype, ncache);
+ tree valid1
+ = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
+ endtype, ncache + 2);
/* If either term is absolute, use the other term's relocation. */
if (valid0 == null_pointer_node)
- return valid1;
- if (valid1 == null_pointer_node)
- return valid0;
+ ret = valid1;
+ else if (valid1 == null_pointer_node)
+ ret = valid0;
+ /* Support narrowing pointer differences. */
+ else
+ ret = narrowing_initializer_constant_valid_p (value, endtype,
+ ncache);
}
-
+ else
/* Support narrowing pointer differences. */
- ret = narrowing_initializer_constant_valid_p (value, endtype);
- if (ret != NULL_TREE)
- return ret;
-
- break;
+ ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
+ if (cache)
+ {
+ cache[0] = value;
+ cache[1] = ret;
+ }
+ return ret;
case MINUS_EXPR:
+ if (TREE_CODE (endtype) == REAL_TYPE)
+ return NULL_TREE;
+ if (cache && cache[0] == value)
+ return cache[1];
if (! INTEGRAL_TYPE_P (endtype)
- || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value)))
{
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
+ tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+ tree valid0
+ = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
+ endtype, ncache);
+ tree valid1
+ = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
+ endtype, ncache + 2);
/* Win if second argument is absolute. */
if (valid1 == null_pointer_node)
- return valid0;
+ ret = valid0;
/* Win if both arguments have the same relocation.
Then the value is absolute. */
- if (valid0 == valid1 && valid0 != 0)
- return null_pointer_node;
-
+ else if (valid0 == valid1 && valid0 != 0)
+ ret = null_pointer_node;
/* Since GCC guarantees that string constants are unique in the
generated code, a subtraction between two copies of the same
constant string is absolute. */
- if (valid0 && TREE_CODE (valid0) == STRING_CST
- && valid1 && TREE_CODE (valid1) == STRING_CST
- && operand_equal_p (valid0, valid1, 1))
- return null_pointer_node;
+ else if (valid0 && TREE_CODE (valid0) == STRING_CST
+ && valid1 && TREE_CODE (valid1) == STRING_CST
+ && operand_equal_p (valid0, valid1, 1))
+ ret = null_pointer_node;
+ /* Support narrowing differences. */
+ else
+ ret = narrowing_initializer_constant_valid_p (value, endtype,
+ ncache);
}
-
- /* Support narrowing differences. */
- ret = narrowing_initializer_constant_valid_p (value, endtype);
- if (ret != NULL_TREE)
- return ret;
-
- break;
+ else
+ /* Support narrowing differences. */
+ ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
+ if (cache)
+ {
+ cache[0] = value;
+ cache[1] = ret;
+ }
+ return ret;
default:
break;
}
- return 0;
+ return NULL_TREE;
+}
+
+/* Return nonzero if VALUE is a valid constant-valued expression
+ for use in initializing a static variable; one that can be an
+ element of a "constant" initializer.
+
+ Return null_pointer_node if the value is absolute;
+ if it is relocatable, return the variable that determines the relocation.
+ We assume that VALUE has been folded as much as possible;
+ therefore, we do not need to check for such things as
+ arithmetic-combinations of integers. */
+tree
+initializer_constant_valid_p (tree value, tree endtype)
+{
+ return initializer_constant_valid_p_1 (value, endtype, NULL);
}
\f
/* Return true if VALUE is a valid constant-valued expression
resolving it. */
if (TREE_CODE (exp) == NOP_EXPR
&& POINTER_TYPE_P (TREE_TYPE (exp))
- && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ && targetm.addr_space.valid_pointer_mode
+ (TYPE_MODE (TREE_TYPE (exp)),
+ TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)))))
{
tree saved_type = TREE_TYPE (exp);
pointer modes. */
while (TREE_CODE (exp) == NOP_EXPR
&& POINTER_TYPE_P (TREE_TYPE (exp))
- && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ && targetm.addr_space.valid_pointer_mode
+ (TYPE_MODE (TREE_TYPE (exp)),
+ TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)))))
exp = TREE_OPERAND (exp, 0);
/* If what we're left with is the address of something, we can
else if (TREE_CODE (exp) == INTEGER_CST)
exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
TREE_INT_CST_HIGH (exp));
-
+
}
/* Eliminate any conversions since we'll be outputting the underlying
case REAL_TYPE:
if (TREE_CODE (exp) != REAL_CST)
error ("initializer for floating value is not a floating constant");
-
- assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), align);
+ else
+ assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), align);
break;
case COMPLEX_TYPE:
unsigned int align2
= min_align (local->align, fieldsize * BITS_PER_UNIT);
-
+
for (index = lo_index; index <= hi_index; index++)
{
/* Output the element's initial value. */
assemble_zeros (fieldsize);
else
output_constant (local->val, fieldsize, align2);
-
+
/* Count its size. */
local->total_bytes += fieldsize;
}
if (local->index != NULL_TREE)
fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
- * ((tree_low_cst (local->index, 0)
+ * ((tree_low_cst (local->index, 0)
- tree_low_cst (local->min_index, 0))));
- else if (local->field != NULL_TREE)
+ else if (local->field != NULL_TREE)
fieldpos = int_byte_position (local->field);
else
- fieldpos = 0;
+ fieldpos = 0;
/* Output any buffered-up bit-fields preceding this element. */
if (local->byte_buffer_in_use)
local->total_bytes++;
local->byte_buffer_in_use = false;
}
-
+
/* Advance to offset of this element.
Note no alignment needed in an array, since that is guaranteed
if each element has the proper size. */
assemble_zeros (fieldpos - local->total_bytes);
local->total_bytes = fieldpos;
}
-
+
/* Find the alignment of this element. */
align2 = min_align (local->align, BITS_PER_UNIT * fieldpos);
if (local->field)
{
fieldsize = 0;
-
+
/* If this is an array with an unspecified upper bound,
the initializer determines the size. */
/* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
-
+
/* Output the element's initial value. */
if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
HOST_WIDE_INT relative_index
= (!local->field
? (local->index
- ? (tree_low_cst (local->index, 0)
+ ? (tree_low_cst (local->index, 0)
- tree_low_cst (local->min_index, 0))
: local->last_relative_index + 1)
: 0);
-
+
/* Bit position of this element from the start of the containing
constructor. */
HOST_WIDE_INT constructor_relative_ebitpos
= (local->field
- ? int_bit_position (local->field)
+ ? int_bit_position (local->field)
: ebitsize * relative_index);
-
+
/* Bit position of this element from the start of a possibly ongoing
outer byte buffer. */
HOST_WIDE_INT byte_relative_ebitpos
= ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos);
- /* From the start of a possibly ongoing outer byte buffer, offsets to
+ /* From the start of a possibly ongoing outer byte buffer, offsets to
the first bit of this element and to the first bit past the end of
this element. */
HOST_WIDE_INT next_offset = byte_relative_ebitpos;
HOST_WIDE_INT end_offset = byte_relative_ebitpos + ebitsize;
-
+
local->last_relative_index = relative_index;
-
+
if (local->val == NULL_TREE)
local->val = integer_zero_node;
-
+
while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
|| TREE_CODE (local->val) == NON_LVALUE_EXPR)
local->val = TREE_OPERAND (local->val, 0);
-
+
if (TREE_CODE (local->val) != INTEGER_CST
&& TREE_CODE (local->val) != CONSTRUCTOR)
{
local->total_bytes++;
local->byte_buffer_in_use = false;
}
-
+
/* If still not at proper byte, advance to there. */
if (next_offset / BITS_PER_UNIT != local->total_bytes)
{
local->total_bytes = next_offset / BITS_PER_UNIT;
}
}
-
+
/* Set up the buffer if necessary. */
if (!local->byte_buffer_in_use)
{
if (ebitsize > 0)
local->byte_buffer_in_use = true;
}
-
+
/* If this is nested constructor, recurse passing the bit offset and the
pending data, then retrieve the new pending data afterwards. */
if (TREE_CODE (local->val) == CONSTRUCTOR)
local->byte = output_state.byte;
return;
}
-
+
/* Otherwise, we must split the element into pieces that fall within
separate bytes, and combine each byte with previous or following
- bit-fields. */
+ bit-fields. */
while (next_offset < end_offset)
{
int this_time;
HOST_WIDE_INT value;
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
-
+
/* Advance from byte to byte
within this element when necessary. */
while (next_byte != local->total_bytes)
local->total_bytes++;
local->byte = 0;
}
-
+
/* Number of bits we can process at once
(all part of the same byte). */
this_time = MIN (end_offset - next_offset,
first (of the bits that are significant)
and put them into bytes from the most significant end. */
shift = end_offset - next_offset - this_time;
-
+
/* Don't try to take a bunch of bits that cross
the word boundary in the INTEGER_CST. We can
only select bits from the LOW or HIGH part
this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
shift = HOST_BITS_PER_WIDE_INT;
}
-
+
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (local->val);
value = TREE_INT_CST_HIGH (local->val);
shift -= HOST_BITS_PER_WIDE_INT;
}
-
+
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
local->byte |= (((value >> shift)
and pack them starting at the least significant
bits of the bytes. */
shift = next_offset - byte_relative_ebitpos;
-
+
/* Don't try to take a bunch of bits that cross
the word boundary in the INTEGER_CST. We can
only select bits from the LOW or HIGH part
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
this_time = (HOST_BITS_PER_WIDE_INT - shift);
-
+
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (local->val);
value = TREE_INT_CST_HIGH (local->val);
shift -= HOST_BITS_PER_WIDE_INT;
}
-
+
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
local->byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< next_bit);
}
-
+
next_offset += this_time;
local->byte_buffer_in_use = true;
}
if (TREE_CODE (local.type) == ARRAY_TYPE
&& TYPE_DOMAIN (local.type) != NULL_TREE)
local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
-
+
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
/* As CE goes through the elements of the constant, FIELD goes through the
&& (local.field == NULL_TREE
|| !CONSTRUCTOR_BITFIELD_P (local.field)))
output_constructor_regular_field (&local);
-
+
/* For a true bitfield or part of an outer one. */
else
output_constructor_bitfield (&local, outer);
local.total_bytes = local.size;
}
}
-
+
return local.total_bytes;
}
warning (0, "weak declaration of %q+D not supported", decl);
mark_weak (decl);
+ if (!lookup_attribute ("weak", DECL_ATTRIBUTES (decl)))
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("weak"), NULL, DECL_ATTRIBUTES (decl));
}
static void
if (TREE_ASM_WRITTEN (decl))
return;
+ /* We must force creation of DECL_RTL for debug info generation, even though
+ we don't use it here. */
+ make_decl_rtl (decl);
+
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
# endif
#endif
}
-
- /* We must force creation of DECL_RTL for debug info generation, even though
- we don't use it here. */
- make_decl_rtl (decl);
TREE_USED (decl) = 1;
/* A quirk of the initial implementation of aliases required that the user
the visibility type VIS, which must not be VISIBILITY_DEFAULT. */
void
-default_assemble_visibility (tree decl, int vis)
+default_assemble_visibility (tree decl ATTRIBUTE_UNUSED,
+ int vis ATTRIBUTE_UNUSED)
{
+#ifdef HAVE_GAS_HIDDEN
static const char * const visibility_types[] = {
NULL, "protected", "hidden", "internal"
};
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
type = visibility_types[vis];
-#ifdef HAVE_GAS_HIDDEN
fprintf (asm_out_file, "\t.%s\t", type);
assemble_name (asm_out_file, name);
fprintf (asm_out_file, "\n");
gcc_unreachable ();
}
+#ifndef TLS_SECTION_ASM_FLAG
+#define TLS_SECTION_ASM_FLAG 'T'
+#endif
+
void
default_elf_asm_named_section (const char *name, unsigned int flags,
tree decl ATTRIBUTE_UNUSED)
if (flags & SECTION_STRINGS)
*f++ = 'S';
if (flags & SECTION_TLS)
- *f++ = 'T';
+ *f++ = TLS_SECTION_ASM_FLAG;
if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
*f++ = 'G';
*f = '\0';
/* If we're using one_only, then there needs to be a .gnu.linkonce
prefix to the section name. */
linkonce = one_only ? ".gnu.linkonce" : "";
-
+
string = ACONCAT ((linkonce, prefix, ".", name, NULL));
DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
return local_p;
}
-/* Determine whether or not a pointer mode is valid. Assume defaults
- of ptr_mode or Pmode - can be overridden. */
-bool
-default_valid_pointer_mode (enum machine_mode mode)
-{
- return (mode == ptr_mode || mode == Pmode);
-}
-
/* Default function to output code that will globalize a label. A
target must define GLOBAL_ASM_OP or provide its own function to
globalize a label. */
else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
{
decl = SYMBOL_REF_DECL (symbol);
- alignment = get_constant_alignment (decl);
- size = get_constant_size (decl);
+ alignment = DECL_ALIGN (decl);
+ size = get_constant_size (DECL_INITIAL (decl));
}
else
{
else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
{
decl = SYMBOL_REF_DECL (symbol);
- assemble_constant_contents (decl, XSTR (symbol, 0),
- get_constant_alignment (decl));
- offset += get_constant_size (decl);
+ assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
+ DECL_ALIGN (decl));
+ offset += get_constant_size (DECL_INITIAL (decl));
}
else
{
maybe_assemble_visibility (decl);
}
+/* Create a DEBUG_EXPR_DECL / DEBUG_EXPR pair from RTL expression
+ EXP. */
+rtx
+make_debug_expr_from_rtl (const_rtx exp)
+{
+ tree ddecl = make_node (DEBUG_EXPR_DECL), type;
+ enum machine_mode mode = GET_MODE (exp);
+ rtx dval;
+
+ DECL_ARTIFICIAL (ddecl) = 1;
+ if (REG_P (exp) && REG_EXPR (exp))
+ type = TREE_TYPE (REG_EXPR (exp));
+ else if (MEM_P (exp) && MEM_EXPR (exp))
+ type = TREE_TYPE (MEM_EXPR (exp));
+ else
+ type = NULL_TREE;
+ if (type && TYPE_MODE (type) == mode)
+ TREE_TYPE (ddecl) = type;
+ else
+ TREE_TYPE (ddecl) = lang_hooks.types.type_for_mode (mode, 1);
+ DECL_MODE (ddecl) = mode;
+ dval = gen_rtx_DEBUG_EXPR (mode);
+ DEBUG_EXPR_TREE_DECL (dval) = ddecl;
+ SET_DECL_RTL (ddecl, dval);
+ return dval;
+}
+
#include "gt-varasm.h"