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