xref: /openbsd-src/gnu/gcc/gcc/varasm.c (revision 8529ddd3cf8b8ffce3ab6c5b64acddb7831726a7)
1404b540aSrobert /* Output variables, constants and external declarations, for GNU compiler.
2404b540aSrobert    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
3404b540aSrobert    1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4404b540aSrobert    Free Software Foundation, Inc.
5404b540aSrobert 
6404b540aSrobert This file is part of GCC.
7404b540aSrobert 
8404b540aSrobert GCC is free software; you can redistribute it and/or modify it under
9404b540aSrobert the terms of the GNU General Public License as published by the Free
10404b540aSrobert Software Foundation; either version 2, or (at your option) any later
11404b540aSrobert version.
12404b540aSrobert 
13404b540aSrobert GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14404b540aSrobert WARRANTY; without even the implied warranty of MERCHANTABILITY or
15404b540aSrobert FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16404b540aSrobert for more details.
17404b540aSrobert 
18404b540aSrobert You should have received a copy of the GNU General Public License
19404b540aSrobert along with GCC; see the file COPYING.  If not, write to the Free
20404b540aSrobert Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21404b540aSrobert 02110-1301, USA.  */
22404b540aSrobert 
23404b540aSrobert 
24404b540aSrobert /* This file handles generation of all the assembler code
25404b540aSrobert    *except* the instructions of a function.
26404b540aSrobert    This includes declarations of variables and their initial values.
27404b540aSrobert 
28404b540aSrobert    We also output the assembler code for constants stored in memory
29404b540aSrobert    and are responsible for combining constants with the same value.  */
30404b540aSrobert 
31404b540aSrobert #include "config.h"
32404b540aSrobert #include "system.h"
33404b540aSrobert #include "coretypes.h"
34404b540aSrobert #include "tm.h"
35404b540aSrobert #include "rtl.h"
36404b540aSrobert #include "tree.h"
37404b540aSrobert #include "flags.h"
38404b540aSrobert #include "function.h"
39404b540aSrobert #include "expr.h"
40404b540aSrobert #include "hard-reg-set.h"
41404b540aSrobert #include "regs.h"
42404b540aSrobert #include "real.h"
43404b540aSrobert #include "output.h"
44404b540aSrobert #include "toplev.h"
45404b540aSrobert #include "hashtab.h"
46404b540aSrobert #include "c-pragma.h"
47404b540aSrobert #include "ggc.h"
48404b540aSrobert #include "langhooks.h"
49404b540aSrobert #include "tm_p.h"
50404b540aSrobert #include "debug.h"
51404b540aSrobert #include "target.h"
52404b540aSrobert #include "tree-mudflap.h"
53404b540aSrobert #include "cgraph.h"
54404b540aSrobert #include "cfglayout.h"
55404b540aSrobert #include "basic-block.h"
56404b540aSrobert 
57404b540aSrobert #ifdef XCOFF_DEBUGGING_INFO
58404b540aSrobert #include "xcoffout.h"		/* Needed for external data
59404b540aSrobert 				   declarations for e.g. AIX 4.x.  */
60404b540aSrobert #endif
61404b540aSrobert 
62404b540aSrobert /* The (assembler) name of the first globally-visible object output.  */
63404b540aSrobert extern GTY(()) const char *first_global_object_name;
64404b540aSrobert extern GTY(()) const char *weak_global_object_name;
65404b540aSrobert 
66404b540aSrobert const char *first_global_object_name;
67404b540aSrobert const char *weak_global_object_name;
68404b540aSrobert 
69404b540aSrobert struct addr_const;
70404b540aSrobert struct constant_descriptor_rtx;
71404b540aSrobert struct rtx_constant_pool;
72404b540aSrobert 
73404b540aSrobert struct varasm_status GTY(())
74404b540aSrobert {
75404b540aSrobert   /* If we're using a per-function constant pool, this is it.  */
76404b540aSrobert   struct rtx_constant_pool *pool;
77404b540aSrobert 
78404b540aSrobert   /* Number of tree-constants deferred during the expansion of this
79404b540aSrobert      function.  */
80404b540aSrobert   unsigned int deferred_constants;
81404b540aSrobert };
82404b540aSrobert 
83404b540aSrobert #define n_deferred_constants (cfun->varasm->deferred_constants)
84404b540aSrobert 
85404b540aSrobert /* Number for making the label on the next
86404b540aSrobert    constant that is stored in memory.  */
87404b540aSrobert 
88404b540aSrobert static GTY(()) int const_labelno;
89404b540aSrobert 
90404b540aSrobert /* Carry information from ASM_DECLARE_OBJECT_NAME
91404b540aSrobert    to ASM_FINISH_DECLARE_OBJECT.  */
92404b540aSrobert 
93404b540aSrobert int size_directive_output;
94404b540aSrobert 
95404b540aSrobert /* The last decl for which assemble_variable was called,
96404b540aSrobert    if it did ASM_DECLARE_OBJECT_NAME.
97404b540aSrobert    If the last call to assemble_variable didn't do that,
98404b540aSrobert    this holds 0.  */
99404b540aSrobert 
100404b540aSrobert tree last_assemble_variable_decl;
101404b540aSrobert 
102404b540aSrobert /* The following global variable indicates if the first basic block
103404b540aSrobert    in a function belongs to the cold partition or not.  */
104404b540aSrobert 
105404b540aSrobert bool first_function_block_is_cold;
106404b540aSrobert 
107404b540aSrobert /* We give all constants their own alias set.  Perhaps redundant with
108404b540aSrobert    MEM_READONLY_P, but pre-dates it.  */
109404b540aSrobert 
110404b540aSrobert static HOST_WIDE_INT const_alias_set;
111404b540aSrobert 
112404b540aSrobert static const char *strip_reg_name (const char *);
113404b540aSrobert static int contains_pointers_p (tree);
114404b540aSrobert #ifdef ASM_OUTPUT_EXTERNAL
115404b540aSrobert static bool incorporeal_function_p (tree);
116404b540aSrobert #endif
117404b540aSrobert static void decode_addr_const (tree, struct addr_const *);
118404b540aSrobert static hashval_t const_desc_hash (const void *);
119404b540aSrobert static int const_desc_eq (const void *, const void *);
120404b540aSrobert static hashval_t const_hash_1 (const tree);
121404b540aSrobert static int compare_constant (const tree, const tree);
122404b540aSrobert static tree copy_constant (tree);
123404b540aSrobert static void output_constant_def_contents (rtx);
124404b540aSrobert static void output_addressed_constants (tree);
125404b540aSrobert static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
126404b540aSrobert static unsigned min_align (unsigned, unsigned);
127404b540aSrobert static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
128404b540aSrobert static void globalize_decl (tree);
129404b540aSrobert #ifdef BSS_SECTION_ASM_OP
130404b540aSrobert #ifdef ASM_OUTPUT_BSS
131404b540aSrobert static void asm_output_bss (FILE *, tree, const char *,
132404b540aSrobert 			    unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
133404b540aSrobert #endif
134404b540aSrobert #ifdef ASM_OUTPUT_ALIGNED_BSS
135404b540aSrobert static void asm_output_aligned_bss (FILE *, tree, const char *,
136404b540aSrobert 				    unsigned HOST_WIDE_INT, int)
137404b540aSrobert      ATTRIBUTE_UNUSED;
138404b540aSrobert #endif
139404b540aSrobert #endif /* BSS_SECTION_ASM_OP */
140404b540aSrobert static void mark_weak (tree);
141404b540aSrobert static void output_constant_pool (const char *, tree);
142404b540aSrobert 
143404b540aSrobert /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
144404b540aSrobert section *text_section;
145404b540aSrobert section *data_section;
146404b540aSrobert section *readonly_data_section;
147404b540aSrobert section *sdata_section;
148404b540aSrobert section *ctors_section;
149404b540aSrobert section *dtors_section;
150404b540aSrobert section *bss_section;
151404b540aSrobert section *sbss_section;
152404b540aSrobert 
153404b540aSrobert /* Various forms of common section.  All are guaranteed to be nonnull.  */
154404b540aSrobert section *tls_comm_section;
155404b540aSrobert section *comm_section;
156404b540aSrobert section *lcomm_section;
157404b540aSrobert 
158404b540aSrobert /* A SECTION_NOSWITCH section used for declaring global BSS variables.
159404b540aSrobert    May be null.  */
160404b540aSrobert section *bss_noswitch_section;
161404b540aSrobert 
162404b540aSrobert /* The section that holds the main exception table, when known.  The section
163404b540aSrobert    is set either by the target's init_sections hook or by the first call to
164404b540aSrobert    switch_to_exception_section.  */
165404b540aSrobert section *exception_section;
166404b540aSrobert 
167404b540aSrobert /* The section that holds the DWARF2 frame unwind information, when known.
168404b540aSrobert    The section is set either by the target's init_sections hook or by the
169404b540aSrobert    first call to switch_to_eh_frame_section.  */
170404b540aSrobert section *eh_frame_section;
171404b540aSrobert 
172404b540aSrobert /* asm_out_file's current section.  This is NULL if no section has yet
173404b540aSrobert    been selected or if we lose track of what the current section is.  */
174404b540aSrobert section *in_section;
175404b540aSrobert 
176404b540aSrobert /* True if code for the current function is currently being directed
177404b540aSrobert    at the cold section.  */
178404b540aSrobert bool in_cold_section_p;
179404b540aSrobert 
180404b540aSrobert /* A linked list of all the unnamed sections.  */
181404b540aSrobert static GTY(()) section *unnamed_sections;
182404b540aSrobert 
183404b540aSrobert /* Return a nonzero value if DECL has a section attribute.  */
184404b540aSrobert #ifndef IN_NAMED_SECTION
185404b540aSrobert #define IN_NAMED_SECTION(DECL) \
186404b540aSrobert   ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
187404b540aSrobert    && DECL_SECTION_NAME (DECL) != NULL_TREE)
188404b540aSrobert #endif
189404b540aSrobert 
190404b540aSrobert /* Hash table of named sections.  */
191404b540aSrobert static GTY((param_is (section))) htab_t section_htab;
192404b540aSrobert 
193404b540aSrobert /* A table of object_blocks, indexed by section.  */
194404b540aSrobert static GTY((param_is (struct object_block))) htab_t object_block_htab;
195404b540aSrobert 
196404b540aSrobert /* The next number to use for internal anchor labels.  */
197404b540aSrobert static GTY(()) int anchor_labelno;
198404b540aSrobert 
199404b540aSrobert /* A pool of constants that can be shared between functions.  */
200404b540aSrobert static GTY(()) struct rtx_constant_pool *shared_constant_pool;
201404b540aSrobert 
202404b540aSrobert /* Helper routines for maintaining section_htab.  */
203404b540aSrobert 
204404b540aSrobert static int
section_entry_eq(const void * p1,const void * p2)205404b540aSrobert section_entry_eq (const void *p1, const void *p2)
206404b540aSrobert {
207404b540aSrobert   const section *old = p1;
208404b540aSrobert   const char *new = p2;
209404b540aSrobert 
210404b540aSrobert   return strcmp (old->named.name, new) == 0;
211404b540aSrobert }
212404b540aSrobert 
213404b540aSrobert static hashval_t
section_entry_hash(const void * p)214404b540aSrobert section_entry_hash (const void *p)
215404b540aSrobert {
216404b540aSrobert   const section *old = p;
217404b540aSrobert   return htab_hash_string (old->named.name);
218404b540aSrobert }
219404b540aSrobert 
220404b540aSrobert /* Return a hash value for section SECT.  */
221404b540aSrobert 
222404b540aSrobert static hashval_t
hash_section(section * sect)223404b540aSrobert hash_section (section *sect)
224404b540aSrobert {
225404b540aSrobert   if (sect->common.flags & SECTION_NAMED)
226404b540aSrobert     return htab_hash_string (sect->named.name);
227404b540aSrobert   return sect->common.flags;
228404b540aSrobert }
229404b540aSrobert 
230404b540aSrobert /* Helper routines for maintaining object_block_htab.  */
231404b540aSrobert 
232404b540aSrobert static int
object_block_entry_eq(const void * p1,const void * p2)233404b540aSrobert object_block_entry_eq (const void *p1, const void *p2)
234404b540aSrobert {
235404b540aSrobert   const struct object_block *old = p1;
236404b540aSrobert   const section *new = p2;
237404b540aSrobert 
238404b540aSrobert   return old->sect == new;
239404b540aSrobert }
240404b540aSrobert 
241404b540aSrobert static hashval_t
object_block_entry_hash(const void * p)242404b540aSrobert object_block_entry_hash (const void *p)
243404b540aSrobert {
244404b540aSrobert   const struct object_block *old = p;
245404b540aSrobert   return hash_section (old->sect);
246404b540aSrobert }
247404b540aSrobert 
248404b540aSrobert /* Return a new unnamed section with the given fields.  */
249404b540aSrobert 
250404b540aSrobert section *
get_unnamed_section(unsigned int flags,void (* callback)(const void *),const void * data)251404b540aSrobert get_unnamed_section (unsigned int flags, void (*callback) (const void *),
252404b540aSrobert 		     const void *data)
253404b540aSrobert {
254404b540aSrobert   section *sect;
255404b540aSrobert 
256404b540aSrobert   sect = ggc_alloc (sizeof (struct unnamed_section));
257404b540aSrobert   sect->unnamed.common.flags = flags | SECTION_UNNAMED;
258404b540aSrobert   sect->unnamed.callback = callback;
259404b540aSrobert   sect->unnamed.data = data;
260404b540aSrobert   sect->unnamed.next = unnamed_sections;
261404b540aSrobert 
262404b540aSrobert   unnamed_sections = sect;
263404b540aSrobert   return sect;
264404b540aSrobert }
265404b540aSrobert 
266404b540aSrobert /* Return a SECTION_NOSWITCH section with the given fields.  */
267404b540aSrobert 
268404b540aSrobert static section *
get_noswitch_section(unsigned int flags,noswitch_section_callback callback)269404b540aSrobert get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
270404b540aSrobert {
271404b540aSrobert   section *sect;
272404b540aSrobert 
273404b540aSrobert   sect = ggc_alloc (sizeof (struct unnamed_section));
274404b540aSrobert   sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
275404b540aSrobert   sect->noswitch.callback = callback;
276404b540aSrobert 
277404b540aSrobert   return sect;
278404b540aSrobert }
279404b540aSrobert 
280404b540aSrobert /* Return the named section structure associated with NAME.  Create
281404b540aSrobert    a new section with the given fields if no such structure exists.  */
282404b540aSrobert 
283404b540aSrobert section *
get_section(const char * name,unsigned int flags,tree decl)284404b540aSrobert get_section (const char *name, unsigned int flags, tree decl)
285404b540aSrobert {
286404b540aSrobert   section *sect, **slot;
287404b540aSrobert 
288404b540aSrobert   slot = (section **)
289404b540aSrobert     htab_find_slot_with_hash (section_htab, name,
290404b540aSrobert 			      htab_hash_string (name), INSERT);
291404b540aSrobert   flags |= SECTION_NAMED;
292404b540aSrobert   if (*slot == NULL)
293404b540aSrobert     {
294404b540aSrobert       sect = ggc_alloc (sizeof (struct named_section));
295404b540aSrobert       sect->named.common.flags = flags;
296404b540aSrobert       sect->named.name = ggc_strdup (name);
297404b540aSrobert       sect->named.decl = decl;
298404b540aSrobert       *slot = sect;
299404b540aSrobert     }
300404b540aSrobert   else
301404b540aSrobert     {
302404b540aSrobert       sect = *slot;
303404b540aSrobert       if ((sect->common.flags & ~SECTION_DECLARED) != flags
304404b540aSrobert 	  && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0)
305404b540aSrobert 	{
306404b540aSrobert 	  /* Sanity check user variables for flag changes.  */
307404b540aSrobert 	  if (decl == 0)
308404b540aSrobert 	    decl = sect->named.decl;
309404b540aSrobert 	  gcc_assert (decl);
310404b540aSrobert 	  error ("%+D causes a section type conflict", decl);
311404b540aSrobert 	}
312404b540aSrobert     }
313404b540aSrobert   return sect;
314404b540aSrobert }
315404b540aSrobert 
316404b540aSrobert /* Return true if the current compilation mode benefits from having
317404b540aSrobert    objects grouped into blocks.  */
318404b540aSrobert 
319404b540aSrobert static bool
use_object_blocks_p(void)320404b540aSrobert use_object_blocks_p (void)
321404b540aSrobert {
322404b540aSrobert   return flag_section_anchors;
323404b540aSrobert }
324404b540aSrobert 
325404b540aSrobert /* Return the object_block structure for section SECT.  Create a new
326404b540aSrobert    structure if we haven't created one already.  Return null if SECT
327404b540aSrobert    itself is null.  */
328404b540aSrobert 
329404b540aSrobert static struct object_block *
get_block_for_section(section * sect)330404b540aSrobert get_block_for_section (section *sect)
331404b540aSrobert {
332404b540aSrobert   struct object_block *block;
333404b540aSrobert   void **slot;
334404b540aSrobert 
335404b540aSrobert   if (sect == NULL)
336404b540aSrobert     return NULL;
337404b540aSrobert 
338404b540aSrobert   slot = htab_find_slot_with_hash (object_block_htab, sect,
339404b540aSrobert 				   hash_section (sect), INSERT);
340404b540aSrobert   block = (struct object_block *) *slot;
341404b540aSrobert   if (block == NULL)
342404b540aSrobert     {
343404b540aSrobert       block = (struct object_block *)
344404b540aSrobert 	ggc_alloc_cleared (sizeof (struct object_block));
345404b540aSrobert       block->sect = sect;
346404b540aSrobert       *slot = block;
347404b540aSrobert     }
348404b540aSrobert   return block;
349404b540aSrobert }
350404b540aSrobert 
351404b540aSrobert /* Create a symbol with label LABEL and place it at byte offset
352404b540aSrobert    OFFSET in BLOCK.  OFFSET can be negative if the symbol's offset
353404b540aSrobert    is not yet known.  LABEL must be a garbage-collected string.  */
354404b540aSrobert 
355404b540aSrobert static rtx
create_block_symbol(const char * label,struct object_block * block,HOST_WIDE_INT offset)356404b540aSrobert create_block_symbol (const char *label, struct object_block *block,
357404b540aSrobert 		     HOST_WIDE_INT offset)
358404b540aSrobert {
359404b540aSrobert   rtx symbol;
360404b540aSrobert   unsigned int size;
361404b540aSrobert 
362404b540aSrobert   /* Create the extended SYMBOL_REF.  */
363404b540aSrobert   size = RTX_HDR_SIZE + sizeof (struct block_symbol);
364404b540aSrobert   symbol = ggc_alloc_zone (size, &rtl_zone);
365404b540aSrobert 
366404b540aSrobert   /* Initialize the normal SYMBOL_REF fields.  */
367404b540aSrobert   memset (symbol, 0, size);
368404b540aSrobert   PUT_CODE (symbol, SYMBOL_REF);
369404b540aSrobert   PUT_MODE (symbol, Pmode);
370404b540aSrobert   XSTR (symbol, 0) = label;
371404b540aSrobert   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_HAS_BLOCK_INFO;
372404b540aSrobert 
373404b540aSrobert   /* Initialize the block_symbol stuff.  */
374404b540aSrobert   SYMBOL_REF_BLOCK (symbol) = block;
375404b540aSrobert   SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
376404b540aSrobert 
377404b540aSrobert   return symbol;
378404b540aSrobert }
379404b540aSrobert 
380404b540aSrobert static void
initialize_cold_section_name(void)381404b540aSrobert initialize_cold_section_name (void)
382404b540aSrobert {
383404b540aSrobert   const char *stripped_name;
384404b540aSrobert   char *name, *buffer;
385404b540aSrobert   tree dsn;
386404b540aSrobert 
387404b540aSrobert   gcc_assert (cfun && current_function_decl);
388404b540aSrobert   if (cfun->unlikely_text_section_name)
389404b540aSrobert     return;
390404b540aSrobert 
391404b540aSrobert   dsn = DECL_SECTION_NAME (current_function_decl);
392404b540aSrobert   if (flag_function_sections && dsn)
393404b540aSrobert     {
394404b540aSrobert       name = alloca (TREE_STRING_LENGTH (dsn) + 1);
395404b540aSrobert       memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
396404b540aSrobert 
397404b540aSrobert       stripped_name = targetm.strip_name_encoding (name);
398404b540aSrobert 
399404b540aSrobert       buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
400404b540aSrobert       cfun->unlikely_text_section_name = ggc_strdup (buffer);
401404b540aSrobert     }
402404b540aSrobert   else
403404b540aSrobert     cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
404404b540aSrobert }
405404b540aSrobert 
406404b540aSrobert /* Tell assembler to switch to unlikely-to-be-executed text section.  */
407404b540aSrobert 
408404b540aSrobert section *
unlikely_text_section(void)409404b540aSrobert unlikely_text_section (void)
410404b540aSrobert {
411404b540aSrobert   if (cfun)
412404b540aSrobert     {
413404b540aSrobert       if (!cfun->unlikely_text_section_name)
414404b540aSrobert 	initialize_cold_section_name ();
415404b540aSrobert 
416404b540aSrobert       return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
417404b540aSrobert     }
418404b540aSrobert   else
419404b540aSrobert     return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
420404b540aSrobert }
421404b540aSrobert 
422404b540aSrobert /* When called within a function context, return true if the function
423404b540aSrobert    has been assigned a cold text section and if SECT is that section.
424404b540aSrobert    When called outside a function context, return true if SECT is the
425404b540aSrobert    default cold section.  */
426404b540aSrobert 
427404b540aSrobert bool
unlikely_text_section_p(section * sect)428404b540aSrobert unlikely_text_section_p (section *sect)
429404b540aSrobert {
430404b540aSrobert   const char *name;
431404b540aSrobert 
432404b540aSrobert   if (cfun)
433404b540aSrobert     name = cfun->unlikely_text_section_name;
434404b540aSrobert   else
435404b540aSrobert     name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
436404b540aSrobert 
437404b540aSrobert   return (name
438404b540aSrobert 	  && sect
439404b540aSrobert 	  && SECTION_STYLE (sect) == SECTION_NAMED
440404b540aSrobert 	  && strcmp (name, sect->named.name) == 0);
441404b540aSrobert }
442404b540aSrobert 
443404b540aSrobert /* Return a section with a particular name and with whatever SECTION_*
444404b540aSrobert    flags section_type_flags deems appropriate.  The name of the section
445404b540aSrobert    is taken from NAME if nonnull, otherwise it is taken from DECL's
446404b540aSrobert    DECL_SECTION_NAME.  DECL is the decl associated with the section
447404b540aSrobert    (see the section comment for details) and RELOC is as for
448404b540aSrobert    section_type_flags.  */
449404b540aSrobert 
450404b540aSrobert section *
get_named_section(tree decl,const char * name,int reloc)451404b540aSrobert get_named_section (tree decl, const char *name, int reloc)
452404b540aSrobert {
453404b540aSrobert   unsigned int flags;
454404b540aSrobert 
455404b540aSrobert   gcc_assert (!decl || DECL_P (decl));
456404b540aSrobert   if (name == NULL)
457404b540aSrobert     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
458404b540aSrobert 
459404b540aSrobert   flags = targetm.section_type_flags (decl, name, reloc);
460404b540aSrobert 
461404b540aSrobert   return get_section (name, flags, decl);
462404b540aSrobert }
463404b540aSrobert 
464404b540aSrobert /* If required, set DECL_SECTION_NAME to a unique name.  */
465404b540aSrobert 
466404b540aSrobert void
resolve_unique_section(tree decl,int reloc ATTRIBUTE_UNUSED,int flag_function_or_data_sections)467404b540aSrobert resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
468404b540aSrobert 			int flag_function_or_data_sections)
469404b540aSrobert {
470404b540aSrobert   if (DECL_SECTION_NAME (decl) == NULL_TREE
471404b540aSrobert       && targetm.have_named_sections
472404b540aSrobert       && (flag_function_or_data_sections
473404b540aSrobert 	  || DECL_ONE_ONLY (decl)))
474404b540aSrobert     targetm.asm_out.unique_section (decl, reloc);
475404b540aSrobert }
476404b540aSrobert 
477404b540aSrobert #ifdef BSS_SECTION_ASM_OP
478404b540aSrobert 
479404b540aSrobert #ifdef ASM_OUTPUT_BSS
480404b540aSrobert 
481404b540aSrobert /* Utility function for ASM_OUTPUT_BSS for targets to use if
482404b540aSrobert    they don't support alignments in .bss.
483404b540aSrobert    ??? It is believed that this function will work in most cases so such
484404b540aSrobert    support is localized here.  */
485404b540aSrobert 
486404b540aSrobert static void
asm_output_bss(FILE * file,tree decl ATTRIBUTE_UNUSED,const char * name,unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT rounded)487404b540aSrobert asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
488404b540aSrobert 		const char *name,
489404b540aSrobert 		unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
490404b540aSrobert 		unsigned HOST_WIDE_INT rounded)
491404b540aSrobert {
492404b540aSrobert   targetm.asm_out.globalize_label (file, name);
493404b540aSrobert   switch_to_section (bss_section);
494404b540aSrobert #ifdef ASM_DECLARE_OBJECT_NAME
495404b540aSrobert   last_assemble_variable_decl = decl;
496404b540aSrobert   ASM_DECLARE_OBJECT_NAME (file, name, decl);
497404b540aSrobert #else
498404b540aSrobert   /* Standard thing is just output label for the object.  */
499404b540aSrobert   ASM_OUTPUT_LABEL (file, name);
500404b540aSrobert #endif /* ASM_DECLARE_OBJECT_NAME */
501404b540aSrobert   ASM_OUTPUT_SKIP (file, rounded ? rounded : 1);
502404b540aSrobert }
503404b540aSrobert 
504404b540aSrobert #endif
505404b540aSrobert 
506404b540aSrobert #ifdef ASM_OUTPUT_ALIGNED_BSS
507404b540aSrobert 
508404b540aSrobert /* Utility function for targets to use in implementing
509404b540aSrobert    ASM_OUTPUT_ALIGNED_BSS.
510404b540aSrobert    ??? It is believed that this function will work in most cases so such
511404b540aSrobert    support is localized here.  */
512404b540aSrobert 
513404b540aSrobert static void
asm_output_aligned_bss(FILE * file,tree decl ATTRIBUTE_UNUSED,const char * name,unsigned HOST_WIDE_INT size,int align)514404b540aSrobert asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
515404b540aSrobert 			const char *name, unsigned HOST_WIDE_INT size,
516404b540aSrobert 			int align)
517404b540aSrobert {
518404b540aSrobert   switch_to_section (bss_section);
519404b540aSrobert   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
520404b540aSrobert #ifdef ASM_DECLARE_OBJECT_NAME
521404b540aSrobert   last_assemble_variable_decl = decl;
522404b540aSrobert   ASM_DECLARE_OBJECT_NAME (file, name, decl);
523404b540aSrobert #else
524404b540aSrobert   /* Standard thing is just output label for the object.  */
525404b540aSrobert   ASM_OUTPUT_LABEL (file, name);
526404b540aSrobert #endif /* ASM_DECLARE_OBJECT_NAME */
527404b540aSrobert   ASM_OUTPUT_SKIP (file, size ? size : 1);
528404b540aSrobert }
529404b540aSrobert 
530404b540aSrobert #endif
531404b540aSrobert 
532404b540aSrobert #endif /* BSS_SECTION_ASM_OP */
533404b540aSrobert 
534404b540aSrobert #ifndef USE_SELECT_SECTION_FOR_FUNCTIONS
535404b540aSrobert /* Return the hot section for function DECL.  Return text_section for
536404b540aSrobert    null DECLs.  */
537404b540aSrobert 
538404b540aSrobert static section *
hot_function_section(tree decl)539404b540aSrobert hot_function_section (tree decl)
540404b540aSrobert {
541404b540aSrobert   if (decl != NULL_TREE
542404b540aSrobert       && DECL_SECTION_NAME (decl) != NULL_TREE
543404b540aSrobert       && targetm.have_named_sections)
544404b540aSrobert     return get_named_section (decl, NULL, 0);
545404b540aSrobert   else
546404b540aSrobert     return text_section;
547404b540aSrobert }
548404b540aSrobert #endif
549404b540aSrobert 
550404b540aSrobert /* Return the section for function DECL.
551404b540aSrobert 
552404b540aSrobert    If DECL is NULL_TREE, return the text section.  We can be passed
553404b540aSrobert    NULL_TREE under some circumstances by dbxout.c at least.  */
554404b540aSrobert 
555404b540aSrobert section *
function_section(tree decl)556404b540aSrobert function_section (tree decl)
557404b540aSrobert {
558404b540aSrobert   int reloc = 0;
559404b540aSrobert 
560404b540aSrobert   if (first_function_block_is_cold)
561404b540aSrobert     reloc = 1;
562404b540aSrobert 
563404b540aSrobert #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
564404b540aSrobert   if (decl != NULL_TREE
565404b540aSrobert       && DECL_SECTION_NAME (decl) != NULL_TREE)
566404b540aSrobert     return reloc ? unlikely_text_section ()
567404b540aSrobert 		 : get_named_section (decl, NULL, 0);
568404b540aSrobert   else
569404b540aSrobert     return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
570404b540aSrobert #else
571404b540aSrobert   return reloc ? unlikely_text_section () : hot_function_section (decl);
572404b540aSrobert #endif
573404b540aSrobert }
574404b540aSrobert 
575404b540aSrobert section *
current_function_section(void)576404b540aSrobert current_function_section (void)
577404b540aSrobert {
578404b540aSrobert #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
579404b540aSrobert   if (current_function_decl != NULL_TREE
580404b540aSrobert       && DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
581404b540aSrobert     return in_cold_section_p ? unlikely_text_section ()
582404b540aSrobert 			     : get_named_section (current_function_decl,
583404b540aSrobert 						  NULL, 0);
584404b540aSrobert   else
585404b540aSrobert     return targetm.asm_out.select_section (current_function_decl,
586404b540aSrobert 					   in_cold_section_p,
587404b540aSrobert 					   DECL_ALIGN (current_function_decl));
588404b540aSrobert #else
589404b540aSrobert   return (in_cold_section_p
590404b540aSrobert 	  ? unlikely_text_section ()
591404b540aSrobert 	  : hot_function_section (current_function_decl));
592404b540aSrobert #endif
593404b540aSrobert }
594404b540aSrobert 
595404b540aSrobert /* Return the read-only data section associated with function DECL.  */
596404b540aSrobert 
597404b540aSrobert section *
default_function_rodata_section(tree decl)598404b540aSrobert default_function_rodata_section (tree decl)
599404b540aSrobert {
600404b540aSrobert   if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
601404b540aSrobert     {
602404b540aSrobert       const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
603404b540aSrobert 
604404b540aSrobert       if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
605404b540aSrobert         {
606404b540aSrobert 	  size_t len = strlen (name) + 3;
607404b540aSrobert 	  char* rname = alloca (len);
608404b540aSrobert 
609404b540aSrobert 	  strcpy (rname, ".rodata");
610404b540aSrobert 	  strcat (rname, name + 5);
611404b540aSrobert 	  return get_section (rname, SECTION_LINKONCE, decl);
612404b540aSrobert 	}
613404b540aSrobert       /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo.  */
614404b540aSrobert       else if (DECL_ONE_ONLY (decl)
615404b540aSrobert 	       && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
616404b540aSrobert 	{
617404b540aSrobert 	  size_t len = strlen (name) + 1;
618404b540aSrobert 	  char *rname = alloca (len);
619404b540aSrobert 
620404b540aSrobert 	  memcpy (rname, name, len);
621404b540aSrobert 	  rname[14] = 'r';
622404b540aSrobert 	  return get_section (rname, SECTION_LINKONCE, decl);
623404b540aSrobert 	}
624404b540aSrobert       /* For .text.foo we want to use .rodata.foo.  */
625404b540aSrobert       else if (flag_function_sections && flag_data_sections
626404b540aSrobert 	       && strncmp (name, ".text.", 6) == 0)
627404b540aSrobert 	{
628404b540aSrobert 	  size_t len = strlen (name) + 1;
629404b540aSrobert 	  char *rname = alloca (len + 2);
630404b540aSrobert 
631404b540aSrobert 	  memcpy (rname, ".rodata", 7);
632404b540aSrobert 	  memcpy (rname + 7, name + 5, len - 5);
633404b540aSrobert 	  return get_section (rname, 0, decl);
634404b540aSrobert 	}
635404b540aSrobert     }
636404b540aSrobert 
637404b540aSrobert   return readonly_data_section;
638404b540aSrobert }
639404b540aSrobert 
640404b540aSrobert /* Return the read-only data section associated with function DECL
641404b540aSrobert    for targets where that section should be always the single
642404b540aSrobert    readonly data section.  */
643404b540aSrobert 
644404b540aSrobert section *
default_no_function_rodata_section(tree decl ATTRIBUTE_UNUSED)645404b540aSrobert default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
646404b540aSrobert {
647404b540aSrobert   return readonly_data_section;
648404b540aSrobert }
649404b540aSrobert 
650404b540aSrobert /* Return the section to use for string merging.  */
651404b540aSrobert 
652404b540aSrobert static section *
mergeable_string_section(tree decl ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,unsigned int flags ATTRIBUTE_UNUSED)653404b540aSrobert mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
654404b540aSrobert 			  unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
655404b540aSrobert 			  unsigned int flags ATTRIBUTE_UNUSED)
656404b540aSrobert {
657404b540aSrobert   HOST_WIDE_INT len;
658404b540aSrobert 
659404b540aSrobert   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
660404b540aSrobert       && TREE_CODE (decl) == STRING_CST
661404b540aSrobert       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
662404b540aSrobert       && align <= 256
663404b540aSrobert       && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
664404b540aSrobert       && TREE_STRING_LENGTH (decl) >= len)
665404b540aSrobert     {
666404b540aSrobert       enum machine_mode mode;
667404b540aSrobert       unsigned int modesize;
668404b540aSrobert       const char *str;
669404b540aSrobert       HOST_WIDE_INT i;
670404b540aSrobert       int j, unit;
671404b540aSrobert       char name[30];
672404b540aSrobert 
673404b540aSrobert       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
674404b540aSrobert       modesize = GET_MODE_BITSIZE (mode);
675404b540aSrobert       if (modesize >= 8 && modesize <= 256
676404b540aSrobert 	  && (modesize & (modesize - 1)) == 0)
677404b540aSrobert 	{
678404b540aSrobert 	  if (align < modesize)
679404b540aSrobert 	    align = modesize;
680404b540aSrobert 
681404b540aSrobert 	  str = TREE_STRING_POINTER (decl);
682404b540aSrobert 	  unit = GET_MODE_SIZE (mode);
683404b540aSrobert 
684404b540aSrobert 	  /* Check for embedded NUL characters.  */
685404b540aSrobert 	  for (i = 0; i < len; i += unit)
686404b540aSrobert 	    {
687404b540aSrobert 	      for (j = 0; j < unit; j++)
688404b540aSrobert 		if (str[i + j] != '\0')
689404b540aSrobert 		  break;
690404b540aSrobert 	      if (j == unit)
691404b540aSrobert 		break;
692404b540aSrobert 	    }
693404b540aSrobert 	  if (i == len - unit)
694404b540aSrobert 	    {
695404b540aSrobert 	      sprintf (name, ".rodata.str%d.%d", modesize / 8,
696404b540aSrobert 		       (int) (align / 8));
697404b540aSrobert 	      flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
698404b540aSrobert 	      return get_section (name, flags, NULL);
699404b540aSrobert 	    }
700404b540aSrobert 	}
701404b540aSrobert     }
702404b540aSrobert 
703404b540aSrobert   return readonly_data_section;
704404b540aSrobert }
705404b540aSrobert 
706404b540aSrobert /* Return the section to use for constant merging.  */
707404b540aSrobert 
708404b540aSrobert section *
mergeable_constant_section(enum machine_mode mode ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,unsigned int flags ATTRIBUTE_UNUSED)709404b540aSrobert mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
710404b540aSrobert 			    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
711404b540aSrobert 			    unsigned int flags ATTRIBUTE_UNUSED)
712404b540aSrobert {
713404b540aSrobert   unsigned int modesize = GET_MODE_BITSIZE (mode);
714404b540aSrobert 
715404b540aSrobert   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
716404b540aSrobert       && mode != VOIDmode
717404b540aSrobert       && mode != BLKmode
718404b540aSrobert       && modesize <= align
719404b540aSrobert       && align >= 8
720404b540aSrobert       && align <= 256
721404b540aSrobert       && (align & (align - 1)) == 0)
722404b540aSrobert     {
723404b540aSrobert       char name[24];
724404b540aSrobert 
725404b540aSrobert       sprintf (name, ".rodata.cst%d", (int) (align / 8));
726404b540aSrobert       flags |= (align / 8) | SECTION_MERGE;
727404b540aSrobert       return get_section (name, flags, NULL);
728404b540aSrobert     }
729404b540aSrobert   return readonly_data_section;
730404b540aSrobert }
731404b540aSrobert 
732404b540aSrobert /* Given NAME, a putative register name, discard any customary prefixes.  */
733404b540aSrobert 
734404b540aSrobert static const char *
strip_reg_name(const char * name)735404b540aSrobert strip_reg_name (const char *name)
736404b540aSrobert {
737404b540aSrobert #ifdef REGISTER_PREFIX
738404b540aSrobert   if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
739404b540aSrobert     name += strlen (REGISTER_PREFIX);
740404b540aSrobert #endif
741404b540aSrobert   if (name[0] == '%' || name[0] == '#')
742404b540aSrobert     name++;
743404b540aSrobert   return name;
744404b540aSrobert }
745404b540aSrobert 
746404b540aSrobert /* The user has asked for a DECL to have a particular name.  Set (or
747404b540aSrobert    change) it in such a way that we don't prefix an underscore to
748404b540aSrobert    it.  */
749404b540aSrobert void
set_user_assembler_name(tree decl,const char * name)750404b540aSrobert set_user_assembler_name (tree decl, const char *name)
751404b540aSrobert {
752404b540aSrobert   char *starred = alloca (strlen (name) + 2);
753404b540aSrobert   starred[0] = '*';
754404b540aSrobert   strcpy (starred + 1, name);
755404b540aSrobert   change_decl_assembler_name (decl, get_identifier (starred));
756404b540aSrobert   SET_DECL_RTL (decl, NULL_RTX);
757404b540aSrobert }
758404b540aSrobert 
759404b540aSrobert /* Decode an `asm' spec for a declaration as a register name.
760404b540aSrobert    Return the register number, or -1 if nothing specified,
761404b540aSrobert    or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
762404b540aSrobert    or -3 if ASMSPEC is `cc' and is not recognized,
763404b540aSrobert    or -4 if ASMSPEC is `memory' and is not recognized.
764404b540aSrobert    Accept an exact spelling or a decimal number.
765404b540aSrobert    Prefixes such as % are optional.  */
766404b540aSrobert 
767404b540aSrobert int
decode_reg_name(const char * asmspec)768404b540aSrobert decode_reg_name (const char *asmspec)
769404b540aSrobert {
770404b540aSrobert   if (asmspec != 0)
771404b540aSrobert     {
772404b540aSrobert       int i;
773404b540aSrobert 
774404b540aSrobert       /* Get rid of confusing prefixes.  */
775404b540aSrobert       asmspec = strip_reg_name (asmspec);
776404b540aSrobert 
777404b540aSrobert       /* Allow a decimal number as a "register name".  */
778404b540aSrobert       for (i = strlen (asmspec) - 1; i >= 0; i--)
779404b540aSrobert 	if (! ISDIGIT (asmspec[i]))
780404b540aSrobert 	  break;
781404b540aSrobert       if (asmspec[0] != 0 && i < 0)
782404b540aSrobert 	{
783404b540aSrobert 	  i = atoi (asmspec);
784404b540aSrobert 	  if (i < FIRST_PSEUDO_REGISTER && i >= 0)
785404b540aSrobert 	    return i;
786404b540aSrobert 	  else
787404b540aSrobert 	    return -2;
788404b540aSrobert 	}
789404b540aSrobert 
790404b540aSrobert       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
791404b540aSrobert 	if (reg_names[i][0]
792404b540aSrobert 	    && ! strcmp (asmspec, strip_reg_name (reg_names[i])))
793404b540aSrobert 	  return i;
794404b540aSrobert 
795404b540aSrobert #ifdef ADDITIONAL_REGISTER_NAMES
796404b540aSrobert       {
797404b540aSrobert 	static const struct { const char *const name; const int number; } table[]
798404b540aSrobert 	  = ADDITIONAL_REGISTER_NAMES;
799404b540aSrobert 
800404b540aSrobert 	for (i = 0; i < (int) ARRAY_SIZE (table); i++)
801404b540aSrobert 	  if (table[i].name[0]
802404b540aSrobert 	      && ! strcmp (asmspec, table[i].name))
803404b540aSrobert 	    return table[i].number;
804404b540aSrobert       }
805404b540aSrobert #endif /* ADDITIONAL_REGISTER_NAMES */
806404b540aSrobert 
807404b540aSrobert       if (!strcmp (asmspec, "memory"))
808404b540aSrobert 	return -4;
809404b540aSrobert 
810404b540aSrobert       if (!strcmp (asmspec, "cc"))
811404b540aSrobert 	return -3;
812404b540aSrobert 
813404b540aSrobert       return -2;
814404b540aSrobert     }
815404b540aSrobert 
816404b540aSrobert   return -1;
817404b540aSrobert }
818404b540aSrobert 
819404b540aSrobert /* Return true if DECL's initializer is suitable for a BSS section.  */
820404b540aSrobert 
821404b540aSrobert static bool
bss_initializer_p(tree decl)822404b540aSrobert bss_initializer_p (tree decl)
823404b540aSrobert {
824404b540aSrobert   return (DECL_INITIAL (decl) == NULL
825404b540aSrobert 	  || DECL_INITIAL (decl) == error_mark_node
826404b540aSrobert 	  || (flag_zero_initialized_in_bss
827404b540aSrobert 	      /* Leave constant zeroes in .rodata so they
828404b540aSrobert 		 can be shared.  */
829404b540aSrobert 	      && !TREE_READONLY (decl)
830404b540aSrobert 	      && initializer_zerop (DECL_INITIAL (decl))));
831404b540aSrobert }
832404b540aSrobert 
833404b540aSrobert /* Compute the alignment of variable specified by DECL.
834404b540aSrobert    DONT_OUTPUT_DATA is from assemble_variable.  */
835404b540aSrobert 
836404b540aSrobert void
align_variable(tree decl,bool dont_output_data)837404b540aSrobert align_variable (tree decl, bool dont_output_data)
838404b540aSrobert {
839404b540aSrobert   unsigned int align = DECL_ALIGN (decl);
840404b540aSrobert 
841404b540aSrobert   /* In the case for initialing an array whose length isn't specified,
842404b540aSrobert      where we have not yet been able to do the layout,
843404b540aSrobert      figure out the proper alignment now.  */
844404b540aSrobert   if (dont_output_data && DECL_SIZE (decl) == 0
845404b540aSrobert       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
846404b540aSrobert     align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
847404b540aSrobert 
848404b540aSrobert   /* Some object file formats have a maximum alignment which they support.
849404b540aSrobert      In particular, a.out format supports a maximum alignment of 4.  */
850404b540aSrobert   if (align > MAX_OFILE_ALIGNMENT)
851404b540aSrobert     {
852404b540aSrobert       warning (0, "alignment of %q+D is greater than maximum object "
853404b540aSrobert                "file alignment.  Using %d", decl,
854404b540aSrobert 	       MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
855404b540aSrobert       align = MAX_OFILE_ALIGNMENT;
856404b540aSrobert     }
857404b540aSrobert 
858404b540aSrobert   /* On some machines, it is good to increase alignment sometimes.  */
859404b540aSrobert   if (! DECL_USER_ALIGN (decl))
860404b540aSrobert     {
861404b540aSrobert #ifdef DATA_ALIGNMENT
862404b540aSrobert       align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
863404b540aSrobert #endif
864404b540aSrobert #ifdef CONSTANT_ALIGNMENT
865404b540aSrobert       if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
866404b540aSrobert 	align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
867404b540aSrobert #endif
868404b540aSrobert     }
869404b540aSrobert 
870404b540aSrobert   /* Reset the alignment in case we have made it tighter, so we can benefit
871404b540aSrobert      from it in get_pointer_alignment.  */
872404b540aSrobert   DECL_ALIGN (decl) = align;
873404b540aSrobert }
874404b540aSrobert 
875404b540aSrobert /* Return the section into which the given VAR_DECL or CONST_DECL
876404b540aSrobert    should be placed.  PREFER_NOSWITCH_P is true if a noswitch
877404b540aSrobert    section should be used wherever possible.  */
878404b540aSrobert 
879404b540aSrobert static section *
get_variable_section(tree decl,bool prefer_noswitch_p)880404b540aSrobert get_variable_section (tree decl, bool prefer_noswitch_p)
881404b540aSrobert {
882404b540aSrobert   int reloc;
883404b540aSrobert 
884404b540aSrobert   /* If the decl has been given an explicit section name, then it
885404b540aSrobert      isn't common, and shouldn't be handled as such.  */
886404b540aSrobert   if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
887404b540aSrobert     {
888404b540aSrobert       if (DECL_THREAD_LOCAL_P (decl))
889404b540aSrobert 	return tls_comm_section;
890404b540aSrobert       if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
891404b540aSrobert 	return comm_section;
892404b540aSrobert     }
893404b540aSrobert 
894404b540aSrobert   if (DECL_INITIAL (decl) == error_mark_node)
895404b540aSrobert     reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
896404b540aSrobert   else if (DECL_INITIAL (decl))
897404b540aSrobert     reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
898404b540aSrobert   else
899404b540aSrobert     reloc = 0;
900404b540aSrobert 
901404b540aSrobert   resolve_unique_section (decl, reloc, flag_data_sections);
902404b540aSrobert   if (IN_NAMED_SECTION (decl))
903404b540aSrobert     return get_named_section (decl, NULL, reloc);
904404b540aSrobert 
905404b540aSrobert   if (!DECL_THREAD_LOCAL_P (decl)
906404b540aSrobert       && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
907404b540aSrobert       && bss_initializer_p (decl))
908404b540aSrobert     {
909404b540aSrobert       if (!TREE_PUBLIC (decl))
910404b540aSrobert 	return lcomm_section;
911404b540aSrobert       if (bss_noswitch_section)
912404b540aSrobert 	return bss_noswitch_section;
913404b540aSrobert     }
914404b540aSrobert 
915404b540aSrobert   return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
916404b540aSrobert }
917404b540aSrobert 
918404b540aSrobert /* Return the block into which object_block DECL should be placed.  */
919404b540aSrobert 
920404b540aSrobert static struct object_block *
get_block_for_decl(tree decl)921404b540aSrobert get_block_for_decl (tree decl)
922404b540aSrobert {
923404b540aSrobert   section *sect;
924404b540aSrobert 
925404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL)
926404b540aSrobert     {
927404b540aSrobert       /* The object must be defined in this translation unit.  */
928404b540aSrobert       if (DECL_EXTERNAL (decl))
929404b540aSrobert 	return NULL;
930404b540aSrobert 
931404b540aSrobert       /* There's no point using object blocks for something that is
932404b540aSrobert 	 isolated by definition.  */
933404b540aSrobert       if (DECL_ONE_ONLY (decl))
934404b540aSrobert 	return NULL;
935404b540aSrobert     }
936404b540aSrobert 
937404b540aSrobert   /* We can only calculate block offsets if the decl has a known
938404b540aSrobert      constant size.  */
939404b540aSrobert   if (DECL_SIZE_UNIT (decl) == NULL)
940404b540aSrobert     return NULL;
941404b540aSrobert   if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
942404b540aSrobert     return NULL;
943404b540aSrobert 
944404b540aSrobert   /* Find out which section should contain DECL.  We cannot put it into
945404b540aSrobert      an object block if it requires a standalone definition.  */
946404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL)
947404b540aSrobert       align_variable (decl, 0);
948404b540aSrobert   sect = get_variable_section (decl, true);
949404b540aSrobert   if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
950404b540aSrobert     return NULL;
951404b540aSrobert 
952404b540aSrobert   return get_block_for_section (sect);
953404b540aSrobert }
954404b540aSrobert 
955404b540aSrobert /* Make sure block symbol SYMBOL is in block BLOCK.  */
956404b540aSrobert 
957404b540aSrobert static void
change_symbol_block(rtx symbol,struct object_block * block)958404b540aSrobert change_symbol_block (rtx symbol, struct object_block *block)
959404b540aSrobert {
960404b540aSrobert   if (block != SYMBOL_REF_BLOCK (symbol))
961404b540aSrobert     {
962404b540aSrobert       gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
963404b540aSrobert       SYMBOL_REF_BLOCK (symbol) = block;
964404b540aSrobert     }
965404b540aSrobert }
966404b540aSrobert 
967404b540aSrobert /* Return true if it is possible to put DECL in an object_block.  */
968404b540aSrobert 
969404b540aSrobert static bool
use_blocks_for_decl_p(tree decl)970404b540aSrobert use_blocks_for_decl_p (tree decl)
971404b540aSrobert {
972404b540aSrobert   /* Only data DECLs can be placed into object blocks.  */
973404b540aSrobert   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
974404b540aSrobert     return false;
975404b540aSrobert 
976404b540aSrobert   /* Detect decls created by dw2_force_const_mem.  Such decls are
977404b540aSrobert      special because DECL_INITIAL doesn't specify the decl's true value.
978404b540aSrobert      dw2_output_indirect_constants will instead call assemble_variable
979404b540aSrobert      with dont_output_data set to 1 and then print the contents itself.  */
980404b540aSrobert   if (DECL_INITIAL (decl) == decl)
981404b540aSrobert     return false;
982404b540aSrobert 
983404b540aSrobert   /* If this decl is an alias, then we don't want to emit a definition.  */
984404b540aSrobert   if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
985404b540aSrobert     return false;
986404b540aSrobert 
987404b540aSrobert   return true;
988404b540aSrobert }
989404b540aSrobert 
990404b540aSrobert /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
991404b540aSrobert    have static storage duration.  In other words, it should not be an
992404b540aSrobert    automatic variable, including PARM_DECLs.
993404b540aSrobert 
994404b540aSrobert    There is, however, one exception: this function handles variables
995404b540aSrobert    explicitly placed in a particular register by the user.
996404b540aSrobert 
997404b540aSrobert    This is never called for PARM_DECL nodes.  */
998404b540aSrobert 
999404b540aSrobert void
make_decl_rtl(tree decl)1000404b540aSrobert make_decl_rtl (tree decl)
1001404b540aSrobert {
1002404b540aSrobert   const char *name = 0;
1003404b540aSrobert   int reg_number;
1004404b540aSrobert   rtx x;
1005404b540aSrobert 
1006404b540aSrobert   /* Check that we are not being given an automatic variable.  */
1007404b540aSrobert   gcc_assert (TREE_CODE (decl) != PARM_DECL
1008404b540aSrobert 	      && TREE_CODE (decl) != RESULT_DECL);
1009404b540aSrobert 
1010404b540aSrobert   /* A weak alias has TREE_PUBLIC set but not the other bits.  */
1011404b540aSrobert   gcc_assert (TREE_CODE (decl) != VAR_DECL
1012404b540aSrobert 	      || TREE_STATIC (decl)
1013404b540aSrobert 	      || TREE_PUBLIC (decl)
1014404b540aSrobert 	      || DECL_EXTERNAL (decl)
1015404b540aSrobert 	      || DECL_REGISTER (decl));
1016404b540aSrobert 
1017404b540aSrobert   /* And that we were not given a type or a label.  */
1018404b540aSrobert   gcc_assert (TREE_CODE (decl) != TYPE_DECL
1019404b540aSrobert 	      && TREE_CODE (decl) != LABEL_DECL);
1020404b540aSrobert 
1021404b540aSrobert   /* For a duplicate declaration, we can be called twice on the
1022404b540aSrobert      same DECL node.  Don't discard the RTL already made.  */
1023404b540aSrobert   if (DECL_RTL_SET_P (decl))
1024404b540aSrobert     {
1025404b540aSrobert       /* If the old RTL had the wrong mode, fix the mode.  */
1026404b540aSrobert       x = DECL_RTL (decl);
1027404b540aSrobert       if (GET_MODE (x) != DECL_MODE (decl))
1028404b540aSrobert 	SET_DECL_RTL (decl, adjust_address_nv (x, DECL_MODE (decl), 0));
1029404b540aSrobert 
1030404b540aSrobert       if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
1031404b540aSrobert 	return;
1032404b540aSrobert 
1033404b540aSrobert       /* ??? Another way to do this would be to maintain a hashed
1034404b540aSrobert 	 table of such critters.  Instead of adding stuff to a DECL
1035404b540aSrobert 	 to give certain attributes to it, we could use an external
1036404b540aSrobert 	 hash map from DECL to set of attributes.  */
1037404b540aSrobert 
1038404b540aSrobert       /* Let the target reassign the RTL if it wants.
1039404b540aSrobert 	 This is necessary, for example, when one machine specific
1040404b540aSrobert 	 decl attribute overrides another.  */
1041404b540aSrobert       targetm.encode_section_info (decl, DECL_RTL (decl), false);
1042404b540aSrobert 
1043404b540aSrobert       /* If the symbol has a SYMBOL_REF_BLOCK field, update it based
1044404b540aSrobert 	 on the new decl information.  */
1045404b540aSrobert       if (MEM_P (x)
1046404b540aSrobert 	  && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
1047404b540aSrobert 	  && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (x, 0)))
1048404b540aSrobert 	change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
1049404b540aSrobert 
1050404b540aSrobert       /* Make this function static known to the mudflap runtime.  */
1051404b540aSrobert       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
1052404b540aSrobert 	mudflap_enqueue_decl (decl);
1053404b540aSrobert 
1054404b540aSrobert       return;
1055404b540aSrobert     }
1056404b540aSrobert 
1057404b540aSrobert   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1058404b540aSrobert 
1059404b540aSrobert   if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
1060404b540aSrobert       && DECL_REGISTER (decl))
1061404b540aSrobert     {
1062404b540aSrobert       error ("register name not specified for %q+D", decl);
1063404b540aSrobert     }
1064404b540aSrobert   else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
1065404b540aSrobert     {
1066404b540aSrobert       const char *asmspec = name+1;
1067404b540aSrobert       reg_number = decode_reg_name (asmspec);
1068404b540aSrobert       /* First detect errors in declaring global registers.  */
1069404b540aSrobert       if (reg_number == -1)
1070404b540aSrobert 	error ("register name not specified for %q+D", decl);
1071404b540aSrobert       else if (reg_number < 0)
1072404b540aSrobert 	error ("invalid register name for %q+D", decl);
1073404b540aSrobert       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
1074404b540aSrobert 	error ("data type of %q+D isn%'t suitable for a register",
1075404b540aSrobert 	       decl);
1076404b540aSrobert       else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
1077404b540aSrobert 	error ("register specified for %q+D isn%'t suitable for data type",
1078404b540aSrobert                decl);
1079404b540aSrobert       /* Now handle properly declared static register variables.  */
1080404b540aSrobert       else
1081404b540aSrobert 	{
1082404b540aSrobert 	  int nregs;
1083404b540aSrobert 
1084404b540aSrobert 	  if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl))
1085404b540aSrobert 	    {
1086404b540aSrobert 	      DECL_INITIAL (decl) = 0;
1087404b540aSrobert 	      error ("global register variable has initial value");
1088404b540aSrobert 	    }
1089404b540aSrobert 	  if (TREE_THIS_VOLATILE (decl))
1090404b540aSrobert 	    warning (OPT_Wvolatile_register_var,
1091404b540aSrobert 		     "optimization may eliminate reads and/or "
1092404b540aSrobert 		     "writes to register variables");
1093404b540aSrobert 
1094404b540aSrobert 	  /* If the user specified one of the eliminables registers here,
1095404b540aSrobert 	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
1096404b540aSrobert 	     confused with that register and be eliminated.  This usage is
1097404b540aSrobert 	     somewhat suspect...  */
1098404b540aSrobert 
1099404b540aSrobert 	  SET_DECL_RTL (decl, gen_rtx_raw_REG (DECL_MODE (decl), reg_number));
1100404b540aSrobert 	  ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number;
1101404b540aSrobert 	  REG_USERVAR_P (DECL_RTL (decl)) = 1;
1102404b540aSrobert 
1103404b540aSrobert 	  if (TREE_STATIC (decl))
1104404b540aSrobert 	    {
1105404b540aSrobert 	      /* Make this register global, so not usable for anything
1106404b540aSrobert 		 else.  */
1107404b540aSrobert #ifdef ASM_DECLARE_REGISTER_GLOBAL
1108404b540aSrobert 	      name = IDENTIFIER_POINTER (DECL_NAME (decl));
1109404b540aSrobert 	      ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
1110404b540aSrobert #endif
1111404b540aSrobert 	      nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
1112404b540aSrobert 	      while (nregs > 0)
1113404b540aSrobert 		globalize_reg (reg_number + --nregs);
1114404b540aSrobert 	    }
1115404b540aSrobert 
1116404b540aSrobert 	  /* As a register variable, it has no section.  */
1117404b540aSrobert 	  return;
1118404b540aSrobert 	}
1119404b540aSrobert     }
1120404b540aSrobert   /* Now handle ordinary static variables and functions (in memory).
1121404b540aSrobert      Also handle vars declared register invalidly.  */
1122404b540aSrobert   else if (name[0] == '*')
1123404b540aSrobert   {
1124404b540aSrobert #ifdef REGISTER_PREFIX
1125404b540aSrobert     if (strlen (REGISTER_PREFIX) != 0)
1126404b540aSrobert       {
1127404b540aSrobert 	reg_number = decode_reg_name (name);
1128404b540aSrobert 	if (reg_number >= 0 || reg_number == -3)
1129404b540aSrobert 	  error ("register name given for non-register variable %q+D", decl);
1130404b540aSrobert       }
1131404b540aSrobert #endif
1132404b540aSrobert   }
1133404b540aSrobert 
1134404b540aSrobert   /* Specifying a section attribute on a variable forces it into a
1135404b540aSrobert      non-.bss section, and thus it cannot be common.  */
1136404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL
1137404b540aSrobert       && DECL_SECTION_NAME (decl) != NULL_TREE
1138404b540aSrobert       && DECL_INITIAL (decl) == NULL_TREE
1139404b540aSrobert       && DECL_COMMON (decl))
1140404b540aSrobert     DECL_COMMON (decl) = 0;
1141404b540aSrobert 
1142404b540aSrobert   /* Variables can't be both common and weak.  */
1143404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
1144404b540aSrobert     DECL_COMMON (decl) = 0;
1145404b540aSrobert 
1146404b540aSrobert   if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
1147404b540aSrobert     x = create_block_symbol (name, get_block_for_decl (decl), -1);
1148404b540aSrobert   else
1149404b540aSrobert     x = gen_rtx_SYMBOL_REF (Pmode, name);
1150404b540aSrobert   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
1151404b540aSrobert   SET_SYMBOL_REF_DECL (x, decl);
1152404b540aSrobert 
1153404b540aSrobert   x = gen_rtx_MEM (DECL_MODE (decl), x);
1154404b540aSrobert   if (TREE_CODE (decl) != FUNCTION_DECL)
1155404b540aSrobert     set_mem_attributes (x, decl, 1);
1156404b540aSrobert   SET_DECL_RTL (decl, x);
1157404b540aSrobert 
1158404b540aSrobert   /* Optionally set flags or add text to the name to record information
1159404b540aSrobert      such as that it is a function name.
1160404b540aSrobert      If the name is changed, the macro ASM_OUTPUT_LABELREF
1161404b540aSrobert      will have to know how to strip this information.  */
1162404b540aSrobert   targetm.encode_section_info (decl, DECL_RTL (decl), true);
1163404b540aSrobert 
1164404b540aSrobert   /* Make this function static known to the mudflap runtime.  */
1165404b540aSrobert   if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
1166404b540aSrobert     mudflap_enqueue_decl (decl);
1167404b540aSrobert }
1168404b540aSrobert 
1169404b540aSrobert /* Output a string of literal assembler code
1170404b540aSrobert    for an `asm' keyword used between functions.  */
1171404b540aSrobert 
1172404b540aSrobert void
assemble_asm(tree string)1173404b540aSrobert assemble_asm (tree string)
1174404b540aSrobert {
1175404b540aSrobert   app_enable ();
1176404b540aSrobert 
1177404b540aSrobert   if (TREE_CODE (string) == ADDR_EXPR)
1178404b540aSrobert     string = TREE_OPERAND (string, 0);
1179404b540aSrobert 
1180404b540aSrobert   fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
1181404b540aSrobert }
1182404b540aSrobert 
1183404b540aSrobert /* Record an element in the table of global destructors.  SYMBOL is
1184404b540aSrobert    a SYMBOL_REF of the function to be called; PRIORITY is a number
1185404b540aSrobert    between 0 and MAX_INIT_PRIORITY.  */
1186404b540aSrobert 
1187404b540aSrobert void
default_stabs_asm_out_destructor(rtx symbol ATTRIBUTE_UNUSED,int priority ATTRIBUTE_UNUSED)1188404b540aSrobert default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
1189404b540aSrobert 				  int priority ATTRIBUTE_UNUSED)
1190404b540aSrobert {
1191404b540aSrobert #if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
1192404b540aSrobert   /* Tell GNU LD that this is part of the static destructor set.
1193404b540aSrobert      This will work for any system that uses stabs, most usefully
1194404b540aSrobert      aout systems.  */
1195404b540aSrobert   dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */);
1196404b540aSrobert   dbxout_stab_value_label (XSTR (symbol, 0));
1197404b540aSrobert #else
1198404b540aSrobert   sorry ("global destructors not supported on this target");
1199404b540aSrobert #endif
1200404b540aSrobert }
1201404b540aSrobert 
1202404b540aSrobert void
default_named_section_asm_out_destructor(rtx symbol,int priority)1203404b540aSrobert default_named_section_asm_out_destructor (rtx symbol, int priority)
1204404b540aSrobert {
1205404b540aSrobert   const char *section = ".dtors";
1206404b540aSrobert   char buf[16];
1207404b540aSrobert 
1208404b540aSrobert   /* ??? This only works reliably with the GNU linker.  */
1209404b540aSrobert   if (priority != DEFAULT_INIT_PRIORITY)
1210404b540aSrobert     {
1211404b540aSrobert       sprintf (buf, ".dtors.%.5u",
1212404b540aSrobert 	       /* Invert the numbering so the linker puts us in the proper
1213404b540aSrobert 		  order; constructors are run from right to left, and the
1214404b540aSrobert 		  linker sorts in increasing order.  */
1215404b540aSrobert 	       MAX_INIT_PRIORITY - priority);
1216404b540aSrobert       section = buf;
1217404b540aSrobert     }
1218404b540aSrobert 
1219404b540aSrobert   switch_to_section (get_section (section, SECTION_WRITE, NULL));
1220404b540aSrobert   assemble_align (POINTER_SIZE);
1221404b540aSrobert   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1222404b540aSrobert }
1223404b540aSrobert 
1224404b540aSrobert #ifdef DTORS_SECTION_ASM_OP
1225404b540aSrobert void
default_dtor_section_asm_out_destructor(rtx symbol,int priority ATTRIBUTE_UNUSED)1226404b540aSrobert default_dtor_section_asm_out_destructor (rtx symbol,
1227404b540aSrobert 					 int priority ATTRIBUTE_UNUSED)
1228404b540aSrobert {
1229404b540aSrobert   switch_to_section (dtors_section);
1230404b540aSrobert   assemble_align (POINTER_SIZE);
1231404b540aSrobert   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1232404b540aSrobert }
1233404b540aSrobert #endif
1234404b540aSrobert 
1235404b540aSrobert /* Likewise for global constructors.  */
1236404b540aSrobert 
1237404b540aSrobert void
default_stabs_asm_out_constructor(rtx symbol ATTRIBUTE_UNUSED,int priority ATTRIBUTE_UNUSED)1238404b540aSrobert default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
1239404b540aSrobert 				   int priority ATTRIBUTE_UNUSED)
1240404b540aSrobert {
1241404b540aSrobert #if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
1242404b540aSrobert   /* Tell GNU LD that this is part of the static destructor set.
1243404b540aSrobert      This will work for any system that uses stabs, most usefully
1244404b540aSrobert      aout systems.  */
1245404b540aSrobert   dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */);
1246404b540aSrobert   dbxout_stab_value_label (XSTR (symbol, 0));
1247404b540aSrobert #else
1248404b540aSrobert   sorry ("global constructors not supported on this target");
1249404b540aSrobert #endif
1250404b540aSrobert }
1251404b540aSrobert 
1252404b540aSrobert void
default_named_section_asm_out_constructor(rtx symbol,int priority)1253404b540aSrobert default_named_section_asm_out_constructor (rtx symbol, int priority)
1254404b540aSrobert {
1255404b540aSrobert   const char *section = ".ctors";
1256404b540aSrobert   char buf[16];
1257404b540aSrobert 
1258404b540aSrobert   /* ??? This only works reliably with the GNU linker.  */
1259404b540aSrobert   if (priority != DEFAULT_INIT_PRIORITY)
1260404b540aSrobert     {
1261404b540aSrobert       sprintf (buf, ".ctors.%.5u",
1262404b540aSrobert 	       /* Invert the numbering so the linker puts us in the proper
1263404b540aSrobert 		  order; constructors are run from right to left, and the
1264404b540aSrobert 		  linker sorts in increasing order.  */
1265404b540aSrobert 	       MAX_INIT_PRIORITY - priority);
1266404b540aSrobert       section = buf;
1267404b540aSrobert     }
1268404b540aSrobert 
1269404b540aSrobert   switch_to_section (get_section (section, SECTION_WRITE, NULL));
1270404b540aSrobert   assemble_align (POINTER_SIZE);
1271404b540aSrobert   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1272404b540aSrobert }
1273404b540aSrobert 
1274404b540aSrobert #ifdef CTORS_SECTION_ASM_OP
1275404b540aSrobert void
default_ctor_section_asm_out_constructor(rtx symbol,int priority ATTRIBUTE_UNUSED)1276404b540aSrobert default_ctor_section_asm_out_constructor (rtx symbol,
1277404b540aSrobert 					  int priority ATTRIBUTE_UNUSED)
1278404b540aSrobert {
1279404b540aSrobert   switch_to_section (ctors_section);
1280404b540aSrobert   assemble_align (POINTER_SIZE);
1281404b540aSrobert   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1282404b540aSrobert }
1283404b540aSrobert #endif
1284404b540aSrobert 
1285404b540aSrobert /* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with
1286404b540aSrobert    a nonzero value if the constant pool should be output before the
1287404b540aSrobert    start of the function, or a zero value if the pool should output
1288404b540aSrobert    after the end of the function.  The default is to put it before the
1289404b540aSrobert    start.  */
1290404b540aSrobert 
1291404b540aSrobert #ifndef CONSTANT_POOL_BEFORE_FUNCTION
1292404b540aSrobert #define CONSTANT_POOL_BEFORE_FUNCTION 1
1293404b540aSrobert #endif
1294404b540aSrobert 
1295404b540aSrobert /* DECL is an object (either VAR_DECL or FUNCTION_DECL) which is going
1296404b540aSrobert    to be output to assembler.
1297404b540aSrobert    Set first_global_object_name and weak_global_object_name as appropriate.  */
1298404b540aSrobert 
1299404b540aSrobert void
notice_global_symbol(tree decl)1300404b540aSrobert notice_global_symbol (tree decl)
1301404b540aSrobert {
1302404b540aSrobert   const char **type = &first_global_object_name;
1303404b540aSrobert 
1304404b540aSrobert   if (first_global_object_name
1305404b540aSrobert       || !TREE_PUBLIC (decl)
1306404b540aSrobert       || DECL_EXTERNAL (decl)
1307404b540aSrobert       || !DECL_NAME (decl)
1308404b540aSrobert       || (TREE_CODE (decl) != FUNCTION_DECL
1309404b540aSrobert 	  && (TREE_CODE (decl) != VAR_DECL
1310404b540aSrobert 	      || (DECL_COMMON (decl)
1311404b540aSrobert 		  && (DECL_INITIAL (decl) == 0
1312404b540aSrobert 		      || DECL_INITIAL (decl) == error_mark_node))))
1313404b540aSrobert       || !MEM_P (DECL_RTL (decl)))
1314404b540aSrobert     return;
1315404b540aSrobert 
1316404b540aSrobert   /* We win when global object is found, but it is useful to know about weak
1317404b540aSrobert      symbol as well so we can produce nicer unique names.  */
1318404b540aSrobert   if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl))
1319404b540aSrobert     type = &weak_global_object_name;
1320404b540aSrobert 
1321404b540aSrobert   if (!*type)
1322404b540aSrobert     {
1323404b540aSrobert       const char *p;
1324404b540aSrobert       const char *name;
1325404b540aSrobert       rtx decl_rtl = DECL_RTL (decl);
1326404b540aSrobert 
1327404b540aSrobert       p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
1328404b540aSrobert       name = ggc_strdup (p);
1329404b540aSrobert 
1330404b540aSrobert       *type = name;
1331404b540aSrobert     }
1332404b540aSrobert }
1333404b540aSrobert 
1334404b540aSrobert /* Output assembler code for the constant pool of a function and associated
1335404b540aSrobert    with defining the name of the function.  DECL describes the function.
1336404b540aSrobert    NAME is the function's name.  For the constant pool, we use the current
1337404b540aSrobert    constant pool data.  */
1338404b540aSrobert 
1339404b540aSrobert void
assemble_start_function(tree decl,const char * fnname)1340404b540aSrobert assemble_start_function (tree decl, const char *fnname)
1341404b540aSrobert {
1342404b540aSrobert   int align;
1343404b540aSrobert   char tmp_label[100];
1344404b540aSrobert   bool hot_label_written = false;
1345404b540aSrobert 
1346404b540aSrobert   cfun->unlikely_text_section_name = NULL;
1347404b540aSrobert 
1348404b540aSrobert   first_function_block_is_cold = false;
1349404b540aSrobert   if (flag_reorder_blocks_and_partition)
1350404b540aSrobert     {
1351404b540aSrobert       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
1352404b540aSrobert       cfun->hot_section_label = ggc_strdup (tmp_label);
1353404b540aSrobert       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
1354404b540aSrobert       cfun->cold_section_label = ggc_strdup (tmp_label);
1355404b540aSrobert       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
1356404b540aSrobert       cfun->hot_section_end_label = ggc_strdup (tmp_label);
1357404b540aSrobert       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
1358404b540aSrobert       cfun->cold_section_end_label = ggc_strdup (tmp_label);
1359404b540aSrobert       const_labelno++;
1360404b540aSrobert     }
1361404b540aSrobert   else
1362404b540aSrobert     {
1363404b540aSrobert       cfun->hot_section_label = NULL;
1364404b540aSrobert       cfun->cold_section_label = NULL;
1365404b540aSrobert       cfun->hot_section_end_label = NULL;
1366404b540aSrobert       cfun->cold_section_end_label = NULL;
1367404b540aSrobert     }
1368404b540aSrobert 
1369404b540aSrobert   /* The following code does not need preprocessing in the assembler.  */
1370404b540aSrobert 
1371404b540aSrobert   app_disable ();
1372404b540aSrobert 
1373404b540aSrobert   if (CONSTANT_POOL_BEFORE_FUNCTION)
1374404b540aSrobert     output_constant_pool (fnname, decl);
1375404b540aSrobert 
1376404b540aSrobert   resolve_unique_section (decl, 0, flag_function_sections);
1377404b540aSrobert 
1378404b540aSrobert   /* Make sure the not and cold text (code) sections are properly
1379404b540aSrobert      aligned.  This is necessary here in the case where the function
1380404b540aSrobert      has both hot and cold sections, because we don't want to re-set
1381404b540aSrobert      the alignment when the section switch happens mid-function.  */
1382404b540aSrobert 
1383404b540aSrobert   if (flag_reorder_blocks_and_partition)
1384404b540aSrobert     {
1385404b540aSrobert       switch_to_section (unlikely_text_section ());
1386404b540aSrobert       assemble_align (FUNCTION_BOUNDARY);
1387404b540aSrobert       ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
1388404b540aSrobert 
1389404b540aSrobert       /* When the function starts with a cold section, we need to explicitly
1390404b540aSrobert 	 align the hot section and write out the hot section label.
1391404b540aSrobert 	 But if the current function is a thunk, we do not have a CFG.  */
1392404b540aSrobert       if (!current_function_is_thunk
1393404b540aSrobert 	  && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
1394404b540aSrobert 	{
1395404b540aSrobert 	  switch_to_section (text_section);
1396404b540aSrobert 	  assemble_align (FUNCTION_BOUNDARY);
1397404b540aSrobert 	  ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
1398404b540aSrobert 	  hot_label_written = true;
1399404b540aSrobert 	  first_function_block_is_cold = true;
1400404b540aSrobert 	}
1401404b540aSrobert     }
1402404b540aSrobert   else if (DECL_SECTION_NAME (decl))
1403404b540aSrobert     {
1404404b540aSrobert       /* Calls to function_section rely on first_function_block_is_cold
1405404b540aSrobert 	 being accurate.  The first block may be cold even if we aren't
1406404b540aSrobert 	 doing partitioning, if the entire function was decided by
1407404b540aSrobert 	 choose_function_section (predict.c) to be cold.  */
1408404b540aSrobert 
1409404b540aSrobert       initialize_cold_section_name ();
1410404b540aSrobert 
1411404b540aSrobert       if (cfun->unlikely_text_section_name
1412404b540aSrobert 	  && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
1413404b540aSrobert 		     cfun->unlikely_text_section_name) == 0)
1414404b540aSrobert 	first_function_block_is_cold = true;
1415404b540aSrobert     }
1416404b540aSrobert 
1417404b540aSrobert   in_cold_section_p = first_function_block_is_cold;
1418404b540aSrobert 
1419404b540aSrobert   /* Switch to the correct text section for the start of the function.  */
1420404b540aSrobert 
1421404b540aSrobert   switch_to_section (function_section (decl));
1422404b540aSrobert   if (flag_reorder_blocks_and_partition
1423404b540aSrobert       && !hot_label_written)
1424404b540aSrobert     ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
1425404b540aSrobert 
1426404b540aSrobert   /* Tell assembler to move to target machine's alignment for functions.  */
1427404b540aSrobert   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
1428404b540aSrobert   if (align < force_align_functions_log)
1429404b540aSrobert     align = force_align_functions_log;
1430404b540aSrobert   if (align > 0)
1431404b540aSrobert     {
1432404b540aSrobert       ASM_OUTPUT_ALIGN (asm_out_file, align);
1433404b540aSrobert     }
1434404b540aSrobert 
1435404b540aSrobert   /* Handle a user-specified function alignment.
1436404b540aSrobert      Note that we still need to align to FUNCTION_BOUNDARY, as above,
1437404b540aSrobert      because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all.  */
1438404b540aSrobert   if (align_functions_log > align
1439404b540aSrobert       && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
1440404b540aSrobert     {
1441404b540aSrobert #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
1442404b540aSrobert       ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
1443404b540aSrobert 				 align_functions_log, align_functions - 1);
1444404b540aSrobert #else
1445404b540aSrobert       ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log);
1446404b540aSrobert #endif
1447404b540aSrobert     }
1448404b540aSrobert 
1449404b540aSrobert #ifdef ASM_OUTPUT_FUNCTION_PREFIX
1450404b540aSrobert   ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
1451404b540aSrobert #endif
1452404b540aSrobert 
1453404b540aSrobert   (*debug_hooks->begin_function) (decl);
1454404b540aSrobert 
1455404b540aSrobert   /* Make function name accessible from other files, if appropriate.  */
1456404b540aSrobert 
1457404b540aSrobert   if (TREE_PUBLIC (decl))
1458404b540aSrobert     {
1459404b540aSrobert       notice_global_symbol (decl);
1460404b540aSrobert 
1461404b540aSrobert       globalize_decl (decl);
1462404b540aSrobert 
1463404b540aSrobert       maybe_assemble_visibility (decl);
1464404b540aSrobert     }
1465404b540aSrobert 
1466404b540aSrobert   if (DECL_PRESERVE_P (decl))
1467404b540aSrobert     targetm.asm_out.mark_decl_preserved (fnname);
1468404b540aSrobert 
1469404b540aSrobert   /* Do any machine/system dependent processing of the function name.  */
1470404b540aSrobert #ifdef ASM_DECLARE_FUNCTION_NAME
1471404b540aSrobert   ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
1472404b540aSrobert #else
1473404b540aSrobert   /* Standard thing is just output label for the function.  */
1474404b540aSrobert   ASM_OUTPUT_LABEL (asm_out_file, fnname);
1475404b540aSrobert #endif /* ASM_DECLARE_FUNCTION_NAME */
1476404b540aSrobert }
1477404b540aSrobert 
1478404b540aSrobert /* Output assembler code associated with defining the size of the
1479404b540aSrobert    function.  DECL describes the function.  NAME is the function's name.  */
1480404b540aSrobert 
1481404b540aSrobert void
assemble_end_function(tree decl,const char * fnname ATTRIBUTE_UNUSED)1482404b540aSrobert assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED)
1483404b540aSrobert {
1484404b540aSrobert #ifdef ASM_DECLARE_FUNCTION_SIZE
1485404b540aSrobert   /* We could have switched section in the middle of the function.  */
1486404b540aSrobert   if (flag_reorder_blocks_and_partition)
1487404b540aSrobert     switch_to_section (function_section (decl));
1488404b540aSrobert   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
1489404b540aSrobert #endif
1490404b540aSrobert   if (! CONSTANT_POOL_BEFORE_FUNCTION)
1491404b540aSrobert     {
1492404b540aSrobert       output_constant_pool (fnname, decl);
1493404b540aSrobert       switch_to_section (function_section (decl)); /* need to switch back */
1494404b540aSrobert     }
1495404b540aSrobert   /* Output labels for end of hot/cold text sections (to be used by
1496404b540aSrobert      debug info.)  */
1497404b540aSrobert   if (flag_reorder_blocks_and_partition)
1498404b540aSrobert     {
1499404b540aSrobert       section *save_text_section;
1500404b540aSrobert 
1501404b540aSrobert       save_text_section = in_section;
1502404b540aSrobert       switch_to_section (unlikely_text_section ());
1503404b540aSrobert       ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
1504404b540aSrobert       if (first_function_block_is_cold)
1505404b540aSrobert 	switch_to_section (text_section);
1506404b540aSrobert       else
1507404b540aSrobert 	switch_to_section (function_section (decl));
1508404b540aSrobert       ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
1509404b540aSrobert       switch_to_section (save_text_section);
1510404b540aSrobert     }
1511404b540aSrobert }
1512404b540aSrobert 
1513404b540aSrobert /* Assemble code to leave SIZE bytes of zeros.  */
1514404b540aSrobert 
1515404b540aSrobert void
assemble_zeros(unsigned HOST_WIDE_INT size)1516404b540aSrobert assemble_zeros (unsigned HOST_WIDE_INT size)
1517404b540aSrobert {
1518404b540aSrobert   /* Do no output if -fsyntax-only.  */
1519404b540aSrobert   if (flag_syntax_only)
1520404b540aSrobert     return;
1521404b540aSrobert 
1522404b540aSrobert #ifdef ASM_NO_SKIP_IN_TEXT
1523404b540aSrobert   /* The `space' pseudo in the text section outputs nop insns rather than 0s,
1524404b540aSrobert      so we must output 0s explicitly in the text section.  */
1525404b540aSrobert   if (ASM_NO_SKIP_IN_TEXT && (in_section->common.flags & SECTION_CODE) != 0)
1526404b540aSrobert     {
1527404b540aSrobert       unsigned HOST_WIDE_INT i;
1528404b540aSrobert       for (i = 0; i < size; i++)
1529404b540aSrobert 	assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
1530404b540aSrobert     }
1531404b540aSrobert   else
1532404b540aSrobert #endif
1533404b540aSrobert     if (size > 0)
1534404b540aSrobert       ASM_OUTPUT_SKIP (asm_out_file, size);
1535404b540aSrobert }
1536404b540aSrobert 
1537404b540aSrobert /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
1538404b540aSrobert 
1539404b540aSrobert void
assemble_align(int align)1540404b540aSrobert assemble_align (int align)
1541404b540aSrobert {
1542404b540aSrobert   if (align > BITS_PER_UNIT)
1543404b540aSrobert     {
1544404b540aSrobert       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
1545404b540aSrobert     }
1546404b540aSrobert }
1547404b540aSrobert 
1548404b540aSrobert /* Assemble a string constant with the specified C string as contents.  */
1549404b540aSrobert 
1550404b540aSrobert void
assemble_string(const char * p,int size)1551404b540aSrobert assemble_string (const char *p, int size)
1552404b540aSrobert {
1553404b540aSrobert   int pos = 0;
1554404b540aSrobert   int maximum = 2000;
1555404b540aSrobert 
1556404b540aSrobert   /* If the string is very long, split it up.  */
1557404b540aSrobert 
1558404b540aSrobert   while (pos < size)
1559404b540aSrobert     {
1560404b540aSrobert       int thissize = size - pos;
1561404b540aSrobert       if (thissize > maximum)
1562404b540aSrobert 	thissize = maximum;
1563404b540aSrobert 
1564404b540aSrobert       ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
1565404b540aSrobert 
1566404b540aSrobert       pos += thissize;
1567404b540aSrobert       p += thissize;
1568404b540aSrobert     }
1569404b540aSrobert }
1570404b540aSrobert 
1571404b540aSrobert 
1572404b540aSrobert /* A noswitch_section_callback for lcomm_section.  */
1573404b540aSrobert 
1574404b540aSrobert static bool
emit_local(tree decl ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)1575404b540aSrobert emit_local (tree decl ATTRIBUTE_UNUSED,
1576404b540aSrobert 	    const char *name ATTRIBUTE_UNUSED,
1577404b540aSrobert 	    unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
1578404b540aSrobert 	    unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
1579404b540aSrobert {
1580404b540aSrobert #if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
1581404b540aSrobert   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
1582404b540aSrobert 				 size, DECL_ALIGN (decl));
1583404b540aSrobert   return true;
1584404b540aSrobert #elif defined ASM_OUTPUT_ALIGNED_LOCAL
1585404b540aSrobert   ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
1586404b540aSrobert   return true;
1587404b540aSrobert #else
1588404b540aSrobert   ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
1589404b540aSrobert   return false;
1590404b540aSrobert #endif
1591404b540aSrobert }
1592404b540aSrobert 
1593404b540aSrobert /* A noswitch_section_callback for bss_noswitch_section.  */
1594404b540aSrobert 
1595404b540aSrobert #if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
1596404b540aSrobert static bool
emit_bss(tree decl ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)1597404b540aSrobert emit_bss (tree decl ATTRIBUTE_UNUSED,
1598404b540aSrobert 	  const char *name ATTRIBUTE_UNUSED,
1599404b540aSrobert 	  unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
1600404b540aSrobert 	  unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
1601404b540aSrobert {
1602404b540aSrobert #if defined ASM_OUTPUT_ALIGNED_BSS
1603404b540aSrobert   ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
1604404b540aSrobert   return true;
1605404b540aSrobert #else
1606404b540aSrobert   ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
1607404b540aSrobert   return false;
1608404b540aSrobert #endif
1609404b540aSrobert }
1610404b540aSrobert #endif
1611404b540aSrobert 
1612404b540aSrobert /* A noswitch_section_callback for comm_section.  */
1613404b540aSrobert 
1614404b540aSrobert static bool
emit_common(tree decl ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)1615404b540aSrobert emit_common (tree decl ATTRIBUTE_UNUSED,
1616404b540aSrobert 	     const char *name ATTRIBUTE_UNUSED,
1617404b540aSrobert 	     unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
1618404b540aSrobert 	     unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
1619404b540aSrobert {
1620404b540aSrobert #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
1621404b540aSrobert   ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
1622404b540aSrobert 				  size, DECL_ALIGN (decl));
1623404b540aSrobert   return true;
1624404b540aSrobert #elif defined ASM_OUTPUT_ALIGNED_COMMON
1625404b540aSrobert   ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
1626404b540aSrobert   return true;
1627404b540aSrobert #else
1628404b540aSrobert   ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
1629404b540aSrobert   return false;
1630404b540aSrobert #endif
1631404b540aSrobert }
1632404b540aSrobert 
1633404b540aSrobert /* A noswitch_section_callback for tls_comm_section.  */
1634404b540aSrobert 
1635404b540aSrobert static bool
emit_tls_common(tree decl ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)1636404b540aSrobert emit_tls_common (tree decl ATTRIBUTE_UNUSED,
1637404b540aSrobert 		 const char *name ATTRIBUTE_UNUSED,
1638404b540aSrobert 		 unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
1639404b540aSrobert 		 unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
1640404b540aSrobert {
1641404b540aSrobert #ifdef ASM_OUTPUT_TLS_COMMON
1642404b540aSrobert   ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
1643404b540aSrobert   return true;
1644404b540aSrobert #else
1645404b540aSrobert   sorry ("thread-local COMMON data not implemented");
1646404b540aSrobert   return true;
1647404b540aSrobert #endif
1648404b540aSrobert }
1649404b540aSrobert 
1650404b540aSrobert /* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT.
1651404b540aSrobert    NAME is the name of DECL's SYMBOL_REF.  */
1652404b540aSrobert 
1653404b540aSrobert static void
assemble_noswitch_variable(tree decl,const char * name,section * sect)1654404b540aSrobert assemble_noswitch_variable (tree decl, const char *name, section *sect)
1655404b540aSrobert {
1656404b540aSrobert   unsigned HOST_WIDE_INT size, rounded;
1657404b540aSrobert 
1658404b540aSrobert   size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
1659404b540aSrobert   rounded = size;
1660404b540aSrobert 
1661404b540aSrobert   /* Don't allocate zero bytes of common,
1662404b540aSrobert      since that means "undefined external" in the linker.  */
1663404b540aSrobert   if (size == 0)
1664404b540aSrobert     rounded = 1;
1665404b540aSrobert 
1666404b540aSrobert   /* Round size up to multiple of BIGGEST_ALIGNMENT bits
1667404b540aSrobert      so that each uninitialized object starts on such a boundary.  */
1668404b540aSrobert   rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
1669404b540aSrobert   rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
1670404b540aSrobert 	     * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
1671404b540aSrobert 
1672404b540aSrobert   if (!sect->noswitch.callback (decl, name, size, rounded)
1673404b540aSrobert       && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
1674404b540aSrobert     warning (0, "requested alignment for %q+D is greater than "
1675404b540aSrobert 	     "implemented alignment of %wu", decl, rounded);
1676404b540aSrobert }
1677404b540aSrobert 
1678404b540aSrobert /* A subroutine of assemble_variable.  Output the label and contents of
1679404b540aSrobert    DECL, whose address is a SYMBOL_REF with name NAME.  DONT_OUTPUT_DATA
1680404b540aSrobert    is as for assemble_variable.  */
1681404b540aSrobert 
1682404b540aSrobert static void
assemble_variable_contents(tree decl,const char * name,bool dont_output_data)1683404b540aSrobert assemble_variable_contents (tree decl, const char *name,
1684404b540aSrobert 			    bool dont_output_data)
1685404b540aSrobert {
1686404b540aSrobert   /* Do any machine/system dependent processing of the object.  */
1687404b540aSrobert #ifdef ASM_DECLARE_OBJECT_NAME
1688404b540aSrobert   last_assemble_variable_decl = decl;
1689404b540aSrobert   ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
1690404b540aSrobert #else
1691404b540aSrobert   /* Standard thing is just output label for the object.  */
1692404b540aSrobert   ASM_OUTPUT_LABEL (asm_out_file, name);
1693404b540aSrobert #endif /* ASM_DECLARE_OBJECT_NAME */
1694404b540aSrobert 
1695404b540aSrobert   if (!dont_output_data)
1696404b540aSrobert     {
1697404b540aSrobert       if (DECL_INITIAL (decl)
1698404b540aSrobert 	  && DECL_INITIAL (decl) != error_mark_node
1699404b540aSrobert 	  && !initializer_zerop (DECL_INITIAL (decl)))
1700404b540aSrobert 	/* Output the actual data.  */
1701404b540aSrobert 	output_constant (DECL_INITIAL (decl),
1702404b540aSrobert 			 tree_low_cst (DECL_SIZE_UNIT (decl), 1),
1703404b540aSrobert 			 DECL_ALIGN (decl));
1704404b540aSrobert       else
1705404b540aSrobert 	/* Leave space for it.  */
1706404b540aSrobert 	assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
1707404b540aSrobert     }
1708404b540aSrobert }
1709404b540aSrobert 
1710404b540aSrobert /* Assemble everything that is needed for a variable or function declaration.
1711404b540aSrobert    Not used for automatic variables, and not used for function definitions.
1712404b540aSrobert    Should not be called for variables of incomplete structure type.
1713404b540aSrobert 
1714404b540aSrobert    TOP_LEVEL is nonzero if this variable has file scope.
1715404b540aSrobert    AT_END is nonzero if this is the special handling, at end of compilation,
1716404b540aSrobert    to define things that have had only tentative definitions.
1717404b540aSrobert    DONT_OUTPUT_DATA if nonzero means don't actually output the
1718404b540aSrobert    initial value (that will be done by the caller).  */
1719404b540aSrobert 
1720404b540aSrobert void
assemble_variable(tree decl,int top_level ATTRIBUTE_UNUSED,int at_end ATTRIBUTE_UNUSED,int dont_output_data)1721404b540aSrobert assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
1722404b540aSrobert 		   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
1723404b540aSrobert {
1724404b540aSrobert   const char *name;
1725404b540aSrobert   rtx decl_rtl, symbol;
1726404b540aSrobert   section *sect;
1727404b540aSrobert 
1728404b540aSrobert   if (lang_hooks.decls.prepare_assemble_variable)
1729404b540aSrobert     lang_hooks.decls.prepare_assemble_variable (decl);
1730404b540aSrobert 
1731404b540aSrobert   last_assemble_variable_decl = 0;
1732404b540aSrobert 
1733404b540aSrobert   /* Normally no need to say anything here for external references,
1734404b540aSrobert      since assemble_external is called by the language-specific code
1735404b540aSrobert      when a declaration is first seen.  */
1736404b540aSrobert 
1737404b540aSrobert   if (DECL_EXTERNAL (decl))
1738404b540aSrobert     return;
1739404b540aSrobert 
1740404b540aSrobert   /* Output no assembler code for a function declaration.
1741404b540aSrobert      Only definitions of functions output anything.  */
1742404b540aSrobert 
1743404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
1744404b540aSrobert     return;
1745404b540aSrobert 
1746404b540aSrobert   /* Do nothing for global register variables.  */
1747404b540aSrobert   if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
1748404b540aSrobert     {
1749404b540aSrobert       TREE_ASM_WRITTEN (decl) = 1;
1750404b540aSrobert       return;
1751404b540aSrobert     }
1752404b540aSrobert 
1753404b540aSrobert   /* If type was incomplete when the variable was declared,
1754404b540aSrobert      see if it is complete now.  */
1755404b540aSrobert 
1756404b540aSrobert   if (DECL_SIZE (decl) == 0)
1757404b540aSrobert     layout_decl (decl, 0);
1758404b540aSrobert 
1759404b540aSrobert   /* Still incomplete => don't allocate it; treat the tentative defn
1760404b540aSrobert      (which is what it must have been) as an `extern' reference.  */
1761404b540aSrobert 
1762404b540aSrobert   if (!dont_output_data && DECL_SIZE (decl) == 0)
1763404b540aSrobert     {
1764404b540aSrobert       error ("storage size of %q+D isn%'t known", decl);
1765404b540aSrobert       TREE_ASM_WRITTEN (decl) = 1;
1766404b540aSrobert       return;
1767404b540aSrobert     }
1768404b540aSrobert 
1769404b540aSrobert   /* The first declaration of a variable that comes through this function
1770404b540aSrobert      decides whether it is global (in C, has external linkage)
1771404b540aSrobert      or local (in C, has internal linkage).  So do nothing more
1772404b540aSrobert      if this function has already run.  */
1773404b540aSrobert 
1774404b540aSrobert   if (TREE_ASM_WRITTEN (decl))
1775404b540aSrobert     return;
1776404b540aSrobert 
1777404b540aSrobert   /* Make sure targetm.encode_section_info is invoked before we set
1778404b540aSrobert      ASM_WRITTEN.  */
1779404b540aSrobert   decl_rtl = DECL_RTL (decl);
1780404b540aSrobert 
1781404b540aSrobert   TREE_ASM_WRITTEN (decl) = 1;
1782404b540aSrobert 
1783404b540aSrobert   /* Do no output if -fsyntax-only.  */
1784404b540aSrobert   if (flag_syntax_only)
1785404b540aSrobert     return;
1786404b540aSrobert 
1787404b540aSrobert   app_disable ();
1788404b540aSrobert 
1789404b540aSrobert   if (! dont_output_data
1790404b540aSrobert       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
1791404b540aSrobert     {
1792404b540aSrobert       error ("size of variable %q+D is too large", decl);
1793404b540aSrobert       return;
1794404b540aSrobert     }
1795404b540aSrobert 
1796404b540aSrobert   gcc_assert (MEM_P (decl_rtl));
1797404b540aSrobert   gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
1798404b540aSrobert   symbol = XEXP (decl_rtl, 0);
1799404b540aSrobert   name = XSTR (symbol, 0);
1800404b540aSrobert   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
1801404b540aSrobert     notice_global_symbol (decl);
1802404b540aSrobert 
1803404b540aSrobert   /* Compute the alignment of this data.  */
1804404b540aSrobert 
1805404b540aSrobert   align_variable (decl, dont_output_data);
1806404b540aSrobert   set_mem_align (decl_rtl, DECL_ALIGN (decl));
1807404b540aSrobert 
1808404b540aSrobert   if (TREE_PUBLIC (decl))
1809404b540aSrobert     maybe_assemble_visibility (decl);
1810404b540aSrobert 
1811404b540aSrobert   if (DECL_PRESERVE_P (decl))
1812404b540aSrobert     targetm.asm_out.mark_decl_preserved (name);
1813404b540aSrobert 
1814404b540aSrobert   /* First make the assembler name(s) global if appropriate.  */
1815404b540aSrobert   sect = get_variable_section (decl, false);
1816404b540aSrobert   if (TREE_PUBLIC (decl)
1817404b540aSrobert       && DECL_NAME (decl)
1818404b540aSrobert       && (sect->common.flags & SECTION_COMMON) == 0)
1819404b540aSrobert     globalize_decl (decl);
1820404b540aSrobert 
1821404b540aSrobert   /* Output any data that we will need to use the address of.  */
1822404b540aSrobert   if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
1823404b540aSrobert     output_addressed_constants (DECL_INITIAL (decl));
1824404b540aSrobert 
1825404b540aSrobert   /* dbxout.c needs to know this.  */
1826404b540aSrobert   if (sect && (sect->common.flags & SECTION_CODE) != 0)
1827404b540aSrobert     DECL_IN_TEXT_SECTION (decl) = 1;
1828404b540aSrobert 
1829404b540aSrobert   /* If the decl is part of an object_block, make sure that the decl
1830404b540aSrobert      has been positioned within its block, but do not write out its
1831404b540aSrobert      definition yet.  output_object_blocks will do that later.  */
1832404b540aSrobert   if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
1833404b540aSrobert     {
1834404b540aSrobert       gcc_assert (!dont_output_data);
1835404b540aSrobert       place_block_symbol (symbol);
1836404b540aSrobert     }
1837404b540aSrobert   else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
1838404b540aSrobert     assemble_noswitch_variable (decl, name, sect);
1839404b540aSrobert   else
1840404b540aSrobert     {
1841404b540aSrobert       switch_to_section (sect);
1842404b540aSrobert       if (DECL_ALIGN (decl) > BITS_PER_UNIT)
1843404b540aSrobert 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
1844404b540aSrobert       assemble_variable_contents (decl, name, dont_output_data);
1845404b540aSrobert     }
1846404b540aSrobert }
1847404b540aSrobert 
1848404b540aSrobert /* Return 1 if type TYPE contains any pointers.  */
1849404b540aSrobert 
1850404b540aSrobert static int
contains_pointers_p(tree type)1851404b540aSrobert contains_pointers_p (tree type)
1852404b540aSrobert {
1853404b540aSrobert   switch (TREE_CODE (type))
1854404b540aSrobert     {
1855404b540aSrobert     case POINTER_TYPE:
1856404b540aSrobert     case REFERENCE_TYPE:
1857404b540aSrobert       /* I'm not sure whether OFFSET_TYPE needs this treatment,
1858404b540aSrobert 	 so I'll play safe and return 1.  */
1859404b540aSrobert     case OFFSET_TYPE:
1860404b540aSrobert       return 1;
1861404b540aSrobert 
1862404b540aSrobert     case RECORD_TYPE:
1863404b540aSrobert     case UNION_TYPE:
1864404b540aSrobert     case QUAL_UNION_TYPE:
1865404b540aSrobert       {
1866404b540aSrobert 	tree fields;
1867404b540aSrobert 	/* For a type that has fields, see if the fields have pointers.  */
1868404b540aSrobert 	for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
1869404b540aSrobert 	  if (TREE_CODE (fields) == FIELD_DECL
1870404b540aSrobert 	      && contains_pointers_p (TREE_TYPE (fields)))
1871404b540aSrobert 	    return 1;
1872404b540aSrobert 	return 0;
1873404b540aSrobert       }
1874404b540aSrobert 
1875404b540aSrobert     case ARRAY_TYPE:
1876404b540aSrobert       /* An array type contains pointers if its element type does.  */
1877404b540aSrobert       return contains_pointers_p (TREE_TYPE (type));
1878404b540aSrobert 
1879404b540aSrobert     default:
1880404b540aSrobert       return 0;
1881404b540aSrobert     }
1882404b540aSrobert }
1883404b540aSrobert 
1884404b540aSrobert /* In unit-at-a-time mode, we delay assemble_external processing until
1885404b540aSrobert    the compilation unit is finalized.  This is the best we can do for
1886404b540aSrobert    right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
1887404b540aSrobert    it all the way to final.  See PR 17982 for further discussion.  */
1888404b540aSrobert static GTY(()) tree pending_assemble_externals;
1889404b540aSrobert 
1890404b540aSrobert #ifdef ASM_OUTPUT_EXTERNAL
1891404b540aSrobert /* True if DECL is a function decl for which no out-of-line copy exists.
1892404b540aSrobert    It is assumed that DECL's assembler name has been set.  */
1893404b540aSrobert 
1894404b540aSrobert static bool
incorporeal_function_p(tree decl)1895404b540aSrobert incorporeal_function_p (tree decl)
1896404b540aSrobert {
1897404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
1898404b540aSrobert     {
1899404b540aSrobert       const char *name;
1900404b540aSrobert 
1901404b540aSrobert       if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
1902404b540aSrobert 	  && DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA)
1903404b540aSrobert 	return true;
1904404b540aSrobert 
1905404b540aSrobert       name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1906404b540aSrobert       if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
1907404b540aSrobert 	return true;
1908404b540aSrobert     }
1909404b540aSrobert   return false;
1910404b540aSrobert }
1911404b540aSrobert 
1912404b540aSrobert /* Actually do the tests to determine if this is necessary, and invoke
1913404b540aSrobert    ASM_OUTPUT_EXTERNAL.  */
1914404b540aSrobert static void
assemble_external_real(tree decl)1915404b540aSrobert assemble_external_real (tree decl)
1916404b540aSrobert {
1917404b540aSrobert   rtx rtl = DECL_RTL (decl);
1918404b540aSrobert 
1919404b540aSrobert   if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
1920404b540aSrobert       && !SYMBOL_REF_USED (XEXP (rtl, 0))
1921404b540aSrobert       && !incorporeal_function_p (decl))
1922404b540aSrobert     {
1923404b540aSrobert       /* Some systems do require some output.  */
1924404b540aSrobert       SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
1925404b540aSrobert       ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
1926404b540aSrobert     }
1927404b540aSrobert }
1928404b540aSrobert #endif
1929404b540aSrobert 
1930404b540aSrobert void
process_pending_assemble_externals(void)1931404b540aSrobert process_pending_assemble_externals (void)
1932404b540aSrobert {
1933404b540aSrobert #ifdef ASM_OUTPUT_EXTERNAL
1934404b540aSrobert   tree list;
1935404b540aSrobert   for (list = pending_assemble_externals; list; list = TREE_CHAIN (list))
1936404b540aSrobert     assemble_external_real (TREE_VALUE (list));
1937404b540aSrobert 
1938404b540aSrobert   pending_assemble_externals = 0;
1939404b540aSrobert #endif
1940404b540aSrobert }
1941404b540aSrobert 
1942404b540aSrobert /* Output something to declare an external symbol to the assembler.
1943404b540aSrobert    (Most assemblers don't need this, so we normally output nothing.)
1944404b540aSrobert    Do nothing if DECL is not external.  */
1945404b540aSrobert 
1946404b540aSrobert void
assemble_external(tree decl ATTRIBUTE_UNUSED)1947404b540aSrobert assemble_external (tree decl ATTRIBUTE_UNUSED)
1948404b540aSrobert {
1949404b540aSrobert   /* Because most platforms do not define ASM_OUTPUT_EXTERNAL, the
1950404b540aSrobert      main body of this code is only rarely exercised.  To provide some
1951404b540aSrobert      testing, on all platforms, we make sure that the ASM_OUT_FILE is
1952404b540aSrobert      open.  If it's not, we should not be calling this function.  */
1953404b540aSrobert   gcc_assert (asm_out_file);
1954404b540aSrobert 
1955404b540aSrobert #ifdef ASM_OUTPUT_EXTERNAL
1956404b540aSrobert   if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
1957404b540aSrobert     return;
1958404b540aSrobert 
1959*8529ddd3Skettenis   /* We want to output external symbols at very last to check if they
1960*8529ddd3Skettenis      are references or not.  */
1961404b540aSrobert   pending_assemble_externals = tree_cons (0, decl,
1962404b540aSrobert 					  pending_assemble_externals);
1963404b540aSrobert #endif
1964404b540aSrobert }
1965404b540aSrobert 
1966404b540aSrobert /* Similar, for calling a library function FUN.  */
1967404b540aSrobert 
1968404b540aSrobert void
assemble_external_libcall(rtx fun)1969404b540aSrobert assemble_external_libcall (rtx fun)
1970404b540aSrobert {
1971404b540aSrobert   /* Declare library function name external when first used, if nec.  */
1972404b540aSrobert   if (! SYMBOL_REF_USED (fun))
1973404b540aSrobert     {
1974404b540aSrobert       SYMBOL_REF_USED (fun) = 1;
1975404b540aSrobert       targetm.asm_out.external_libcall (fun);
1976404b540aSrobert     }
1977404b540aSrobert }
1978404b540aSrobert 
1979404b540aSrobert /* Assemble a label named NAME.  */
1980404b540aSrobert 
1981404b540aSrobert void
assemble_label(const char * name)1982404b540aSrobert assemble_label (const char *name)
1983404b540aSrobert {
1984404b540aSrobert   ASM_OUTPUT_LABEL (asm_out_file, name);
1985404b540aSrobert }
1986404b540aSrobert 
1987404b540aSrobert /* Set the symbol_referenced flag for ID.  */
1988404b540aSrobert void
mark_referenced(tree id)1989404b540aSrobert mark_referenced (tree id)
1990404b540aSrobert {
1991404b540aSrobert   TREE_SYMBOL_REFERENCED (id) = 1;
1992404b540aSrobert }
1993404b540aSrobert 
1994404b540aSrobert /* Set the symbol_referenced flag for DECL and notify callgraph.  */
1995404b540aSrobert void
mark_decl_referenced(tree decl)1996404b540aSrobert mark_decl_referenced (tree decl)
1997404b540aSrobert {
1998404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
1999404b540aSrobert     {
2000404b540aSrobert       /* Extern inline functions don't become needed when referenced.
2001404b540aSrobert 	 If we know a method will be emitted in other TU and no new
2002404b540aSrobert 	 functions can be marked reachable, just use the external
2003404b540aSrobert 	 definition.  */
2004404b540aSrobert       struct cgraph_node *node = cgraph_node (decl);
2005404b540aSrobert       if (!DECL_EXTERNAL (decl)
2006404b540aSrobert 	  && (!node->local.vtable_method || !cgraph_global_info_ready
2007404b540aSrobert 	      || !node->local.finalized))
2008404b540aSrobert 	cgraph_mark_needed_node (node);
2009404b540aSrobert     }
2010404b540aSrobert   else if (TREE_CODE (decl) == VAR_DECL)
2011404b540aSrobert     {
2012404b540aSrobert       struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
2013404b540aSrobert       cgraph_varpool_mark_needed_node (node);
2014404b540aSrobert       /* C++ frontend use mark_decl_references to force COMDAT variables
2015404b540aSrobert          to be output that might appear dead otherwise.  */
2016404b540aSrobert       node->force_output = true;
2017404b540aSrobert     }
2018404b540aSrobert   /* else do nothing - we can get various sorts of CST nodes here,
2019404b540aSrobert      which do not need to be marked.  */
2020404b540aSrobert }
2021404b540aSrobert 
2022404b540aSrobert 
2023404b540aSrobert /* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
2024404b540aSrobert    until we find an identifier that is not itself a transparent alias.
2025404b540aSrobert    Modify the alias passed to it by reference (and all aliases on the
2026404b540aSrobert    way to the ultimate target), such that they do not have to be
2027404b540aSrobert    followed again, and return the ultimate target of the alias
2028404b540aSrobert    chain.  */
2029404b540aSrobert 
2030404b540aSrobert static inline tree
ultimate_transparent_alias_target(tree * alias)2031404b540aSrobert ultimate_transparent_alias_target (tree *alias)
2032404b540aSrobert {
2033404b540aSrobert   tree target = *alias;
2034404b540aSrobert 
2035404b540aSrobert   if (IDENTIFIER_TRANSPARENT_ALIAS (target))
2036404b540aSrobert     {
2037404b540aSrobert       gcc_assert (TREE_CHAIN (target));
2038404b540aSrobert       target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
2039404b540aSrobert       gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
2040404b540aSrobert 		  && ! TREE_CHAIN (target));
2041404b540aSrobert       *alias = target;
2042404b540aSrobert     }
2043404b540aSrobert 
2044404b540aSrobert   return target;
2045404b540aSrobert }
2046404b540aSrobert 
2047404b540aSrobert /* Output to FILE (an assembly file) a reference to NAME.  If NAME
2048404b540aSrobert    starts with a *, the rest of NAME is output verbatim.  Otherwise
2049404b540aSrobert    NAME is transformed in a target-specific way (usually by the
2050404b540aSrobert    addition of an underscore).  */
2051404b540aSrobert 
2052404b540aSrobert void
assemble_name_raw(FILE * file,const char * name)2053404b540aSrobert assemble_name_raw (FILE *file, const char *name)
2054404b540aSrobert {
2055404b540aSrobert   if (name[0] == '*')
2056404b540aSrobert     fputs (&name[1], file);
2057404b540aSrobert   else
2058404b540aSrobert     ASM_OUTPUT_LABELREF (file, name);
2059404b540aSrobert }
2060404b540aSrobert 
2061404b540aSrobert /* Like assemble_name_raw, but should be used when NAME might refer to
2062404b540aSrobert    an entity that is also represented as a tree (like a function or
2063404b540aSrobert    variable).  If NAME does refer to such an entity, that entity will
2064404b540aSrobert    be marked as referenced.  */
2065404b540aSrobert 
2066404b540aSrobert void
assemble_name(FILE * file,const char * name)2067404b540aSrobert assemble_name (FILE *file, const char *name)
2068404b540aSrobert {
2069404b540aSrobert   const char *real_name;
2070404b540aSrobert   tree id;
2071404b540aSrobert 
2072404b540aSrobert   real_name = targetm.strip_name_encoding (name);
2073404b540aSrobert 
2074404b540aSrobert   id = maybe_get_identifier (real_name);
2075404b540aSrobert   if (id)
2076404b540aSrobert     {
2077404b540aSrobert       tree id_orig = id;
2078404b540aSrobert 
2079404b540aSrobert       mark_referenced (id);
2080404b540aSrobert       ultimate_transparent_alias_target (&id);
2081404b540aSrobert       if (id != id_orig)
2082404b540aSrobert 	name = IDENTIFIER_POINTER (id);
2083404b540aSrobert       gcc_assert (! TREE_CHAIN (id));
2084404b540aSrobert     }
2085404b540aSrobert 
2086404b540aSrobert   assemble_name_raw (file, name);
2087404b540aSrobert }
2088404b540aSrobert 
2089404b540aSrobert /* Allocate SIZE bytes writable static space with a gensym name
2090404b540aSrobert    and return an RTX to refer to its address.  */
2091404b540aSrobert 
2092404b540aSrobert rtx
assemble_static_space(unsigned HOST_WIDE_INT size)2093404b540aSrobert assemble_static_space (unsigned HOST_WIDE_INT size)
2094404b540aSrobert {
2095404b540aSrobert   char name[12];
2096404b540aSrobert   const char *namestring;
2097404b540aSrobert   rtx x;
2098404b540aSrobert 
2099404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
2100404b540aSrobert   ++const_labelno;
2101404b540aSrobert   namestring = ggc_strdup (name);
2102404b540aSrobert 
2103404b540aSrobert   x = gen_rtx_SYMBOL_REF (Pmode, namestring);
2104404b540aSrobert   SYMBOL_REF_FLAGS (x) = SYMBOL_FLAG_LOCAL;
2105404b540aSrobert 
2106404b540aSrobert #ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
2107404b540aSrobert   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
2108404b540aSrobert 				 BIGGEST_ALIGNMENT);
2109404b540aSrobert #else
2110404b540aSrobert #ifdef ASM_OUTPUT_ALIGNED_LOCAL
2111404b540aSrobert   ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
2112404b540aSrobert #else
2113404b540aSrobert   {
2114404b540aSrobert     /* Round size up to multiple of BIGGEST_ALIGNMENT bits
2115404b540aSrobert        so that each uninitialized object starts on such a boundary.  */
2116404b540aSrobert     /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL.  */
2117404b540aSrobert     unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED
2118404b540aSrobert       = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
2119404b540aSrobert 	 / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
2120404b540aSrobert 	 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
2121404b540aSrobert     ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
2122404b540aSrobert   }
2123404b540aSrobert #endif
2124404b540aSrobert #endif
2125404b540aSrobert   return x;
2126404b540aSrobert }
2127404b540aSrobert 
2128404b540aSrobert /* Assemble the static constant template for function entry trampolines.
2129404b540aSrobert    This is done at most once per compilation.
2130404b540aSrobert    Returns an RTX for the address of the template.  */
2131404b540aSrobert 
2132404b540aSrobert static GTY(()) rtx initial_trampoline;
2133404b540aSrobert 
2134404b540aSrobert #ifdef TRAMPOLINE_TEMPLATE
2135404b540aSrobert rtx
assemble_trampoline_template(void)2136404b540aSrobert assemble_trampoline_template (void)
2137404b540aSrobert {
2138404b540aSrobert   char label[256];
2139404b540aSrobert   const char *name;
2140404b540aSrobert   int align;
2141404b540aSrobert   rtx symbol;
2142404b540aSrobert 
2143404b540aSrobert   if (initial_trampoline)
2144404b540aSrobert     return initial_trampoline;
2145404b540aSrobert 
2146404b540aSrobert   /* By default, put trampoline templates in read-only data section.  */
2147404b540aSrobert 
2148404b540aSrobert #ifdef TRAMPOLINE_SECTION
2149404b540aSrobert   switch_to_section (TRAMPOLINE_SECTION);
2150404b540aSrobert #else
2151404b540aSrobert   switch_to_section (readonly_data_section);
2152404b540aSrobert #endif
2153404b540aSrobert 
2154404b540aSrobert   /* Write the assembler code to define one.  */
2155404b540aSrobert   align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
2156404b540aSrobert   if (align > 0)
2157404b540aSrobert     {
2158404b540aSrobert       ASM_OUTPUT_ALIGN (asm_out_file, align);
2159404b540aSrobert     }
2160404b540aSrobert 
2161404b540aSrobert   targetm.asm_out.internal_label (asm_out_file, "LTRAMP", 0);
2162404b540aSrobert   TRAMPOLINE_TEMPLATE (asm_out_file);
2163404b540aSrobert 
2164404b540aSrobert   /* Record the rtl to refer to it.  */
2165404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
2166404b540aSrobert   name = ggc_strdup (label);
2167404b540aSrobert   symbol = gen_rtx_SYMBOL_REF (Pmode, name);
2168404b540aSrobert   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
2169404b540aSrobert 
2170404b540aSrobert   initial_trampoline = gen_rtx_MEM (BLKmode, symbol);
2171404b540aSrobert   set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
2172404b540aSrobert 
2173404b540aSrobert   return initial_trampoline;
2174404b540aSrobert }
2175404b540aSrobert #endif
2176404b540aSrobert 
2177404b540aSrobert /* A and B are either alignments or offsets.  Return the minimum alignment
2178404b540aSrobert    that may be assumed after adding the two together.  */
2179404b540aSrobert 
2180404b540aSrobert static inline unsigned
min_align(unsigned int a,unsigned int b)2181404b540aSrobert min_align (unsigned int a, unsigned int b)
2182404b540aSrobert {
2183404b540aSrobert   return (a | b) & -(a | b);
2184404b540aSrobert }
2185404b540aSrobert 
2186404b540aSrobert /* Return the assembler directive for creating a given kind of integer
2187404b540aSrobert    object.  SIZE is the number of bytes in the object and ALIGNED_P
2188404b540aSrobert    indicates whether it is known to be aligned.  Return NULL if the
2189404b540aSrobert    assembly dialect has no such directive.
2190404b540aSrobert 
2191404b540aSrobert    The returned string should be printed at the start of a new line and
2192404b540aSrobert    be followed immediately by the object's initial value.  */
2193404b540aSrobert 
2194404b540aSrobert const char *
integer_asm_op(int size,int aligned_p)2195404b540aSrobert integer_asm_op (int size, int aligned_p)
2196404b540aSrobert {
2197404b540aSrobert   struct asm_int_op *ops;
2198404b540aSrobert 
2199404b540aSrobert   if (aligned_p)
2200404b540aSrobert     ops = &targetm.asm_out.aligned_op;
2201404b540aSrobert   else
2202404b540aSrobert     ops = &targetm.asm_out.unaligned_op;
2203404b540aSrobert 
2204404b540aSrobert   switch (size)
2205404b540aSrobert     {
2206404b540aSrobert     case 1:
2207404b540aSrobert       return targetm.asm_out.byte_op;
2208404b540aSrobert     case 2:
2209404b540aSrobert       return ops->hi;
2210404b540aSrobert     case 4:
2211404b540aSrobert       return ops->si;
2212404b540aSrobert     case 8:
2213404b540aSrobert       return ops->di;
2214404b540aSrobert     case 16:
2215404b540aSrobert       return ops->ti;
2216404b540aSrobert     default:
2217404b540aSrobert       return NULL;
2218404b540aSrobert     }
2219404b540aSrobert }
2220404b540aSrobert 
2221404b540aSrobert /* Use directive OP to assemble an integer object X.  Print OP at the
2222404b540aSrobert    start of the line, followed immediately by the value of X.  */
2223404b540aSrobert 
2224404b540aSrobert void
assemble_integer_with_op(const char * op,rtx x)2225404b540aSrobert assemble_integer_with_op (const char *op, rtx x)
2226404b540aSrobert {
2227404b540aSrobert   fputs (op, asm_out_file);
2228404b540aSrobert   output_addr_const (asm_out_file, x);
2229404b540aSrobert   fputc ('\n', asm_out_file);
2230404b540aSrobert }
2231404b540aSrobert 
2232404b540aSrobert /* The default implementation of the asm_out.integer target hook.  */
2233404b540aSrobert 
2234404b540aSrobert bool
default_assemble_integer(rtx x ATTRIBUTE_UNUSED,unsigned int size ATTRIBUTE_UNUSED,int aligned_p ATTRIBUTE_UNUSED)2235404b540aSrobert default_assemble_integer (rtx x ATTRIBUTE_UNUSED,
2236404b540aSrobert 			  unsigned int size ATTRIBUTE_UNUSED,
2237404b540aSrobert 			  int aligned_p ATTRIBUTE_UNUSED)
2238404b540aSrobert {
2239404b540aSrobert   const char *op = integer_asm_op (size, aligned_p);
2240404b540aSrobert   /* Avoid GAS bugs for large values.  Specifically negative values whose
2241404b540aSrobert      absolute value fits in a bfd_vma, but not in a bfd_signed_vma.  */
2242404b540aSrobert   if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
2243404b540aSrobert     return false;
2244404b540aSrobert   return op && (assemble_integer_with_op (op, x), true);
2245404b540aSrobert }
2246404b540aSrobert 
2247404b540aSrobert /* Assemble the integer constant X into an object of SIZE bytes.  ALIGN is
2248404b540aSrobert    the alignment of the integer in bits.  Return 1 if we were able to output
2249404b540aSrobert    the constant, otherwise 0.  We must be able to output the constant,
2250404b540aSrobert    if FORCE is nonzero.  */
2251404b540aSrobert 
2252404b540aSrobert bool
assemble_integer(rtx x,unsigned int size,unsigned int align,int force)2253404b540aSrobert assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
2254404b540aSrobert {
2255404b540aSrobert   int aligned_p;
2256404b540aSrobert 
2257404b540aSrobert   aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));
2258404b540aSrobert 
2259404b540aSrobert   /* See if the target hook can handle this kind of object.  */
2260404b540aSrobert   if (targetm.asm_out.integer (x, size, aligned_p))
2261404b540aSrobert     return true;
2262404b540aSrobert 
2263404b540aSrobert   /* If the object is a multi-byte one, try splitting it up.  Split
2264404b540aSrobert      it into words it if is multi-word, otherwise split it into bytes.  */
2265404b540aSrobert   if (size > 1)
2266404b540aSrobert     {
2267404b540aSrobert       enum machine_mode omode, imode;
2268404b540aSrobert       unsigned int subalign;
2269404b540aSrobert       unsigned int subsize, i;
2270404b540aSrobert 
2271404b540aSrobert       subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
2272404b540aSrobert       subalign = MIN (align, subsize * BITS_PER_UNIT);
2273404b540aSrobert       omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0);
2274404b540aSrobert       imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
2275404b540aSrobert 
2276404b540aSrobert       for (i = 0; i < size; i += subsize)
2277404b540aSrobert 	{
2278404b540aSrobert 	  rtx partial = simplify_subreg (omode, x, imode, i);
2279404b540aSrobert 	  if (!partial || !assemble_integer (partial, subsize, subalign, 0))
2280404b540aSrobert 	    break;
2281404b540aSrobert 	}
2282404b540aSrobert       if (i == size)
2283404b540aSrobert 	return true;
2284404b540aSrobert 
2285404b540aSrobert       /* If we've printed some of it, but not all of it, there's no going
2286404b540aSrobert 	 back now.  */
2287404b540aSrobert       gcc_assert (!i);
2288404b540aSrobert     }
2289404b540aSrobert 
2290404b540aSrobert   gcc_assert (!force);
2291404b540aSrobert 
2292404b540aSrobert   return false;
2293404b540aSrobert }
2294404b540aSrobert 
2295404b540aSrobert void
assemble_real(REAL_VALUE_TYPE d,enum machine_mode mode,unsigned int align)2296404b540aSrobert assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
2297404b540aSrobert {
2298404b540aSrobert   long data[4] = {0, 0, 0, 0};
2299404b540aSrobert   int i;
2300404b540aSrobert   int bitsize, nelts, nunits, units_per;
2301404b540aSrobert 
2302404b540aSrobert   /* This is hairy.  We have a quantity of known size.  real_to_target
2303404b540aSrobert      will put it into an array of *host* longs, 32 bits per element
2304404b540aSrobert      (even if long is more than 32 bits).  We need to determine the
2305404b540aSrobert      number of array elements that are occupied (nelts) and the number
2306404b540aSrobert      of *target* min-addressable units that will be occupied in the
2307404b540aSrobert      object file (nunits).  We cannot assume that 32 divides the
2308404b540aSrobert      mode's bitsize (size * BITS_PER_UNIT) evenly.
2309404b540aSrobert 
2310404b540aSrobert      size * BITS_PER_UNIT is used here to make sure that padding bits
2311404b540aSrobert      (which might appear at either end of the value; real_to_target
2312404b540aSrobert      will include the padding bits in its output array) are included.  */
2313404b540aSrobert 
2314404b540aSrobert   nunits = GET_MODE_SIZE (mode);
2315404b540aSrobert   bitsize = nunits * BITS_PER_UNIT;
2316404b540aSrobert   nelts = CEIL (bitsize, 32);
2317404b540aSrobert   units_per = 32 / BITS_PER_UNIT;
2318404b540aSrobert 
2319404b540aSrobert   real_to_target (data, &d, mode);
2320404b540aSrobert 
2321404b540aSrobert   /* Put out the first word with the specified alignment.  */
2322404b540aSrobert   assemble_integer (GEN_INT (data[0]), MIN (nunits, units_per), align, 1);
2323404b540aSrobert   nunits -= units_per;
2324404b540aSrobert 
2325404b540aSrobert   /* Subsequent words need only 32-bit alignment.  */
2326404b540aSrobert   align = min_align (align, 32);
2327404b540aSrobert 
2328404b540aSrobert   for (i = 1; i < nelts; i++)
2329404b540aSrobert     {
2330404b540aSrobert       assemble_integer (GEN_INT (data[i]), MIN (nunits, units_per), align, 1);
2331404b540aSrobert       nunits -= units_per;
2332404b540aSrobert     }
2333404b540aSrobert }
2334404b540aSrobert 
2335404b540aSrobert /* Given an expression EXP with a constant value,
2336404b540aSrobert    reduce it to the sum of an assembler symbol and an integer.
2337404b540aSrobert    Store them both in the structure *VALUE.
2338404b540aSrobert    EXP must be reducible.  */
2339404b540aSrobert 
2340404b540aSrobert struct addr_const GTY(())
2341404b540aSrobert {
2342404b540aSrobert   rtx base;
2343404b540aSrobert   HOST_WIDE_INT offset;
2344404b540aSrobert };
2345404b540aSrobert 
2346404b540aSrobert static void
decode_addr_const(tree exp,struct addr_const * value)2347404b540aSrobert decode_addr_const (tree exp, struct addr_const *value)
2348404b540aSrobert {
2349404b540aSrobert   tree target = TREE_OPERAND (exp, 0);
2350404b540aSrobert   int offset = 0;
2351404b540aSrobert   rtx x;
2352404b540aSrobert 
2353404b540aSrobert   while (1)
2354404b540aSrobert     {
2355404b540aSrobert       if (TREE_CODE (target) == COMPONENT_REF
2356404b540aSrobert 	  && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
2357404b540aSrobert 
2358404b540aSrobert 	{
2359404b540aSrobert 	  offset += int_byte_position (TREE_OPERAND (target, 1));
2360404b540aSrobert 	  target = TREE_OPERAND (target, 0);
2361404b540aSrobert 	}
2362404b540aSrobert       else if (TREE_CODE (target) == ARRAY_REF
2363404b540aSrobert 	       || TREE_CODE (target) == ARRAY_RANGE_REF)
2364404b540aSrobert 	{
2365404b540aSrobert 	  offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
2366404b540aSrobert 		     * tree_low_cst (TREE_OPERAND (target, 1), 0));
2367404b540aSrobert 	  target = TREE_OPERAND (target, 0);
2368404b540aSrobert 	}
2369404b540aSrobert       else
2370404b540aSrobert 	break;
2371404b540aSrobert     }
2372404b540aSrobert 
2373404b540aSrobert   switch (TREE_CODE (target))
2374404b540aSrobert     {
2375404b540aSrobert     case VAR_DECL:
2376404b540aSrobert     case FUNCTION_DECL:
2377404b540aSrobert       x = DECL_RTL (target);
2378404b540aSrobert       break;
2379404b540aSrobert 
2380404b540aSrobert     case LABEL_DECL:
2381404b540aSrobert       x = gen_rtx_MEM (FUNCTION_MODE,
2382404b540aSrobert 		       gen_rtx_LABEL_REF (Pmode, force_label_rtx (target)));
2383404b540aSrobert       break;
2384404b540aSrobert 
2385404b540aSrobert     case REAL_CST:
2386404b540aSrobert     case STRING_CST:
2387404b540aSrobert     case COMPLEX_CST:
2388404b540aSrobert     case CONSTRUCTOR:
2389404b540aSrobert     case INTEGER_CST:
2390404b540aSrobert       x = output_constant_def (target, 1);
2391404b540aSrobert       break;
2392404b540aSrobert 
2393404b540aSrobert     default:
2394404b540aSrobert       gcc_unreachable ();
2395404b540aSrobert     }
2396404b540aSrobert 
2397404b540aSrobert   gcc_assert (MEM_P (x));
2398404b540aSrobert   x = XEXP (x, 0);
2399404b540aSrobert 
2400404b540aSrobert   value->base = x;
2401404b540aSrobert   value->offset = offset;
2402404b540aSrobert }
2403404b540aSrobert 
2404404b540aSrobert /* Uniquize all constants that appear in memory.
2405404b540aSrobert    Each constant in memory thus far output is recorded
2406404b540aSrobert    in `const_desc_table'.  */
2407404b540aSrobert 
2408404b540aSrobert struct constant_descriptor_tree GTY(())
2409404b540aSrobert {
2410404b540aSrobert   /* A MEM for the constant.  */
2411404b540aSrobert   rtx rtl;
2412404b540aSrobert 
2413404b540aSrobert   /* The value of the constant.  */
2414404b540aSrobert   tree value;
2415404b540aSrobert 
2416404b540aSrobert   /* Hash of value.  Computing the hash from value each time
2417404b540aSrobert      hashfn is called can't work properly, as that means recursive
2418404b540aSrobert      use of the hash table during hash table expansion.  */
2419404b540aSrobert   hashval_t hash;
2420404b540aSrobert };
2421404b540aSrobert 
2422404b540aSrobert static GTY((param_is (struct constant_descriptor_tree)))
2423404b540aSrobert      htab_t const_desc_htab;
2424404b540aSrobert 
2425404b540aSrobert static struct constant_descriptor_tree * build_constant_desc (tree);
2426404b540aSrobert static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
2427404b540aSrobert 
2428404b540aSrobert /* Compute a hash code for a constant expression.  */
2429404b540aSrobert 
2430404b540aSrobert static hashval_t
const_desc_hash(const void * ptr)2431404b540aSrobert const_desc_hash (const void *ptr)
2432404b540aSrobert {
2433404b540aSrobert   return ((struct constant_descriptor_tree *)ptr)->hash;
2434404b540aSrobert }
2435404b540aSrobert 
2436404b540aSrobert static hashval_t
const_hash_1(const tree exp)2437404b540aSrobert const_hash_1 (const tree exp)
2438404b540aSrobert {
2439404b540aSrobert   const char *p;
2440404b540aSrobert   hashval_t hi;
2441404b540aSrobert   int len, i;
2442404b540aSrobert   enum tree_code code = TREE_CODE (exp);
2443404b540aSrobert 
2444404b540aSrobert   /* Either set P and LEN to the address and len of something to hash and
2445404b540aSrobert      exit the switch or return a value.  */
2446404b540aSrobert 
2447404b540aSrobert   switch (code)
2448404b540aSrobert     {
2449404b540aSrobert     case INTEGER_CST:
2450404b540aSrobert       p = (char *) &TREE_INT_CST (exp);
2451404b540aSrobert       len = sizeof TREE_INT_CST (exp);
2452404b540aSrobert       break;
2453404b540aSrobert 
2454404b540aSrobert     case REAL_CST:
2455404b540aSrobert       return real_hash (TREE_REAL_CST_PTR (exp));
2456404b540aSrobert 
2457404b540aSrobert     case STRING_CST:
2458404b540aSrobert       p = TREE_STRING_POINTER (exp);
2459404b540aSrobert       len = TREE_STRING_LENGTH (exp);
2460404b540aSrobert       break;
2461404b540aSrobert 
2462404b540aSrobert     case COMPLEX_CST:
2463404b540aSrobert       return (const_hash_1 (TREE_REALPART (exp)) * 5
2464404b540aSrobert 	      + const_hash_1 (TREE_IMAGPART (exp)));
2465404b540aSrobert 
2466404b540aSrobert     case CONSTRUCTOR:
2467404b540aSrobert       {
2468404b540aSrobert 	unsigned HOST_WIDE_INT idx;
2469404b540aSrobert 	tree value;
2470404b540aSrobert 
2471404b540aSrobert 	hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
2472404b540aSrobert 
2473404b540aSrobert 	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
2474404b540aSrobert 	  if (value)
2475404b540aSrobert 	    hi = hi * 603 + const_hash_1 (value);
2476404b540aSrobert 
2477404b540aSrobert 	return hi;
2478404b540aSrobert       }
2479404b540aSrobert 
2480404b540aSrobert     case ADDR_EXPR:
2481404b540aSrobert     case FDESC_EXPR:
2482404b540aSrobert       {
2483404b540aSrobert 	struct addr_const value;
2484404b540aSrobert 
2485404b540aSrobert 	decode_addr_const (exp, &value);
2486404b540aSrobert 	switch (GET_CODE (value.base))
2487404b540aSrobert 	  {
2488404b540aSrobert 	  case SYMBOL_REF:
2489404b540aSrobert 	    /* Don't hash the address of the SYMBOL_REF;
2490404b540aSrobert 	       only use the offset and the symbol name.  */
2491404b540aSrobert 	    hi = value.offset;
2492404b540aSrobert 	    p = XSTR (value.base, 0);
2493404b540aSrobert 	    for (i = 0; p[i] != 0; i++)
2494404b540aSrobert 	      hi = ((hi * 613) + (unsigned) (p[i]));
2495404b540aSrobert 	    break;
2496404b540aSrobert 
2497404b540aSrobert 	  case LABEL_REF:
2498404b540aSrobert 	    hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
2499404b540aSrobert 	    break;
2500404b540aSrobert 
2501404b540aSrobert 	  default:
2502404b540aSrobert 	    gcc_unreachable ();
2503404b540aSrobert 	  }
2504404b540aSrobert       }
2505404b540aSrobert       return hi;
2506404b540aSrobert 
2507404b540aSrobert     case PLUS_EXPR:
2508404b540aSrobert     case MINUS_EXPR:
2509404b540aSrobert       return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
2510404b540aSrobert 	      + const_hash_1 (TREE_OPERAND (exp, 1)));
2511404b540aSrobert 
2512404b540aSrobert     case NOP_EXPR:
2513404b540aSrobert     case CONVERT_EXPR:
2514404b540aSrobert     case NON_LVALUE_EXPR:
2515404b540aSrobert       return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
2516404b540aSrobert 
2517404b540aSrobert     default:
2518404b540aSrobert       /* A language specific constant. Just hash the code.  */
2519404b540aSrobert       return code;
2520404b540aSrobert     }
2521404b540aSrobert 
2522404b540aSrobert   /* Compute hashing function.  */
2523404b540aSrobert   hi = len;
2524404b540aSrobert   for (i = 0; i < len; i++)
2525404b540aSrobert     hi = ((hi * 613) + (unsigned) (p[i]));
2526404b540aSrobert 
2527404b540aSrobert   return hi;
2528404b540aSrobert }
2529404b540aSrobert 
2530404b540aSrobert /* Wrapper of compare_constant, for the htab interface.  */
2531404b540aSrobert static int
const_desc_eq(const void * p1,const void * p2)2532404b540aSrobert const_desc_eq (const void *p1, const void *p2)
2533404b540aSrobert {
2534404b540aSrobert   const struct constant_descriptor_tree *c1 = p1;
2535404b540aSrobert   const struct constant_descriptor_tree *c2 = p2;
2536404b540aSrobert   if (c1->hash != c2->hash)
2537404b540aSrobert     return 0;
2538404b540aSrobert   return compare_constant (c1->value, c2->value);
2539404b540aSrobert }
2540404b540aSrobert 
2541404b540aSrobert /* Compare t1 and t2, and return 1 only if they are known to result in
2542404b540aSrobert    the same bit pattern on output.  */
2543404b540aSrobert 
2544404b540aSrobert static int
compare_constant(const tree t1,const tree t2)2545404b540aSrobert compare_constant (const tree t1, const tree t2)
2546404b540aSrobert {
2547404b540aSrobert   enum tree_code typecode;
2548404b540aSrobert 
2549404b540aSrobert   if (t1 == NULL_TREE)
2550404b540aSrobert     return t2 == NULL_TREE;
2551404b540aSrobert   if (t2 == NULL_TREE)
2552404b540aSrobert     return 0;
2553404b540aSrobert 
2554404b540aSrobert   if (TREE_CODE (t1) != TREE_CODE (t2))
2555404b540aSrobert     return 0;
2556404b540aSrobert 
2557404b540aSrobert   switch (TREE_CODE (t1))
2558404b540aSrobert     {
2559404b540aSrobert     case INTEGER_CST:
2560404b540aSrobert       /* Integer constants are the same only if the same width of type.  */
2561404b540aSrobert       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
2562404b540aSrobert 	return 0;
2563404b540aSrobert       if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
2564404b540aSrobert 	return 0;
2565404b540aSrobert       return tree_int_cst_equal (t1, t2);
2566404b540aSrobert 
2567404b540aSrobert     case REAL_CST:
2568404b540aSrobert       /* Real constants are the same only if the same width of type.  */
2569404b540aSrobert       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
2570404b540aSrobert 	return 0;
2571404b540aSrobert 
2572404b540aSrobert       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
2573404b540aSrobert 
2574404b540aSrobert     case STRING_CST:
2575404b540aSrobert       if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
2576404b540aSrobert 	return 0;
2577404b540aSrobert 
2578404b540aSrobert       return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
2579404b540aSrobert 	      && ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
2580404b540aSrobert 			 TREE_STRING_LENGTH (t1)));
2581404b540aSrobert 
2582404b540aSrobert     case COMPLEX_CST:
2583404b540aSrobert       return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
2584404b540aSrobert 	      && compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
2585404b540aSrobert 
2586404b540aSrobert     case CONSTRUCTOR:
2587404b540aSrobert       {
2588404b540aSrobert 	VEC(constructor_elt, gc) *v1, *v2;
2589404b540aSrobert 	unsigned HOST_WIDE_INT idx;
2590404b540aSrobert 
2591404b540aSrobert 	typecode = TREE_CODE (TREE_TYPE (t1));
2592404b540aSrobert 	if (typecode != TREE_CODE (TREE_TYPE (t2)))
2593404b540aSrobert 	  return 0;
2594404b540aSrobert 
2595404b540aSrobert 	if (typecode == ARRAY_TYPE)
2596404b540aSrobert 	  {
2597404b540aSrobert 	    HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
2598404b540aSrobert 	    /* For arrays, check that the sizes all match.  */
2599404b540aSrobert 	    if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
2600404b540aSrobert 		|| size_1 == -1
2601404b540aSrobert 		|| size_1 != int_size_in_bytes (TREE_TYPE (t2)))
2602404b540aSrobert 	      return 0;
2603404b540aSrobert 	  }
2604404b540aSrobert 	else
2605404b540aSrobert 	  {
2606404b540aSrobert 	    /* For record and union constructors, require exact type
2607404b540aSrobert                equality.  */
2608404b540aSrobert 	    if (TREE_TYPE (t1) != TREE_TYPE (t2))
2609404b540aSrobert 	      return 0;
2610404b540aSrobert 	  }
2611404b540aSrobert 
2612404b540aSrobert 	v1 = CONSTRUCTOR_ELTS (t1);
2613404b540aSrobert 	v2 = CONSTRUCTOR_ELTS (t2);
2614404b540aSrobert 	if (VEC_length (constructor_elt, v1)
2615404b540aSrobert 	    != VEC_length (constructor_elt, v2))
2616404b540aSrobert 	    return 0;
2617404b540aSrobert 
2618404b540aSrobert 	for (idx = 0; idx < VEC_length (constructor_elt, v1); ++idx)
2619404b540aSrobert 	  {
2620404b540aSrobert 	    constructor_elt *c1 = VEC_index (constructor_elt, v1, idx);
2621404b540aSrobert 	    constructor_elt *c2 = VEC_index (constructor_elt, v2, idx);
2622404b540aSrobert 
2623404b540aSrobert 	    /* Check that each value is the same...  */
2624404b540aSrobert 	    if (!compare_constant (c1->value, c2->value))
2625404b540aSrobert 	      return 0;
2626404b540aSrobert 	    /* ... and that they apply to the same fields!  */
2627404b540aSrobert 	    if (typecode == ARRAY_TYPE)
2628404b540aSrobert 	      {
2629404b540aSrobert 		if (!compare_constant (c1->index, c2->index))
2630404b540aSrobert 		  return 0;
2631404b540aSrobert 	      }
2632404b540aSrobert 	    else
2633404b540aSrobert 	      {
2634404b540aSrobert 		if (c1->index != c2->index)
2635404b540aSrobert 		  return 0;
2636404b540aSrobert 	      }
2637404b540aSrobert 	  }
2638404b540aSrobert 
2639404b540aSrobert 	return 1;
2640404b540aSrobert       }
2641404b540aSrobert 
2642404b540aSrobert     case ADDR_EXPR:
2643404b540aSrobert     case FDESC_EXPR:
2644404b540aSrobert       {
2645404b540aSrobert 	struct addr_const value1, value2;
2646404b540aSrobert 
2647404b540aSrobert 	decode_addr_const (t1, &value1);
2648404b540aSrobert 	decode_addr_const (t2, &value2);
2649404b540aSrobert 	return (value1.offset == value2.offset
2650404b540aSrobert 		&& strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
2651404b540aSrobert       }
2652404b540aSrobert 
2653404b540aSrobert     case PLUS_EXPR:
2654404b540aSrobert     case MINUS_EXPR:
2655404b540aSrobert     case RANGE_EXPR:
2656404b540aSrobert       return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
2657404b540aSrobert 	      && compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
2658404b540aSrobert 
2659404b540aSrobert     case NOP_EXPR:
2660404b540aSrobert     case CONVERT_EXPR:
2661404b540aSrobert     case NON_LVALUE_EXPR:
2662404b540aSrobert     case VIEW_CONVERT_EXPR:
2663404b540aSrobert       return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
2664404b540aSrobert 
2665404b540aSrobert     default:
2666404b540aSrobert       {
2667404b540aSrobert 	tree nt1, nt2;
2668404b540aSrobert 	nt1 = lang_hooks.expand_constant (t1);
2669404b540aSrobert 	nt2 = lang_hooks.expand_constant (t2);
2670404b540aSrobert 	if (nt1 != t1 || nt2 != t2)
2671404b540aSrobert 	  return compare_constant (nt1, nt2);
2672404b540aSrobert 	else
2673404b540aSrobert 	  return 0;
2674404b540aSrobert       }
2675404b540aSrobert     }
2676404b540aSrobert 
2677404b540aSrobert   gcc_unreachable ();
2678404b540aSrobert }
2679404b540aSrobert 
2680404b540aSrobert /* Make a copy of the whole tree structure for a constant.  This
2681404b540aSrobert    handles the same types of nodes that compare_constant handles.  */
2682404b540aSrobert 
2683404b540aSrobert static tree
copy_constant(tree exp)2684404b540aSrobert copy_constant (tree exp)
2685404b540aSrobert {
2686404b540aSrobert   switch (TREE_CODE (exp))
2687404b540aSrobert     {
2688404b540aSrobert     case ADDR_EXPR:
2689404b540aSrobert       /* For ADDR_EXPR, we do not want to copy the decl whose address
2690404b540aSrobert 	 is requested.  We do want to copy constants though.  */
2691404b540aSrobert       if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
2692404b540aSrobert 	return build1 (TREE_CODE (exp), TREE_TYPE (exp),
2693404b540aSrobert 		       copy_constant (TREE_OPERAND (exp, 0)));
2694404b540aSrobert       else
2695404b540aSrobert 	return copy_node (exp);
2696404b540aSrobert 
2697404b540aSrobert     case INTEGER_CST:
2698404b540aSrobert     case REAL_CST:
2699404b540aSrobert     case STRING_CST:
2700404b540aSrobert       return copy_node (exp);
2701404b540aSrobert 
2702404b540aSrobert     case COMPLEX_CST:
2703404b540aSrobert       return build_complex (TREE_TYPE (exp),
2704404b540aSrobert 			    copy_constant (TREE_REALPART (exp)),
2705404b540aSrobert 			    copy_constant (TREE_IMAGPART (exp)));
2706404b540aSrobert 
2707404b540aSrobert     case PLUS_EXPR:
2708404b540aSrobert     case MINUS_EXPR:
2709404b540aSrobert       return build2 (TREE_CODE (exp), TREE_TYPE (exp),
2710404b540aSrobert 		     copy_constant (TREE_OPERAND (exp, 0)),
2711404b540aSrobert 		     copy_constant (TREE_OPERAND (exp, 1)));
2712404b540aSrobert 
2713404b540aSrobert     case NOP_EXPR:
2714404b540aSrobert     case CONVERT_EXPR:
2715404b540aSrobert     case NON_LVALUE_EXPR:
2716404b540aSrobert     case VIEW_CONVERT_EXPR:
2717404b540aSrobert       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
2718404b540aSrobert 		     copy_constant (TREE_OPERAND (exp, 0)));
2719404b540aSrobert 
2720404b540aSrobert     case CONSTRUCTOR:
2721404b540aSrobert       {
2722404b540aSrobert 	tree copy = copy_node (exp);
2723404b540aSrobert 	VEC(constructor_elt, gc) *v;
2724404b540aSrobert 	unsigned HOST_WIDE_INT idx;
2725404b540aSrobert 	tree purpose, value;
2726404b540aSrobert 
2727404b540aSrobert 	v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
2728404b540aSrobert 						      CONSTRUCTOR_ELTS (exp)));
2729404b540aSrobert 	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
2730404b540aSrobert 	  {
2731404b540aSrobert 	    constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
2732404b540aSrobert 	    ce->index = purpose;
2733404b540aSrobert 	    ce->value = copy_constant (value);
2734404b540aSrobert 	  }
2735404b540aSrobert 	CONSTRUCTOR_ELTS (copy) = v;
2736404b540aSrobert 	return copy;
2737404b540aSrobert       }
2738404b540aSrobert 
2739404b540aSrobert     default:
2740404b540aSrobert       {
2741404b540aSrobert 	tree t = lang_hooks.expand_constant (exp);
2742404b540aSrobert 
2743404b540aSrobert 	gcc_assert (t != exp);
2744404b540aSrobert 	return copy_constant (t);
2745404b540aSrobert       }
2746404b540aSrobert     }
2747404b540aSrobert }
2748404b540aSrobert 
2749404b540aSrobert /* Return the alignment of constant EXP in bits.  */
2750404b540aSrobert 
2751404b540aSrobert static unsigned int
get_constant_alignment(tree exp)2752404b540aSrobert get_constant_alignment (tree exp)
2753404b540aSrobert {
2754404b540aSrobert   unsigned int align;
2755404b540aSrobert 
2756404b540aSrobert   align = TYPE_ALIGN (TREE_TYPE (exp));
2757404b540aSrobert #ifdef CONSTANT_ALIGNMENT
2758404b540aSrobert   align = CONSTANT_ALIGNMENT (exp, align);
2759404b540aSrobert #endif
2760404b540aSrobert   return align;
2761404b540aSrobert }
2762404b540aSrobert 
2763404b540aSrobert /* Return the section into which constant EXP should be placed.  */
2764404b540aSrobert 
2765404b540aSrobert static section *
get_constant_section(tree exp)2766404b540aSrobert get_constant_section (tree exp)
2767404b540aSrobert {
2768404b540aSrobert   if (IN_NAMED_SECTION (exp))
2769404b540aSrobert     return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
2770404b540aSrobert   else
2771404b540aSrobert     return targetm.asm_out.select_section (exp,
2772404b540aSrobert 					   compute_reloc_for_constant (exp),
2773404b540aSrobert 					   get_constant_alignment (exp));
2774404b540aSrobert }
2775404b540aSrobert 
2776404b540aSrobert /* Return the size of constant EXP in bytes.  */
2777404b540aSrobert 
2778404b540aSrobert static HOST_WIDE_INT
get_constant_size(tree exp)2779404b540aSrobert get_constant_size (tree exp)
2780404b540aSrobert {
2781404b540aSrobert   HOST_WIDE_INT size;
2782404b540aSrobert 
2783404b540aSrobert   size = int_size_in_bytes (TREE_TYPE (exp));
2784404b540aSrobert   if (TREE_CODE (exp) == STRING_CST)
2785404b540aSrobert     size = MAX (TREE_STRING_LENGTH (exp), size);
2786404b540aSrobert   return size;
2787404b540aSrobert }
2788404b540aSrobert 
2789404b540aSrobert /* Subroutine of output_constant_def:
2790404b540aSrobert    No constant equal to EXP is known to have been output.
2791404b540aSrobert    Make a constant descriptor to enter EXP in the hash table.
2792404b540aSrobert    Assign the label number and construct RTL to refer to the
2793404b540aSrobert    constant's location in memory.
2794404b540aSrobert    Caller is responsible for updating the hash table.  */
2795404b540aSrobert 
2796404b540aSrobert static struct constant_descriptor_tree *
build_constant_desc(tree exp)2797404b540aSrobert build_constant_desc (tree exp)
2798404b540aSrobert {
2799404b540aSrobert   rtx symbol;
2800404b540aSrobert   rtx rtl;
2801404b540aSrobert   char label[256];
2802404b540aSrobert   int labelno;
2803404b540aSrobert   struct constant_descriptor_tree *desc;
2804404b540aSrobert 
2805404b540aSrobert   desc = ggc_alloc (sizeof (*desc));
2806404b540aSrobert   desc->value = copy_constant (exp);
2807404b540aSrobert 
2808404b540aSrobert   /* Propagate marked-ness to copied constant.  */
2809404b540aSrobert   if (flag_mudflap && mf_marked_p (exp))
2810404b540aSrobert     mf_mark (desc->value);
2811404b540aSrobert 
2812404b540aSrobert   /* Create a string containing the label name, in LABEL.  */
2813404b540aSrobert   labelno = const_labelno++;
2814404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
2815404b540aSrobert 
2816404b540aSrobert   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
2817404b540aSrobert   if (use_object_blocks_p ())
2818404b540aSrobert     {
2819404b540aSrobert       section *sect = get_constant_section (exp);
2820404b540aSrobert       symbol = create_block_symbol (ggc_strdup (label),
2821404b540aSrobert 				    get_block_for_section (sect), -1);
2822404b540aSrobert     }
2823404b540aSrobert   else
2824404b540aSrobert     symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
2825404b540aSrobert   SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
2826404b540aSrobert   SET_SYMBOL_REF_DECL (symbol, desc->value);
2827404b540aSrobert   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
2828404b540aSrobert 
2829404b540aSrobert   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
2830404b540aSrobert   set_mem_attributes (rtl, exp, 1);
2831404b540aSrobert   set_mem_alias_set (rtl, 0);
2832404b540aSrobert   set_mem_alias_set (rtl, const_alias_set);
2833404b540aSrobert 
2834404b540aSrobert   /* Set flags or add text to the name to record information, such as
2835404b540aSrobert      that it is a local symbol.  If the name is changed, the macro
2836404b540aSrobert      ASM_OUTPUT_LABELREF will have to know how to strip this
2837404b540aSrobert      information.  This call might invalidate our local variable
2838404b540aSrobert      SYMBOL; we can't use it afterward.  */
2839404b540aSrobert 
2840404b540aSrobert   targetm.encode_section_info (exp, rtl, true);
2841404b540aSrobert 
2842404b540aSrobert   desc->rtl = rtl;
2843404b540aSrobert 
2844404b540aSrobert   return desc;
2845404b540aSrobert }
2846404b540aSrobert 
2847404b540aSrobert /* Return an rtx representing a reference to constant data in memory
2848404b540aSrobert    for the constant expression EXP.
2849404b540aSrobert 
2850404b540aSrobert    If assembler code for such a constant has already been output,
2851404b540aSrobert    return an rtx to refer to it.
2852404b540aSrobert    Otherwise, output such a constant in memory
2853404b540aSrobert    and generate an rtx for it.
2854404b540aSrobert 
2855404b540aSrobert    If DEFER is nonzero, this constant can be deferred and output only
2856404b540aSrobert    if referenced in the function after all optimizations.
2857404b540aSrobert 
2858404b540aSrobert    `const_desc_table' records which constants already have label strings.  */
2859404b540aSrobert 
2860404b540aSrobert rtx
output_constant_def(tree exp,int defer)2861404b540aSrobert output_constant_def (tree exp, int defer)
2862404b540aSrobert {
2863404b540aSrobert   struct constant_descriptor_tree *desc;
2864404b540aSrobert   struct constant_descriptor_tree key;
2865404b540aSrobert   void **loc;
2866404b540aSrobert 
2867404b540aSrobert   /* Look up EXP in the table of constant descriptors.  If we didn't find
2868404b540aSrobert      it, create a new one.  */
2869404b540aSrobert   key.value = exp;
2870404b540aSrobert   key.hash = const_hash_1 (exp);
2871404b540aSrobert   loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
2872404b540aSrobert 
2873404b540aSrobert   desc = *loc;
2874404b540aSrobert   if (desc == 0)
2875404b540aSrobert     {
2876404b540aSrobert       desc = build_constant_desc (exp);
2877404b540aSrobert       desc->hash = key.hash;
2878404b540aSrobert       *loc = desc;
2879404b540aSrobert     }
2880404b540aSrobert 
2881404b540aSrobert   maybe_output_constant_def_contents (desc, defer);
2882404b540aSrobert   return desc->rtl;
2883404b540aSrobert }
2884404b540aSrobert 
2885404b540aSrobert /* Subroutine of output_constant_def: Decide whether or not we need to
2886404b540aSrobert    output the constant DESC now, and if so, do it.  */
2887404b540aSrobert static void
maybe_output_constant_def_contents(struct constant_descriptor_tree * desc,int defer)2888404b540aSrobert maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
2889404b540aSrobert 				    int defer)
2890404b540aSrobert {
2891404b540aSrobert   rtx symbol = XEXP (desc->rtl, 0);
2892404b540aSrobert   tree exp = desc->value;
2893404b540aSrobert 
2894404b540aSrobert   if (flag_syntax_only)
2895404b540aSrobert     return;
2896404b540aSrobert 
2897404b540aSrobert   if (TREE_ASM_WRITTEN (exp))
2898404b540aSrobert     /* Already output; don't do it again.  */
2899404b540aSrobert     return;
2900404b540aSrobert 
2901404b540aSrobert   /* We can always defer constants as long as the context allows
2902404b540aSrobert      doing so.  */
2903404b540aSrobert   if (defer)
2904404b540aSrobert     {
2905404b540aSrobert       /* Increment n_deferred_constants if it exists.  It needs to be at
2906404b540aSrobert 	 least as large as the number of constants actually referred to
2907404b540aSrobert 	 by the function.  If it's too small we'll stop looking too early
2908404b540aSrobert 	 and fail to emit constants; if it's too large we'll only look
2909404b540aSrobert 	 through the entire function when we could have stopped earlier.  */
2910404b540aSrobert       if (cfun)
2911404b540aSrobert 	n_deferred_constants++;
2912404b540aSrobert       return;
2913404b540aSrobert     }
2914404b540aSrobert 
2915404b540aSrobert   output_constant_def_contents (symbol);
2916404b540aSrobert }
2917404b540aSrobert 
2918404b540aSrobert /* Subroutine of output_constant_def_contents.  Output the definition
2919404b540aSrobert    of constant EXP, which is pointed to by label LABEL.  ALIGN is the
2920404b540aSrobert    constant's alignment in bits.  */
2921404b540aSrobert 
2922404b540aSrobert static void
assemble_constant_contents(tree exp,const char * label,unsigned int align)2923404b540aSrobert assemble_constant_contents (tree exp, const char *label, unsigned int align)
2924404b540aSrobert {
2925404b540aSrobert   HOST_WIDE_INT size;
2926404b540aSrobert 
2927404b540aSrobert   size = get_constant_size (exp);
2928404b540aSrobert 
2929404b540aSrobert   /* Do any machine/system dependent processing of the constant.  */
2930404b540aSrobert #ifdef ASM_DECLARE_CONSTANT_NAME
2931404b540aSrobert   ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
2932404b540aSrobert #else
2933404b540aSrobert   /* Standard thing is just output label for the constant.  */
2934404b540aSrobert   ASM_OUTPUT_LABEL (asm_out_file, label);
2935404b540aSrobert #endif /* ASM_DECLARE_CONSTANT_NAME */
2936404b540aSrobert 
2937404b540aSrobert   /* Output the value of EXP.  */
2938404b540aSrobert   output_constant (exp, size, align);
2939404b540aSrobert }
2940404b540aSrobert 
2941404b540aSrobert /* We must output the constant data referred to by SYMBOL; do so.  */
2942404b540aSrobert 
2943404b540aSrobert static void
output_constant_def_contents(rtx symbol)2944404b540aSrobert output_constant_def_contents (rtx symbol)
2945404b540aSrobert {
2946404b540aSrobert   tree exp = SYMBOL_REF_DECL (symbol);
2947404b540aSrobert   unsigned int align;
2948404b540aSrobert 
2949404b540aSrobert   /* Make sure any other constants whose addresses appear in EXP
2950404b540aSrobert      are assigned label numbers.  */
2951404b540aSrobert   output_addressed_constants (exp);
2952404b540aSrobert 
2953404b540aSrobert   /* We are no longer deferring this constant.  */
2954404b540aSrobert   TREE_ASM_WRITTEN (exp) = 1;
2955404b540aSrobert 
2956404b540aSrobert   /* If the constant is part of an object block, make sure that the
2957404b540aSrobert      decl has been positioned within its block, but do not write out
2958404b540aSrobert      its definition yet.  output_object_blocks will do that later.  */
2959404b540aSrobert   if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
2960404b540aSrobert     place_block_symbol (symbol);
2961404b540aSrobert   else
2962404b540aSrobert     {
2963404b540aSrobert       switch_to_section (get_constant_section (exp));
2964404b540aSrobert       align = get_constant_alignment (exp);
2965404b540aSrobert       if (align > BITS_PER_UNIT)
2966404b540aSrobert 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
2967404b540aSrobert       assemble_constant_contents (exp, XSTR (symbol, 0), align);
2968404b540aSrobert     }
2969404b540aSrobert   if (flag_mudflap)
2970404b540aSrobert     mudflap_enqueue_constant (exp);
2971404b540aSrobert }
2972404b540aSrobert 
2973404b540aSrobert /* Look up EXP in the table of constant descriptors.  Return the rtl
2974404b540aSrobert    if it has been emitted, else null.  */
2975404b540aSrobert 
2976404b540aSrobert rtx
lookup_constant_def(tree exp)2977404b540aSrobert lookup_constant_def (tree exp)
2978404b540aSrobert {
2979404b540aSrobert   struct constant_descriptor_tree *desc;
2980404b540aSrobert   struct constant_descriptor_tree key;
2981404b540aSrobert 
2982404b540aSrobert   key.value = exp;
2983404b540aSrobert   key.hash = const_hash_1 (exp);
2984404b540aSrobert   desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
2985404b540aSrobert 
2986404b540aSrobert   return (desc ? desc->rtl : NULL_RTX);
2987404b540aSrobert }
2988404b540aSrobert 
2989404b540aSrobert /* Used in the hash tables to avoid outputting the same constant
2990404b540aSrobert    twice.  Unlike 'struct constant_descriptor_tree', RTX constants
2991404b540aSrobert    are output once per function, not once per file.  */
2992404b540aSrobert /* ??? Only a few targets need per-function constant pools.  Most
2993404b540aSrobert    can use one per-file pool.  Should add a targetm bit to tell the
2994404b540aSrobert    difference.  */
2995404b540aSrobert 
2996404b540aSrobert struct rtx_constant_pool GTY(())
2997404b540aSrobert {
2998404b540aSrobert   /* Pointers to first and last constant in pool, as ordered by offset.  */
2999404b540aSrobert   struct constant_descriptor_rtx *first;
3000404b540aSrobert   struct constant_descriptor_rtx *last;
3001404b540aSrobert 
3002404b540aSrobert   /* Hash facility for making memory-constants from constant rtl-expressions.
3003404b540aSrobert      It is used on RISC machines where immediate integer arguments and
3004404b540aSrobert      constant addresses are restricted so that such constants must be stored
3005404b540aSrobert      in memory.  */
3006404b540aSrobert   htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
3007404b540aSrobert 
3008404b540aSrobert   /* Current offset in constant pool (does not include any
3009404b540aSrobert      machine-specific header).  */
3010404b540aSrobert   HOST_WIDE_INT offset;
3011404b540aSrobert };
3012404b540aSrobert 
3013404b540aSrobert struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
3014404b540aSrobert {
3015404b540aSrobert   struct constant_descriptor_rtx *next;
3016404b540aSrobert   rtx mem;
3017404b540aSrobert   rtx sym;
3018404b540aSrobert   rtx constant;
3019404b540aSrobert   HOST_WIDE_INT offset;
3020404b540aSrobert   hashval_t hash;
3021404b540aSrobert   enum machine_mode mode;
3022404b540aSrobert   unsigned int align;
3023404b540aSrobert   int labelno;
3024404b540aSrobert   int mark;
3025404b540aSrobert };
3026404b540aSrobert 
3027404b540aSrobert /* Hash and compare functions for const_rtx_htab.  */
3028404b540aSrobert 
3029404b540aSrobert static hashval_t
const_desc_rtx_hash(const void * ptr)3030404b540aSrobert const_desc_rtx_hash (const void *ptr)
3031404b540aSrobert {
3032404b540aSrobert   const struct constant_descriptor_rtx *desc = ptr;
3033404b540aSrobert   return desc->hash;
3034404b540aSrobert }
3035404b540aSrobert 
3036404b540aSrobert static int
const_desc_rtx_eq(const void * a,const void * b)3037404b540aSrobert const_desc_rtx_eq (const void *a, const void *b)
3038404b540aSrobert {
3039404b540aSrobert   const struct constant_descriptor_rtx *x = a;
3040404b540aSrobert   const struct constant_descriptor_rtx *y = b;
3041404b540aSrobert 
3042404b540aSrobert   if (x->mode != y->mode)
3043404b540aSrobert     return 0;
3044404b540aSrobert   return rtx_equal_p (x->constant, y->constant);
3045404b540aSrobert }
3046404b540aSrobert 
3047404b540aSrobert /* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
3048404b540aSrobert 
3049404b540aSrobert static int
const_rtx_hash_1(rtx * xp,void * data)3050404b540aSrobert const_rtx_hash_1 (rtx *xp, void *data)
3051404b540aSrobert {
3052404b540aSrobert   unsigned HOST_WIDE_INT hwi;
3053404b540aSrobert   enum machine_mode mode;
3054404b540aSrobert   enum rtx_code code;
3055404b540aSrobert   hashval_t h, *hp;
3056404b540aSrobert   rtx x;
3057404b540aSrobert 
3058404b540aSrobert   x = *xp;
3059404b540aSrobert   code = GET_CODE (x);
3060404b540aSrobert   mode = GET_MODE (x);
3061404b540aSrobert   h = (hashval_t) code * 1048573 + mode;
3062404b540aSrobert 
3063404b540aSrobert   switch (code)
3064404b540aSrobert     {
3065404b540aSrobert     case CONST_INT:
3066404b540aSrobert       hwi = INTVAL (x);
3067404b540aSrobert     fold_hwi:
3068404b540aSrobert       {
3069404b540aSrobert 	const int shift = sizeof (hashval_t) * CHAR_BIT;
3070404b540aSrobert 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
3071404b540aSrobert 	int i;
3072404b540aSrobert 
3073404b540aSrobert 	h ^= (hashval_t) hwi;
3074404b540aSrobert 	for (i = 1; i < n; ++i)
3075404b540aSrobert 	  {
3076404b540aSrobert 	    hwi >>= shift;
3077404b540aSrobert 	    h ^= (hashval_t) hwi;
3078404b540aSrobert 	  }
3079404b540aSrobert       }
3080404b540aSrobert       break;
3081404b540aSrobert 
3082404b540aSrobert     case CONST_DOUBLE:
3083404b540aSrobert       if (mode == VOIDmode)
3084404b540aSrobert 	{
3085404b540aSrobert 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
3086404b540aSrobert 	  goto fold_hwi;
3087404b540aSrobert 	}
3088404b540aSrobert       else
3089404b540aSrobert 	h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
3090404b540aSrobert       break;
3091404b540aSrobert 
3092404b540aSrobert     case CONST_VECTOR:
3093404b540aSrobert       {
3094404b540aSrobert 	int i;
3095404b540aSrobert 	for (i = XVECLEN (x, 0); i-- > 0; )
3096404b540aSrobert 	  h = h * 251 + const_rtx_hash_1 (&XVECEXP (x, 0, i), data);
3097404b540aSrobert       }
3098404b540aSrobert       break;
3099404b540aSrobert 
3100404b540aSrobert     case SYMBOL_REF:
3101404b540aSrobert       h ^= htab_hash_string (XSTR (x, 0));
3102404b540aSrobert       break;
3103404b540aSrobert 
3104404b540aSrobert     case LABEL_REF:
3105404b540aSrobert       h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
3106404b540aSrobert       break;
3107404b540aSrobert 
3108404b540aSrobert     case UNSPEC:
3109404b540aSrobert     case UNSPEC_VOLATILE:
3110404b540aSrobert       h = h * 251 + XINT (x, 1);
3111404b540aSrobert       break;
3112404b540aSrobert 
3113404b540aSrobert     default:
3114404b540aSrobert       break;
3115404b540aSrobert     }
3116404b540aSrobert 
3117404b540aSrobert   hp = data;
3118404b540aSrobert   *hp = *hp * 509 + h;
3119404b540aSrobert   return 0;
3120404b540aSrobert }
3121404b540aSrobert 
3122404b540aSrobert /* Compute a hash value for X, which should be a constant.  */
3123404b540aSrobert 
3124404b540aSrobert static hashval_t
const_rtx_hash(rtx x)3125404b540aSrobert const_rtx_hash (rtx x)
3126404b540aSrobert {
3127404b540aSrobert   hashval_t h = 0;
3128404b540aSrobert   for_each_rtx (&x, const_rtx_hash_1, &h);
3129404b540aSrobert   return h;
3130404b540aSrobert }
3131404b540aSrobert 
3132404b540aSrobert 
3133404b540aSrobert /* Create and return a new rtx constant pool.  */
3134404b540aSrobert 
3135404b540aSrobert static struct rtx_constant_pool *
create_constant_pool(void)3136404b540aSrobert create_constant_pool (void)
3137404b540aSrobert {
3138404b540aSrobert   struct rtx_constant_pool *pool;
3139404b540aSrobert 
3140404b540aSrobert   pool = ggc_alloc (sizeof (struct rtx_constant_pool));
3141404b540aSrobert   pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
3142404b540aSrobert 					  const_desc_rtx_eq, NULL);
3143404b540aSrobert   pool->first = NULL;
3144404b540aSrobert   pool->last = NULL;
3145404b540aSrobert   pool->offset = 0;
3146404b540aSrobert   return pool;
3147404b540aSrobert }
3148404b540aSrobert 
3149404b540aSrobert /* Initialize constant pool hashing for a new function.  */
3150404b540aSrobert 
3151404b540aSrobert void
init_varasm_status(struct function * f)3152404b540aSrobert init_varasm_status (struct function *f)
3153404b540aSrobert {
3154404b540aSrobert   struct varasm_status *p;
3155404b540aSrobert 
3156404b540aSrobert   p = ggc_alloc (sizeof (struct varasm_status));
3157404b540aSrobert   f->varasm = p;
3158404b540aSrobert 
3159404b540aSrobert   p->pool = create_constant_pool ();
3160404b540aSrobert   p->deferred_constants = 0;
3161404b540aSrobert }
3162404b540aSrobert 
3163404b540aSrobert /* Given a MINUS expression, simplify it if both sides
3164404b540aSrobert    include the same symbol.  */
3165404b540aSrobert 
3166404b540aSrobert rtx
simplify_subtraction(rtx x)3167404b540aSrobert simplify_subtraction (rtx x)
3168404b540aSrobert {
3169404b540aSrobert   rtx r = simplify_rtx (x);
3170404b540aSrobert   return r ? r : x;
3171404b540aSrobert }
3172404b540aSrobert 
3173404b540aSrobert /* Given a constant rtx X, make (or find) a memory constant for its value
3174404b540aSrobert    and return a MEM rtx to refer to it in memory.  */
3175404b540aSrobert 
3176404b540aSrobert rtx
force_const_mem(enum machine_mode mode,rtx x)3177404b540aSrobert force_const_mem (enum machine_mode mode, rtx x)
3178404b540aSrobert {
3179404b540aSrobert   struct constant_descriptor_rtx *desc, tmp;
3180404b540aSrobert   struct rtx_constant_pool *pool;
3181404b540aSrobert   char label[256];
3182404b540aSrobert   rtx def, symbol;
3183404b540aSrobert   hashval_t hash;
3184404b540aSrobert   unsigned int align;
3185404b540aSrobert   void **slot;
3186404b540aSrobert 
3187404b540aSrobert   /* If we're not allowed to drop X into the constant pool, don't.  */
3188404b540aSrobert   if (targetm.cannot_force_const_mem (x))
3189404b540aSrobert     return NULL_RTX;
3190404b540aSrobert 
3191404b540aSrobert   /* Record that this function has used a constant pool entry.  */
3192404b540aSrobert   current_function_uses_const_pool = 1;
3193404b540aSrobert 
3194404b540aSrobert   /* Decide which pool to use.  */
3195404b540aSrobert   pool = (targetm.use_blocks_for_constant_p (mode, x)
3196404b540aSrobert 	  ? shared_constant_pool
3197404b540aSrobert 	  : cfun->varasm->pool);
3198404b540aSrobert 
3199404b540aSrobert   /* Lookup the value in the hashtable.  */
3200404b540aSrobert   tmp.constant = x;
3201404b540aSrobert   tmp.mode = mode;
3202404b540aSrobert   hash = const_rtx_hash (x);
3203404b540aSrobert   slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
3204404b540aSrobert   desc = *slot;
3205404b540aSrobert 
3206404b540aSrobert   /* If the constant was already present, return its memory.  */
3207404b540aSrobert   if (desc)
3208404b540aSrobert     return copy_rtx (desc->mem);
3209404b540aSrobert 
3210404b540aSrobert   /* Otherwise, create a new descriptor.  */
3211404b540aSrobert   desc = ggc_alloc (sizeof (*desc));
3212404b540aSrobert   *slot = desc;
3213404b540aSrobert 
3214404b540aSrobert   /* Align the location counter as required by EXP's data type.  */
3215404b540aSrobert   align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
3216404b540aSrobert #ifdef CONSTANT_ALIGNMENT
3217404b540aSrobert   {
3218404b540aSrobert     tree type = lang_hooks.types.type_for_mode (mode, 0);
3219404b540aSrobert     if (type != NULL_TREE)
3220404b540aSrobert       align = CONSTANT_ALIGNMENT (make_tree (type, x), align);
3221404b540aSrobert   }
3222404b540aSrobert #endif
3223404b540aSrobert 
3224404b540aSrobert   pool->offset += (align / BITS_PER_UNIT) - 1;
3225404b540aSrobert   pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
3226404b540aSrobert 
3227404b540aSrobert   desc->next = NULL;
3228404b540aSrobert   desc->constant = tmp.constant;
3229404b540aSrobert   desc->offset = pool->offset;
3230404b540aSrobert   desc->hash = hash;
3231404b540aSrobert   desc->mode = mode;
3232404b540aSrobert   desc->align = align;
3233404b540aSrobert   desc->labelno = const_labelno;
3234404b540aSrobert   desc->mark = 0;
3235404b540aSrobert 
3236404b540aSrobert   pool->offset += GET_MODE_SIZE (mode);
3237404b540aSrobert   if (pool->last)
3238404b540aSrobert     pool->last->next = desc;
3239404b540aSrobert   else
3240404b540aSrobert     pool->first = pool->last = desc;
3241404b540aSrobert   pool->last = desc;
3242404b540aSrobert 
3243404b540aSrobert   /* Create a string containing the label name, in LABEL.  */
3244404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
3245404b540aSrobert   ++const_labelno;
3246404b540aSrobert 
3247404b540aSrobert   /* Construct the SYMBOL_REF.  Make sure to mark it as belonging to
3248404b540aSrobert      the constants pool.  */
3249404b540aSrobert   if (use_object_blocks_p () && targetm.use_blocks_for_constant_p (mode, x))
3250404b540aSrobert     {
3251404b540aSrobert       section *sect = targetm.asm_out.select_rtx_section (mode, x, align);
3252404b540aSrobert       symbol = create_block_symbol (ggc_strdup (label),
3253404b540aSrobert 				    get_block_for_section (sect), -1);
3254404b540aSrobert     }
3255404b540aSrobert   else
3256404b540aSrobert     symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
3257404b540aSrobert   desc->sym = symbol;
3258404b540aSrobert   SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
3259404b540aSrobert   CONSTANT_POOL_ADDRESS_P (symbol) = 1;
3260404b540aSrobert   SET_SYMBOL_REF_CONSTANT (symbol, desc);
3261404b540aSrobert 
3262404b540aSrobert   /* Construct the MEM.  */
3263404b540aSrobert   desc->mem = def = gen_const_mem (mode, symbol);
3264404b540aSrobert   set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
3265404b540aSrobert   set_mem_align (def, align);
3266404b540aSrobert 
3267404b540aSrobert   /* If we're dropping a label to the constant pool, make sure we
3268404b540aSrobert      don't delete it.  */
3269404b540aSrobert   if (GET_CODE (x) == LABEL_REF)
3270404b540aSrobert     LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
3271404b540aSrobert 
3272404b540aSrobert   return copy_rtx (def);
3273404b540aSrobert }
3274404b540aSrobert 
3275404b540aSrobert /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
3276404b540aSrobert 
3277404b540aSrobert rtx
get_pool_constant(rtx addr)3278404b540aSrobert get_pool_constant (rtx addr)
3279404b540aSrobert {
3280404b540aSrobert   return SYMBOL_REF_CONSTANT (addr)->constant;
3281404b540aSrobert }
3282404b540aSrobert 
3283404b540aSrobert /* Given a constant pool SYMBOL_REF, return the corresponding constant
3284404b540aSrobert    and whether it has been output or not.  */
3285404b540aSrobert 
3286404b540aSrobert rtx
get_pool_constant_mark(rtx addr,bool * pmarked)3287404b540aSrobert get_pool_constant_mark (rtx addr, bool *pmarked)
3288404b540aSrobert {
3289404b540aSrobert   struct constant_descriptor_rtx *desc;
3290404b540aSrobert 
3291404b540aSrobert   desc = SYMBOL_REF_CONSTANT (addr);
3292404b540aSrobert   *pmarked = (desc->mark != 0);
3293404b540aSrobert   return desc->constant;
3294404b540aSrobert }
3295404b540aSrobert 
3296404b540aSrobert /* Similar, return the mode.  */
3297404b540aSrobert 
3298404b540aSrobert enum machine_mode
get_pool_mode(rtx addr)3299404b540aSrobert get_pool_mode (rtx addr)
3300404b540aSrobert {
3301404b540aSrobert   return SYMBOL_REF_CONSTANT (addr)->mode;
3302404b540aSrobert }
3303404b540aSrobert 
3304404b540aSrobert /* Return the size of the constant pool.  */
3305404b540aSrobert 
3306404b540aSrobert int
get_pool_size(void)3307404b540aSrobert get_pool_size (void)
3308404b540aSrobert {
3309404b540aSrobert   return cfun->varasm->pool->offset;
3310404b540aSrobert }
3311404b540aSrobert 
3312404b540aSrobert /* Worker function for output_constant_pool_1.  Emit assembly for X
3313404b540aSrobert    in MODE with known alignment ALIGN.  */
3314404b540aSrobert 
3315404b540aSrobert static void
output_constant_pool_2(enum machine_mode mode,rtx x,unsigned int align)3316404b540aSrobert output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
3317404b540aSrobert {
3318404b540aSrobert   switch (GET_MODE_CLASS (mode))
3319404b540aSrobert     {
3320404b540aSrobert     case MODE_FLOAT:
3321404b540aSrobert     case MODE_DECIMAL_FLOAT:
3322404b540aSrobert       {
3323404b540aSrobert 	REAL_VALUE_TYPE r;
3324404b540aSrobert 
3325404b540aSrobert 	gcc_assert (GET_CODE (x) == CONST_DOUBLE);
3326404b540aSrobert 	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3327404b540aSrobert 	assemble_real (r, mode, align);
3328404b540aSrobert 	break;
3329404b540aSrobert       }
3330404b540aSrobert 
3331404b540aSrobert     case MODE_INT:
3332404b540aSrobert     case MODE_PARTIAL_INT:
3333404b540aSrobert       assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
3334404b540aSrobert       break;
3335404b540aSrobert 
3336404b540aSrobert     case MODE_VECTOR_FLOAT:
3337404b540aSrobert     case MODE_VECTOR_INT:
3338404b540aSrobert       {
3339404b540aSrobert 	int i, units;
3340404b540aSrobert         enum machine_mode submode = GET_MODE_INNER (mode);
3341404b540aSrobert 	unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
3342404b540aSrobert 
3343404b540aSrobert 	gcc_assert (GET_CODE (x) == CONST_VECTOR);
3344404b540aSrobert 	units = CONST_VECTOR_NUNITS (x);
3345404b540aSrobert 
3346404b540aSrobert 	for (i = 0; i < units; i++)
3347404b540aSrobert 	  {
3348404b540aSrobert 	    rtx elt = CONST_VECTOR_ELT (x, i);
3349404b540aSrobert 	    output_constant_pool_2 (submode, elt, i ? subalign : align);
3350404b540aSrobert 	  }
3351404b540aSrobert       }
3352404b540aSrobert       break;
3353404b540aSrobert 
3354404b540aSrobert     default:
3355404b540aSrobert       gcc_unreachable ();
3356404b540aSrobert     }
3357404b540aSrobert }
3358404b540aSrobert 
3359404b540aSrobert /* Worker function for output_constant_pool.  Emit constant DESC,
3360404b540aSrobert    giving it ALIGN bits of alignment.  */
3361404b540aSrobert 
3362404b540aSrobert static void
output_constant_pool_1(struct constant_descriptor_rtx * desc,unsigned int align)3363404b540aSrobert output_constant_pool_1 (struct constant_descriptor_rtx *desc,
3364404b540aSrobert 			unsigned int align)
3365404b540aSrobert {
3366404b540aSrobert   rtx x, tmp;
3367404b540aSrobert 
3368404b540aSrobert   x = desc->constant;
3369404b540aSrobert 
3370404b540aSrobert   /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
3371404b540aSrobert      whose CODE_LABEL has been deleted.  This can occur if a jump table
3372404b540aSrobert      is eliminated by optimization.  If so, write a constant of zero
3373404b540aSrobert      instead.  Note that this can also happen by turning the
3374404b540aSrobert      CODE_LABEL into a NOTE.  */
3375404b540aSrobert   /* ??? This seems completely and utterly wrong.  Certainly it's
3376404b540aSrobert      not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
3377404b540aSrobert      functioning even with INSN_DELETED_P and friends.  */
3378404b540aSrobert 
3379404b540aSrobert   tmp = x;
3380404b540aSrobert   switch (GET_CODE (x))
3381404b540aSrobert     {
3382404b540aSrobert     case CONST:
3383404b540aSrobert       if (GET_CODE (XEXP (x, 0)) != PLUS
3384404b540aSrobert 	  || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
3385404b540aSrobert 	break;
3386404b540aSrobert       tmp = XEXP (XEXP (x, 0), 0);
3387404b540aSrobert       /* FALLTHRU  */
3388404b540aSrobert 
3389404b540aSrobert     case LABEL_REF:
3390404b540aSrobert       tmp = XEXP (x, 0);
3391404b540aSrobert       gcc_assert (!INSN_DELETED_P (tmp));
3392404b540aSrobert       gcc_assert (!NOTE_P (tmp)
3393404b540aSrobert 		  || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
3394404b540aSrobert       break;
3395404b540aSrobert 
3396404b540aSrobert     default:
3397404b540aSrobert       break;
3398404b540aSrobert     }
3399404b540aSrobert 
3400404b540aSrobert #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
3401404b540aSrobert   ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
3402404b540aSrobert 				 align, desc->labelno, done);
3403404b540aSrobert #endif
3404404b540aSrobert 
3405404b540aSrobert   assemble_align (align);
3406404b540aSrobert 
3407404b540aSrobert   /* Output the label.  */
3408404b540aSrobert   targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
3409404b540aSrobert 
3410404b540aSrobert   /* Output the data.  */
3411404b540aSrobert   output_constant_pool_2 (desc->mode, x, align);
3412404b540aSrobert 
3413404b540aSrobert   /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
3414404b540aSrobert      sections have proper size.  */
3415404b540aSrobert   if (align > GET_MODE_BITSIZE (desc->mode)
3416404b540aSrobert       && in_section
3417404b540aSrobert       && (in_section->common.flags & SECTION_MERGE))
3418404b540aSrobert     assemble_align (align);
3419404b540aSrobert 
3420404b540aSrobert #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
3421404b540aSrobert  done:
3422404b540aSrobert #endif
3423404b540aSrobert   return;
3424404b540aSrobert }
3425404b540aSrobert 
3426404b540aSrobert /* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
3427404b540aSrobert    to as used.  Emit referenced deferred strings.  This function can
3428404b540aSrobert    be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
3429404b540aSrobert 
3430404b540aSrobert static int
mark_constant(rtx * current_rtx,void * data ATTRIBUTE_UNUSED)3431404b540aSrobert mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
3432404b540aSrobert {
3433404b540aSrobert   rtx x = *current_rtx;
3434404b540aSrobert 
3435404b540aSrobert   if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
3436404b540aSrobert     return 0;
3437404b540aSrobert 
3438404b540aSrobert   if (CONSTANT_POOL_ADDRESS_P (x))
3439404b540aSrobert     {
3440404b540aSrobert       struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
3441404b540aSrobert       if (desc->mark == 0)
3442404b540aSrobert 	{
3443404b540aSrobert 	  desc->mark = 1;
3444404b540aSrobert 	  for_each_rtx (&desc->constant, mark_constant, NULL);
3445404b540aSrobert 	}
3446404b540aSrobert     }
3447404b540aSrobert   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
3448404b540aSrobert     {
3449404b540aSrobert       tree exp = SYMBOL_REF_DECL (x);
3450404b540aSrobert       if (!TREE_ASM_WRITTEN (exp))
3451404b540aSrobert 	{
3452404b540aSrobert 	  n_deferred_constants--;
3453404b540aSrobert 	  output_constant_def_contents (x);
3454404b540aSrobert 	}
3455404b540aSrobert     }
3456404b540aSrobert 
3457404b540aSrobert   return -1;
3458404b540aSrobert }
3459404b540aSrobert 
3460404b540aSrobert /* Look through appropriate parts of INSN, marking all entries in the
3461404b540aSrobert    constant pool which are actually being used.  Entries that are only
3462404b540aSrobert    referenced by other constants are also marked as used.  Emit
3463404b540aSrobert    deferred strings that are used.  */
3464404b540aSrobert 
3465404b540aSrobert static void
mark_constants(rtx insn)3466404b540aSrobert mark_constants (rtx insn)
3467404b540aSrobert {
3468404b540aSrobert   if (!INSN_P (insn))
3469404b540aSrobert     return;
3470404b540aSrobert 
3471404b540aSrobert   /* Insns may appear inside a SEQUENCE.  Only check the patterns of
3472404b540aSrobert      insns, not any notes that may be attached.  We don't want to mark
3473404b540aSrobert      a constant just because it happens to appear in a REG_EQUIV note.  */
3474404b540aSrobert   if (GET_CODE (PATTERN (insn)) == SEQUENCE)
3475404b540aSrobert     {
3476404b540aSrobert       rtx seq = PATTERN (insn);
3477404b540aSrobert       int i, n = XVECLEN (seq, 0);
3478404b540aSrobert       for (i = 0; i < n; ++i)
3479404b540aSrobert 	{
3480404b540aSrobert 	  rtx subinsn = XVECEXP (seq, 0, i);
3481404b540aSrobert 	  if (INSN_P (subinsn))
3482404b540aSrobert 	    for_each_rtx (&PATTERN (subinsn), mark_constant, NULL);
3483404b540aSrobert 	}
3484404b540aSrobert     }
3485404b540aSrobert   else
3486404b540aSrobert     for_each_rtx (&PATTERN (insn), mark_constant, NULL);
3487404b540aSrobert }
3488404b540aSrobert 
3489404b540aSrobert /* Look through the instructions for this function, and mark all the
3490404b540aSrobert    entries in POOL which are actually being used.  Emit deferred constants
3491404b540aSrobert    which have indeed been used.  */
3492404b540aSrobert 
3493404b540aSrobert static void
mark_constant_pool(void)3494404b540aSrobert mark_constant_pool (void)
3495404b540aSrobert {
3496404b540aSrobert   rtx insn, link;
3497404b540aSrobert 
3498404b540aSrobert   if (!current_function_uses_const_pool && n_deferred_constants == 0)
3499404b540aSrobert     return;
3500404b540aSrobert 
3501404b540aSrobert   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
3502404b540aSrobert     mark_constants (insn);
3503404b540aSrobert 
3504404b540aSrobert   for (link = current_function_epilogue_delay_list;
3505404b540aSrobert        link;
3506404b540aSrobert        link = XEXP (link, 1))
3507404b540aSrobert     mark_constants (XEXP (link, 0));
3508404b540aSrobert }
3509404b540aSrobert 
3510404b540aSrobert /* Write all the constants in POOL.  */
3511404b540aSrobert 
3512404b540aSrobert static void
output_constant_pool_contents(struct rtx_constant_pool * pool)3513404b540aSrobert output_constant_pool_contents (struct rtx_constant_pool *pool)
3514404b540aSrobert {
3515404b540aSrobert   struct constant_descriptor_rtx *desc;
3516404b540aSrobert 
3517404b540aSrobert   for (desc = pool->first; desc ; desc = desc->next)
3518404b540aSrobert     if (desc->mark)
3519404b540aSrobert       {
3520404b540aSrobert 	/* If the constant is part of an object_block, make sure that
3521404b540aSrobert 	   the constant has been positioned within its block, but do not
3522404b540aSrobert 	   write out its definition yet.  output_object_blocks will do
3523404b540aSrobert 	   that later.  */
3524404b540aSrobert 	if (SYMBOL_REF_HAS_BLOCK_INFO_P (desc->sym)
3525404b540aSrobert 	    && SYMBOL_REF_BLOCK (desc->sym))
3526404b540aSrobert 	  place_block_symbol (desc->sym);
3527404b540aSrobert 	else
3528404b540aSrobert 	  {
3529404b540aSrobert 	    switch_to_section (targetm.asm_out.select_rtx_section
3530404b540aSrobert 			       (desc->mode, desc->constant, desc->align));
3531404b540aSrobert 	    output_constant_pool_1 (desc, desc->align);
3532404b540aSrobert 	  }
3533404b540aSrobert       }
3534404b540aSrobert }
3535404b540aSrobert 
3536404b540aSrobert /* Mark all constants that are used in the current function, then write
3537404b540aSrobert    out the function's private constant pool.  */
3538404b540aSrobert 
3539404b540aSrobert static void
output_constant_pool(const char * fnname ATTRIBUTE_UNUSED,tree fndecl ATTRIBUTE_UNUSED)3540404b540aSrobert output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
3541404b540aSrobert 		      tree fndecl ATTRIBUTE_UNUSED)
3542404b540aSrobert {
3543404b540aSrobert   struct rtx_constant_pool *pool = cfun->varasm->pool;
3544404b540aSrobert 
3545404b540aSrobert   /* It is possible for gcc to call force_const_mem and then to later
3546404b540aSrobert      discard the instructions which refer to the constant.  In such a
3547404b540aSrobert      case we do not need to output the constant.  */
3548404b540aSrobert   mark_constant_pool ();
3549404b540aSrobert 
3550404b540aSrobert #ifdef ASM_OUTPUT_POOL_PROLOGUE
3551404b540aSrobert   ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
3552404b540aSrobert #endif
3553404b540aSrobert 
3554404b540aSrobert   output_constant_pool_contents (pool);
3555404b540aSrobert 
3556404b540aSrobert #ifdef ASM_OUTPUT_POOL_EPILOGUE
3557404b540aSrobert   ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
3558404b540aSrobert #endif
3559404b540aSrobert }
3560404b540aSrobert 
3561404b540aSrobert /* Write the contents of the shared constant pool.  */
3562404b540aSrobert 
3563404b540aSrobert void
output_shared_constant_pool(void)3564404b540aSrobert output_shared_constant_pool (void)
3565404b540aSrobert {
3566404b540aSrobert   output_constant_pool_contents (shared_constant_pool);
3567404b540aSrobert }
3568404b540aSrobert 
3569404b540aSrobert /* Determine what kind of relocations EXP may need.  */
3570404b540aSrobert 
3571404b540aSrobert int
compute_reloc_for_constant(tree exp)3572404b540aSrobert compute_reloc_for_constant (tree exp)
3573404b540aSrobert {
3574404b540aSrobert   int reloc = 0, reloc2;
3575404b540aSrobert   tree tem;
3576404b540aSrobert 
3577404b540aSrobert   /* Give the front-end a chance to convert VALUE to something that
3578404b540aSrobert      looks more like a constant to the back-end.  */
3579404b540aSrobert   exp = lang_hooks.expand_constant (exp);
3580404b540aSrobert 
3581404b540aSrobert   switch (TREE_CODE (exp))
3582404b540aSrobert     {
3583404b540aSrobert     case ADDR_EXPR:
3584404b540aSrobert     case FDESC_EXPR:
3585404b540aSrobert       /* Go inside any operations that get_inner_reference can handle and see
3586404b540aSrobert 	 if what's inside is a constant: no need to do anything here for
3587404b540aSrobert 	 addresses of variables or functions.  */
3588404b540aSrobert       for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);
3589404b540aSrobert 	   tem = TREE_OPERAND (tem, 0))
3590404b540aSrobert 	;
3591404b540aSrobert 
3592404b540aSrobert       if (TREE_PUBLIC (tem))
3593404b540aSrobert 	reloc |= 2;
3594404b540aSrobert       else
3595404b540aSrobert 	reloc |= 1;
3596404b540aSrobert       break;
3597404b540aSrobert 
3598404b540aSrobert     case PLUS_EXPR:
3599404b540aSrobert       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
3600404b540aSrobert       reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
3601404b540aSrobert       break;
3602404b540aSrobert 
3603404b540aSrobert     case MINUS_EXPR:
3604404b540aSrobert       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
3605404b540aSrobert       reloc2 = compute_reloc_for_constant (TREE_OPERAND (exp, 1));
3606404b540aSrobert       /* The difference of two local labels is computable at link time.  */
3607404b540aSrobert       if (reloc == 1 && reloc2 == 1)
3608404b540aSrobert 	reloc = 0;
3609404b540aSrobert       else
3610404b540aSrobert 	reloc |= reloc2;
3611404b540aSrobert       break;
3612404b540aSrobert 
3613404b540aSrobert     case NOP_EXPR:
3614404b540aSrobert     case CONVERT_EXPR:
3615404b540aSrobert     case NON_LVALUE_EXPR:
3616404b540aSrobert     case VIEW_CONVERT_EXPR:
3617404b540aSrobert       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
3618404b540aSrobert       break;
3619404b540aSrobert 
3620404b540aSrobert     case CONSTRUCTOR:
3621404b540aSrobert       {
3622404b540aSrobert 	unsigned HOST_WIDE_INT idx;
3623404b540aSrobert 	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
3624404b540aSrobert 	  if (tem != 0)
3625404b540aSrobert 	    reloc |= compute_reloc_for_constant (tem);
3626404b540aSrobert       }
3627404b540aSrobert       break;
3628404b540aSrobert 
3629404b540aSrobert     default:
3630404b540aSrobert       break;
3631404b540aSrobert     }
3632404b540aSrobert   return reloc;
3633404b540aSrobert }
3634404b540aSrobert 
3635404b540aSrobert /* Find all the constants whose addresses are referenced inside of EXP,
3636404b540aSrobert    and make sure assembler code with a label has been output for each one.
3637404b540aSrobert    Indicate whether an ADDR_EXPR has been encountered.  */
3638404b540aSrobert 
3639404b540aSrobert static void
output_addressed_constants(tree exp)3640404b540aSrobert output_addressed_constants (tree exp)
3641404b540aSrobert {
3642404b540aSrobert   tree tem;
3643404b540aSrobert 
3644404b540aSrobert   /* Give the front-end a chance to convert VALUE to something that
3645404b540aSrobert      looks more like a constant to the back-end.  */
3646404b540aSrobert   exp = lang_hooks.expand_constant (exp);
3647404b540aSrobert 
3648404b540aSrobert   switch (TREE_CODE (exp))
3649404b540aSrobert     {
3650404b540aSrobert     case ADDR_EXPR:
3651404b540aSrobert     case FDESC_EXPR:
3652404b540aSrobert       /* Go inside any operations that get_inner_reference can handle and see
3653404b540aSrobert 	 if what's inside is a constant: no need to do anything here for
3654404b540aSrobert 	 addresses of variables or functions.  */
3655404b540aSrobert       for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);
3656404b540aSrobert 	   tem = TREE_OPERAND (tem, 0))
3657404b540aSrobert 	;
3658404b540aSrobert 
3659404b540aSrobert       /* If we have an initialized CONST_DECL, retrieve the initializer.  */
3660404b540aSrobert       if (TREE_CODE (tem) == CONST_DECL && DECL_INITIAL (tem))
3661404b540aSrobert 	tem = DECL_INITIAL (tem);
3662404b540aSrobert 
3663404b540aSrobert       if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR)
3664404b540aSrobert 	output_constant_def (tem, 0);
3665404b540aSrobert       break;
3666404b540aSrobert 
3667404b540aSrobert     case PLUS_EXPR:
3668404b540aSrobert     case MINUS_EXPR:
3669404b540aSrobert       output_addressed_constants (TREE_OPERAND (exp, 1));
3670404b540aSrobert       /* Fall through.  */
3671404b540aSrobert 
3672404b540aSrobert     case NOP_EXPR:
3673404b540aSrobert     case CONVERT_EXPR:
3674404b540aSrobert     case NON_LVALUE_EXPR:
3675404b540aSrobert     case VIEW_CONVERT_EXPR:
3676404b540aSrobert       output_addressed_constants (TREE_OPERAND (exp, 0));
3677404b540aSrobert       break;
3678404b540aSrobert 
3679404b540aSrobert     case CONSTRUCTOR:
3680404b540aSrobert       {
3681404b540aSrobert 	unsigned HOST_WIDE_INT idx;
3682404b540aSrobert 	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
3683404b540aSrobert 	  if (tem != 0)
3684404b540aSrobert 	    output_addressed_constants (tem);
3685404b540aSrobert       }
3686404b540aSrobert       break;
3687404b540aSrobert 
3688404b540aSrobert     default:
3689404b540aSrobert       break;
3690404b540aSrobert     }
3691404b540aSrobert }
3692404b540aSrobert 
3693404b540aSrobert /* Whether a constructor CTOR is a valid static constant initializer if all
3694404b540aSrobert    its elements are.  This used to be internal to initializer_constant_valid_p
3695404b540aSrobert    and has been exposed to let other functions like categorize_ctor_elements
3696404b540aSrobert    evaluate the property while walking a constructor for other purposes.  */
3697404b540aSrobert 
3698404b540aSrobert bool
constructor_static_from_elts_p(tree ctor)3699404b540aSrobert constructor_static_from_elts_p (tree ctor)
3700404b540aSrobert {
3701404b540aSrobert   return (TREE_CONSTANT (ctor)
3702404b540aSrobert 	  && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
3703404b540aSrobert 	      || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE)
3704404b540aSrobert 	  && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
3705404b540aSrobert }
3706404b540aSrobert 
3707404b540aSrobert /* Return nonzero if VALUE is a valid constant-valued expression
3708404b540aSrobert    for use in initializing a static variable; one that can be an
3709404b540aSrobert    element of a "constant" initializer.
3710404b540aSrobert 
3711404b540aSrobert    Return null_pointer_node if the value is absolute;
3712404b540aSrobert    if it is relocatable, return the variable that determines the relocation.
3713404b540aSrobert    We assume that VALUE has been folded as much as possible;
3714404b540aSrobert    therefore, we do not need to check for such things as
3715404b540aSrobert    arithmetic-combinations of integers.  */
3716404b540aSrobert 
3717404b540aSrobert tree
initializer_constant_valid_p(tree value,tree endtype)3718404b540aSrobert initializer_constant_valid_p (tree value, tree endtype)
3719404b540aSrobert {
3720404b540aSrobert   /* Give the front-end a chance to convert VALUE to something that
3721404b540aSrobert      looks more like a constant to the back-end.  */
3722404b540aSrobert   value = lang_hooks.expand_constant (value);
3723404b540aSrobert 
3724404b540aSrobert   switch (TREE_CODE (value))
3725404b540aSrobert     {
3726404b540aSrobert     case CONSTRUCTOR:
3727404b540aSrobert       if (constructor_static_from_elts_p (value))
3728404b540aSrobert 	{
3729404b540aSrobert 	  unsigned HOST_WIDE_INT idx;
3730404b540aSrobert 	  tree elt;
3731404b540aSrobert 	  bool absolute = true;
3732404b540aSrobert 
3733404b540aSrobert 	  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
3734404b540aSrobert 	    {
3735404b540aSrobert 	      tree reloc;
3736404b540aSrobert 	      reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
3737404b540aSrobert 	      if (!reloc)
3738404b540aSrobert 		return NULL_TREE;
3739404b540aSrobert 	      if (reloc != null_pointer_node)
3740404b540aSrobert 		absolute = false;
3741404b540aSrobert 	    }
3742404b540aSrobert 	  /* For a non-absolute relocation, there is no single
3743404b540aSrobert 	     variable that can be "the variable that determines the
3744404b540aSrobert 	     relocation."  */
3745404b540aSrobert 	  return absolute ? null_pointer_node : error_mark_node;
3746404b540aSrobert 	}
3747404b540aSrobert 
3748404b540aSrobert       return TREE_STATIC (value) ? null_pointer_node : NULL_TREE;
3749404b540aSrobert 
3750404b540aSrobert     case INTEGER_CST:
3751404b540aSrobert     case VECTOR_CST:
3752404b540aSrobert     case REAL_CST:
3753404b540aSrobert     case STRING_CST:
3754404b540aSrobert     case COMPLEX_CST:
3755404b540aSrobert       return null_pointer_node;
3756404b540aSrobert 
3757404b540aSrobert     case ADDR_EXPR:
3758404b540aSrobert     case FDESC_EXPR:
3759404b540aSrobert       value = staticp (TREE_OPERAND (value, 0));
3760404b540aSrobert       if (value)
3761404b540aSrobert 	{
3762404b540aSrobert 	  /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
3763404b540aSrobert 	     be a constant, this is old-skool offsetof-like nonsense.  */
3764404b540aSrobert 	  if (TREE_CODE (value) == INDIRECT_REF
3765404b540aSrobert 	      && TREE_CONSTANT (TREE_OPERAND (value, 0)))
3766404b540aSrobert 	    return null_pointer_node;
3767404b540aSrobert 	  /* Taking the address of a nested function involves a trampoline.  */
3768404b540aSrobert 	  if (TREE_CODE (value) == FUNCTION_DECL
3769404b540aSrobert 	      && ((decl_function_context (value)
3770404b540aSrobert 		   && !DECL_NO_STATIC_CHAIN (value))
3771404b540aSrobert 		  || DECL_DLLIMPORT_P (value)))
3772404b540aSrobert 	    return NULL_TREE;
3773404b540aSrobert 	  /* "&{...}" requires a temporary to hold the constructed
3774404b540aSrobert 	     object.  */
3775404b540aSrobert 	  if (TREE_CODE (value) == CONSTRUCTOR)
3776404b540aSrobert 	    return NULL_TREE;
3777404b540aSrobert 	}
3778404b540aSrobert       return value;
3779404b540aSrobert 
3780404b540aSrobert     case VIEW_CONVERT_EXPR:
3781404b540aSrobert     case NON_LVALUE_EXPR:
3782404b540aSrobert       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
3783404b540aSrobert 
3784404b540aSrobert     case CONVERT_EXPR:
3785404b540aSrobert     case NOP_EXPR:
3786404b540aSrobert       {
3787404b540aSrobert 	tree src;
3788404b540aSrobert 	tree src_type;
3789404b540aSrobert 	tree dest_type;
3790404b540aSrobert 
3791404b540aSrobert 	src = TREE_OPERAND (value, 0);
3792404b540aSrobert 	src_type = TREE_TYPE (src);
3793404b540aSrobert 	dest_type = TREE_TYPE (value);
3794404b540aSrobert 
3795404b540aSrobert 	/* Allow conversions between pointer types, floating-point
3796404b540aSrobert 	   types, and offset types.  */
3797404b540aSrobert 	if ((POINTER_TYPE_P (dest_type) && POINTER_TYPE_P (src_type))
3798404b540aSrobert 	    || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
3799404b540aSrobert 	    || (TREE_CODE (dest_type) == OFFSET_TYPE
3800404b540aSrobert 		&& TREE_CODE (src_type) == OFFSET_TYPE))
3801404b540aSrobert 	  return initializer_constant_valid_p (src, endtype);
3802404b540aSrobert 
3803404b540aSrobert 	/* Allow length-preserving conversions between integer types.  */
3804404b540aSrobert 	if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
3805404b540aSrobert 	    && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
3806404b540aSrobert 	  return initializer_constant_valid_p (src, endtype);
3807404b540aSrobert 
3808404b540aSrobert 	/* Allow conversions between other integer types only if
3809404b540aSrobert 	   explicit value.  */
3810404b540aSrobert 	if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
3811404b540aSrobert 	  {
3812404b540aSrobert 	    tree inner = initializer_constant_valid_p (src, endtype);
3813404b540aSrobert 	    if (inner == null_pointer_node)
3814404b540aSrobert 	      return null_pointer_node;
3815404b540aSrobert 	    break;
3816404b540aSrobert 	  }
3817404b540aSrobert 
3818404b540aSrobert 	/* Allow (int) &foo provided int is as wide as a pointer.  */
3819404b540aSrobert 	if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
3820404b540aSrobert 	    && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
3821404b540aSrobert 	  return initializer_constant_valid_p (src, endtype);
3822404b540aSrobert 
3823404b540aSrobert 	/* Likewise conversions from int to pointers, but also allow
3824404b540aSrobert 	   conversions from 0.  */
3825404b540aSrobert 	if ((POINTER_TYPE_P (dest_type)
3826404b540aSrobert 	     || TREE_CODE (dest_type) == OFFSET_TYPE)
3827404b540aSrobert 	    && INTEGRAL_TYPE_P (src_type))
3828404b540aSrobert 	  {
3829404b540aSrobert 	    if (TREE_CODE (src) == INTEGER_CST
3830404b540aSrobert 		&& TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))
3831404b540aSrobert 	      return null_pointer_node;
3832404b540aSrobert 	    if (integer_zerop (src))
3833404b540aSrobert 	      return null_pointer_node;
3834404b540aSrobert 	    else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
3835404b540aSrobert 	      return initializer_constant_valid_p (src, endtype);
3836404b540aSrobert 	  }
3837404b540aSrobert 
3838404b540aSrobert 	/* Allow conversions to struct or union types if the value
3839404b540aSrobert 	   inside is okay.  */
3840404b540aSrobert 	if (TREE_CODE (dest_type) == RECORD_TYPE
3841404b540aSrobert 	    || TREE_CODE (dest_type) == UNION_TYPE)
3842404b540aSrobert 	  return initializer_constant_valid_p (src, endtype);
3843404b540aSrobert       }
3844404b540aSrobert       break;
3845404b540aSrobert 
3846404b540aSrobert     case PLUS_EXPR:
3847404b540aSrobert       if (! INTEGRAL_TYPE_P (endtype)
3848404b540aSrobert 	  || TYPE_PRECISION (endtype) >= POINTER_SIZE)
3849404b540aSrobert 	{
3850404b540aSrobert 	  tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
3851404b540aSrobert 						      endtype);
3852404b540aSrobert 	  tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
3853404b540aSrobert 						      endtype);
3854404b540aSrobert 	  /* If either term is absolute, use the other terms relocation.  */
3855404b540aSrobert 	  if (valid0 == null_pointer_node)
3856404b540aSrobert 	    return valid1;
3857404b540aSrobert 	  if (valid1 == null_pointer_node)
3858404b540aSrobert 	    return valid0;
3859404b540aSrobert 	}
3860404b540aSrobert       break;
3861404b540aSrobert 
3862404b540aSrobert     case MINUS_EXPR:
3863404b540aSrobert       if (! INTEGRAL_TYPE_P (endtype)
3864404b540aSrobert 	  || TYPE_PRECISION (endtype) >= POINTER_SIZE)
3865404b540aSrobert 	{
3866404b540aSrobert 	  tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
3867404b540aSrobert 						      endtype);
3868404b540aSrobert 	  tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
3869404b540aSrobert 						      endtype);
3870404b540aSrobert 	  /* Win if second argument is absolute.  */
3871404b540aSrobert 	  if (valid1 == null_pointer_node)
3872404b540aSrobert 	    return valid0;
3873404b540aSrobert 	  /* Win if both arguments have the same relocation.
3874404b540aSrobert 	     Then the value is absolute.  */
3875404b540aSrobert 	  if (valid0 == valid1 && valid0 != 0)
3876404b540aSrobert 	    return null_pointer_node;
3877404b540aSrobert 
3878404b540aSrobert 	  /* Since GCC guarantees that string constants are unique in the
3879404b540aSrobert 	     generated code, a subtraction between two copies of the same
3880404b540aSrobert 	     constant string is absolute.  */
3881404b540aSrobert 	  if (valid0 && TREE_CODE (valid0) == STRING_CST
3882404b540aSrobert 	      && valid1 && TREE_CODE (valid1) == STRING_CST
3883404b540aSrobert 	      && operand_equal_p (valid0, valid1, 1))
3884404b540aSrobert 	    return null_pointer_node;
3885404b540aSrobert 	}
3886404b540aSrobert 
3887404b540aSrobert       /* Support narrowing differences.  */
3888404b540aSrobert       if (INTEGRAL_TYPE_P (endtype))
3889404b540aSrobert 	{
3890404b540aSrobert 	  tree op0, op1;
3891404b540aSrobert 
3892404b540aSrobert 	  op0 = TREE_OPERAND (value, 0);
3893404b540aSrobert 	  op1 = TREE_OPERAND (value, 1);
3894404b540aSrobert 
3895404b540aSrobert 	  /* Like STRIP_NOPS except allow the operand mode to widen.
3896404b540aSrobert 	     This works around a feature of fold that simplifies
3897404b540aSrobert 	     (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
3898404b540aSrobert 	     that the narrower operation is cheaper.  */
3899404b540aSrobert 
3900404b540aSrobert 	  while (TREE_CODE (op0) == NOP_EXPR
3901404b540aSrobert 		 || TREE_CODE (op0) == CONVERT_EXPR
3902404b540aSrobert 		 || TREE_CODE (op0) == NON_LVALUE_EXPR)
3903404b540aSrobert 	    {
3904404b540aSrobert 	      tree inner = TREE_OPERAND (op0, 0);
3905404b540aSrobert 	      if (inner == error_mark_node
3906404b540aSrobert 	          || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
3907404b540aSrobert 		  || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
3908404b540aSrobert 		      > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
3909404b540aSrobert 		break;
3910404b540aSrobert 	      op0 = inner;
3911404b540aSrobert 	    }
3912404b540aSrobert 
3913404b540aSrobert 	  while (TREE_CODE (op1) == NOP_EXPR
3914404b540aSrobert 		 || TREE_CODE (op1) == CONVERT_EXPR
3915404b540aSrobert 		 || TREE_CODE (op1) == NON_LVALUE_EXPR)
3916404b540aSrobert 	    {
3917404b540aSrobert 	      tree inner = TREE_OPERAND (op1, 0);
3918404b540aSrobert 	      if (inner == error_mark_node
3919404b540aSrobert 	          || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
3920404b540aSrobert 		  || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
3921404b540aSrobert 		      > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
3922404b540aSrobert 		break;
3923404b540aSrobert 	      op1 = inner;
3924404b540aSrobert 	    }
3925404b540aSrobert 
3926404b540aSrobert 	  op0 = initializer_constant_valid_p (op0, endtype);
3927404b540aSrobert 	  op1 = initializer_constant_valid_p (op1, endtype);
3928404b540aSrobert 
3929404b540aSrobert 	  /* Both initializers must be known.  */
3930404b540aSrobert 	  if (op0 && op1)
3931404b540aSrobert 	    {
3932404b540aSrobert 	      if (op0 == op1)
3933404b540aSrobert 		return null_pointer_node;
3934404b540aSrobert 
3935404b540aSrobert 	      /* Support differences between labels.  */
3936404b540aSrobert 	      if (TREE_CODE (op0) == LABEL_DECL
3937404b540aSrobert 		  && TREE_CODE (op1) == LABEL_DECL)
3938404b540aSrobert 		return null_pointer_node;
3939404b540aSrobert 
3940404b540aSrobert 	      if (TREE_CODE (op0) == STRING_CST
3941404b540aSrobert 		  && TREE_CODE (op1) == STRING_CST
3942404b540aSrobert 		  && operand_equal_p (op0, op1, 1))
3943404b540aSrobert 		return null_pointer_node;
3944404b540aSrobert 	    }
3945404b540aSrobert 	}
3946404b540aSrobert       break;
3947404b540aSrobert 
3948404b540aSrobert     default:
3949404b540aSrobert       break;
3950404b540aSrobert     }
3951404b540aSrobert 
3952404b540aSrobert   return 0;
3953404b540aSrobert }
3954404b540aSrobert 
3955404b540aSrobert /* Output assembler code for constant EXP to FILE, with no label.
3956404b540aSrobert    This includes the pseudo-op such as ".int" or ".byte", and a newline.
3957404b540aSrobert    Assumes output_addressed_constants has been done on EXP already.
3958404b540aSrobert 
3959404b540aSrobert    Generate exactly SIZE bytes of assembler data, padding at the end
3960404b540aSrobert    with zeros if necessary.  SIZE must always be specified.
3961404b540aSrobert 
3962404b540aSrobert    SIZE is important for structure constructors,
3963404b540aSrobert    since trailing members may have been omitted from the constructor.
3964404b540aSrobert    It is also important for initialization of arrays from string constants
3965404b540aSrobert    since the full length of the string constant might not be wanted.
3966404b540aSrobert    It is also needed for initialization of unions, where the initializer's
3967404b540aSrobert    type is just one member, and that may not be as long as the union.
3968404b540aSrobert 
3969404b540aSrobert    There a case in which we would fail to output exactly SIZE bytes:
3970404b540aSrobert    for a structure constructor that wants to produce more than SIZE bytes.
3971404b540aSrobert    But such constructors will never be generated for any possible input.
3972404b540aSrobert 
3973404b540aSrobert    ALIGN is the alignment of the data in bits.  */
3974404b540aSrobert 
3975404b540aSrobert void
output_constant(tree exp,unsigned HOST_WIDE_INT size,unsigned int align)3976404b540aSrobert output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
3977404b540aSrobert {
3978404b540aSrobert   enum tree_code code;
3979404b540aSrobert   unsigned HOST_WIDE_INT thissize;
3980404b540aSrobert 
3981404b540aSrobert   /* Some front-ends use constants other than the standard language-independent
3982404b540aSrobert      varieties, but which may still be output directly.  Give the front-end a
3983404b540aSrobert      chance to convert EXP to a language-independent representation.  */
3984404b540aSrobert   exp = lang_hooks.expand_constant (exp);
3985404b540aSrobert 
3986404b540aSrobert   if (size == 0 || flag_syntax_only)
3987404b540aSrobert     return;
3988404b540aSrobert 
3989404b540aSrobert   /* See if we're trying to initialize a pointer in a non-default mode
3990404b540aSrobert      to the address of some declaration somewhere.  If the target says
3991404b540aSrobert      the mode is valid for pointers, assume the target has a way of
3992404b540aSrobert      resolving it.  */
3993404b540aSrobert   if (TREE_CODE (exp) == NOP_EXPR
3994404b540aSrobert       && POINTER_TYPE_P (TREE_TYPE (exp))
3995404b540aSrobert       && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
3996404b540aSrobert     {
3997404b540aSrobert       tree saved_type = TREE_TYPE (exp);
3998404b540aSrobert 
3999404b540aSrobert       /* Peel off any intermediate conversions-to-pointer for valid
4000404b540aSrobert 	 pointer modes.  */
4001404b540aSrobert       while (TREE_CODE (exp) == NOP_EXPR
4002404b540aSrobert 	     && POINTER_TYPE_P (TREE_TYPE (exp))
4003404b540aSrobert 	     && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
4004404b540aSrobert 	exp = TREE_OPERAND (exp, 0);
4005404b540aSrobert 
4006404b540aSrobert       /* If what we're left with is the address of something, we can
4007404b540aSrobert 	 convert the address to the final type and output it that
4008404b540aSrobert 	 way.  */
4009404b540aSrobert       if (TREE_CODE (exp) == ADDR_EXPR)
4010404b540aSrobert 	exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
4011404b540aSrobert       /* Likewise for constant ints.  */
4012404b540aSrobert       else if (TREE_CODE (exp) == INTEGER_CST)
4013404b540aSrobert 	exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
4014404b540aSrobert 				  TREE_INT_CST_HIGH (exp));
4015404b540aSrobert 
4016404b540aSrobert     }
4017404b540aSrobert 
4018404b540aSrobert   /* Eliminate any conversions since we'll be outputting the underlying
4019404b540aSrobert      constant.  */
4020404b540aSrobert   while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
4021404b540aSrobert 	 || TREE_CODE (exp) == NON_LVALUE_EXPR
4022404b540aSrobert 	 || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
4023404b540aSrobert     {
4024404b540aSrobert       HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp));
4025404b540aSrobert       HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0)));
4026404b540aSrobert 
4027404b540aSrobert       /* Make sure eliminating the conversion is really a no-op, except with
4028404b540aSrobert 	 VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and
4029404b540aSrobert 	 union types to allow for Ada unchecked unions.  */
4030404b540aSrobert       if (type_size > op_size
4031404b540aSrobert 	  && TREE_CODE (exp) != VIEW_CONVERT_EXPR
4032404b540aSrobert 	  && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
4033404b540aSrobert 	/* Keep the conversion. */
4034404b540aSrobert 	break;
4035404b540aSrobert       else
4036404b540aSrobert 	exp = TREE_OPERAND (exp, 0);
4037404b540aSrobert     }
4038404b540aSrobert 
4039404b540aSrobert   code = TREE_CODE (TREE_TYPE (exp));
4040404b540aSrobert   thissize = int_size_in_bytes (TREE_TYPE (exp));
4041404b540aSrobert 
4042404b540aSrobert   /* Give the front end another chance to expand constants.  */
4043404b540aSrobert   exp = lang_hooks.expand_constant (exp);
4044404b540aSrobert 
4045404b540aSrobert   /* Allow a constructor with no elements for any data type.
4046404b540aSrobert      This means to fill the space with zeros.  */
4047404b540aSrobert   if (TREE_CODE (exp) == CONSTRUCTOR
4048404b540aSrobert       && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (exp)))
4049404b540aSrobert     {
4050404b540aSrobert       assemble_zeros (size);
4051404b540aSrobert       return;
4052404b540aSrobert     }
4053404b540aSrobert 
4054404b540aSrobert   if (TREE_CODE (exp) == FDESC_EXPR)
4055404b540aSrobert     {
4056404b540aSrobert #ifdef ASM_OUTPUT_FDESC
4057404b540aSrobert       HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
4058404b540aSrobert       tree decl = TREE_OPERAND (exp, 0);
4059404b540aSrobert       ASM_OUTPUT_FDESC (asm_out_file, decl, part);
4060404b540aSrobert #else
4061404b540aSrobert       gcc_unreachable ();
4062404b540aSrobert #endif
4063404b540aSrobert       return;
4064404b540aSrobert     }
4065404b540aSrobert 
4066404b540aSrobert   /* Now output the underlying data.  If we've handling the padding, return.
4067404b540aSrobert      Otherwise, break and ensure SIZE is the size written.  */
4068404b540aSrobert   switch (code)
4069404b540aSrobert     {
4070404b540aSrobert     case BOOLEAN_TYPE:
4071404b540aSrobert     case INTEGER_TYPE:
4072404b540aSrobert     case ENUMERAL_TYPE:
4073404b540aSrobert     case POINTER_TYPE:
4074404b540aSrobert     case REFERENCE_TYPE:
4075404b540aSrobert     case OFFSET_TYPE:
4076404b540aSrobert       if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
4077404b540aSrobert 					   EXPAND_INITIALIZER),
4078404b540aSrobert 			      MIN (size, thissize), align, 0))
4079404b540aSrobert 	error ("initializer for integer value is too complicated");
4080404b540aSrobert       break;
4081404b540aSrobert 
4082404b540aSrobert     case REAL_TYPE:
4083404b540aSrobert       if (TREE_CODE (exp) != REAL_CST)
4084404b540aSrobert 	error ("initializer for floating value is not a floating constant");
4085404b540aSrobert 
4086404b540aSrobert       assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), align);
4087404b540aSrobert       break;
4088404b540aSrobert 
4089404b540aSrobert     case COMPLEX_TYPE:
4090404b540aSrobert       output_constant (TREE_REALPART (exp), thissize / 2, align);
4091404b540aSrobert       output_constant (TREE_IMAGPART (exp), thissize / 2,
4092404b540aSrobert 		       min_align (align, BITS_PER_UNIT * (thissize / 2)));
4093404b540aSrobert       break;
4094404b540aSrobert 
4095404b540aSrobert     case ARRAY_TYPE:
4096404b540aSrobert     case VECTOR_TYPE:
4097404b540aSrobert       switch (TREE_CODE (exp))
4098404b540aSrobert 	{
4099404b540aSrobert 	case CONSTRUCTOR:
4100404b540aSrobert 	  output_constructor (exp, size, align);
4101404b540aSrobert 	  return;
4102404b540aSrobert 	case STRING_CST:
4103404b540aSrobert 	  thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
4104404b540aSrobert 			  size);
4105404b540aSrobert 	  assemble_string (TREE_STRING_POINTER (exp), thissize);
4106404b540aSrobert 	  break;
4107404b540aSrobert 
4108404b540aSrobert 	case VECTOR_CST:
4109404b540aSrobert 	  {
4110404b540aSrobert 	    int elt_size;
4111404b540aSrobert 	    tree link;
4112404b540aSrobert 	    unsigned int nalign;
4113404b540aSrobert 	    enum machine_mode inner;
4114404b540aSrobert 
4115404b540aSrobert 	    inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
4116404b540aSrobert 	    nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
4117404b540aSrobert 
4118404b540aSrobert 	    elt_size = GET_MODE_SIZE (inner);
4119404b540aSrobert 
4120404b540aSrobert 	    link = TREE_VECTOR_CST_ELTS (exp);
4121404b540aSrobert 	    output_constant (TREE_VALUE (link), elt_size, align);
4122404b540aSrobert 	    thissize = elt_size;
4123404b540aSrobert 	    while ((link = TREE_CHAIN (link)) != NULL)
4124404b540aSrobert 	      {
4125404b540aSrobert 		output_constant (TREE_VALUE (link), elt_size, nalign);
4126404b540aSrobert 		thissize += elt_size;
4127404b540aSrobert 	      }
4128404b540aSrobert 	    break;
4129404b540aSrobert 	  }
4130404b540aSrobert 	default:
4131404b540aSrobert 	  gcc_unreachable ();
4132404b540aSrobert 	}
4133404b540aSrobert       break;
4134404b540aSrobert 
4135404b540aSrobert     case RECORD_TYPE:
4136404b540aSrobert     case UNION_TYPE:
4137404b540aSrobert       gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
4138404b540aSrobert       output_constructor (exp, size, align);
4139404b540aSrobert       return;
4140404b540aSrobert 
4141404b540aSrobert     case ERROR_MARK:
4142404b540aSrobert       return;
4143404b540aSrobert 
4144404b540aSrobert     default:
4145404b540aSrobert       gcc_unreachable ();
4146404b540aSrobert     }
4147404b540aSrobert 
4148404b540aSrobert   if (size > thissize)
4149404b540aSrobert     assemble_zeros (size - thissize);
4150404b540aSrobert }
4151404b540aSrobert 
4152404b540aSrobert 
4153404b540aSrobert /* Subroutine of output_constructor, used for computing the size of
4154404b540aSrobert    arrays of unspecified length.  VAL must be a CONSTRUCTOR of an array
4155404b540aSrobert    type with an unspecified upper bound.  */
4156404b540aSrobert 
4157404b540aSrobert static unsigned HOST_WIDE_INT
array_size_for_constructor(tree val)4158404b540aSrobert array_size_for_constructor (tree val)
4159404b540aSrobert {
4160404b540aSrobert   tree max_index, i;
4161404b540aSrobert   unsigned HOST_WIDE_INT cnt;
4162404b540aSrobert   tree index, value, tmp;
4163404b540aSrobert 
4164404b540aSrobert   /* This code used to attempt to handle string constants that are not
4165404b540aSrobert      arrays of single-bytes, but nothing else does, so there's no point in
4166404b540aSrobert      doing it here.  */
4167404b540aSrobert   if (TREE_CODE (val) == STRING_CST)
4168404b540aSrobert     return TREE_STRING_LENGTH (val);
4169404b540aSrobert 
4170404b540aSrobert   max_index = NULL_TREE;
4171404b540aSrobert   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (val), cnt, index, value)
4172404b540aSrobert     {
4173404b540aSrobert       if (TREE_CODE (index) == RANGE_EXPR)
4174404b540aSrobert 	index = TREE_OPERAND (index, 1);
4175404b540aSrobert       if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
4176404b540aSrobert 	max_index = index;
4177404b540aSrobert     }
4178404b540aSrobert 
4179404b540aSrobert   if (max_index == NULL_TREE)
4180404b540aSrobert     return 0;
4181404b540aSrobert 
4182404b540aSrobert   /* Compute the total number of array elements.  */
4183404b540aSrobert   tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
4184404b540aSrobert   i = size_binop (MINUS_EXPR, fold_convert (sizetype, max_index),
4185404b540aSrobert 		  fold_convert (sizetype, tmp));
4186404b540aSrobert   i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
4187404b540aSrobert 
4188404b540aSrobert   /* Multiply by the array element unit size to find number of bytes.  */
4189404b540aSrobert   i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
4190404b540aSrobert 
4191404b540aSrobert   return tree_low_cst (i, 1);
4192404b540aSrobert }
4193404b540aSrobert 
4194404b540aSrobert /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
4195404b540aSrobert    Generate at least SIZE bytes, padding if necessary.  */
4196404b540aSrobert 
4197404b540aSrobert static void
output_constructor(tree exp,unsigned HOST_WIDE_INT size,unsigned int align)4198404b540aSrobert output_constructor (tree exp, unsigned HOST_WIDE_INT size,
4199404b540aSrobert 		    unsigned int align)
4200404b540aSrobert {
4201404b540aSrobert   tree type = TREE_TYPE (exp);
4202404b540aSrobert   tree field = 0;
4203404b540aSrobert   tree min_index = 0;
4204404b540aSrobert   /* Number of bytes output or skipped so far.
4205404b540aSrobert      In other words, current position within the constructor.  */
4206404b540aSrobert   HOST_WIDE_INT total_bytes = 0;
4207404b540aSrobert   /* Nonzero means BYTE contains part of a byte, to be output.  */
4208404b540aSrobert   int byte_buffer_in_use = 0;
4209404b540aSrobert   int byte = 0;
4210404b540aSrobert   unsigned HOST_WIDE_INT cnt;
4211404b540aSrobert   constructor_elt *ce;
4212404b540aSrobert 
4213404b540aSrobert   gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
4214404b540aSrobert 
4215404b540aSrobert   if (TREE_CODE (type) == RECORD_TYPE)
4216404b540aSrobert     field = TYPE_FIELDS (type);
4217404b540aSrobert 
4218404b540aSrobert   if (TREE_CODE (type) == ARRAY_TYPE
4219404b540aSrobert       && TYPE_DOMAIN (type) != 0)
4220404b540aSrobert     min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
4221404b540aSrobert 
4222404b540aSrobert   /* As LINK goes through the elements of the constant,
4223404b540aSrobert      FIELD goes through the structure fields, if the constant is a structure.
4224404b540aSrobert      if the constant is a union, then we override this,
4225404b540aSrobert      by getting the field from the TREE_LIST element.
4226404b540aSrobert      But the constant could also be an array.  Then FIELD is zero.
4227404b540aSrobert 
4228404b540aSrobert      There is always a maximum of one element in the chain LINK for unions
4229404b540aSrobert      (even if the initializer in a source program incorrectly contains
4230404b540aSrobert      more one).  */
4231404b540aSrobert   for (cnt = 0;
4232404b540aSrobert        VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
4233404b540aSrobert        cnt++, field = field ? TREE_CHAIN (field) : 0)
4234404b540aSrobert     {
4235404b540aSrobert       tree val = ce->value;
4236404b540aSrobert       tree index = 0;
4237404b540aSrobert 
4238404b540aSrobert       /* The element in a union constructor specifies the proper field
4239404b540aSrobert 	 or index.  */
4240404b540aSrobert       if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
4241404b540aSrobert 	   || TREE_CODE (type) == QUAL_UNION_TYPE)
4242404b540aSrobert 	  && ce->index != 0)
4243404b540aSrobert 	field = ce->index;
4244404b540aSrobert 
4245404b540aSrobert       else if (TREE_CODE (type) == ARRAY_TYPE)
4246404b540aSrobert 	index = ce->index;
4247404b540aSrobert 
4248404b540aSrobert #ifdef ASM_COMMENT_START
4249404b540aSrobert       if (field && flag_verbose_asm)
4250404b540aSrobert 	fprintf (asm_out_file, "%s %s:\n",
4251404b540aSrobert 		 ASM_COMMENT_START,
4252404b540aSrobert 		 DECL_NAME (field)
4253404b540aSrobert 		 ? IDENTIFIER_POINTER (DECL_NAME (field))
4254404b540aSrobert 		 : "<anonymous>");
4255404b540aSrobert #endif
4256404b540aSrobert 
4257404b540aSrobert       /* Eliminate the marker that makes a cast not be an lvalue.  */
4258404b540aSrobert       if (val != 0)
4259404b540aSrobert 	STRIP_NOPS (val);
4260404b540aSrobert 
4261404b540aSrobert       if (index && TREE_CODE (index) == RANGE_EXPR)
4262404b540aSrobert 	{
4263404b540aSrobert 	  unsigned HOST_WIDE_INT fieldsize
4264404b540aSrobert 	    = int_size_in_bytes (TREE_TYPE (type));
4265404b540aSrobert 	  HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
4266404b540aSrobert 	  HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
4267404b540aSrobert 	  HOST_WIDE_INT index;
4268404b540aSrobert 	  unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
4269404b540aSrobert 
4270404b540aSrobert 	  for (index = lo_index; index <= hi_index; index++)
4271404b540aSrobert 	    {
4272404b540aSrobert 	      /* Output the element's initial value.  */
4273404b540aSrobert 	      if (val == 0)
4274404b540aSrobert 		assemble_zeros (fieldsize);
4275404b540aSrobert 	      else
4276404b540aSrobert 		output_constant (val, fieldsize, align2);
4277404b540aSrobert 
4278404b540aSrobert 	      /* Count its size.  */
4279404b540aSrobert 	      total_bytes += fieldsize;
4280404b540aSrobert 	    }
4281404b540aSrobert 	}
4282404b540aSrobert       else if (field == 0 || !DECL_BIT_FIELD (field))
4283404b540aSrobert 	{
4284404b540aSrobert 	  /* An element that is not a bit-field.  */
4285404b540aSrobert 
4286404b540aSrobert 	  unsigned HOST_WIDE_INT fieldsize;
4287404b540aSrobert 	  /* Since this structure is static,
4288404b540aSrobert 	     we know the positions are constant.  */
4289404b540aSrobert 	  HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
4290404b540aSrobert 	  unsigned int align2;
4291404b540aSrobert 
4292404b540aSrobert 	  if (index != 0)
4293404b540aSrobert 	    pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
4294404b540aSrobert 		   * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
4295404b540aSrobert 
4296404b540aSrobert 	  /* Output any buffered-up bit-fields preceding this element.  */
4297404b540aSrobert 	  if (byte_buffer_in_use)
4298404b540aSrobert 	    {
4299404b540aSrobert 	      assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4300404b540aSrobert 	      total_bytes++;
4301404b540aSrobert 	      byte_buffer_in_use = 0;
4302404b540aSrobert 	    }
4303404b540aSrobert 
4304404b540aSrobert 	  /* Advance to offset of this element.
4305404b540aSrobert 	     Note no alignment needed in an array, since that is guaranteed
4306404b540aSrobert 	     if each element has the proper size.  */
4307404b540aSrobert 	  if ((field != 0 || index != 0) && pos != total_bytes)
4308404b540aSrobert 	    {
4309404b540aSrobert 	      gcc_assert (pos >= total_bytes);
4310404b540aSrobert 	      assemble_zeros (pos - total_bytes);
4311404b540aSrobert 	      total_bytes = pos;
4312404b540aSrobert 	    }
4313404b540aSrobert 
4314404b540aSrobert 	  /* Find the alignment of this element.  */
4315404b540aSrobert 	  align2 = min_align (align, BITS_PER_UNIT * pos);
4316404b540aSrobert 
4317404b540aSrobert 	  /* Determine size this element should occupy.  */
4318404b540aSrobert 	  if (field)
4319404b540aSrobert 	    {
4320404b540aSrobert 	      fieldsize = 0;
4321404b540aSrobert 
4322404b540aSrobert 	      /* If this is an array with an unspecified upper bound,
4323404b540aSrobert 		 the initializer determines the size.  */
4324404b540aSrobert 	      /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
4325404b540aSrobert 		 but we cannot do this until the deprecated support for
4326404b540aSrobert 		 initializing zero-length array members is removed.  */
4327404b540aSrobert 	      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
4328404b540aSrobert 		  && TYPE_DOMAIN (TREE_TYPE (field))
4329404b540aSrobert 		  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
4330404b540aSrobert 		{
4331404b540aSrobert 		  fieldsize = array_size_for_constructor (val);
4332404b540aSrobert 		  /* Given a non-empty initialization, this field had
4333404b540aSrobert 		     better be last.  */
4334404b540aSrobert 		  gcc_assert (!fieldsize || !TREE_CHAIN (field));
4335404b540aSrobert 		}
4336404b540aSrobert 	      else if (DECL_SIZE_UNIT (field))
4337404b540aSrobert 		{
4338404b540aSrobert 		  /* ??? This can't be right.  If the decl size overflows
4339404b540aSrobert 		     a host integer we will silently emit no data.  */
4340404b540aSrobert 		  if (host_integerp (DECL_SIZE_UNIT (field), 1))
4341404b540aSrobert 		    fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
4342404b540aSrobert 		}
4343404b540aSrobert 	    }
4344404b540aSrobert 	  else
4345404b540aSrobert 	    fieldsize = int_size_in_bytes (TREE_TYPE (type));
4346404b540aSrobert 
4347404b540aSrobert 	  /* Output the element's initial value.  */
4348404b540aSrobert 	  if (val == 0)
4349404b540aSrobert 	    assemble_zeros (fieldsize);
4350404b540aSrobert 	  else
4351404b540aSrobert 	    output_constant (val, fieldsize, align2);
4352404b540aSrobert 
4353404b540aSrobert 	  /* Count its size.  */
4354404b540aSrobert 	  total_bytes += fieldsize;
4355404b540aSrobert 	}
4356404b540aSrobert       else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
4357404b540aSrobert 	error ("invalid initial value for member %qs",
4358404b540aSrobert 	       IDENTIFIER_POINTER (DECL_NAME (field)));
4359404b540aSrobert       else
4360404b540aSrobert 	{
4361404b540aSrobert 	  /* Element that is a bit-field.  */
4362404b540aSrobert 
4363404b540aSrobert 	  HOST_WIDE_INT next_offset = int_bit_position (field);
4364404b540aSrobert 	  HOST_WIDE_INT end_offset
4365404b540aSrobert 	    = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
4366404b540aSrobert 
4367404b540aSrobert 	  if (val == 0)
4368404b540aSrobert 	    val = integer_zero_node;
4369404b540aSrobert 
4370404b540aSrobert 	  /* If this field does not start in this (or, next) byte,
4371404b540aSrobert 	     skip some bytes.  */
4372404b540aSrobert 	  if (next_offset / BITS_PER_UNIT != total_bytes)
4373404b540aSrobert 	    {
4374404b540aSrobert 	      /* Output remnant of any bit field in previous bytes.  */
4375404b540aSrobert 	      if (byte_buffer_in_use)
4376404b540aSrobert 		{
4377404b540aSrobert 		  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4378404b540aSrobert 		  total_bytes++;
4379404b540aSrobert 		  byte_buffer_in_use = 0;
4380404b540aSrobert 		}
4381404b540aSrobert 
4382404b540aSrobert 	      /* If still not at proper byte, advance to there.  */
4383404b540aSrobert 	      if (next_offset / BITS_PER_UNIT != total_bytes)
4384404b540aSrobert 		{
4385404b540aSrobert 		  gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
4386404b540aSrobert 		  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
4387404b540aSrobert 		  total_bytes = next_offset / BITS_PER_UNIT;
4388404b540aSrobert 		}
4389404b540aSrobert 	    }
4390404b540aSrobert 
4391404b540aSrobert 	  if (! byte_buffer_in_use)
4392404b540aSrobert 	    byte = 0;
4393404b540aSrobert 
4394404b540aSrobert 	  /* We must split the element into pieces that fall within
4395404b540aSrobert 	     separate bytes, and combine each byte with previous or
4396404b540aSrobert 	     following bit-fields.  */
4397404b540aSrobert 
4398404b540aSrobert 	  /* next_offset is the offset n fbits from the beginning of
4399404b540aSrobert 	     the structure to the next bit of this element to be processed.
4400404b540aSrobert 	     end_offset is the offset of the first bit past the end of
4401404b540aSrobert 	     this element.  */
4402404b540aSrobert 	  while (next_offset < end_offset)
4403404b540aSrobert 	    {
4404404b540aSrobert 	      int this_time;
4405404b540aSrobert 	      int shift;
4406404b540aSrobert 	      HOST_WIDE_INT value;
4407404b540aSrobert 	      HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
4408404b540aSrobert 	      HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
4409404b540aSrobert 
4410404b540aSrobert 	      /* Advance from byte to byte
4411404b540aSrobert 		 within this element when necessary.  */
4412404b540aSrobert 	      while (next_byte != total_bytes)
4413404b540aSrobert 		{
4414404b540aSrobert 		  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4415404b540aSrobert 		  total_bytes++;
4416404b540aSrobert 		  byte = 0;
4417404b540aSrobert 		}
4418404b540aSrobert 
4419404b540aSrobert 	      /* Number of bits we can process at once
4420404b540aSrobert 		 (all part of the same byte).  */
4421404b540aSrobert 	      this_time = MIN (end_offset - next_offset,
4422404b540aSrobert 			       BITS_PER_UNIT - next_bit);
4423404b540aSrobert 	      if (BYTES_BIG_ENDIAN)
4424404b540aSrobert 		{
4425404b540aSrobert 		  /* On big-endian machine, take the most significant bits
4426404b540aSrobert 		     first (of the bits that are significant)
4427404b540aSrobert 		     and put them into bytes from the most significant end.  */
4428404b540aSrobert 		  shift = end_offset - next_offset - this_time;
4429404b540aSrobert 
4430404b540aSrobert 		  /* Don't try to take a bunch of bits that cross
4431404b540aSrobert 		     the word boundary in the INTEGER_CST. We can
4432404b540aSrobert 		     only select bits from the LOW or HIGH part
4433404b540aSrobert 		     not from both.  */
4434404b540aSrobert 		  if (shift < HOST_BITS_PER_WIDE_INT
4435404b540aSrobert 		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
4436404b540aSrobert 		    {
4437404b540aSrobert 		      this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
4438404b540aSrobert 		      shift = HOST_BITS_PER_WIDE_INT;
4439404b540aSrobert 		    }
4440404b540aSrobert 
4441404b540aSrobert 		  /* Now get the bits from the appropriate constant word.  */
4442404b540aSrobert 		  if (shift < HOST_BITS_PER_WIDE_INT)
4443404b540aSrobert 		    value = TREE_INT_CST_LOW (val);
4444404b540aSrobert 		  else
4445404b540aSrobert 		    {
4446404b540aSrobert 		      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
4447404b540aSrobert 		      value = TREE_INT_CST_HIGH (val);
4448404b540aSrobert 		      shift -= HOST_BITS_PER_WIDE_INT;
4449404b540aSrobert 		    }
4450404b540aSrobert 
4451404b540aSrobert 		  /* Get the result. This works only when:
4452404b540aSrobert 		     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
4453404b540aSrobert 		  byte |= (((value >> shift)
4454404b540aSrobert 			    & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
4455404b540aSrobert 			   << (BITS_PER_UNIT - this_time - next_bit));
4456404b540aSrobert 		}
4457404b540aSrobert 	      else
4458404b540aSrobert 		{
4459404b540aSrobert 		  /* On little-endian machines,
4460404b540aSrobert 		     take first the least significant bits of the value
4461404b540aSrobert 		     and pack them starting at the least significant
4462404b540aSrobert 		     bits of the bytes.  */
4463404b540aSrobert 		  shift = next_offset - int_bit_position (field);
4464404b540aSrobert 
4465404b540aSrobert 		  /* Don't try to take a bunch of bits that cross
4466404b540aSrobert 		     the word boundary in the INTEGER_CST. We can
4467404b540aSrobert 		     only select bits from the LOW or HIGH part
4468404b540aSrobert 		     not from both.  */
4469404b540aSrobert 		  if (shift < HOST_BITS_PER_WIDE_INT
4470404b540aSrobert 		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
4471404b540aSrobert 		    this_time = (HOST_BITS_PER_WIDE_INT - shift);
4472404b540aSrobert 
4473404b540aSrobert 		  /* Now get the bits from the appropriate constant word.  */
4474404b540aSrobert 		  if (shift < HOST_BITS_PER_WIDE_INT)
4475404b540aSrobert 		    value = TREE_INT_CST_LOW (val);
4476404b540aSrobert 		  else
4477404b540aSrobert 		    {
4478404b540aSrobert 		      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
4479404b540aSrobert 		      value = TREE_INT_CST_HIGH (val);
4480404b540aSrobert 		      shift -= HOST_BITS_PER_WIDE_INT;
4481404b540aSrobert 		    }
4482404b540aSrobert 
4483404b540aSrobert 		  /* Get the result. This works only when:
4484404b540aSrobert 		     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
4485404b540aSrobert 		  byte |= (((value >> shift)
4486404b540aSrobert 			    & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
4487404b540aSrobert 			   << next_bit);
4488404b540aSrobert 		}
4489404b540aSrobert 
4490404b540aSrobert 	      next_offset += this_time;
4491404b540aSrobert 	      byte_buffer_in_use = 1;
4492404b540aSrobert 	    }
4493404b540aSrobert 	}
4494404b540aSrobert     }
4495404b540aSrobert 
4496404b540aSrobert   if (byte_buffer_in_use)
4497404b540aSrobert     {
4498404b540aSrobert       assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4499404b540aSrobert       total_bytes++;
4500404b540aSrobert     }
4501404b540aSrobert 
4502404b540aSrobert   if ((unsigned HOST_WIDE_INT)total_bytes < size)
4503404b540aSrobert     assemble_zeros (size - total_bytes);
4504404b540aSrobert }
4505404b540aSrobert 
4506404b540aSrobert /* This TREE_LIST contains any weak symbol declarations waiting
4507404b540aSrobert    to be emitted.  */
4508404b540aSrobert static GTY(()) tree weak_decls;
4509404b540aSrobert 
4510404b540aSrobert /* Mark DECL as weak.  */
4511404b540aSrobert 
4512404b540aSrobert static void
mark_weak(tree decl)4513404b540aSrobert mark_weak (tree decl)
4514404b540aSrobert {
4515404b540aSrobert   DECL_WEAK (decl) = 1;
4516404b540aSrobert 
4517404b540aSrobert   if (DECL_RTL_SET_P (decl)
4518404b540aSrobert       && MEM_P (DECL_RTL (decl))
4519404b540aSrobert       && XEXP (DECL_RTL (decl), 0)
4520404b540aSrobert       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
4521404b540aSrobert     SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
4522404b540aSrobert }
4523404b540aSrobert 
4524404b540aSrobert /* Merge weak status between NEWDECL and OLDDECL.  */
4525404b540aSrobert 
4526404b540aSrobert void
merge_weak(tree newdecl,tree olddecl)4527404b540aSrobert merge_weak (tree newdecl, tree olddecl)
4528404b540aSrobert {
4529404b540aSrobert   if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
4530404b540aSrobert     {
4531404b540aSrobert       if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
4532404b540aSrobert         {
4533404b540aSrobert           tree *pwd;
4534404b540aSrobert           /* We put the NEWDECL on the weak_decls list at some point
4535404b540aSrobert              and OLDDECL as well.  Keep just OLDDECL on the list.  */
4536404b540aSrobert 	  for (pwd = &weak_decls; *pwd; pwd = &TREE_CHAIN (*pwd))
4537404b540aSrobert 	    if (TREE_VALUE (*pwd) == newdecl)
4538404b540aSrobert 	      {
4539404b540aSrobert 	        *pwd = TREE_CHAIN (*pwd);
4540404b540aSrobert 		break;
4541404b540aSrobert 	      }
4542404b540aSrobert         }
4543404b540aSrobert       return;
4544404b540aSrobert     }
4545404b540aSrobert 
4546404b540aSrobert   if (DECL_WEAK (newdecl))
4547404b540aSrobert     {
4548404b540aSrobert       tree wd;
4549404b540aSrobert 
4550404b540aSrobert       /* NEWDECL is weak, but OLDDECL is not.  */
4551404b540aSrobert 
4552404b540aSrobert       /* If we already output the OLDDECL, we're in trouble; we can't
4553404b540aSrobert 	 go back and make it weak.  This error cannot caught in
4554404b540aSrobert 	 declare_weak because the NEWDECL and OLDDECL was not yet
4555404b540aSrobert 	 been merged; therefore, TREE_ASM_WRITTEN was not set.  */
4556404b540aSrobert       if (TREE_ASM_WRITTEN (olddecl))
4557404b540aSrobert 	error ("weak declaration of %q+D must precede definition",
4558404b540aSrobert 	       newdecl);
4559404b540aSrobert 
4560404b540aSrobert       /* If we've already generated rtl referencing OLDDECL, we may
4561404b540aSrobert 	 have done so in a way that will not function properly with
4562404b540aSrobert 	 a weak symbol.  */
4563404b540aSrobert       else if (TREE_USED (olddecl)
4564404b540aSrobert 	       && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
4565404b540aSrobert 	warning (0, "weak declaration of %q+D after first use results "
4566404b540aSrobert                  "in unspecified behavior", newdecl);
4567404b540aSrobert 
4568404b540aSrobert       if (SUPPORTS_WEAK)
4569404b540aSrobert 	{
4570404b540aSrobert 	  /* We put the NEWDECL on the weak_decls list at some point.
4571404b540aSrobert 	     Replace it with the OLDDECL.  */
4572404b540aSrobert 	  for (wd = weak_decls; wd; wd = TREE_CHAIN (wd))
4573404b540aSrobert 	    if (TREE_VALUE (wd) == newdecl)
4574404b540aSrobert 	      {
4575404b540aSrobert 		TREE_VALUE (wd) = olddecl;
4576404b540aSrobert 		break;
4577404b540aSrobert 	      }
4578404b540aSrobert 	  /* We may not find the entry on the list.  If NEWDECL is a
4579404b540aSrobert 	     weak alias, then we will have already called
4580404b540aSrobert 	     globalize_decl to remove the entry; in that case, we do
4581404b540aSrobert 	     not need to do anything.  */
4582404b540aSrobert 	}
4583404b540aSrobert 
4584404b540aSrobert       /* Make the OLDDECL weak; it's OLDDECL that we'll be keeping.  */
4585404b540aSrobert       mark_weak (olddecl);
4586404b540aSrobert     }
4587404b540aSrobert   else
4588404b540aSrobert     /* OLDDECL was weak, but NEWDECL was not explicitly marked as
4589404b540aSrobert        weak.  Just update NEWDECL to indicate that it's weak too.  */
4590404b540aSrobert     mark_weak (newdecl);
4591404b540aSrobert }
4592404b540aSrobert 
4593404b540aSrobert /* Declare DECL to be a weak symbol.  */
4594404b540aSrobert 
4595404b540aSrobert void
declare_weak(tree decl)4596404b540aSrobert declare_weak (tree decl)
4597404b540aSrobert {
4598404b540aSrobert   if (! TREE_PUBLIC (decl))
4599404b540aSrobert     error ("weak declaration of %q+D must be public", decl);
4600404b540aSrobert   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
4601404b540aSrobert     error ("weak declaration of %q+D must precede definition", decl);
4602404b540aSrobert   else if (SUPPORTS_WEAK)
4603404b540aSrobert     {
4604404b540aSrobert       if (! DECL_WEAK (decl))
4605404b540aSrobert 	weak_decls = tree_cons (NULL, decl, weak_decls);
4606404b540aSrobert     }
4607404b540aSrobert   else
4608404b540aSrobert     warning (0, "weak declaration of %q+D not supported", decl);
4609404b540aSrobert 
4610404b540aSrobert   mark_weak (decl);
4611404b540aSrobert }
4612404b540aSrobert 
4613404b540aSrobert static void
weak_finish_1(tree decl)4614404b540aSrobert weak_finish_1 (tree decl)
4615404b540aSrobert {
4616404b540aSrobert #if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
4617404b540aSrobert   const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
4618404b540aSrobert #endif
4619404b540aSrobert 
4620404b540aSrobert   if (! TREE_USED (decl))
4621404b540aSrobert     return;
4622404b540aSrobert 
4623404b540aSrobert #ifdef ASM_WEAKEN_DECL
4624404b540aSrobert   ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
4625404b540aSrobert #else
4626404b540aSrobert #ifdef ASM_WEAKEN_LABEL
4627404b540aSrobert   ASM_WEAKEN_LABEL (asm_out_file, name);
4628404b540aSrobert #else
4629404b540aSrobert #ifdef ASM_OUTPUT_WEAK_ALIAS
4630404b540aSrobert   {
4631404b540aSrobert     static bool warn_once = 0;
4632404b540aSrobert     if (! warn_once)
4633404b540aSrobert       {
4634404b540aSrobert 	warning (0, "only weak aliases are supported in this configuration");
4635404b540aSrobert 	warn_once = 1;
4636404b540aSrobert       }
4637404b540aSrobert     return;
4638404b540aSrobert   }
4639404b540aSrobert #endif
4640404b540aSrobert #endif
4641404b540aSrobert #endif
4642404b540aSrobert }
4643404b540aSrobert 
4644404b540aSrobert /* This TREE_LIST contains weakref targets.  */
4645404b540aSrobert 
4646404b540aSrobert static GTY(()) tree weakref_targets;
4647404b540aSrobert 
4648404b540aSrobert /* Forward declaration.  */
4649404b540aSrobert static tree find_decl_and_mark_needed (tree decl, tree target);
4650404b540aSrobert 
4651404b540aSrobert /* Emit any pending weak declarations.  */
4652404b540aSrobert 
4653404b540aSrobert void
weak_finish(void)4654404b540aSrobert weak_finish (void)
4655404b540aSrobert {
4656404b540aSrobert   tree t;
4657404b540aSrobert 
4658404b540aSrobert   for (t = weakref_targets; t; t = TREE_CHAIN (t))
4659404b540aSrobert     {
4660404b540aSrobert       tree alias_decl = TREE_PURPOSE (t);
4661404b540aSrobert       tree target = ultimate_transparent_alias_target (&TREE_VALUE (t));
4662404b540aSrobert 
4663404b540aSrobert       if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)))
4664404b540aSrobert 	/* Remove alias_decl from the weak list, but leave entries for
4665404b540aSrobert 	   the target alone.  */
4666404b540aSrobert 	target = NULL_TREE;
4667404b540aSrobert #ifndef ASM_OUTPUT_WEAKREF
4668404b540aSrobert       else if (! TREE_SYMBOL_REFERENCED (target))
4669404b540aSrobert 	{
4670404b540aSrobert 	  /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
4671404b540aSrobert 	     defined, otherwise we and weak_finish_1 would use a
4672404b540aSrobert 	     different macros.  */
4673404b540aSrobert # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
4674404b540aSrobert 	  ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
4675404b540aSrobert # else
4676404b540aSrobert 	  tree decl = find_decl_and_mark_needed (alias_decl, target);
4677404b540aSrobert 
4678404b540aSrobert 	  if (! decl)
4679404b540aSrobert 	    {
4680404b540aSrobert 	      decl = build_decl (TREE_CODE (alias_decl), target,
4681404b540aSrobert 				 TREE_TYPE (alias_decl));
4682404b540aSrobert 
4683404b540aSrobert 	      DECL_EXTERNAL (decl) = 1;
4684404b540aSrobert 	      TREE_PUBLIC (decl) = 1;
4685404b540aSrobert 	      DECL_ARTIFICIAL (decl) = 1;
4686404b540aSrobert 	      TREE_NOTHROW (decl) = TREE_NOTHROW (alias_decl);
4687404b540aSrobert 	      TREE_USED (decl) = 1;
4688404b540aSrobert 	    }
4689404b540aSrobert 
4690404b540aSrobert 	  weak_finish_1 (decl);
4691404b540aSrobert # endif
4692404b540aSrobert 	}
4693404b540aSrobert #endif
4694404b540aSrobert 
4695404b540aSrobert       {
4696404b540aSrobert 	tree *p;
4697404b540aSrobert 	tree t2;
4698404b540aSrobert 
4699404b540aSrobert 	/* Remove the alias and the target from the pending weak list
4700404b540aSrobert 	   so that we do not emit any .weak directives for the former,
4701404b540aSrobert 	   nor multiple .weak directives for the latter.  */
4702404b540aSrobert 	for (p = &weak_decls; (t2 = *p) ; )
4703404b540aSrobert 	  {
4704404b540aSrobert 	    if (TREE_VALUE (t2) == alias_decl
4705404b540aSrobert 		|| target == DECL_ASSEMBLER_NAME (TREE_VALUE (t2)))
4706404b540aSrobert 	      *p = TREE_CHAIN (t2);
4707404b540aSrobert 	    else
4708404b540aSrobert 	      p = &TREE_CHAIN (t2);
4709404b540aSrobert 	  }
4710404b540aSrobert 
4711404b540aSrobert 	/* Remove other weakrefs to the same target, to speed things up.  */
4712404b540aSrobert 	for (p = &TREE_CHAIN (t); (t2 = *p) ; )
4713404b540aSrobert 	  {
4714404b540aSrobert 	    if (target == ultimate_transparent_alias_target (&TREE_VALUE (t2)))
4715404b540aSrobert 	      *p = TREE_CHAIN (t2);
4716404b540aSrobert 	    else
4717404b540aSrobert 	      p = &TREE_CHAIN (t2);
4718404b540aSrobert 	  }
4719404b540aSrobert       }
4720404b540aSrobert     }
4721404b540aSrobert 
4722404b540aSrobert   for (t = weak_decls; t; t = TREE_CHAIN (t))
4723404b540aSrobert     {
4724404b540aSrobert       tree decl = TREE_VALUE (t);
4725404b540aSrobert 
4726404b540aSrobert       weak_finish_1 (decl);
4727404b540aSrobert     }
4728404b540aSrobert }
4729404b540aSrobert 
4730404b540aSrobert /* Emit the assembly bits to indicate that DECL is globally visible.  */
4731404b540aSrobert 
4732404b540aSrobert static void
globalize_decl(tree decl)4733404b540aSrobert globalize_decl (tree decl)
4734404b540aSrobert {
4735404b540aSrobert   const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4736404b540aSrobert 
4737404b540aSrobert #if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
4738404b540aSrobert   if (DECL_WEAK (decl))
4739404b540aSrobert     {
4740404b540aSrobert       tree *p, t;
4741404b540aSrobert 
4742404b540aSrobert #ifdef ASM_WEAKEN_DECL
4743404b540aSrobert       ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
4744404b540aSrobert #else
4745404b540aSrobert       ASM_WEAKEN_LABEL (asm_out_file, name);
4746404b540aSrobert #endif
4747404b540aSrobert 
4748404b540aSrobert       /* Remove this function from the pending weak list so that
4749404b540aSrobert 	 we do not emit multiple .weak directives for it.  */
4750404b540aSrobert       for (p = &weak_decls; (t = *p) ; )
4751404b540aSrobert 	{
4752404b540aSrobert 	  if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
4753404b540aSrobert 	    *p = TREE_CHAIN (t);
4754404b540aSrobert 	  else
4755404b540aSrobert 	    p = &TREE_CHAIN (t);
4756404b540aSrobert 	}
4757404b540aSrobert 
4758404b540aSrobert       /* Remove weakrefs to the same target from the pending weakref
4759404b540aSrobert 	 list, for the same reason.  */
4760404b540aSrobert       for (p = &weakref_targets; (t = *p) ; )
4761404b540aSrobert 	{
4762404b540aSrobert 	  if (DECL_ASSEMBLER_NAME (decl)
4763404b540aSrobert 	      == ultimate_transparent_alias_target (&TREE_VALUE (t)))
4764404b540aSrobert 	    *p = TREE_CHAIN (t);
4765404b540aSrobert 	  else
4766404b540aSrobert 	    p = &TREE_CHAIN (t);
4767404b540aSrobert 	}
4768404b540aSrobert 
4769404b540aSrobert       return;
4770404b540aSrobert     }
4771404b540aSrobert #elif defined(ASM_MAKE_LABEL_LINKONCE)
4772404b540aSrobert   if (DECL_ONE_ONLY (decl))
4773404b540aSrobert     ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
4774404b540aSrobert #endif
4775404b540aSrobert 
4776404b540aSrobert   targetm.asm_out.globalize_label (asm_out_file, name);
4777404b540aSrobert }
4778404b540aSrobert 
4779404b540aSrobert /* We have to be able to tell cgraph about the needed-ness of the target
4780404b540aSrobert    of an alias.  This requires that the decl have been defined.  Aliases
4781404b540aSrobert    that precede their definition have to be queued for later processing.  */
4782404b540aSrobert 
4783404b540aSrobert typedef struct alias_pair GTY(())
4784404b540aSrobert {
4785404b540aSrobert   tree decl;
4786404b540aSrobert   tree target;
4787404b540aSrobert } alias_pair;
4788404b540aSrobert 
4789404b540aSrobert /* Define gc'd vector type.  */
4790404b540aSrobert DEF_VEC_O(alias_pair);
4791404b540aSrobert DEF_VEC_ALLOC_O(alias_pair,gc);
4792404b540aSrobert 
4793404b540aSrobert static GTY(()) VEC(alias_pair,gc) *alias_pairs;
4794404b540aSrobert 
4795404b540aSrobert /* Given an assembly name, find the decl it is associated with.  At the
4796404b540aSrobert    same time, mark it needed for cgraph.  */
4797404b540aSrobert 
4798404b540aSrobert static tree
find_decl_and_mark_needed(tree decl,tree target)4799404b540aSrobert find_decl_and_mark_needed (tree decl, tree target)
4800404b540aSrobert {
4801404b540aSrobert   struct cgraph_node *fnode = NULL;
4802404b540aSrobert   struct cgraph_varpool_node *vnode = NULL;
4803404b540aSrobert 
4804404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
4805404b540aSrobert     {
4806404b540aSrobert       fnode = cgraph_node_for_asm (target);
4807404b540aSrobert       if (fnode == NULL)
4808404b540aSrobert 	vnode = cgraph_varpool_node_for_asm (target);
4809404b540aSrobert     }
4810404b540aSrobert   else
4811404b540aSrobert     {
4812404b540aSrobert       vnode = cgraph_varpool_node_for_asm (target);
4813404b540aSrobert       if (vnode == NULL)
4814404b540aSrobert 	fnode = cgraph_node_for_asm (target);
4815404b540aSrobert     }
4816404b540aSrobert 
4817404b540aSrobert   if (fnode)
4818404b540aSrobert     {
4819404b540aSrobert       /* We can't mark function nodes as used after cgraph global info
4820404b540aSrobert 	 is finished.  This wouldn't generally be necessary, but C++
4821404b540aSrobert 	 virtual table thunks are introduced late in the game and
4822404b540aSrobert 	 might seem like they need marking, although in fact they
4823404b540aSrobert 	 don't.  */
4824404b540aSrobert       if (! cgraph_global_info_ready)
4825404b540aSrobert 	cgraph_mark_needed_node (fnode);
4826404b540aSrobert       return fnode->decl;
4827404b540aSrobert     }
4828404b540aSrobert   else if (vnode)
4829404b540aSrobert     {
4830404b540aSrobert       cgraph_varpool_mark_needed_node (vnode);
4831404b540aSrobert       return vnode->decl;
4832404b540aSrobert     }
4833404b540aSrobert   else
4834404b540aSrobert     return NULL_TREE;
4835404b540aSrobert }
4836404b540aSrobert 
4837404b540aSrobert /* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
4838404b540aSrobert    or ASM_OUTPUT_DEF_FROM_DECLS.  The function defines the symbol whose
4839404b540aSrobert    tree node is DECL to have the value of the tree node TARGET.  */
4840404b540aSrobert 
4841404b540aSrobert static void
do_assemble_alias(tree decl,tree target)4842404b540aSrobert do_assemble_alias (tree decl, tree target)
4843404b540aSrobert {
4844404b540aSrobert   if (TREE_ASM_WRITTEN (decl))
4845404b540aSrobert     return;
4846404b540aSrobert 
4847404b540aSrobert   TREE_ASM_WRITTEN (decl) = 1;
4848404b540aSrobert   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
4849404b540aSrobert 
4850404b540aSrobert   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
4851404b540aSrobert     {
4852404b540aSrobert       ultimate_transparent_alias_target (&target);
4853404b540aSrobert 
4854404b540aSrobert       if (!TREE_SYMBOL_REFERENCED (target))
4855404b540aSrobert 	weakref_targets = tree_cons (decl, target, weakref_targets);
4856404b540aSrobert 
4857404b540aSrobert #ifdef ASM_OUTPUT_WEAKREF
4858404b540aSrobert       ASM_OUTPUT_WEAKREF (asm_out_file, decl,
4859404b540aSrobert 			  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
4860404b540aSrobert 			  IDENTIFIER_POINTER (target));
4861404b540aSrobert #else
4862404b540aSrobert       if (!SUPPORTS_WEAK)
4863404b540aSrobert 	{
4864404b540aSrobert 	  error ("%Jweakref is not supported in this configuration", decl);
4865404b540aSrobert 	  return;
4866404b540aSrobert 	}
4867404b540aSrobert #endif
4868404b540aSrobert       return;
4869404b540aSrobert     }
4870404b540aSrobert 
4871404b540aSrobert #ifdef ASM_OUTPUT_DEF
4872404b540aSrobert   /* Make name accessible from other files, if appropriate.  */
4873404b540aSrobert 
4874404b540aSrobert   if (TREE_PUBLIC (decl))
4875404b540aSrobert     {
4876404b540aSrobert       globalize_decl (decl);
4877404b540aSrobert       maybe_assemble_visibility (decl);
4878404b540aSrobert     }
4879404b540aSrobert 
4880404b540aSrobert # ifdef ASM_OUTPUT_DEF_FROM_DECLS
4881404b540aSrobert   ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
4882404b540aSrobert # else
4883404b540aSrobert   ASM_OUTPUT_DEF (asm_out_file,
4884404b540aSrobert 		  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
4885404b540aSrobert 		  IDENTIFIER_POINTER (target));
4886404b540aSrobert # endif
4887404b540aSrobert #elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
4888404b540aSrobert   {
4889404b540aSrobert     const char *name;
4890404b540aSrobert     tree *p, t;
4891404b540aSrobert 
4892404b540aSrobert     name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
4893404b540aSrobert # ifdef ASM_WEAKEN_DECL
4894404b540aSrobert     ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
4895404b540aSrobert # else
4896404b540aSrobert     ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
4897404b540aSrobert # endif
4898404b540aSrobert     /* Remove this function from the pending weak list so that
4899404b540aSrobert        we do not emit multiple .weak directives for it.  */
4900404b540aSrobert     for (p = &weak_decls; (t = *p) ; )
4901404b540aSrobert       if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
4902404b540aSrobert 	*p = TREE_CHAIN (t);
4903404b540aSrobert       else
4904404b540aSrobert 	p = &TREE_CHAIN (t);
4905404b540aSrobert 
4906404b540aSrobert     /* Remove weakrefs to the same target from the pending weakref
4907404b540aSrobert        list, for the same reason.  */
4908404b540aSrobert     for (p = &weakref_targets; (t = *p) ; )
4909404b540aSrobert       {
4910404b540aSrobert 	if (DECL_ASSEMBLER_NAME (decl)
4911404b540aSrobert 	    == ultimate_transparent_alias_target (&TREE_VALUE (t)))
4912404b540aSrobert 	  *p = TREE_CHAIN (t);
4913404b540aSrobert 	else
4914404b540aSrobert 	  p = &TREE_CHAIN (t);
4915404b540aSrobert       }
4916404b540aSrobert   }
4917404b540aSrobert #endif
4918404b540aSrobert }
4919404b540aSrobert 
4920404b540aSrobert /* First pass of completing pending aliases.  Make sure that cgraph knows
4921404b540aSrobert    which symbols will be required.  */
4922404b540aSrobert 
4923404b540aSrobert void
finish_aliases_1(void)4924404b540aSrobert finish_aliases_1 (void)
4925404b540aSrobert {
4926404b540aSrobert   unsigned i;
4927404b540aSrobert   alias_pair *p;
4928404b540aSrobert 
4929404b540aSrobert   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
4930404b540aSrobert     {
4931404b540aSrobert       tree target_decl;
4932404b540aSrobert 
4933404b540aSrobert       target_decl = find_decl_and_mark_needed (p->decl, p->target);
4934404b540aSrobert       if (target_decl == NULL)
4935404b540aSrobert 	{
4936404b540aSrobert 	  if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
4937404b540aSrobert 	    error ("%q+D aliased to undefined symbol %qs",
4938404b540aSrobert 		   p->decl, IDENTIFIER_POINTER (p->target));
4939404b540aSrobert 	}
4940404b540aSrobert       else if (DECL_EXTERNAL (target_decl)
4941404b540aSrobert 	       && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
4942404b540aSrobert 	error ("%q+D aliased to external symbol %qs",
4943404b540aSrobert 	       p->decl, IDENTIFIER_POINTER (p->target));
4944404b540aSrobert     }
4945404b540aSrobert }
4946404b540aSrobert 
4947404b540aSrobert /* Second pass of completing pending aliases.  Emit the actual assembly.
4948404b540aSrobert    This happens at the end of compilation and thus it is assured that the
4949404b540aSrobert    target symbol has been emitted.  */
4950404b540aSrobert 
4951404b540aSrobert void
finish_aliases_2(void)4952404b540aSrobert finish_aliases_2 (void)
4953404b540aSrobert {
4954404b540aSrobert   unsigned i;
4955404b540aSrobert   alias_pair *p;
4956404b540aSrobert 
4957404b540aSrobert   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
4958404b540aSrobert     do_assemble_alias (p->decl, p->target);
4959404b540aSrobert 
4960404b540aSrobert   VEC_truncate (alias_pair, alias_pairs, 0);
4961404b540aSrobert }
4962404b540aSrobert 
4963404b540aSrobert /* Emit an assembler directive to make the symbol for DECL an alias to
4964404b540aSrobert    the symbol for TARGET.  */
4965404b540aSrobert 
4966404b540aSrobert void
assemble_alias(tree decl,tree target)4967404b540aSrobert assemble_alias (tree decl, tree target)
4968404b540aSrobert {
4969404b540aSrobert   tree target_decl;
4970404b540aSrobert   bool is_weakref = false;
4971404b540aSrobert 
4972404b540aSrobert   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
4973404b540aSrobert     {
4974404b540aSrobert       tree alias = DECL_ASSEMBLER_NAME (decl);
4975404b540aSrobert 
4976404b540aSrobert       is_weakref = true;
4977404b540aSrobert 
4978404b540aSrobert       ultimate_transparent_alias_target (&target);
4979404b540aSrobert 
4980404b540aSrobert       if (alias == target)
4981404b540aSrobert 	error ("weakref %q+D ultimately targets itself", decl);
4982404b540aSrobert       else
4983404b540aSrobert 	{
4984404b540aSrobert #ifndef ASM_OUTPUT_WEAKREF
4985404b540aSrobert 	  IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
4986404b540aSrobert 	  TREE_CHAIN (alias) = target;
4987404b540aSrobert #endif
4988404b540aSrobert 	}
4989404b540aSrobert       if (TREE_PUBLIC (decl))
4990404b540aSrobert 	error ("weakref %q+D must have static linkage", decl);
4991404b540aSrobert     }
4992404b540aSrobert   else
4993404b540aSrobert     {
4994404b540aSrobert #if !defined (ASM_OUTPUT_DEF)
4995404b540aSrobert # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
4996404b540aSrobert       error ("%Jalias definitions not supported in this configuration", decl);
4997404b540aSrobert       return;
4998404b540aSrobert # else
4999404b540aSrobert       if (!DECL_WEAK (decl))
5000404b540aSrobert 	{
5001404b540aSrobert 	  error ("%Jonly weak aliases are supported in this configuration", decl);
5002404b540aSrobert 	  return;
5003404b540aSrobert 	}
5004404b540aSrobert # endif
5005404b540aSrobert #endif
5006404b540aSrobert     }
5007404b540aSrobert 
5008404b540aSrobert   /* We must force creation of DECL_RTL for debug info generation, even though
5009404b540aSrobert      we don't use it here.  */
5010404b540aSrobert   make_decl_rtl (decl);
5011404b540aSrobert   TREE_USED (decl) = 1;
5012404b540aSrobert 
5013404b540aSrobert   /* A quirk of the initial implementation of aliases required that the user
5014404b540aSrobert      add "extern" to all of them.  Which is silly, but now historical.  Do
5015404b540aSrobert      note that the symbol is in fact locally defined.  */
5016404b540aSrobert   if (! is_weakref)
5017404b540aSrobert     DECL_EXTERNAL (decl) = 0;
5018404b540aSrobert 
5019404b540aSrobert   /* Allow aliases to aliases.  */
5020404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
5021404b540aSrobert     cgraph_node (decl)->alias = true;
5022404b540aSrobert   else
5023404b540aSrobert     cgraph_varpool_node (decl)->alias = true;
5024404b540aSrobert 
5025404b540aSrobert   /* If the target has already been emitted, we don't have to queue the
5026404b540aSrobert      alias.  This saves a tad o memory.  */
5027404b540aSrobert   target_decl = find_decl_and_mark_needed (decl, target);
5028404b540aSrobert   if (target_decl && TREE_ASM_WRITTEN (target_decl))
5029404b540aSrobert     do_assemble_alias (decl, target);
5030404b540aSrobert   else
5031404b540aSrobert     {
5032404b540aSrobert       alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
5033404b540aSrobert       p->decl = decl;
5034404b540aSrobert       p->target = target;
5035404b540aSrobert     }
5036404b540aSrobert }
5037404b540aSrobert 
5038404b540aSrobert /* Emit an assembler directive to set symbol for DECL visibility to
5039404b540aSrobert    the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */
5040404b540aSrobert 
5041404b540aSrobert void
default_assemble_visibility(tree decl,int vis)5042404b540aSrobert default_assemble_visibility (tree decl, int vis)
5043404b540aSrobert {
5044404b540aSrobert   static const char * const visibility_types[] = {
5045404b540aSrobert     NULL, "protected", "hidden", "internal"
5046404b540aSrobert   };
5047404b540aSrobert 
5048404b540aSrobert   const char *name, *type;
5049404b540aSrobert 
5050404b540aSrobert   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
5051404b540aSrobert   type = visibility_types[vis];
5052404b540aSrobert 
5053404b540aSrobert #ifdef HAVE_GAS_HIDDEN
5054404b540aSrobert   fprintf (asm_out_file, "\t.%s\t", type);
5055404b540aSrobert   assemble_name (asm_out_file, name);
5056404b540aSrobert   fprintf (asm_out_file, "\n");
5057404b540aSrobert #else
5058404b540aSrobert   warning (OPT_Wattributes, "visibility attribute not supported "
5059404b540aSrobert 	   "in this configuration; ignored");
5060404b540aSrobert #endif
5061404b540aSrobert }
5062404b540aSrobert 
5063404b540aSrobert /* A helper function to call assemble_visibility when needed for a decl.  */
5064404b540aSrobert 
5065*8529ddd3Skettenis int
maybe_assemble_visibility(tree decl)5066404b540aSrobert maybe_assemble_visibility (tree decl)
5067404b540aSrobert {
5068404b540aSrobert   enum symbol_visibility vis = DECL_VISIBILITY (decl);
5069404b540aSrobert 
5070404b540aSrobert   if (vis != VISIBILITY_DEFAULT)
5071*8529ddd3Skettenis     {
5072404b540aSrobert       targetm.asm_out.visibility (decl, vis);
5073*8529ddd3Skettenis       return 1;
5074*8529ddd3Skettenis     }
5075*8529ddd3Skettenis   else
5076*8529ddd3Skettenis     return 0;
5077404b540aSrobert }
5078404b540aSrobert 
5079404b540aSrobert /* Returns 1 if the target configuration supports defining public symbols
5080404b540aSrobert    so that one of them will be chosen at link time instead of generating a
5081404b540aSrobert    multiply-defined symbol error, whether through the use of weak symbols or
5082404b540aSrobert    a target-specific mechanism for having duplicates discarded.  */
5083404b540aSrobert 
5084404b540aSrobert int
supports_one_only(void)5085404b540aSrobert supports_one_only (void)
5086404b540aSrobert {
5087404b540aSrobert   if (SUPPORTS_ONE_ONLY)
5088404b540aSrobert     return 1;
5089404b540aSrobert   return SUPPORTS_WEAK;
5090404b540aSrobert }
5091404b540aSrobert 
5092404b540aSrobert /* Set up DECL as a public symbol that can be defined in multiple
5093404b540aSrobert    translation units without generating a linker error.  */
5094404b540aSrobert 
5095404b540aSrobert void
make_decl_one_only(tree decl)5096404b540aSrobert make_decl_one_only (tree decl)
5097404b540aSrobert {
5098404b540aSrobert   gcc_assert (TREE_CODE (decl) == VAR_DECL
5099404b540aSrobert 	      || TREE_CODE (decl) == FUNCTION_DECL);
5100404b540aSrobert 
5101404b540aSrobert   TREE_PUBLIC (decl) = 1;
5102404b540aSrobert 
5103404b540aSrobert   if (SUPPORTS_ONE_ONLY)
5104404b540aSrobert     {
5105404b540aSrobert #ifdef MAKE_DECL_ONE_ONLY
5106404b540aSrobert       MAKE_DECL_ONE_ONLY (decl);
5107404b540aSrobert #endif
5108404b540aSrobert       DECL_ONE_ONLY (decl) = 1;
5109404b540aSrobert     }
5110404b540aSrobert   else if (TREE_CODE (decl) == VAR_DECL
5111404b540aSrobert       && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
5112404b540aSrobert     DECL_COMMON (decl) = 1;
5113404b540aSrobert   else
5114404b540aSrobert     {
5115404b540aSrobert       gcc_assert (SUPPORTS_WEAK);
5116404b540aSrobert       DECL_WEAK (decl) = 1;
5117404b540aSrobert     }
5118404b540aSrobert }
5119404b540aSrobert 
5120404b540aSrobert void
init_varasm_once(void)5121404b540aSrobert init_varasm_once (void)
5122404b540aSrobert {
5123404b540aSrobert   section_htab = htab_create_ggc (31, section_entry_hash,
5124404b540aSrobert 				  section_entry_eq, NULL);
5125404b540aSrobert   object_block_htab = htab_create_ggc (31, object_block_entry_hash,
5126404b540aSrobert 				       object_block_entry_eq, NULL);
5127404b540aSrobert   const_desc_htab = htab_create_ggc (1009, const_desc_hash,
5128404b540aSrobert 				     const_desc_eq, NULL);
5129404b540aSrobert 
5130404b540aSrobert   const_alias_set = new_alias_set ();
5131404b540aSrobert   shared_constant_pool = create_constant_pool ();
5132404b540aSrobert 
5133404b540aSrobert #ifdef TEXT_SECTION_ASM_OP
5134404b540aSrobert   text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,
5135404b540aSrobert 				      TEXT_SECTION_ASM_OP);
5136404b540aSrobert #endif
5137404b540aSrobert 
5138404b540aSrobert #ifdef DATA_SECTION_ASM_OP
5139404b540aSrobert   data_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
5140404b540aSrobert 				      DATA_SECTION_ASM_OP);
5141404b540aSrobert #endif
5142404b540aSrobert 
5143404b540aSrobert #ifdef SDATA_SECTION_ASM_OP
5144404b540aSrobert   sdata_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
5145404b540aSrobert 				       SDATA_SECTION_ASM_OP);
5146404b540aSrobert #endif
5147404b540aSrobert 
5148404b540aSrobert #ifdef READONLY_DATA_SECTION_ASM_OP
5149404b540aSrobert   readonly_data_section = get_unnamed_section (0, output_section_asm_op,
5150404b540aSrobert 					       READONLY_DATA_SECTION_ASM_OP);
5151404b540aSrobert #endif
5152404b540aSrobert 
5153404b540aSrobert #ifdef CTORS_SECTION_ASM_OP
5154404b540aSrobert   ctors_section = get_unnamed_section (0, output_section_asm_op,
5155404b540aSrobert 				       CTORS_SECTION_ASM_OP);
5156404b540aSrobert #endif
5157404b540aSrobert 
5158404b540aSrobert #ifdef DTORS_SECTION_ASM_OP
5159404b540aSrobert   dtors_section = get_unnamed_section (0, output_section_asm_op,
5160404b540aSrobert 				       DTORS_SECTION_ASM_OP);
5161404b540aSrobert #endif
5162404b540aSrobert 
5163404b540aSrobert #ifdef BSS_SECTION_ASM_OP
5164404b540aSrobert   bss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
5165404b540aSrobert 				     output_section_asm_op,
5166404b540aSrobert 				     BSS_SECTION_ASM_OP);
5167404b540aSrobert #endif
5168404b540aSrobert 
5169404b540aSrobert #ifdef SBSS_SECTION_ASM_OP
5170404b540aSrobert   sbss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
5171404b540aSrobert 				      output_section_asm_op,
5172404b540aSrobert 				      SBSS_SECTION_ASM_OP);
5173404b540aSrobert #endif
5174404b540aSrobert 
5175404b540aSrobert   tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
5176404b540aSrobert 					   | SECTION_COMMON, emit_tls_common);
5177404b540aSrobert   lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
5178404b540aSrobert 					| SECTION_COMMON, emit_local);
5179404b540aSrobert   comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
5180404b540aSrobert 				       | SECTION_COMMON, emit_common);
5181404b540aSrobert 
5182404b540aSrobert #if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
5183404b540aSrobert   bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS,
5184404b540aSrobert 					       emit_bss);
5185404b540aSrobert #endif
5186404b540aSrobert 
5187404b540aSrobert   targetm.asm_out.init_sections ();
5188404b540aSrobert 
5189404b540aSrobert   if (readonly_data_section == NULL)
5190404b540aSrobert     readonly_data_section = text_section;
5191404b540aSrobert }
5192404b540aSrobert 
5193404b540aSrobert enum tls_model
decl_default_tls_model(tree decl)5194404b540aSrobert decl_default_tls_model (tree decl)
5195404b540aSrobert {
5196404b540aSrobert   enum tls_model kind;
5197404b540aSrobert   bool is_local;
5198404b540aSrobert 
5199404b540aSrobert   is_local = targetm.binds_local_p (decl);
5200404b540aSrobert   if (!flag_shlib)
5201404b540aSrobert     {
5202404b540aSrobert       if (is_local)
5203404b540aSrobert 	kind = TLS_MODEL_LOCAL_EXEC;
5204404b540aSrobert       else
5205404b540aSrobert 	kind = TLS_MODEL_INITIAL_EXEC;
5206404b540aSrobert     }
5207404b540aSrobert 
5208404b540aSrobert   /* Local dynamic is inefficient when we're not combining the
5209404b540aSrobert      parts of the address.  */
5210404b540aSrobert   else if (optimize && is_local)
5211404b540aSrobert     kind = TLS_MODEL_LOCAL_DYNAMIC;
5212404b540aSrobert   else
5213404b540aSrobert     kind = TLS_MODEL_GLOBAL_DYNAMIC;
5214404b540aSrobert   if (kind < flag_tls_default)
5215404b540aSrobert     kind = flag_tls_default;
5216404b540aSrobert 
5217404b540aSrobert   return kind;
5218404b540aSrobert }
5219404b540aSrobert 
5220404b540aSrobert /* Select a set of attributes for section NAME based on the properties
5221404b540aSrobert    of DECL and whether or not RELOC indicates that DECL's initializer
5222404b540aSrobert    might contain runtime relocations.
5223404b540aSrobert 
5224404b540aSrobert    We make the section read-only and executable for a function decl,
5225404b540aSrobert    read-only for a const data decl, and writable for a non-const data decl.  */
5226404b540aSrobert 
5227404b540aSrobert unsigned int
default_section_type_flags(tree decl,const char * name,int reloc)5228404b540aSrobert default_section_type_flags (tree decl, const char *name, int reloc)
5229404b540aSrobert {
5230404b540aSrobert   unsigned int flags;
5231404b540aSrobert 
5232404b540aSrobert   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
5233404b540aSrobert     flags = SECTION_CODE;
5234404b540aSrobert   else if (decl && decl_readonly_section (decl, reloc))
5235404b540aSrobert     flags = 0;
5236404b540aSrobert   else if (current_function_decl
5237404b540aSrobert 	   && cfun
5238404b540aSrobert 	   && cfun->unlikely_text_section_name
5239404b540aSrobert 	   && strcmp (name, cfun->unlikely_text_section_name) == 0)
5240404b540aSrobert     flags = SECTION_CODE;
5241404b540aSrobert   else if (!decl
5242404b540aSrobert 	   && (!current_function_decl || !cfun)
5243404b540aSrobert 	   && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
5244404b540aSrobert     flags = SECTION_CODE;
5245404b540aSrobert   else
5246404b540aSrobert     flags = SECTION_WRITE;
5247404b540aSrobert 
5248404b540aSrobert   if (decl && DECL_ONE_ONLY (decl))
5249404b540aSrobert     flags |= SECTION_LINKONCE;
5250404b540aSrobert 
5251404b540aSrobert   if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
5252404b540aSrobert     flags |= SECTION_TLS | SECTION_WRITE;
5253404b540aSrobert 
5254404b540aSrobert   if (strcmp (name, ".bss") == 0
5255404b540aSrobert       || strncmp (name, ".bss.", 5) == 0
5256404b540aSrobert       || strncmp (name, ".gnu.linkonce.b.", 16) == 0
5257404b540aSrobert       || strcmp (name, ".sbss") == 0
5258404b540aSrobert       || strncmp (name, ".sbss.", 6) == 0
5259404b540aSrobert       || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
5260404b540aSrobert     flags |= SECTION_BSS;
5261404b540aSrobert 
5262404b540aSrobert   if (strcmp (name, ".tdata") == 0
5263404b540aSrobert       || strncmp (name, ".tdata.", 7) == 0
5264404b540aSrobert       || strncmp (name, ".gnu.linkonce.td.", 17) == 0)
5265404b540aSrobert     flags |= SECTION_TLS;
5266404b540aSrobert 
5267404b540aSrobert   if (strcmp (name, ".tbss") == 0
5268404b540aSrobert       || strncmp (name, ".tbss.", 6) == 0
5269404b540aSrobert       || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
5270404b540aSrobert     flags |= SECTION_TLS | SECTION_BSS;
5271404b540aSrobert 
5272404b540aSrobert   /* These three sections have special ELF types.  They are neither
5273404b540aSrobert      SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't
5274404b540aSrobert      want to print a section type (@progbits or @nobits).  If someone
5275404b540aSrobert      is silly enough to emit code or TLS variables to one of these
5276404b540aSrobert      sections, then don't handle them specially.  */
5277404b540aSrobert   if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS))
5278404b540aSrobert       && (strcmp (name, ".init_array") == 0
5279404b540aSrobert 	  || strcmp (name, ".fini_array") == 0
5280404b540aSrobert 	  || strcmp (name, ".preinit_array") == 0))
5281404b540aSrobert     flags |= SECTION_NOTYPE;
5282404b540aSrobert 
5283404b540aSrobert   return flags;
5284404b540aSrobert }
5285404b540aSrobert 
5286404b540aSrobert /* Return true if the target supports some form of global BSS,
5287404b540aSrobert    either through bss_noswitch_section, or by selecting a BSS
5288404b540aSrobert    section in TARGET_ASM_SELECT_SECTION.  */
5289404b540aSrobert 
5290404b540aSrobert bool
have_global_bss_p(void)5291404b540aSrobert have_global_bss_p (void)
5292404b540aSrobert {
5293404b540aSrobert   return bss_noswitch_section || targetm.have_switchable_bss_sections;
5294404b540aSrobert }
5295404b540aSrobert 
5296404b540aSrobert /* Output assembly to switch to section NAME with attribute FLAGS.
5297404b540aSrobert    Four variants for common object file formats.  */
5298404b540aSrobert 
5299404b540aSrobert void
default_no_named_section(const char * name ATTRIBUTE_UNUSED,unsigned int flags ATTRIBUTE_UNUSED,tree decl ATTRIBUTE_UNUSED)5300404b540aSrobert default_no_named_section (const char *name ATTRIBUTE_UNUSED,
5301404b540aSrobert 			  unsigned int flags ATTRIBUTE_UNUSED,
5302404b540aSrobert 			  tree decl ATTRIBUTE_UNUSED)
5303404b540aSrobert {
5304404b540aSrobert   /* Some object formats don't support named sections at all.  The
5305404b540aSrobert      front-end should already have flagged this as an error.  */
5306404b540aSrobert   gcc_unreachable ();
5307404b540aSrobert }
5308404b540aSrobert 
5309404b540aSrobert void
default_elf_asm_named_section(const char * name,unsigned int flags,tree decl ATTRIBUTE_UNUSED)5310404b540aSrobert default_elf_asm_named_section (const char *name, unsigned int flags,
5311404b540aSrobert 			       tree decl ATTRIBUTE_UNUSED)
5312404b540aSrobert {
5313404b540aSrobert   char flagchars[10], *f = flagchars;
5314404b540aSrobert 
5315404b540aSrobert   /* If we have already declared this section, we can use an
5316404b540aSrobert      abbreviated form to switch back to it -- unless this section is
5317404b540aSrobert      part of a COMDAT groups, in which case GAS requires the full
5318404b540aSrobert      declaration every time.  */
5319404b540aSrobert   if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
5320404b540aSrobert       && (flags & SECTION_DECLARED))
5321404b540aSrobert     {
5322404b540aSrobert       fprintf (asm_out_file, "\t.section\t%s\n", name);
5323404b540aSrobert       return;
5324404b540aSrobert     }
5325404b540aSrobert 
5326404b540aSrobert   if (!(flags & SECTION_DEBUG))
5327404b540aSrobert     *f++ = 'a';
5328404b540aSrobert   if (flags & SECTION_WRITE)
5329404b540aSrobert     *f++ = 'w';
5330404b540aSrobert   if (flags & SECTION_CODE)
5331404b540aSrobert     *f++ = 'x';
5332404b540aSrobert   if (flags & SECTION_SMALL)
5333404b540aSrobert     *f++ = 's';
5334404b540aSrobert   if (flags & SECTION_MERGE)
5335404b540aSrobert     *f++ = 'M';
5336404b540aSrobert   if (flags & SECTION_STRINGS)
5337404b540aSrobert     *f++ = 'S';
5338404b540aSrobert   if (flags & SECTION_TLS)
5339404b540aSrobert     *f++ = 'T';
5340404b540aSrobert   if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
5341404b540aSrobert     *f++ = 'G';
5342404b540aSrobert   *f = '\0';
5343404b540aSrobert 
5344404b540aSrobert   fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
5345404b540aSrobert 
5346404b540aSrobert   if (!(flags & SECTION_NOTYPE))
5347404b540aSrobert     {
5348404b540aSrobert       const char *type;
5349404b540aSrobert       const char *format;
5350404b540aSrobert 
5351404b540aSrobert       if (flags & SECTION_BSS)
5352404b540aSrobert 	type = "nobits";
5353404b540aSrobert       else
5354404b540aSrobert 	type = "progbits";
5355404b540aSrobert 
5356404b540aSrobert       format = ",@%s";
5357404b540aSrobert #ifdef ASM_COMMENT_START
5358404b540aSrobert       /* On platforms that use "@" as the assembly comment character,
5359404b540aSrobert 	 use "%" instead.  */
5360404b540aSrobert       if (strcmp (ASM_COMMENT_START, "@") == 0)
5361404b540aSrobert 	format = ",%%%s";
5362404b540aSrobert #endif
5363404b540aSrobert       fprintf (asm_out_file, format, type);
5364404b540aSrobert 
5365404b540aSrobert       if (flags & SECTION_ENTSIZE)
5366404b540aSrobert 	fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
5367404b540aSrobert       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
5368404b540aSrobert 	fprintf (asm_out_file, ",%s,comdat",
5369404b540aSrobert 		 lang_hooks.decls.comdat_group (decl));
5370404b540aSrobert     }
5371404b540aSrobert 
5372404b540aSrobert   putc ('\n', asm_out_file);
5373404b540aSrobert }
5374404b540aSrobert 
5375404b540aSrobert void
default_coff_asm_named_section(const char * name,unsigned int flags,tree decl ATTRIBUTE_UNUSED)5376404b540aSrobert default_coff_asm_named_section (const char *name, unsigned int flags,
5377404b540aSrobert 				tree decl ATTRIBUTE_UNUSED)
5378404b540aSrobert {
5379404b540aSrobert   char flagchars[8], *f = flagchars;
5380404b540aSrobert 
5381404b540aSrobert   if (flags & SECTION_WRITE)
5382404b540aSrobert     *f++ = 'w';
5383404b540aSrobert   if (flags & SECTION_CODE)
5384404b540aSrobert     *f++ = 'x';
5385404b540aSrobert   *f = '\0';
5386404b540aSrobert 
5387404b540aSrobert   fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
5388404b540aSrobert }
5389404b540aSrobert 
5390404b540aSrobert void
default_pe_asm_named_section(const char * name,unsigned int flags,tree decl)5391404b540aSrobert default_pe_asm_named_section (const char *name, unsigned int flags,
5392404b540aSrobert 			      tree decl)
5393404b540aSrobert {
5394404b540aSrobert   default_coff_asm_named_section (name, flags, decl);
5395404b540aSrobert 
5396404b540aSrobert   if (flags & SECTION_LINKONCE)
5397404b540aSrobert     {
5398404b540aSrobert       /* Functions may have been compiled at various levels of
5399404b540aSrobert          optimization so we can't use `same_size' here.
5400404b540aSrobert          Instead, have the linker pick one.  */
5401404b540aSrobert       fprintf (asm_out_file, "\t.linkonce %s\n",
5402404b540aSrobert 	       (flags & SECTION_CODE ? "discard" : "same_size"));
5403404b540aSrobert     }
5404404b540aSrobert }
5405404b540aSrobert 
5406404b540aSrobert /* The lame default section selector.  */
5407404b540aSrobert 
5408404b540aSrobert section *
default_select_section(tree decl,int reloc,unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)5409404b540aSrobert default_select_section (tree decl, int reloc,
5410404b540aSrobert 			unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
5411404b540aSrobert {
5412404b540aSrobert   if (DECL_P (decl))
5413404b540aSrobert     {
5414404b540aSrobert       if (decl_readonly_section (decl, reloc))
5415404b540aSrobert 	return readonly_data_section;
5416404b540aSrobert     }
5417404b540aSrobert   else if (TREE_CODE (decl) == CONSTRUCTOR)
5418404b540aSrobert     {
5419404b540aSrobert       if (! ((flag_pic && reloc)
5420404b540aSrobert 	     || !TREE_READONLY (decl)
5421404b540aSrobert 	     || TREE_SIDE_EFFECTS (decl)
5422404b540aSrobert 	     || !TREE_CONSTANT (decl)))
5423404b540aSrobert 	return readonly_data_section;
5424404b540aSrobert     }
5425404b540aSrobert   else if (TREE_CODE (decl) == STRING_CST)
5426404b540aSrobert     return readonly_data_section;
5427404b540aSrobert   else if (! (flag_pic && reloc))
5428404b540aSrobert     return readonly_data_section;
5429404b540aSrobert 
5430404b540aSrobert   return data_section;
5431404b540aSrobert }
5432404b540aSrobert 
5433404b540aSrobert enum section_category
categorize_decl_for_section(tree decl,int reloc)5434404b540aSrobert categorize_decl_for_section (tree decl, int reloc)
5435404b540aSrobert {
5436404b540aSrobert   enum section_category ret;
5437404b540aSrobert 
5438404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
5439404b540aSrobert     return SECCAT_TEXT;
5440404b540aSrobert   else if (TREE_CODE (decl) == STRING_CST)
5441404b540aSrobert     {
5442404b540aSrobert       if (flag_mudflap) /* or !flag_merge_constants */
5443404b540aSrobert         return SECCAT_RODATA;
5444404b540aSrobert       else
5445404b540aSrobert 	return SECCAT_RODATA_MERGE_STR;
5446404b540aSrobert     }
5447404b540aSrobert   else if (TREE_CODE (decl) == VAR_DECL)
5448404b540aSrobert     {
5449404b540aSrobert       if (bss_initializer_p (decl))
5450404b540aSrobert 	ret = SECCAT_BSS;
5451404b540aSrobert       else if (! TREE_READONLY (decl)
5452404b540aSrobert 	       || TREE_SIDE_EFFECTS (decl)
5453404b540aSrobert 	       || ! TREE_CONSTANT (DECL_INITIAL (decl)))
5454404b540aSrobert 	{
5455404b540aSrobert 	  /* Here the reloc_rw_mask is not testing whether the section should
5456404b540aSrobert 	     be read-only or not, but whether the dynamic link will have to
5457404b540aSrobert 	     do something.  If so, we wish to segregate the data in order to
5458404b540aSrobert 	     minimize cache misses inside the dynamic linker.  */
5459404b540aSrobert 	  if (reloc & targetm.asm_out.reloc_rw_mask ())
5460404b540aSrobert 	    ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
5461404b540aSrobert 	  else
5462404b540aSrobert 	    ret = SECCAT_DATA;
5463404b540aSrobert 	}
5464404b540aSrobert       else if (reloc & targetm.asm_out.reloc_rw_mask ())
5465404b540aSrobert 	ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
5466404b540aSrobert       else if (reloc || flag_merge_constants < 2)
5467404b540aSrobert 	/* C and C++ don't allow different variables to share the same
5468404b540aSrobert 	   location.  -fmerge-all-constants allows even that (at the
5469404b540aSrobert 	   expense of not conforming).  */
5470404b540aSrobert 	ret = SECCAT_RODATA;
5471404b540aSrobert       else if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
5472404b540aSrobert 	ret = SECCAT_RODATA_MERGE_STR_INIT;
5473404b540aSrobert       else
5474404b540aSrobert 	ret = SECCAT_RODATA_MERGE_CONST;
5475404b540aSrobert     }
5476404b540aSrobert   else if (TREE_CODE (decl) == CONSTRUCTOR)
5477404b540aSrobert     {
5478404b540aSrobert       if ((reloc & targetm.asm_out.reloc_rw_mask ())
5479404b540aSrobert 	  || TREE_SIDE_EFFECTS (decl)
5480404b540aSrobert 	  || ! TREE_CONSTANT (decl))
5481404b540aSrobert 	ret = SECCAT_DATA;
5482404b540aSrobert       else
5483404b540aSrobert 	ret = SECCAT_RODATA;
5484404b540aSrobert     }
5485404b540aSrobert   else
5486404b540aSrobert     ret = SECCAT_RODATA;
5487404b540aSrobert 
5488404b540aSrobert   /* There are no read-only thread-local sections.  */
5489404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
5490404b540aSrobert     {
5491404b540aSrobert       /* Note that this would be *just* SECCAT_BSS, except that there's
5492404b540aSrobert 	 no concept of a read-only thread-local-data section.  */
5493404b540aSrobert       if (ret == SECCAT_BSS
5494404b540aSrobert 	  || (flag_zero_initialized_in_bss
5495404b540aSrobert 	      && initializer_zerop (DECL_INITIAL (decl))))
5496404b540aSrobert 	ret = SECCAT_TBSS;
5497404b540aSrobert       else
5498404b540aSrobert 	ret = SECCAT_TDATA;
5499404b540aSrobert     }
5500404b540aSrobert 
5501404b540aSrobert   /* If the target uses small data sections, select it.  */
5502404b540aSrobert   else if (targetm.in_small_data_p (decl))
5503404b540aSrobert     {
5504404b540aSrobert       if (ret == SECCAT_BSS)
5505404b540aSrobert 	ret = SECCAT_SBSS;
5506404b540aSrobert       else if (targetm.have_srodata_section && ret == SECCAT_RODATA)
5507404b540aSrobert 	ret = SECCAT_SRODATA;
5508404b540aSrobert       else
5509404b540aSrobert 	ret = SECCAT_SDATA;
5510404b540aSrobert     }
5511404b540aSrobert 
5512404b540aSrobert   return ret;
5513404b540aSrobert }
5514404b540aSrobert 
5515404b540aSrobert bool
decl_readonly_section(tree decl,int reloc)5516404b540aSrobert decl_readonly_section (tree decl, int reloc)
5517404b540aSrobert {
5518404b540aSrobert   switch (categorize_decl_for_section (decl, reloc))
5519404b540aSrobert     {
5520404b540aSrobert     case SECCAT_RODATA:
5521404b540aSrobert     case SECCAT_RODATA_MERGE_STR:
5522404b540aSrobert     case SECCAT_RODATA_MERGE_STR_INIT:
5523404b540aSrobert     case SECCAT_RODATA_MERGE_CONST:
5524404b540aSrobert     case SECCAT_SRODATA:
5525404b540aSrobert       return true;
5526404b540aSrobert       break;
5527404b540aSrobert     default:
5528404b540aSrobert       return false;
5529404b540aSrobert       break;
5530404b540aSrobert     }
5531404b540aSrobert }
5532404b540aSrobert 
5533404b540aSrobert /* Select a section based on the above categorization.  */
5534404b540aSrobert 
5535404b540aSrobert section *
default_elf_select_section(tree decl,int reloc,unsigned HOST_WIDE_INT align)5536404b540aSrobert default_elf_select_section (tree decl, int reloc,
5537404b540aSrobert 			    unsigned HOST_WIDE_INT align)
5538404b540aSrobert {
5539404b540aSrobert   const char *sname;
5540404b540aSrobert   switch (categorize_decl_for_section (decl, reloc))
5541404b540aSrobert     {
5542404b540aSrobert     case SECCAT_TEXT:
5543404b540aSrobert       /* We're not supposed to be called on FUNCTION_DECLs.  */
5544404b540aSrobert       gcc_unreachable ();
5545404b540aSrobert     case SECCAT_RODATA:
5546404b540aSrobert       return readonly_data_section;
5547404b540aSrobert     case SECCAT_RODATA_MERGE_STR:
5548404b540aSrobert       return mergeable_string_section (decl, align, 0);
5549404b540aSrobert     case SECCAT_RODATA_MERGE_STR_INIT:
5550404b540aSrobert       return mergeable_string_section (DECL_INITIAL (decl), align, 0);
5551404b540aSrobert     case SECCAT_RODATA_MERGE_CONST:
5552404b540aSrobert       return mergeable_constant_section (DECL_MODE (decl), align, 0);
5553404b540aSrobert     case SECCAT_SRODATA:
5554404b540aSrobert       sname = ".sdata2";
5555404b540aSrobert       break;
5556404b540aSrobert     case SECCAT_DATA:
5557404b540aSrobert       return data_section;
5558404b540aSrobert     case SECCAT_DATA_REL:
5559404b540aSrobert       sname = ".data.rel";
5560404b540aSrobert       break;
5561404b540aSrobert     case SECCAT_DATA_REL_LOCAL:
5562404b540aSrobert       sname = ".data.rel.local";
5563404b540aSrobert       break;
5564404b540aSrobert     case SECCAT_DATA_REL_RO:
5565404b540aSrobert       sname = ".data.rel.ro";
5566404b540aSrobert       break;
5567404b540aSrobert     case SECCAT_DATA_REL_RO_LOCAL:
5568404b540aSrobert       sname = ".data.rel.ro.local";
5569404b540aSrobert       break;
5570404b540aSrobert     case SECCAT_SDATA:
5571404b540aSrobert       sname = ".sdata";
5572404b540aSrobert       break;
5573404b540aSrobert     case SECCAT_TDATA:
5574404b540aSrobert       sname = ".tdata";
5575404b540aSrobert       break;
5576404b540aSrobert     case SECCAT_BSS:
5577404b540aSrobert       if (bss_section)
5578404b540aSrobert 	return bss_section;
5579404b540aSrobert       sname = ".bss";
5580404b540aSrobert       break;
5581404b540aSrobert     case SECCAT_SBSS:
5582404b540aSrobert       sname = ".sbss";
5583404b540aSrobert       break;
5584404b540aSrobert     case SECCAT_TBSS:
5585404b540aSrobert       sname = ".tbss";
5586404b540aSrobert       break;
5587404b540aSrobert     default:
5588404b540aSrobert       gcc_unreachable ();
5589404b540aSrobert     }
5590404b540aSrobert 
5591404b540aSrobert   if (!DECL_P (decl))
5592404b540aSrobert     decl = NULL_TREE;
5593404b540aSrobert   return get_named_section (decl, sname, reloc);
5594404b540aSrobert }
5595404b540aSrobert 
5596404b540aSrobert /* Construct a unique section name based on the decl name and the
5597404b540aSrobert    categorization performed above.  */
5598404b540aSrobert 
5599404b540aSrobert void
default_unique_section(tree decl,int reloc)5600404b540aSrobert default_unique_section (tree decl, int reloc)
5601404b540aSrobert {
5602404b540aSrobert   /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
5603404b540aSrobert   bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
5604404b540aSrobert   const char *prefix, *name;
5605404b540aSrobert   size_t nlen, plen;
5606404b540aSrobert   char *string;
5607404b540aSrobert 
5608404b540aSrobert   switch (categorize_decl_for_section (decl, reloc))
5609404b540aSrobert     {
5610404b540aSrobert     case SECCAT_TEXT:
5611404b540aSrobert       prefix = one_only ? ".gnu.linkonce.t." : ".text.";
5612404b540aSrobert       break;
5613404b540aSrobert     case SECCAT_RODATA:
5614404b540aSrobert     case SECCAT_RODATA_MERGE_STR:
5615404b540aSrobert     case SECCAT_RODATA_MERGE_STR_INIT:
5616404b540aSrobert     case SECCAT_RODATA_MERGE_CONST:
5617404b540aSrobert       prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
5618404b540aSrobert       break;
5619404b540aSrobert     case SECCAT_SRODATA:
5620404b540aSrobert       prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
5621404b540aSrobert       break;
5622404b540aSrobert     case SECCAT_DATA:
5623404b540aSrobert       prefix = one_only ? ".gnu.linkonce.d." : ".data.";
5624404b540aSrobert       break;
5625404b540aSrobert     case SECCAT_DATA_REL:
5626404b540aSrobert       prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
5627404b540aSrobert       break;
5628404b540aSrobert     case SECCAT_DATA_REL_LOCAL:
5629404b540aSrobert       prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
5630404b540aSrobert       break;
5631404b540aSrobert     case SECCAT_DATA_REL_RO:
5632404b540aSrobert       prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
5633404b540aSrobert       break;
5634404b540aSrobert     case SECCAT_DATA_REL_RO_LOCAL:
5635404b540aSrobert       prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
5636404b540aSrobert 	       : ".data.rel.ro.local.";
5637404b540aSrobert       break;
5638404b540aSrobert     case SECCAT_SDATA:
5639404b540aSrobert       prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
5640404b540aSrobert       break;
5641404b540aSrobert     case SECCAT_BSS:
5642404b540aSrobert       prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
5643404b540aSrobert       break;
5644404b540aSrobert     case SECCAT_SBSS:
5645404b540aSrobert       prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
5646404b540aSrobert       break;
5647404b540aSrobert     case SECCAT_TDATA:
5648404b540aSrobert       prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
5649404b540aSrobert       break;
5650404b540aSrobert     case SECCAT_TBSS:
5651404b540aSrobert       prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
5652404b540aSrobert       break;
5653404b540aSrobert     default:
5654404b540aSrobert       gcc_unreachable ();
5655404b540aSrobert     }
5656404b540aSrobert   plen = strlen (prefix);
5657404b540aSrobert 
5658404b540aSrobert   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
5659404b540aSrobert   name = targetm.strip_name_encoding (name);
5660404b540aSrobert   nlen = strlen (name);
5661404b540aSrobert 
5662404b540aSrobert   string = alloca (nlen + plen + 1);
5663404b540aSrobert   memcpy (string, prefix, plen);
5664404b540aSrobert   memcpy (string + plen, name, nlen + 1);
5665404b540aSrobert 
5666404b540aSrobert   DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
5667404b540aSrobert }
5668404b540aSrobert 
5669404b540aSrobert /* Like compute_reloc_for_constant, except for an RTX.  The return value
5670404b540aSrobert    is a mask for which bit 1 indicates a global relocation, and bit 0
5671404b540aSrobert    indicates a local relocation.  */
5672404b540aSrobert 
5673404b540aSrobert static int
compute_reloc_for_rtx_1(rtx * xp,void * data)5674404b540aSrobert compute_reloc_for_rtx_1 (rtx *xp, void *data)
5675404b540aSrobert {
5676404b540aSrobert   int *preloc = data;
5677404b540aSrobert   rtx x = *xp;
5678404b540aSrobert 
5679404b540aSrobert   switch (GET_CODE (x))
5680404b540aSrobert     {
5681404b540aSrobert     case SYMBOL_REF:
5682404b540aSrobert       *preloc |= SYMBOL_REF_LOCAL_P (x) ? 1 : 2;
5683404b540aSrobert       break;
5684404b540aSrobert     case LABEL_REF:
5685404b540aSrobert       *preloc |= 1;
5686404b540aSrobert       break;
5687404b540aSrobert     default:
5688404b540aSrobert       break;
5689404b540aSrobert     }
5690404b540aSrobert 
5691404b540aSrobert   return 0;
5692404b540aSrobert }
5693404b540aSrobert 
5694404b540aSrobert static int
compute_reloc_for_rtx(rtx x)5695404b540aSrobert compute_reloc_for_rtx (rtx x)
5696404b540aSrobert {
5697404b540aSrobert   int reloc;
5698404b540aSrobert 
5699404b540aSrobert   switch (GET_CODE (x))
5700404b540aSrobert     {
5701404b540aSrobert     case CONST:
5702404b540aSrobert     case SYMBOL_REF:
5703404b540aSrobert     case LABEL_REF:
5704404b540aSrobert       reloc = 0;
5705404b540aSrobert       for_each_rtx (&x, compute_reloc_for_rtx_1, &reloc);
5706404b540aSrobert       return reloc;
5707404b540aSrobert 
5708404b540aSrobert     default:
5709404b540aSrobert       return 0;
5710404b540aSrobert     }
5711404b540aSrobert }
5712404b540aSrobert 
5713404b540aSrobert section *
default_select_rtx_section(enum machine_mode mode ATTRIBUTE_UNUSED,rtx x,unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)5714404b540aSrobert default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
5715404b540aSrobert 			    rtx x,
5716404b540aSrobert 			    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
5717404b540aSrobert {
5718404b540aSrobert   if (compute_reloc_for_rtx (x) & targetm.asm_out.reloc_rw_mask ())
5719404b540aSrobert     return data_section;
5720404b540aSrobert   else
5721404b540aSrobert     return readonly_data_section;
5722404b540aSrobert }
5723404b540aSrobert 
5724404b540aSrobert section *
default_elf_select_rtx_section(enum machine_mode mode,rtx x,unsigned HOST_WIDE_INT align)5725404b540aSrobert default_elf_select_rtx_section (enum machine_mode mode, rtx x,
5726404b540aSrobert 				unsigned HOST_WIDE_INT align)
5727404b540aSrobert {
5728404b540aSrobert   int reloc = compute_reloc_for_rtx (x);
5729404b540aSrobert 
5730404b540aSrobert   /* ??? Handle small data here somehow.  */
5731404b540aSrobert 
5732404b540aSrobert   if (reloc & targetm.asm_out.reloc_rw_mask ())
5733404b540aSrobert     {
5734404b540aSrobert       if (reloc == 1)
5735404b540aSrobert 	return get_named_section (NULL, ".data.rel.ro.local", 1);
5736404b540aSrobert       else
5737404b540aSrobert 	return get_named_section (NULL, ".data.rel.ro", 3);
5738404b540aSrobert     }
5739404b540aSrobert 
5740404b540aSrobert   return mergeable_constant_section (mode, align, 0);
5741404b540aSrobert }
5742404b540aSrobert 
5743404b540aSrobert /* Set the generally applicable flags on the SYMBOL_REF for EXP.  */
5744404b540aSrobert 
5745404b540aSrobert void
default_encode_section_info(tree decl,rtx rtl,int first ATTRIBUTE_UNUSED)5746404b540aSrobert default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
5747404b540aSrobert {
5748404b540aSrobert   rtx symbol;
5749404b540aSrobert   int flags;
5750404b540aSrobert 
5751404b540aSrobert   /* Careful not to prod global register variables.  */
5752404b540aSrobert   if (!MEM_P (rtl))
5753404b540aSrobert     return;
5754404b540aSrobert   symbol = XEXP (rtl, 0);
5755404b540aSrobert   if (GET_CODE (symbol) != SYMBOL_REF)
5756404b540aSrobert     return;
5757404b540aSrobert 
5758404b540aSrobert   flags = SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_HAS_BLOCK_INFO;
5759404b540aSrobert   if (TREE_CODE (decl) == FUNCTION_DECL)
5760404b540aSrobert     flags |= SYMBOL_FLAG_FUNCTION;
5761404b540aSrobert   if (targetm.binds_local_p (decl))
5762404b540aSrobert     flags |= SYMBOL_FLAG_LOCAL;
5763404b540aSrobert   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
5764404b540aSrobert     flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
5765404b540aSrobert   else if (targetm.in_small_data_p (decl))
5766404b540aSrobert     flags |= SYMBOL_FLAG_SMALL;
5767404b540aSrobert   /* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names?  Without
5768404b540aSrobert      being PUBLIC, the thing *must* be defined in this translation unit.
5769404b540aSrobert      Prevent this buglet from being propagated into rtl code as well.  */
5770404b540aSrobert   if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
5771404b540aSrobert     flags |= SYMBOL_FLAG_EXTERNAL;
5772404b540aSrobert 
5773404b540aSrobert   SYMBOL_REF_FLAGS (symbol) = flags;
5774404b540aSrobert }
5775404b540aSrobert 
5776404b540aSrobert /* By default, we do nothing for encode_section_info, so we need not
5777404b540aSrobert    do anything but discard the '*' marker.  */
5778404b540aSrobert 
5779404b540aSrobert const char *
default_strip_name_encoding(const char * str)5780404b540aSrobert default_strip_name_encoding (const char *str)
5781404b540aSrobert {
5782404b540aSrobert   return str + (*str == '*');
5783404b540aSrobert }
5784404b540aSrobert 
5785404b540aSrobert #ifdef ASM_OUTPUT_DEF
5786404b540aSrobert /* The default implementation of TARGET_ASM_OUTPUT_ANCHOR.  Define the
5787404b540aSrobert    anchor relative to ".", the current section position.  */
5788404b540aSrobert 
5789404b540aSrobert void
default_asm_output_anchor(rtx symbol)5790404b540aSrobert default_asm_output_anchor (rtx symbol)
5791404b540aSrobert {
5792404b540aSrobert   char buffer[100];
5793404b540aSrobert 
5794404b540aSrobert   sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC,
5795404b540aSrobert 	   SYMBOL_REF_BLOCK_OFFSET (symbol));
5796404b540aSrobert   ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
5797404b540aSrobert }
5798404b540aSrobert #endif
5799404b540aSrobert 
5800404b540aSrobert /* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P.  */
5801404b540aSrobert 
5802404b540aSrobert bool
default_use_anchors_for_symbol_p(rtx symbol)5803404b540aSrobert default_use_anchors_for_symbol_p (rtx symbol)
5804404b540aSrobert {
5805404b540aSrobert   section *sect;
5806404b540aSrobert   tree decl;
5807404b540aSrobert 
5808404b540aSrobert   /* Don't use anchors for mergeable sections.  The linker might move
5809404b540aSrobert      the objects around.  */
5810404b540aSrobert   sect = SYMBOL_REF_BLOCK (symbol)->sect;
5811404b540aSrobert   if (sect->common.flags & SECTION_MERGE)
5812404b540aSrobert     return false;
5813404b540aSrobert 
5814404b540aSrobert   /* Don't use anchors for small data sections.  The small data register
5815404b540aSrobert      acts as an anchor for such sections.  */
5816404b540aSrobert   if (sect->common.flags & SECTION_SMALL)
5817404b540aSrobert     return false;
5818404b540aSrobert 
5819404b540aSrobert   decl = SYMBOL_REF_DECL (symbol);
5820404b540aSrobert   if (decl && DECL_P (decl))
5821404b540aSrobert     {
5822404b540aSrobert       /* Don't use section anchors for decls that might be defined by
5823404b540aSrobert 	 other modules.  */
5824404b540aSrobert       if (!targetm.binds_local_p (decl))
5825404b540aSrobert 	return false;
5826404b540aSrobert 
5827404b540aSrobert       /* Don't use section anchors for decls that will be placed in a
5828404b540aSrobert 	 small data section.  */
5829404b540aSrobert       /* ??? Ideally, this check would be redundant with the SECTION_SMALL
5830404b540aSrobert 	 one above.  The problem is that we only use SECTION_SMALL for
5831404b540aSrobert 	 sections that should be marked as small in the section directive.  */
5832404b540aSrobert       if (targetm.in_small_data_p (decl))
5833404b540aSrobert 	return false;
5834404b540aSrobert     }
5835404b540aSrobert   return true;
5836404b540aSrobert }
5837404b540aSrobert 
5838404b540aSrobert /* Assume ELF-ish defaults, since that's pretty much the most liberal
5839404b540aSrobert    wrt cross-module name binding.  */
5840404b540aSrobert 
5841404b540aSrobert bool
default_binds_local_p(tree exp)5842404b540aSrobert default_binds_local_p (tree exp)
5843404b540aSrobert {
5844404b540aSrobert   return default_binds_local_p_1 (exp, flag_shlib);
5845404b540aSrobert }
5846404b540aSrobert 
5847404b540aSrobert bool
default_binds_local_p_1(tree exp,int shlib)5848404b540aSrobert default_binds_local_p_1 (tree exp, int shlib)
5849404b540aSrobert {
5850404b540aSrobert   bool local_p;
5851404b540aSrobert 
5852404b540aSrobert   /* A non-decl is an entry in the constant pool.  */
5853404b540aSrobert   if (!DECL_P (exp))
5854404b540aSrobert     local_p = true;
5855404b540aSrobert   /* Weakrefs may not bind locally, even though the weakref itself is
5856404b540aSrobert      always static and therefore local.  */
5857404b540aSrobert   else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)))
5858404b540aSrobert     local_p = false;
5859404b540aSrobert   /* Static variables are always local.  */
5860404b540aSrobert   else if (! TREE_PUBLIC (exp))
5861404b540aSrobert     local_p = true;
5862404b540aSrobert   /* A variable is local if the user has said explicitly that it will
5863404b540aSrobert      be.  */
5864404b540aSrobert   else if (DECL_VISIBILITY_SPECIFIED (exp)
5865404b540aSrobert 	   && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
5866404b540aSrobert     local_p = true;
5867404b540aSrobert   /* Variables defined outside this object might not be local.  */
5868404b540aSrobert   else if (DECL_EXTERNAL (exp))
5869404b540aSrobert     local_p = false;
5870404b540aSrobert   /* If defined in this object and visibility is not default, must be
5871404b540aSrobert      local.  */
5872404b540aSrobert   else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
5873404b540aSrobert     local_p = true;
5874404b540aSrobert   /* Default visibility weak data can be overridden by a strong symbol
5875404b540aSrobert      in another module and so are not local.  */
5876404b540aSrobert   else if (DECL_WEAK (exp))
5877404b540aSrobert     local_p = false;
5878404b540aSrobert   /* If PIC, then assume that any global name can be overridden by
5879404b540aSrobert      symbols resolved from other modules.  */
5880404b540aSrobert   else if (shlib)
5881404b540aSrobert     local_p = false;
5882404b540aSrobert   /* Uninitialized COMMON variable may be unified with symbols
5883404b540aSrobert      resolved from other modules.  */
5884404b540aSrobert   else if (DECL_COMMON (exp)
5885404b540aSrobert 	   && (DECL_INITIAL (exp) == NULL
5886404b540aSrobert 	       || DECL_INITIAL (exp) == error_mark_node))
5887404b540aSrobert     local_p = false;
5888404b540aSrobert   /* Otherwise we're left with initialized (or non-common) global data
5889404b540aSrobert      which is of necessity defined locally.  */
5890404b540aSrobert   else
5891404b540aSrobert     local_p = true;
5892404b540aSrobert 
5893404b540aSrobert   return local_p;
5894404b540aSrobert }
5895404b540aSrobert 
5896404b540aSrobert /* Determine whether or not a pointer mode is valid. Assume defaults
5897404b540aSrobert    of ptr_mode or Pmode - can be overridden.  */
5898404b540aSrobert bool
default_valid_pointer_mode(enum machine_mode mode)5899404b540aSrobert default_valid_pointer_mode (enum machine_mode mode)
5900404b540aSrobert {
5901404b540aSrobert   return (mode == ptr_mode || mode == Pmode);
5902404b540aSrobert }
5903404b540aSrobert 
5904404b540aSrobert /* Default function to output code that will globalize a label.  A
5905404b540aSrobert    target must define GLOBAL_ASM_OP or provide its own function to
5906404b540aSrobert    globalize a label.  */
5907404b540aSrobert #ifdef GLOBAL_ASM_OP
5908404b540aSrobert void
default_globalize_label(FILE * stream,const char * name)5909404b540aSrobert default_globalize_label (FILE * stream, const char *name)
5910404b540aSrobert {
5911404b540aSrobert   fputs (GLOBAL_ASM_OP, stream);
5912404b540aSrobert   assemble_name (stream, name);
5913404b540aSrobert   putc ('\n', stream);
5914404b540aSrobert }
5915404b540aSrobert #endif /* GLOBAL_ASM_OP */
5916404b540aSrobert 
5917404b540aSrobert /* Default function to output a label for unwind information.  The
5918404b540aSrobert    default is to do nothing.  A target that needs nonlocal labels for
5919404b540aSrobert    unwind information must provide its own function to do this.  */
5920404b540aSrobert void
default_emit_unwind_label(FILE * stream ATTRIBUTE_UNUSED,tree decl ATTRIBUTE_UNUSED,int for_eh ATTRIBUTE_UNUSED,int empty ATTRIBUTE_UNUSED)5921404b540aSrobert default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
5922404b540aSrobert 			   tree decl ATTRIBUTE_UNUSED,
5923404b540aSrobert 			   int for_eh ATTRIBUTE_UNUSED,
5924404b540aSrobert 			   int empty ATTRIBUTE_UNUSED)
5925404b540aSrobert {
5926404b540aSrobert }
5927404b540aSrobert 
5928404b540aSrobert /* Default function to output a label to divide up the exception table.
5929404b540aSrobert    The default is to do nothing.  A target that needs/wants to divide
5930404b540aSrobert    up the table must provide it's own function to do this.  */
5931404b540aSrobert void
default_emit_except_table_label(FILE * stream ATTRIBUTE_UNUSED)5932404b540aSrobert default_emit_except_table_label (FILE * stream ATTRIBUTE_UNUSED)
5933404b540aSrobert {
5934404b540aSrobert }
5935404b540aSrobert 
5936404b540aSrobert /* This is how to output an internal numbered label where PREFIX is
5937404b540aSrobert    the class of label and LABELNO is the number within the class.  */
5938404b540aSrobert 
5939404b540aSrobert void
default_internal_label(FILE * stream,const char * prefix,unsigned long labelno)5940404b540aSrobert default_internal_label (FILE *stream, const char *prefix,
5941404b540aSrobert 			unsigned long labelno)
5942404b540aSrobert {
5943404b540aSrobert   char *const buf = alloca (40 + strlen (prefix));
5944404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
5945404b540aSrobert   ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
5946404b540aSrobert }
5947404b540aSrobert 
5948404b540aSrobert /* This is the default behavior at the beginning of a file.  It's
5949404b540aSrobert    controlled by two other target-hook toggles.  */
5950404b540aSrobert void
default_file_start(void)5951404b540aSrobert default_file_start (void)
5952404b540aSrobert {
5953404b540aSrobert   if (targetm.file_start_app_off && !flag_verbose_asm)
5954404b540aSrobert     fputs (ASM_APP_OFF, asm_out_file);
5955404b540aSrobert 
5956404b540aSrobert   if (targetm.file_start_file_directive)
5957404b540aSrobert     output_file_directive (asm_out_file, main_input_filename);
5958404b540aSrobert }
5959404b540aSrobert 
5960404b540aSrobert /* This is a generic routine suitable for use as TARGET_ASM_FILE_END
5961404b540aSrobert    which emits a special section directive used to indicate whether or
5962404b540aSrobert    not this object file needs an executable stack.  This is primarily
5963404b540aSrobert    a GNU extension to ELF but could be used on other targets.  */
5964404b540aSrobert 
5965404b540aSrobert int trampolines_created;
5966404b540aSrobert 
5967404b540aSrobert void
file_end_indicate_exec_stack(void)5968404b540aSrobert file_end_indicate_exec_stack (void)
5969404b540aSrobert {
5970404b540aSrobert   unsigned int flags = SECTION_DEBUG;
5971404b540aSrobert   if (trampolines_created)
5972404b540aSrobert     flags |= SECTION_CODE;
5973404b540aSrobert 
5974404b540aSrobert   switch_to_section (get_section (".note.GNU-stack", flags, NULL));
5975404b540aSrobert }
5976404b540aSrobert 
5977404b540aSrobert /* Output DIRECTIVE (a C string) followed by a newline.  This is used as
5978404b540aSrobert    a get_unnamed_section callback.  */
5979404b540aSrobert 
5980404b540aSrobert void
output_section_asm_op(const void * directive)5981404b540aSrobert output_section_asm_op (const void *directive)
5982404b540aSrobert {
5983404b540aSrobert   fprintf (asm_out_file, "%s\n", (const char *) directive);
5984404b540aSrobert }
5985404b540aSrobert 
5986404b540aSrobert /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
5987404b540aSrobert    the current section is NEW_SECTION.  */
5988404b540aSrobert 
5989404b540aSrobert void
switch_to_section(section * new_section)5990404b540aSrobert switch_to_section (section *new_section)
5991404b540aSrobert {
5992404b540aSrobert   if (in_section == new_section)
5993404b540aSrobert     return;
5994404b540aSrobert 
5995404b540aSrobert   if (new_section->common.flags & SECTION_FORGET)
5996404b540aSrobert     in_section = NULL;
5997404b540aSrobert   else
5998404b540aSrobert     in_section = new_section;
5999404b540aSrobert 
6000404b540aSrobert   switch (SECTION_STYLE (new_section))
6001404b540aSrobert     {
6002404b540aSrobert     case SECTION_NAMED:
6003404b540aSrobert       if (cfun
6004404b540aSrobert 	  && !cfun->unlikely_text_section_name
6005404b540aSrobert 	  && strcmp (new_section->named.name,
6006404b540aSrobert 		     UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
6007404b540aSrobert 	cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
6008404b540aSrobert 
6009404b540aSrobert       targetm.asm_out.named_section (new_section->named.name,
6010404b540aSrobert 				     new_section->named.common.flags,
6011404b540aSrobert 				     new_section->named.decl);
6012404b540aSrobert       break;
6013404b540aSrobert 
6014404b540aSrobert     case SECTION_UNNAMED:
6015404b540aSrobert       new_section->unnamed.callback (new_section->unnamed.data);
6016404b540aSrobert       break;
6017404b540aSrobert 
6018404b540aSrobert     case SECTION_NOSWITCH:
6019404b540aSrobert       gcc_unreachable ();
6020404b540aSrobert       break;
6021404b540aSrobert     }
6022404b540aSrobert 
6023404b540aSrobert   new_section->common.flags |= SECTION_DECLARED;
6024404b540aSrobert }
6025404b540aSrobert 
6026404b540aSrobert /* If block symbol SYMBOL has not yet been assigned an offset, place
6027404b540aSrobert    it at the end of its block.  */
6028404b540aSrobert 
6029404b540aSrobert void
place_block_symbol(rtx symbol)6030404b540aSrobert place_block_symbol (rtx symbol)
6031404b540aSrobert {
6032404b540aSrobert   unsigned HOST_WIDE_INT size, mask, offset;
6033404b540aSrobert   struct constant_descriptor_rtx *desc;
6034404b540aSrobert   unsigned int alignment;
6035404b540aSrobert   struct object_block *block;
6036404b540aSrobert   tree decl;
6037404b540aSrobert 
6038404b540aSrobert   gcc_assert (SYMBOL_REF_BLOCK (symbol));
6039404b540aSrobert   if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
6040404b540aSrobert     return;
6041404b540aSrobert 
6042404b540aSrobert   /* Work out the symbol's size and alignment.  */
6043404b540aSrobert   if (CONSTANT_POOL_ADDRESS_P (symbol))
6044404b540aSrobert     {
6045404b540aSrobert       desc = SYMBOL_REF_CONSTANT (symbol);
6046404b540aSrobert       alignment = desc->align;
6047404b540aSrobert       size = GET_MODE_SIZE (desc->mode);
6048404b540aSrobert     }
6049404b540aSrobert   else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
6050404b540aSrobert     {
6051404b540aSrobert       decl = SYMBOL_REF_DECL (symbol);
6052404b540aSrobert       alignment = get_constant_alignment (decl);
6053404b540aSrobert       size = get_constant_size (decl);
6054404b540aSrobert     }
6055404b540aSrobert   else
6056404b540aSrobert     {
6057404b540aSrobert       decl = SYMBOL_REF_DECL (symbol);
6058404b540aSrobert       alignment = DECL_ALIGN (decl);
6059404b540aSrobert       size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
6060404b540aSrobert     }
6061404b540aSrobert 
6062404b540aSrobert   /* Calculate the object's offset from the start of the block.  */
6063404b540aSrobert   block = SYMBOL_REF_BLOCK (symbol);
6064404b540aSrobert   mask = alignment / BITS_PER_UNIT - 1;
6065404b540aSrobert   offset = (block->size + mask) & ~mask;
6066404b540aSrobert   SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
6067404b540aSrobert 
6068404b540aSrobert   /* Record the block's new alignment and size.  */
6069404b540aSrobert   block->alignment = MAX (block->alignment, alignment);
6070404b540aSrobert   block->size = offset + size;
6071404b540aSrobert 
6072404b540aSrobert   VEC_safe_push (rtx, gc, block->objects, symbol);
6073404b540aSrobert }
6074404b540aSrobert 
6075404b540aSrobert /* Return the anchor that should be used to address byte offset OFFSET
6076404b540aSrobert    from the first object in BLOCK.  MODEL is the TLS model used
6077404b540aSrobert    to access it.  */
6078404b540aSrobert 
6079404b540aSrobert rtx
get_section_anchor(struct object_block * block,HOST_WIDE_INT offset,enum tls_model model)6080404b540aSrobert get_section_anchor (struct object_block *block, HOST_WIDE_INT offset,
6081404b540aSrobert 		    enum tls_model model)
6082404b540aSrobert {
6083404b540aSrobert   char label[100];
6084404b540aSrobert   unsigned int begin, middle, end;
6085404b540aSrobert   unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
6086404b540aSrobert   rtx anchor;
6087404b540aSrobert 
6088404b540aSrobert   /* Work out the anchor's offset.  Use an offset of 0 for the first
6089404b540aSrobert      anchor so that we don't pessimize the case where we take the address
6090404b540aSrobert      of a variable at the beginning of the block.  This is particularly
6091404b540aSrobert      useful when a block has only one variable assigned to it.
6092404b540aSrobert 
6093404b540aSrobert      We try to place anchors RANGE bytes apart, so there can then be
6094404b540aSrobert      anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
6095404b540aSrobert      a ptr_mode offset.  With some target settings, the lowest such
6096404b540aSrobert      anchor might be out of range for the lowest ptr_mode offset;
6097404b540aSrobert      likewise the highest anchor for the highest offset.  Use anchors
6098404b540aSrobert      at the extreme ends of the ptr_mode range in such cases.
6099404b540aSrobert 
6100404b540aSrobert      All arithmetic uses unsigned integers in order to avoid
6101404b540aSrobert      signed overflow.  */
6102404b540aSrobert   max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
6103404b540aSrobert   min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
6104404b540aSrobert   range = max_offset - min_offset + 1;
6105404b540aSrobert   if (range == 0)
6106404b540aSrobert     offset = 0;
6107404b540aSrobert   else
6108404b540aSrobert     {
6109404b540aSrobert       bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
6110404b540aSrobert       if (offset < 0)
6111404b540aSrobert 	{
6112404b540aSrobert 	  delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
6113404b540aSrobert 	  delta -= delta % range;
6114404b540aSrobert 	  if (delta > bias)
6115404b540aSrobert 	    delta = bias;
6116404b540aSrobert 	  offset = (HOST_WIDE_INT) (-delta);
6117404b540aSrobert 	}
6118404b540aSrobert       else
6119404b540aSrobert 	{
6120404b540aSrobert 	  delta = (unsigned HOST_WIDE_INT) offset - min_offset;
6121404b540aSrobert 	  delta -= delta % range;
6122404b540aSrobert 	  if (delta > bias - 1)
6123404b540aSrobert 	    delta = bias - 1;
6124404b540aSrobert 	  offset = (HOST_WIDE_INT) delta;
6125404b540aSrobert 	}
6126404b540aSrobert     }
6127404b540aSrobert 
6128404b540aSrobert   /* Do a binary search to see if there's already an anchor we can use.
6129404b540aSrobert      Set BEGIN to the new anchor's index if not.  */
6130404b540aSrobert   begin = 0;
6131404b540aSrobert   end = VEC_length (rtx, block->anchors);
6132404b540aSrobert   while (begin != end)
6133404b540aSrobert     {
6134404b540aSrobert       middle = (end + begin) / 2;
6135404b540aSrobert       anchor = VEC_index (rtx, block->anchors, middle);
6136404b540aSrobert       if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset)
6137404b540aSrobert 	end = middle;
6138404b540aSrobert       else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset)
6139404b540aSrobert 	begin = middle + 1;
6140404b540aSrobert       else if (SYMBOL_REF_TLS_MODEL (anchor) > model)
6141404b540aSrobert 	end = middle;
6142404b540aSrobert       else if (SYMBOL_REF_TLS_MODEL (anchor) < model)
6143404b540aSrobert 	begin = middle + 1;
6144404b540aSrobert       else
6145404b540aSrobert 	return anchor;
6146404b540aSrobert     }
6147404b540aSrobert 
6148404b540aSrobert   /* Create a new anchor with a unique label.  */
6149404b540aSrobert   ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++);
6150404b540aSrobert   anchor = create_block_symbol (ggc_strdup (label), block, offset);
6151404b540aSrobert   SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR;
6152404b540aSrobert   SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT;
6153404b540aSrobert 
6154404b540aSrobert   /* Insert it at index BEGIN.  */
6155404b540aSrobert   VEC_safe_insert (rtx, gc, block->anchors, begin, anchor);
6156404b540aSrobert   return anchor;
6157404b540aSrobert }
6158404b540aSrobert 
6159404b540aSrobert /* Output the objects in BLOCK.  */
6160404b540aSrobert 
6161404b540aSrobert static void
output_object_block(struct object_block * block)6162404b540aSrobert output_object_block (struct object_block *block)
6163404b540aSrobert {
6164404b540aSrobert   struct constant_descriptor_rtx *desc;
6165404b540aSrobert   unsigned int i;
6166404b540aSrobert   HOST_WIDE_INT offset;
6167404b540aSrobert   tree decl;
6168404b540aSrobert   rtx symbol;
6169404b540aSrobert 
6170404b540aSrobert   if (block->objects == NULL)
6171404b540aSrobert     return;
6172404b540aSrobert 
6173404b540aSrobert   /* Switch to the section and make sure that the first byte is
6174404b540aSrobert      suitably aligned.  */
6175404b540aSrobert   switch_to_section (block->sect);
6176404b540aSrobert   assemble_align (block->alignment);
6177404b540aSrobert 
6178404b540aSrobert   /* Define the values of all anchors relative to the current section
6179404b540aSrobert      position.  */
6180404b540aSrobert   for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
6181404b540aSrobert     targetm.asm_out.output_anchor (symbol);
6182404b540aSrobert 
6183404b540aSrobert   /* Output the objects themselves.  */
6184404b540aSrobert   offset = 0;
6185404b540aSrobert   for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
6186404b540aSrobert     {
6187404b540aSrobert       /* Move to the object's offset, padding with zeros if necessary.  */
6188404b540aSrobert       assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
6189404b540aSrobert       offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
6190404b540aSrobert       if (CONSTANT_POOL_ADDRESS_P (symbol))
6191404b540aSrobert 	{
6192404b540aSrobert 	  desc = SYMBOL_REF_CONSTANT (symbol);
6193404b540aSrobert 	  output_constant_pool_1 (desc, 1);
6194404b540aSrobert 	  offset += GET_MODE_SIZE (desc->mode);
6195404b540aSrobert 	}
6196404b540aSrobert       else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
6197404b540aSrobert 	{
6198404b540aSrobert 	  decl = SYMBOL_REF_DECL (symbol);
6199404b540aSrobert 	  assemble_constant_contents (decl, XSTR (symbol, 0),
6200404b540aSrobert 				      get_constant_alignment (decl));
6201404b540aSrobert 	  offset += get_constant_size (decl);
6202404b540aSrobert 	}
6203404b540aSrobert       else
6204404b540aSrobert 	{
6205404b540aSrobert 	  decl = SYMBOL_REF_DECL (symbol);
6206404b540aSrobert 	  assemble_variable_contents (decl, XSTR (symbol, 0), false);
6207404b540aSrobert 	  offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1);
6208404b540aSrobert 	}
6209404b540aSrobert     }
6210404b540aSrobert }
6211404b540aSrobert 
6212404b540aSrobert /* A htab_traverse callback used to call output_object_block for
6213404b540aSrobert    each member of object_block_htab.  */
6214404b540aSrobert 
6215404b540aSrobert static int
output_object_block_htab(void ** slot,void * data ATTRIBUTE_UNUSED)6216404b540aSrobert output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
6217404b540aSrobert {
6218404b540aSrobert   output_object_block ((struct object_block *) (*slot));
6219404b540aSrobert   return 1;
6220404b540aSrobert }
6221404b540aSrobert 
6222404b540aSrobert /* Output the definitions of all object_blocks.  */
6223404b540aSrobert 
6224404b540aSrobert void
output_object_blocks(void)6225404b540aSrobert output_object_blocks (void)
6226404b540aSrobert {
6227404b540aSrobert   htab_traverse (object_block_htab, output_object_block_htab, NULL);
6228404b540aSrobert }
6229404b540aSrobert 
6230*8529ddd3Skettenis /* Emit text to declare externally defined symbols. It is needed to
6231*8529ddd3Skettenis    properly support non-default visibility.  */
6232*8529ddd3Skettenis void
default_elf_asm_output_external(FILE * file ATTRIBUTE_UNUSED,tree decl,const char * name ATTRIBUTE_UNUSED)6233*8529ddd3Skettenis default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
6234*8529ddd3Skettenis 				 tree decl,
6235*8529ddd3Skettenis 				 const char *name ATTRIBUTE_UNUSED)
6236*8529ddd3Skettenis {
6237*8529ddd3Skettenis   /* We output the name if and only if TREE_SYMBOL_REFERENCED is
6238*8529ddd3Skettenis      set in order to avoid putting out names that are never really
6239*8529ddd3Skettenis      used. */
6240*8529ddd3Skettenis   if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
6241*8529ddd3Skettenis       && targetm.binds_local_p (decl))
6242*8529ddd3Skettenis     maybe_assemble_visibility (decl);
6243*8529ddd3Skettenis }
6244*8529ddd3Skettenis 
6245404b540aSrobert #include "gt-varasm.h"
6246