varasm.c revision 52284
118334Speter/* Output variables, constants and external declarations, for GNU compiler.
252284Sobrien   Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
318334Speter
418334SpeterThis file is part of GNU CC.
518334Speter
618334SpeterGNU CC is free software; you can redistribute it and/or modify
718334Speterit under the terms of the GNU General Public License as published by
818334Speterthe Free Software Foundation; either version 2, or (at your option)
918334Speterany later version.
1018334Speter
1118334SpeterGNU CC is distributed in the hope that it will be useful,
1218334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1318334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1418334SpeterGNU General Public License for more details.
1518334Speter
1618334SpeterYou should have received a copy of the GNU General Public License
1718334Speteralong with GNU CC; see the file COPYING.  If not, write to
1818334Speterthe Free Software Foundation, 59 Temple Place - Suite 330,
1918334SpeterBoston, MA 02111-1307, USA.  */
2018334Speter
2118334Speter
2218334Speter/* This file handles generation of all the assembler code
2318334Speter   *except* the instructions of a function.
2418334Speter   This includes declarations of variables and their initial values.
2518334Speter
2618334Speter   We also output the assembler code for constants stored in memory
2718334Speter   and are responsible for combining constants with the same value.  */
2818334Speter
2950397Sobrien#include "config.h"
3050397Sobrien#include "system.h"
3118334Speter#include <setjmp.h>
3218334Speter/* #include <stab.h> */
3318334Speter#include "rtl.h"
3418334Speter#include "tree.h"
3518334Speter#include "flags.h"
3650397Sobrien#include "except.h"
3718334Speter#include "function.h"
3818334Speter#include "expr.h"
3918334Speter#include "output.h"
4018334Speter#include "hard-reg-set.h"
4118334Speter#include "regs.h"
4218334Speter#include "defaults.h"
4318334Speter#include "real.h"
4450397Sobrien#include "toplev.h"
4550397Sobrien#include "dbxout.h"
4650397Sobrien#include "sdbout.h"
4718334Speter
4818334Speter#include "obstack.h"
4918334Speter#include "c-pragma.h"
5018334Speter
5118334Speter#ifdef XCOFF_DEBUGGING_INFO
5218334Speter#include "xcoffout.h"
5318334Speter#endif
5418334Speter
5550397Sobrien#ifndef TRAMPOLINE_ALIGNMENT
5650397Sobrien#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
5750397Sobrien#endif
5818334Speter
5918334Speter#ifndef ASM_STABS_OP
6018334Speter#define ASM_STABS_OP ".stabs"
6118334Speter#endif
6218334Speter
6350397Sobrien/* Define the prefix to use when check_memory_usage_flag is enable.  */
6450397Sobrien#ifdef NO_DOLLAR_IN_LABEL
6550397Sobrien#ifdef NO_DOT_IN_LABEL
6650397Sobrien#define CHKR_PREFIX "chkr_prefix_"
6750397Sobrien#else /* !NO_DOT_IN_LABEL */
6850397Sobrien#define CHKR_PREFIX "chkr."
6950397Sobrien#endif
7050397Sobrien#else /* !NO_DOLLAR_IN_LABEL */
7150397Sobrien#define CHKR_PREFIX "chkr$"
7250397Sobrien#endif
7350397Sobrien#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
7450397Sobrien
7518334Speter/* File in which assembler code is being written.  */
7618334Speter
7718334Speterextern FILE *asm_out_file;
7818334Speter
7918334Speter/* The (assembler) name of the first globally-visible object output.  */
8018334Speterchar *first_global_object_name;
8150397Sobrienchar *weak_global_object_name;
8218334Speter
8318334Speterextern struct obstack *current_obstack;
8418334Speterextern struct obstack *saveable_obstack;
8518334Speterextern struct obstack *rtl_obstack;
8618334Speterextern struct obstack permanent_obstack;
8718334Speter#define obstack_chunk_alloc xmalloc
8818334Speter
8918334Speter/* Number for making the label on the next
9018334Speter   constant that is stored in memory.  */
9118334Speter
9218334Speterint const_labelno;
9318334Speter
9418334Speter/* Number for making the label on the next
9518334Speter   static variable internal to a function.  */
9618334Speter
9718334Speterint var_labelno;
9818334Speter
9918334Speter/* Carry information from ASM_DECLARE_OBJECT_NAME
10018334Speter   to ASM_FINISH_DECLARE_OBJECT.  */
10118334Speter
10218334Speterint size_directive_output;
10318334Speter
10418334Speter/* The last decl for which assemble_variable was called,
10518334Speter   if it did ASM_DECLARE_OBJECT_NAME.
10618334Speter   If the last call to assemble_variable didn't do that,
10718334Speter   this holds 0.  */
10818334Speter
10918334Spetertree last_assemble_variable_decl;
11018334Speter
11118334Speter/* Nonzero if at least one function definition has been seen.  */
11218334Speter
11318334Speterstatic int function_defined;
11418334Speter
11518334Speterstruct addr_const;
11618334Speterstruct constant_descriptor;
11718334Speterstruct rtx_const;
11818334Speterstruct pool_constant;
11918334Speter
12052284Sobrienstatic const char *strip_reg_name	PROTO((const char *));
12118334Speterstatic int contains_pointers_p		PROTO((tree));
12218334Speterstatic void decode_addr_const		PROTO((tree, struct addr_const *));
12318334Speterstatic int const_hash			PROTO((tree));
12418334Speterstatic int compare_constant		PROTO((tree,
12518334Speter					       struct constant_descriptor *));
12618334Speterstatic char *compare_constant_1		PROTO((tree, char *));
12718334Speterstatic struct constant_descriptor *record_constant PROTO((tree));
12818334Speterstatic void record_constant_1		PROTO((tree));
12918334Speterstatic tree copy_constant		PROTO((tree));
13018334Speterstatic void output_constant_def_contents  PROTO((tree, int, int));
13118334Speterstatic void decode_rtx_const		PROTO((enum machine_mode, rtx,
13218334Speter					       struct rtx_const *));
13318334Speterstatic int const_hash_rtx		PROTO((enum machine_mode, rtx));
13418334Speterstatic int compare_constant_rtx		PROTO((enum machine_mode, rtx,
13518334Speter					       struct constant_descriptor *));
13618334Speterstatic struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
13718334Speter							      rtx));
13818334Speterstatic struct pool_constant *find_pool_constant PROTO((rtx));
13950397Sobrienstatic void mark_constant_pool		PROTO((void));
14050397Sobrienstatic void mark_constants		PROTO((rtx));
14118334Speterstatic int output_addressed_constants	PROTO((tree));
14250397Sobrienstatic void output_after_function_constants PROTO((void));
14318334Speterstatic void output_constructor		PROTO((tree, int));
14452284Sobrienstatic void remove_from_pending_weak_list	PROTO ((char *));
14550397Sobrien#ifdef ASM_OUTPUT_BSS
14650397Sobrienstatic void asm_output_bss		PROTO((FILE *, tree, char *, int, int));
14750397Sobrien#endif
14850397Sobrien#ifdef BSS_SECTION_ASM_OP
14950397Sobrien#ifdef ASM_OUTPUT_ALIGNED_BSS
15050397Sobrienstatic void asm_output_aligned_bss	PROTO((FILE *, tree, char *, int, int));
15150397Sobrien#endif
15250397Sobrien#endif /* BSS_SECTION_ASM_OP */
15318334Speter
15450397Sobrienstatic enum in_section { no_section, in_text, in_data, in_named
15550397Sobrien#ifdef BSS_SECTION_ASM_OP
15650397Sobrien  , in_bss
15750397Sobrien#endif
15850397Sobrien#ifdef EH_FRAME_SECTION_ASM_OP
15950397Sobrien  , in_eh_frame
16050397Sobrien#endif
16118334Speter#ifdef EXTRA_SECTIONS
16250397Sobrien  , EXTRA_SECTIONS
16318334Speter#endif
16450397Sobrien} in_section = no_section;
16518334Speter
16618334Speter/* Return a non-zero value if DECL has a section attribute.  */
16718334Speter#define IN_NAMED_SECTION(DECL) \
16818334Speter  ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
16918334Speter   && DECL_SECTION_NAME (DECL) != NULL_TREE)
17018334Speter
17118334Speter/* Text of section name when in_section == in_named.  */
17218334Speterstatic char *in_named_name;
17318334Speter
17418334Speter/* Define functions like text_section for any extra sections.  */
17518334Speter#ifdef EXTRA_SECTION_FUNCTIONS
17618334SpeterEXTRA_SECTION_FUNCTIONS
17718334Speter#endif
17818334Speter
17918334Speter/* Tell assembler to switch to text section.  */
18018334Speter
18118334Spetervoid
18218334Spetertext_section ()
18318334Speter{
18418334Speter  if (in_section != in_text)
18518334Speter    {
18650397Sobrien      fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
18718334Speter      in_section = in_text;
18818334Speter    }
18918334Speter}
19018334Speter
19118334Speter/* Tell assembler to switch to data section.  */
19218334Speter
19318334Spetervoid
19418334Speterdata_section ()
19518334Speter{
19618334Speter  if (in_section != in_data)
19718334Speter    {
19850397Sobrien      if (flag_shared_data)
19918334Speter	{
20018334Speter#ifdef SHARED_SECTION_ASM_OP
20150397Sobrien	  fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
20218334Speter#else
20350397Sobrien	  fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
20418334Speter#endif
20518334Speter	}
20650397Sobrien      else
20750397Sobrien	fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
20818334Speter
20918334Speter      in_section = in_data;
21018334Speter    }
21118334Speter}
21252284Sobrien/* Tell assembler to ALWAYS switch to data section, in case
21352284Sobrien   it's not sure where it it.  */
21418334Speter
21552284Sobrienvoid
21652284Sobrienforce_data_section ()
21752284Sobrien{
21852284Sobrien  in_section = no_section;
21952284Sobrien  data_section ();
22052284Sobrien}
22152284Sobrien
22218334Speter/* Tell assembler to switch to read-only data section.  This is normally
22318334Speter   the text section.  */
22418334Speter
22518334Spetervoid
22618334Speterreadonly_data_section ()
22718334Speter{
22818334Speter#ifdef READONLY_DATA_SECTION
22918334Speter  READONLY_DATA_SECTION ();  /* Note this can call data_section.  */
23018334Speter#else
23118334Speter  text_section ();
23218334Speter#endif
23318334Speter}
23418334Speter
23550397Sobrien/* Determine if we're in the text section.  */
23618334Speter
23718334Speterint
23818334Speterin_text_section ()
23918334Speter{
24018334Speter  return in_section == in_text;
24118334Speter}
24218334Speter
24350397Sobrien/* Determine if we're in the data section.  */
24450397Sobrien
24550397Sobrienint
24650397Sobrienin_data_section ()
24750397Sobrien{
24850397Sobrien  return in_section == in_data;
24950397Sobrien}
25050397Sobrien
25118334Speter/* Tell assembler to change to section NAME for DECL.
25218334Speter   If DECL is NULL, just switch to section NAME.
25350397Sobrien   If NAME is NULL, get the name from DECL.
25450397Sobrien   If RELOC is 1, the initializer for DECL contains relocs.  */
25518334Speter
25618334Spetervoid
25750397Sobriennamed_section (decl, name, reloc)
25818334Speter     tree decl;
25952284Sobrien     const char *name;
26052284Sobrien     int reloc ATTRIBUTE_UNUSED;
26118334Speter{
26218334Speter  if (decl != NULL_TREE
26350397Sobrien      && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
26418334Speter    abort ();
26518334Speter  if (name == NULL)
26618334Speter    name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
26718334Speter
26818334Speter  if (in_section != in_named || strcmp (name, in_named_name))
26918334Speter    {
27018334Speter#ifdef ASM_OUTPUT_SECTION_NAME
27150397Sobrien      ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name, reloc);
27218334Speter#else
27318334Speter      /* Section attributes are not supported if this macro isn't provided -
27418334Speter	 some host formats don't support them at all.  The front-end should
27518334Speter	 already have flagged this as an error.  */
27618334Speter      abort ();
27718334Speter#endif
27850397Sobrien
27950397Sobrien      in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
28050397Sobrien      strcpy (in_named_name, name);
28150397Sobrien      in_section = in_named;
28218334Speter    }
28318334Speter}
28418334Speter
28550397Sobrien#ifdef ASM_OUTPUT_SECTION_NAME
28650397Sobrien#ifndef UNIQUE_SECTION
28750397Sobrien#define UNIQUE_SECTION(DECL,RELOC)				\
28850397Sobriendo {								\
28950397Sobrien  int len;							\
29050397Sobrien  char *name, *string;						\
29150397Sobrien								\
29250397Sobrien  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL));	\
29350397Sobrien  /* Strip off any encoding in name.  */			\
29450397Sobrien  STRIP_NAME_ENCODING (name, name);				\
29550397Sobrien								\
29650397Sobrien  len = strlen (name) + 1;					\
29750397Sobrien  string = alloca (len + 1);					\
29850397Sobrien  sprintf (string, ".%s", name);				\
29950397Sobrien								\
30050397Sobrien  DECL_SECTION_NAME (DECL) = build_string (len, string);	\
30150397Sobrien} while (0)
30250397Sobrien#endif
30350397Sobrien#ifndef UNIQUE_SECTION_P
30450397Sobrien#define UNIQUE_SECTION_P(DECL) 0
30550397Sobrien#endif
30650397Sobrien#endif
30750397Sobrien
30850397Sobrien#ifdef BSS_SECTION_ASM_OP
30950397Sobrien
31050397Sobrien/* Tell the assembler to switch to the bss section.  */
31150397Sobrien
31250397Sobrienvoid
31350397Sobrienbss_section ()
31450397Sobrien{
31550397Sobrien  if (in_section != in_bss)
31650397Sobrien    {
31750397Sobrien#ifdef SHARED_BSS_SECTION_ASM_OP
31850397Sobrien      if (flag_shared_data)
31950397Sobrien	fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP);
32050397Sobrien      else
32150397Sobrien#endif
32250397Sobrien	fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
32350397Sobrien
32450397Sobrien      in_section = in_bss;
32550397Sobrien    }
32650397Sobrien}
32750397Sobrien
32850397Sobrien#ifdef ASM_OUTPUT_BSS
32950397Sobrien
33050397Sobrien/* Utility function for ASM_OUTPUT_BSS for targets to use if
33150397Sobrien   they don't support alignments in .bss.
33250397Sobrien   ??? It is believed that this function will work in most cases so such
33350397Sobrien   support is localized here.  */
33450397Sobrien
33550397Sobrienstatic void
33650397Sobrienasm_output_bss (file, decl, name, size, rounded)
33750397Sobrien     FILE *file;
33850397Sobrien     tree decl;
33950397Sobrien     char *name;
34050397Sobrien     int size, rounded;
34150397Sobrien{
34250397Sobrien  ASM_GLOBALIZE_LABEL (file, name);
34350397Sobrien  bss_section ();
34450397Sobrien#ifdef ASM_DECLARE_OBJECT_NAME
34550397Sobrien  last_assemble_variable_decl = decl;
34650397Sobrien  ASM_DECLARE_OBJECT_NAME (file, name, decl);
34750397Sobrien#else
34850397Sobrien  /* Standard thing is just output label for the object.  */
34950397Sobrien  ASM_OUTPUT_LABEL (file, name);
35050397Sobrien#endif /* ASM_DECLARE_OBJECT_NAME */
35150397Sobrien  ASM_OUTPUT_SKIP (file, rounded);
35250397Sobrien}
35350397Sobrien
35450397Sobrien#endif
35550397Sobrien
35650397Sobrien#ifdef ASM_OUTPUT_ALIGNED_BSS
35750397Sobrien
35850397Sobrien/* Utility function for targets to use in implementing
35950397Sobrien   ASM_OUTPUT_ALIGNED_BSS.
36050397Sobrien   ??? It is believed that this function will work in most cases so such
36150397Sobrien   support is localized here.  */
36250397Sobrien
36350397Sobrienstatic void
36450397Sobrienasm_output_aligned_bss (file, decl, name, size, align)
36550397Sobrien     FILE *file;
36650397Sobrien     tree decl;
36750397Sobrien     char *name;
36850397Sobrien     int size, align;
36950397Sobrien{
37050397Sobrien  ASM_GLOBALIZE_LABEL (file, name);
37150397Sobrien  bss_section ();
37250397Sobrien  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
37350397Sobrien#ifdef ASM_DECLARE_OBJECT_NAME
37450397Sobrien  last_assemble_variable_decl = decl;
37550397Sobrien  ASM_DECLARE_OBJECT_NAME (file, name, decl);
37650397Sobrien#else
37750397Sobrien  /* Standard thing is just output label for the object.  */
37850397Sobrien  ASM_OUTPUT_LABEL (file, name);
37950397Sobrien#endif /* ASM_DECLARE_OBJECT_NAME */
38050397Sobrien  ASM_OUTPUT_SKIP (file, size ? size : 1);
38150397Sobrien}
38250397Sobrien
38350397Sobrien#endif
38450397Sobrien
38550397Sobrien#endif /* BSS_SECTION_ASM_OP */
38650397Sobrien
38750397Sobrien#ifdef EH_FRAME_SECTION_ASM_OP
38850397Sobrienvoid
38950397Sobrieneh_frame_section ()
39050397Sobrien{
39150397Sobrien  if (in_section != in_eh_frame)
39250397Sobrien    {
39350397Sobrien      fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
39450397Sobrien      in_section = in_eh_frame;
39550397Sobrien    }
39650397Sobrien}
39750397Sobrien#endif
39850397Sobrien
39918334Speter/* Switch to the section for function DECL.
40018334Speter
40118334Speter   If DECL is NULL_TREE, switch to the text section.
40218334Speter   ??? It's not clear that we will ever be passed NULL_TREE, but it's
40318334Speter   safer to handle it.  */
40418334Speter
40518334Spetervoid
40618334Speterfunction_section (decl)
40718334Speter     tree decl;
40818334Speter{
40918334Speter  if (decl != NULL_TREE
41018334Speter      && DECL_SECTION_NAME (decl) != NULL_TREE)
41150397Sobrien    named_section (decl, (char *) 0, 0);
41250397Sobrien  else
41350397Sobrien    text_section ();
41418334Speter}
41550397Sobrien
41650397Sobrien/* Switch to section for variable DECL.
41750397Sobrien
41850397Sobrien   RELOC is the `reloc' argument to SELECT_SECTION.  */
41950397Sobrien
42050397Sobrienvoid
42150397Sobrienvariable_section (decl, reloc)
42250397Sobrien     tree decl;
42350397Sobrien     int reloc;
42450397Sobrien{
42550397Sobrien  if (IN_NAMED_SECTION (decl))
42650397Sobrien    named_section (decl, NULL, reloc);
42750397Sobrien  else
42850397Sobrien    {
42950397Sobrien      /* C++ can have const variables that get initialized from constructors,
43050397Sobrien	 and thus can not be in a readonly section.  We prevent this by
43150397Sobrien	 verifying that the initial value is constant for objects put in a
43250397Sobrien	 readonly section.
43350397Sobrien
43450397Sobrien	 error_mark_node is used by the C front end to indicate that the
43550397Sobrien	 initializer has not been seen yet.  In this case, we assume that
43650397Sobrien	 the initializer must be constant.
43750397Sobrien
43850397Sobrien	 C++ uses error_mark_node for variables that have complicated
43950397Sobrien	 initializers, but these variables go in BSS so we won't be called
44050397Sobrien	 for them.  */
44150397Sobrien
44250397Sobrien#ifdef SELECT_SECTION
44350397Sobrien      SELECT_SECTION (decl, reloc);
44450397Sobrien#else
44550397Sobrien      if (DECL_READONLY_SECTION (decl, reloc))
44650397Sobrien	readonly_data_section ();
44750397Sobrien      else
44850397Sobrien	data_section ();
44950397Sobrien#endif
45050397Sobrien    }
45150397Sobrien}
45250397Sobrien
45350397Sobrien/* Tell assembler to switch to the section for the exception handling
45450397Sobrien   table.  */
45550397Sobrien
45650397Sobrienvoid
45750397Sobrienexception_section ()
45850397Sobrien{
45950397Sobrien#if defined (EXCEPTION_SECTION)
46050397Sobrien  EXCEPTION_SECTION ();
46150397Sobrien#else
46250397Sobrien#ifdef ASM_OUTPUT_SECTION_NAME
46350397Sobrien  named_section (NULL_TREE, ".gcc_except_table", 0);
46450397Sobrien#else
46550397Sobrien  if (flag_pic)
46650397Sobrien    data_section ();
46750397Sobrien  else
46850397Sobrien    readonly_data_section ();
46950397Sobrien#endif
47050397Sobrien#endif
47150397Sobrien}
47218334Speter
47318334Speter/* Create the rtl to represent a function, for a function definition.
47418334Speter   DECL is a FUNCTION_DECL node which describes which function.
47518334Speter   The rtl is stored into DECL.  */
47618334Speter
47718334Spetervoid
47818334Spetermake_function_rtl (decl)
47918334Speter     tree decl;
48018334Speter{
48118334Speter  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
48250397Sobrien  char *new_name = name;
48318334Speter
48418334Speter  /* Rename a nested function to avoid conflicts.  */
48518334Speter  if (decl_function_context (decl) != 0
48618334Speter      && DECL_INITIAL (decl) != 0
48718334Speter      && DECL_RTL (decl) == 0)
48818334Speter    {
48918334Speter      char *label;
49018334Speter
49118334Speter      name = IDENTIFIER_POINTER (DECL_NAME (decl));
49218334Speter      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
49318334Speter      name = obstack_copy0 (saveable_obstack, label, strlen (label));
49418334Speter      var_labelno++;
49518334Speter    }
49650397Sobrien  else
49750397Sobrien    {
49850397Sobrien      /* When -fprefix-function-name is used, every function name is
49950397Sobrien         prefixed.  Even static functions are prefixed because they
50050397Sobrien         could be declared latter.  Note that a nested function name
50150397Sobrien         is not prefixed.  */
50250397Sobrien      if (flag_prefix_function_name)
50350397Sobrien        {
50450397Sobrien          new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1);
50550397Sobrien          strcpy (new_name, CHKR_PREFIX);
50650397Sobrien          strcpy (new_name + CHKR_PREFIX_SIZE, name);
50750397Sobrien          name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name));
50850397Sobrien        }
50950397Sobrien    }
51018334Speter
51118334Speter  if (DECL_RTL (decl) == 0)
51218334Speter    {
51318334Speter      DECL_RTL (decl)
51450397Sobrien	= gen_rtx_MEM (DECL_MODE (decl),
51550397Sobrien		       gen_rtx_SYMBOL_REF (Pmode, name));
51618334Speter
51718334Speter      /* Optionally set flags or add text to the name to record information
51818334Speter	 such as that it is a function name.  If the name is changed, the macro
51918334Speter	 ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
52018334Speter#ifdef ENCODE_SECTION_INFO
52118334Speter      ENCODE_SECTION_INFO (decl);
52218334Speter#endif
52318334Speter    }
52450397Sobrien  else
52550397Sobrien    {
52650397Sobrien      /* ??? Another way to do this would be to do what halfpic.c does
52750397Sobrien	 and maintain a hashed table of such critters.  */
52850397Sobrien      /* ??? Another way to do this would be to pass a flag bit to
52950397Sobrien	 ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
53050397Sobrien      /* Let the target reassign the RTL if it wants.
53150397Sobrien	 This is necessary, for example, when one machine specific
53250397Sobrien	 decl attribute overrides another.  */
53350397Sobrien#ifdef REDO_SECTION_INFO_P
53450397Sobrien      if (REDO_SECTION_INFO_P (decl))
53550397Sobrien	ENCODE_SECTION_INFO (decl);
53650397Sobrien#endif
53750397Sobrien    }
53818334Speter
53918334Speter  /* Record at least one function has been defined.  */
54018334Speter  function_defined = 1;
54118334Speter}
54218334Speter
54318334Speter/* Given NAME, a putative register name, discard any customary prefixes.  */
54418334Speter
54552284Sobrienstatic const char *
54618334Speterstrip_reg_name (name)
54752284Sobrien  const char *name;
54818334Speter{
54918334Speter#ifdef REGISTER_PREFIX
55018334Speter  if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
55118334Speter    name += strlen (REGISTER_PREFIX);
55218334Speter#endif
55318334Speter  if (name[0] == '%' || name[0] == '#')
55418334Speter    name++;
55518334Speter  return name;
55618334Speter}
55718334Speter
55818334Speter/* Decode an `asm' spec for a declaration as a register name.
55918334Speter   Return the register number, or -1 if nothing specified,
56018334Speter   or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
56118334Speter   or -3 if ASMSPEC is `cc' and is not recognized,
56218334Speter   or -4 if ASMSPEC is `memory' and is not recognized.
56318334Speter   Accept an exact spelling or a decimal number.
56418334Speter   Prefixes such as % are optional.  */
56518334Speter
56618334Speterint
56718334Speterdecode_reg_name (asmspec)
56852284Sobrien  const char *asmspec;
56918334Speter{
57018334Speter  if (asmspec != 0)
57118334Speter    {
57218334Speter      int i;
57318334Speter
57418334Speter      /* Get rid of confusing prefixes.  */
57518334Speter      asmspec = strip_reg_name (asmspec);
57618334Speter
57718334Speter      /* Allow a decimal number as a "register name".  */
57818334Speter      for (i = strlen (asmspec) - 1; i >= 0; i--)
57918334Speter	if (! (asmspec[i] >= '0' && asmspec[i] <= '9'))
58018334Speter	  break;
58118334Speter      if (asmspec[0] != 0 && i < 0)
58218334Speter	{
58318334Speter	  i = atoi (asmspec);
58418334Speter	  if (i < FIRST_PSEUDO_REGISTER && i >= 0)
58518334Speter	    return i;
58618334Speter	  else
58718334Speter	    return -2;
58818334Speter	}
58918334Speter
59018334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
59118334Speter	if (reg_names[i][0]
59218334Speter	    && ! strcmp (asmspec, strip_reg_name (reg_names[i])))
59318334Speter	  return i;
59418334Speter
59518334Speter#ifdef ADDITIONAL_REGISTER_NAMES
59618334Speter      {
59752284Sobrien	static struct { const char *name; int number; } table[]
59818334Speter	  = ADDITIONAL_REGISTER_NAMES;
59918334Speter
60052284Sobrien	for (i = 0; i < (int)(sizeof (table) / sizeof (table[0])); i++)
60118334Speter	  if (! strcmp (asmspec, table[i].name))
60218334Speter	    return table[i].number;
60318334Speter      }
60418334Speter#endif /* ADDITIONAL_REGISTER_NAMES */
60518334Speter
60618334Speter      if (!strcmp (asmspec, "memory"))
60718334Speter	return -4;
60818334Speter
60918334Speter      if (!strcmp (asmspec, "cc"))
61018334Speter	return -3;
61118334Speter
61218334Speter      return -2;
61318334Speter    }
61418334Speter
61518334Speter  return -1;
61618334Speter}
61718334Speter
61818334Speter/* Create the DECL_RTL for a declaration for a static or external variable
61918334Speter   or static or external function.
62018334Speter   ASMSPEC, if not 0, is the string which the user specified
62118334Speter   as the assembler symbol name.
62218334Speter   TOP_LEVEL is nonzero if this is a file-scope variable.
62318334Speter
62418334Speter   This is never called for PARM_DECL nodes.  */
62518334Speter
62618334Spetervoid
62718334Spetermake_decl_rtl (decl, asmspec, top_level)
62818334Speter     tree decl;
62952284Sobrien     const char *asmspec;
63018334Speter     int top_level;
63118334Speter{
63218334Speter  register char *name = 0;
63318334Speter  int reg_number;
63418334Speter
63518334Speter  reg_number = decode_reg_name (asmspec);
63618334Speter
63718334Speter  if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
63818334Speter    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
63918334Speter
64018334Speter  if (reg_number == -2)
64118334Speter    {
64218334Speter      /* ASMSPEC is given, and not the name of a register.  */
64318334Speter      name = (char *) obstack_alloc (saveable_obstack,
64418334Speter				     strlen (asmspec) + 2);
64518334Speter      name[0] = '*';
64618334Speter      strcpy (&name[1], asmspec);
64718334Speter    }
64818334Speter
64918334Speter  /* For a duplicate declaration, we can be called twice on the
65018334Speter     same DECL node.  Don't discard the RTL already made.  */
65118334Speter  if (DECL_RTL (decl) == 0)
65218334Speter    {
65318334Speter      /* First detect errors in declaring global registers.  */
65450397Sobrien      if (TREE_CODE (decl) != FUNCTION_DECL
65550397Sobrien	  && DECL_REGISTER (decl) && reg_number == -1)
65618334Speter	error_with_decl (decl,
65718334Speter			 "register name not specified for `%s'");
65850397Sobrien      else if (TREE_CODE (decl) != FUNCTION_DECL
65950397Sobrien	       && DECL_REGISTER (decl) && reg_number < 0)
66018334Speter	error_with_decl (decl,
66118334Speter			 "invalid register name for `%s'");
66250397Sobrien      else if ((reg_number >= 0 || reg_number == -3)
66350397Sobrien	       && (TREE_CODE (decl) == FUNCTION_DECL
66450397Sobrien		   && ! DECL_REGISTER (decl)))
66518334Speter	error_with_decl (decl,
66618334Speter			 "register name given for non-register variable `%s'");
66750397Sobrien      else if (TREE_CODE (decl) != FUNCTION_DECL
66850397Sobrien	       && DECL_REGISTER (decl)
66950397Sobrien	       && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
67050397Sobrien	error_with_decl (decl,
67150397Sobrien			 "data type of `%s' isn't suitable for a register");
67250397Sobrien      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)
67350397Sobrien	       && ! HARD_REGNO_MODE_OK (reg_number,
67450397Sobrien					TYPE_MODE (TREE_TYPE (decl))))
67550397Sobrien	error_with_decl (decl,
67650397Sobrien			 "register number for `%s' isn't suitable for data type");
67718334Speter      /* Now handle properly declared static register variables.  */
67850397Sobrien      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
67918334Speter	{
68018334Speter	  int nregs;
68150397Sobrien
68218334Speter	  if (DECL_INITIAL (decl) != 0 && top_level)
68318334Speter	    {
68418334Speter	      DECL_INITIAL (decl) = 0;
68518334Speter	      error ("global register variable has initial value");
68618334Speter	    }
68718334Speter	  if (fixed_regs[reg_number] == 0
68818334Speter	      && function_defined && top_level)
68918334Speter	    error ("global register variable follows a function definition");
69018334Speter	  if (TREE_THIS_VOLATILE (decl))
69118334Speter	    warning ("volatile register variables don't work as you might wish");
69218334Speter
69318334Speter	  /* If the user specified one of the eliminables registers here,
69418334Speter	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
69518334Speter	     confused with that register and be eliminated.  Although this
69618334Speter	     usage is somewhat suspect, we nevertheless use the following
69718334Speter	     kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
69818334Speter
69918334Speter	  DECL_RTL (decl)
70050397Sobrien	    = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
70118334Speter	  REGNO (DECL_RTL (decl)) = reg_number;
70218334Speter	  REG_USERVAR_P (DECL_RTL (decl)) = 1;
70318334Speter
70418334Speter	  if (top_level)
70518334Speter	    {
70618334Speter	      /* Make this register global, so not usable for anything
70718334Speter		 else.  */
70818334Speter	      nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
70918334Speter	      while (nregs > 0)
71018334Speter		globalize_reg (reg_number + --nregs);
71118334Speter	    }
71218334Speter	}
71350397Sobrien      /* Specifying a section attribute on a variable forces it into a
71450397Sobrien         non-.bss section, and thus it cannot be common. */
71518334Speter      else if (TREE_CODE (decl) == VAR_DECL
71618334Speter	       && DECL_SECTION_NAME (decl) != NULL_TREE
71718334Speter	       && DECL_INITIAL (decl) == NULL_TREE
71850397Sobrien	       && DECL_COMMON (decl))
71950397Sobrien          DECL_COMMON (decl) = 0;
72018334Speter
72118334Speter      /* Now handle ordinary static variables and functions (in memory).
72218334Speter	 Also handle vars declared register invalidly.  */
72318334Speter      if (DECL_RTL (decl) == 0)
72418334Speter	{
72518334Speter	  /* Can't use just the variable's own name for a variable
72618334Speter	     whose scope is less than the whole file.
72718334Speter	     Concatenate a distinguishing number.  */
72850397Sobrien	  if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
72918334Speter	    {
73018334Speter	      char *label;
73118334Speter
73218334Speter	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
73318334Speter	      name = obstack_copy0 (saveable_obstack, label, strlen (label));
73418334Speter	      var_labelno++;
73518334Speter	    }
73618334Speter
73718334Speter	  if (name == 0)
73818334Speter	    abort ();
73918334Speter
74050397Sobrien	  /* When -fprefix-function-name is used, the functions
74150397Sobrien	     names are prefixed.  Only nested function names are not
74250397Sobrien	     prefixed.  */
74350397Sobrien	  if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
74450397Sobrien	    {
74550397Sobrien	      char *new_name;
74650397Sobrien	      new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE
74750397Sobrien	      				  + 1);
74850397Sobrien	      strcpy (new_name, CHKR_PREFIX);
74950397Sobrien	      strcpy (new_name + CHKR_PREFIX_SIZE, name);
75050397Sobrien	      name = obstack_copy0 (saveable_obstack,
75150397Sobrien	      			   new_name, strlen (new_name));
75250397Sobrien	    }
75318334Speter
75450397Sobrien	  DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
75550397Sobrien					 gen_rtx_SYMBOL_REF (Pmode, name));
75650397Sobrien	  MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
75750397Sobrien
75818334Speter	  /* If this variable is to be treated as volatile, show its
75918334Speter	     tree node has side effects.  If it has side effects, either
76018334Speter	     because of this test or from TREE_THIS_VOLATILE also
76118334Speter	     being set, show the MEM is volatile.  */
76218334Speter	  if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
76318334Speter	      && TREE_PUBLIC (decl))
76418334Speter	    TREE_SIDE_EFFECTS (decl) = 1;
76552284Sobrien	  else if (flag_volatile_static && TREE_CODE (decl) == VAR_DECL
76652284Sobrien	       && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))
76752284Sobrien	    TREE_SIDE_EFFECTS (decl) = 1;
76852284Sobrien
76918334Speter	  if (TREE_SIDE_EFFECTS (decl))
77018334Speter	    MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
77118334Speter
77218334Speter	  if (TREE_READONLY (decl))
77318334Speter	    RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
77452284Sobrien	  MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
77552284Sobrien			       AGGREGATE_TYPE_P (TREE_TYPE (decl)));
77618334Speter
77718334Speter	  /* Optionally set flags or add text to the name to record information
77818334Speter	     such as that it is a function name.
77918334Speter	     If the name is changed, the macro ASM_OUTPUT_LABELREF
78018334Speter	     will have to know how to strip this information.  */
78118334Speter#ifdef ENCODE_SECTION_INFO
78218334Speter	  ENCODE_SECTION_INFO (decl);
78318334Speter#endif
78418334Speter	}
78518334Speter    }
78650397Sobrien  else
78718334Speter    {
78850397Sobrien      /* If the old RTL had the wrong mode, fix the mode.  */
78950397Sobrien      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
79050397Sobrien	{
79150397Sobrien	  rtx rtl = DECL_RTL (decl);
79250397Sobrien	  PUT_MODE (rtl, DECL_MODE (decl));
79350397Sobrien	}
79450397Sobrien
79550397Sobrien      /* ??? Another way to do this would be to do what halfpic.c does
79650397Sobrien	 and maintain a hashed table of such critters.  */
79750397Sobrien      /* ??? Another way to do this would be to pass a flag bit to
79850397Sobrien	 ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
79950397Sobrien      /* Let the target reassign the RTL if it wants.
80050397Sobrien	 This is necessary, for example, when one machine specific
80150397Sobrien	 decl attribute overrides another.  */
80250397Sobrien#ifdef REDO_SECTION_INFO_P
80350397Sobrien      if (REDO_SECTION_INFO_P (decl))
80450397Sobrien	ENCODE_SECTION_INFO (decl);
80550397Sobrien#endif
80618334Speter    }
80718334Speter}
80818334Speter
80918334Speter/* Make the rtl for variable VAR be volatile.
81018334Speter   Use this only for static variables.  */
81118334Speter
81218334Spetervoid
81318334Spetermake_var_volatile (var)
81418334Speter     tree var;
81518334Speter{
81618334Speter  if (GET_CODE (DECL_RTL (var)) != MEM)
81718334Speter    abort ();
81818334Speter
81918334Speter  MEM_VOLATILE_P (DECL_RTL (var)) = 1;
82018334Speter}
82118334Speter
82218334Speter/* Output alignment directive to align for constant expression EXP.  */
82318334Speter
82418334Spetervoid
82518334Speterassemble_constant_align (exp)
82618334Speter     tree exp;
82718334Speter{
82818334Speter  int align;
82918334Speter
83018334Speter  /* Align the location counter as required by EXP's data type.  */
83118334Speter  align = TYPE_ALIGN (TREE_TYPE (exp));
83218334Speter#ifdef CONSTANT_ALIGNMENT
83318334Speter  align = CONSTANT_ALIGNMENT (exp, align);
83418334Speter#endif
83518334Speter
83618334Speter  if (align > BITS_PER_UNIT)
83718334Speter    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
83818334Speter}
83918334Speter
84018334Speter/* Output a string of literal assembler code
84118334Speter   for an `asm' keyword used between functions.  */
84218334Speter
84318334Spetervoid
84418334Speterassemble_asm (string)
84518334Speter     tree string;
84618334Speter{
84718334Speter  app_enable ();
84818334Speter
84918334Speter  if (TREE_CODE (string) == ADDR_EXPR)
85018334Speter    string = TREE_OPERAND (string, 0);
85118334Speter
85218334Speter  fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
85318334Speter}
85418334Speter
85518334Speter#if 0 /* This should no longer be needed, because
85618334Speter	 flag_gnu_linker should be 0 on these systems,
85718334Speter	 which should prevent any output
85818334Speter	 if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent.  */
85918334Speter#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))
86018334Speter#ifndef ASM_OUTPUT_CONSTRUCTOR
86118334Speter#define ASM_OUTPUT_CONSTRUCTOR(file, name)
86218334Speter#endif
86318334Speter#ifndef ASM_OUTPUT_DESTRUCTOR
86418334Speter#define ASM_OUTPUT_DESTRUCTOR(file, name)
86518334Speter#endif
86618334Speter#endif
86718334Speter#endif /* 0 */
86818334Speter
86918334Speter/* Record an element in the table of global destructors.
87018334Speter   How this is done depends on what sort of assembler and linker
87118334Speter   are in use.
87218334Speter
87318334Speter   NAME should be the name of a global function to be called
87418334Speter   at exit time.  This name is output using assemble_name.  */
87518334Speter
87618334Spetervoid
87718334Speterassemble_destructor (name)
87818334Speter     char *name;
87918334Speter{
88018334Speter#ifdef ASM_OUTPUT_DESTRUCTOR
88118334Speter  ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
88218334Speter#else
88318334Speter  if (flag_gnu_linker)
88418334Speter    {
88518334Speter      /* Now tell GNU LD that this is part of the static destructor set.  */
88618334Speter      /* This code works for any machine provided you use GNU as/ld.  */
88718334Speter      fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
88818334Speter      assemble_name (asm_out_file, name);
88918334Speter      fputc ('\n', asm_out_file);
89018334Speter    }
89118334Speter#endif
89218334Speter}
89318334Speter
89418334Speter/* Likewise for global constructors.  */
89518334Speter
89618334Spetervoid
89718334Speterassemble_constructor (name)
89818334Speter     char *name;
89918334Speter{
90018334Speter#ifdef ASM_OUTPUT_CONSTRUCTOR
90118334Speter  ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
90218334Speter#else
90318334Speter  if (flag_gnu_linker)
90418334Speter    {
90518334Speter      /* Now tell GNU LD that this is part of the static constructor set.  */
90618334Speter      /* This code works for any machine provided you use GNU as/ld.  */
90718334Speter      fprintf (asm_out_file, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
90818334Speter      assemble_name (asm_out_file, name);
90918334Speter      fputc ('\n', asm_out_file);
91018334Speter    }
91118334Speter#endif
91218334Speter}
91318334Speter
91418334Speter/* Likewise for entries we want to record for garbage collection.
91518334Speter   Garbage collection is still under development.  */
91618334Speter
91718334Spetervoid
91818334Speterassemble_gc_entry (name)
91918334Speter     char *name;
92018334Speter{
92118334Speter#ifdef ASM_OUTPUT_GC_ENTRY
92218334Speter  ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
92318334Speter#else
92418334Speter  if (flag_gnu_linker)
92518334Speter    {
92618334Speter      /* Now tell GNU LD that this is part of the static constructor set.  */
92718334Speter      fprintf (asm_out_file, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
92818334Speter      assemble_name (asm_out_file, name);
92918334Speter      fputc ('\n', asm_out_file);
93018334Speter    }
93118334Speter#endif
93218334Speter}
93318334Speter
93450397Sobrien/* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with
93550397Sobrien   a non-zero value if the constant pool should be output before the
93650397Sobrien   start of the function, or a zero value if the pool should output
93750397Sobrien   after the end of the function.  The default is to put it before the
93850397Sobrien   start.  */
93950397Sobrien
94050397Sobrien#ifndef CONSTANT_POOL_BEFORE_FUNCTION
94150397Sobrien#define CONSTANT_POOL_BEFORE_FUNCTION 1
94250397Sobrien#endif
94350397Sobrien
94418334Speter/* Output assembler code for the constant pool of a function and associated
94518334Speter   with defining the name of the function.  DECL describes the function.
94618334Speter   NAME is the function's name.  For the constant pool, we use the current
94718334Speter   constant pool data.  */
94818334Speter
94918334Spetervoid
95018334Speterassemble_start_function (decl, fnname)
95118334Speter     tree decl;
95218334Speter     char *fnname;
95318334Speter{
95418334Speter  int align;
95518334Speter
95618334Speter  /* The following code does not need preprocessing in the assembler.  */
95718334Speter
95818334Speter  app_disable ();
95918334Speter
96050397Sobrien  if (CONSTANT_POOL_BEFORE_FUNCTION)
96150397Sobrien    output_constant_pool (fnname, decl);
96218334Speter
96350397Sobrien#ifdef ASM_OUTPUT_SECTION_NAME
96450397Sobrien  /* If the function is to be put in its own section and it's not in a section
96550397Sobrien     already, indicate so.  */
96650397Sobrien  if ((flag_function_sections
96750397Sobrien       && DECL_SECTION_NAME (decl) == NULL_TREE)
96850397Sobrien      || UNIQUE_SECTION_P (decl))
96950397Sobrien    UNIQUE_SECTION (decl, 0);
97050397Sobrien#endif
97150397Sobrien
97218334Speter  function_section (decl);
97318334Speter
97418334Speter  /* Tell assembler to move to target machine's alignment for functions.  */
97518334Speter  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
97618334Speter  if (align > 0)
97750397Sobrien    ASM_OUTPUT_ALIGN (asm_out_file, align);
97818334Speter
97918334Speter#ifdef ASM_OUTPUT_FUNCTION_PREFIX
98018334Speter  ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
98118334Speter#endif
98218334Speter
98318334Speter#ifdef SDB_DEBUGGING_INFO
98418334Speter  /* Output SDB definition of the function.  */
98518334Speter  if (write_symbols == SDB_DEBUG)
98618334Speter    sdbout_mark_begin_function ();
98718334Speter#endif
98818334Speter
98918334Speter#ifdef DBX_DEBUGGING_INFO
99018334Speter  /* Output DBX definition of the function.  */
99118334Speter  if (write_symbols == DBX_DEBUG)
99218334Speter    dbxout_begin_function (decl);
99318334Speter#endif
99418334Speter
99518334Speter  /* Make function name accessible from other files, if appropriate.  */
99618334Speter
99718334Speter  if (TREE_PUBLIC (decl))
99818334Speter    {
99950397Sobrien      if (! first_global_object_name)
100018334Speter	{
100118334Speter	  char *p;
100250397Sobrien	  char **name;
100318334Speter
100450397Sobrien	  if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
100550397Sobrien	    name = &first_global_object_name;
100650397Sobrien	  else
100750397Sobrien	    name = &weak_global_object_name;
100850397Sobrien
100918334Speter	  STRIP_NAME_ENCODING (p, fnname);
101050397Sobrien	  *name = permalloc (strlen (p) + 1);
101150397Sobrien	  strcpy (*name, p);
101218334Speter	}
101318334Speter
101418334Speter#ifdef ASM_WEAKEN_LABEL
101518334Speter      if (DECL_WEAK (decl))
101652284Sobrien	{
101752284Sobrien	  ASM_WEAKEN_LABEL (asm_out_file, fnname);
101852284Sobrien	  /* Remove this function from the pending weak list so that
101952284Sobrien	     we do not emit multiple .weak directives for it.  */
102052284Sobrien	  remove_from_pending_weak_list
102152284Sobrien	    (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
102252284Sobrien	}
102318334Speter      else
102418334Speter#endif
102550397Sobrien      ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
102618334Speter    }
102718334Speter
102818334Speter  /* Do any machine/system dependent processing of the function name */
102918334Speter#ifdef ASM_DECLARE_FUNCTION_NAME
103018334Speter  ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
103118334Speter#else
103218334Speter  /* Standard thing is just output label for the function.  */
103350397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, fnname);
103418334Speter#endif /* ASM_DECLARE_FUNCTION_NAME */
103518334Speter}
103618334Speter
103718334Speter/* Output assembler code associated with defining the size of the
103818334Speter   function.  DECL describes the function.  NAME is the function's name.  */
103918334Speter
104018334Spetervoid
104118334Speterassemble_end_function (decl, fnname)
104218334Speter     tree decl;
104318334Speter     char *fnname;
104418334Speter{
104518334Speter#ifdef ASM_DECLARE_FUNCTION_SIZE
104618334Speter  ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
104718334Speter#endif
104850397Sobrien  if (! CONSTANT_POOL_BEFORE_FUNCTION)
104950397Sobrien    {
105050397Sobrien      output_constant_pool (fnname, decl);
105150397Sobrien      function_section (decl);	/* need to switch back */
105250397Sobrien    }
105350397Sobrien
105450397Sobrien  /* Output any constants which should appear after the function.  */
105550397Sobrien  output_after_function_constants ();
105618334Speter}
105718334Speter
105818334Speter/* Assemble code to leave SIZE bytes of zeros.  */
105918334Speter
106018334Spetervoid
106118334Speterassemble_zeros (size)
106218334Speter     int size;
106318334Speter{
106452284Sobrien  /* Do no output if -fsyntax-only.  */
106552284Sobrien  if (flag_syntax_only)
106652284Sobrien    return;
106752284Sobrien
106818334Speter#ifdef ASM_NO_SKIP_IN_TEXT
106918334Speter  /* The `space' pseudo in the text section outputs nop insns rather than 0s,
107018334Speter     so we must output 0s explicitly in the text section.  */
107118334Speter  if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
107218334Speter    {
107318334Speter      int i;
107418334Speter
107518334Speter      for (i = 0; i < size - 20; i += 20)
107618334Speter	{
107718334Speter#ifdef ASM_BYTE_OP
107818334Speter	  fprintf (asm_out_file,
107918334Speter		   "%s 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
108018334Speter#else
108118334Speter	  fprintf (asm_out_file,
108218334Speter		   "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
108318334Speter#endif
108418334Speter	}
108518334Speter      if (i < size)
108618334Speter        {
108718334Speter#ifdef ASM_BYTE_OP
108818334Speter	  fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);
108918334Speter#else
109018334Speter	  fprintf (asm_out_file, "\tbyte 0");
109118334Speter#endif
109218334Speter	  i++;
109318334Speter	  for (; i < size; i++)
109418334Speter	    fprintf (asm_out_file, ",0");
109518334Speter	  fprintf (asm_out_file, "\n");
109618334Speter	}
109718334Speter    }
109818334Speter  else
109918334Speter#endif
110018334Speter    if (size > 0)
110150397Sobrien      ASM_OUTPUT_SKIP (asm_out_file, size);
110218334Speter}
110318334Speter
110418334Speter/* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
110518334Speter
110618334Spetervoid
110718334Speterassemble_align (align)
110818334Speter     int align;
110918334Speter{
111018334Speter  if (align > BITS_PER_UNIT)
111118334Speter    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
111218334Speter}
111318334Speter
111418334Speter/* Assemble a string constant with the specified C string as contents.  */
111518334Speter
111618334Spetervoid
111718334Speterassemble_string (p, size)
111852284Sobrien     const char *p;
111918334Speter     int size;
112018334Speter{
112118334Speter  int pos = 0;
112218334Speter  int maximum = 2000;
112318334Speter
112418334Speter  /* If the string is very long, split it up.  */
112518334Speter
112618334Speter  while (pos < size)
112718334Speter    {
112818334Speter      int thissize = size - pos;
112918334Speter      if (thissize > maximum)
113018334Speter	thissize = maximum;
113118334Speter
113250397Sobrien      ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
113318334Speter
113418334Speter      pos += thissize;
113518334Speter      p += thissize;
113618334Speter    }
113718334Speter}
113818334Speter
113918334Speter
114018334Speter/* Assemble everything that is needed for a variable or function declaration.
114118334Speter   Not used for automatic variables, and not used for function definitions.
114218334Speter   Should not be called for variables of incomplete structure type.
114318334Speter
114418334Speter   TOP_LEVEL is nonzero if this variable has file scope.
114518334Speter   AT_END is nonzero if this is the special handling, at end of compilation,
114618334Speter   to define things that have had only tentative definitions.
114718334Speter   DONT_OUTPUT_DATA if nonzero means don't actually output the
114818334Speter   initial value (that will be done by the caller).  */
114918334Speter
115018334Spetervoid
115118334Speterassemble_variable (decl, top_level, at_end, dont_output_data)
115218334Speter     tree decl;
115352284Sobrien     int top_level ATTRIBUTE_UNUSED;
115418334Speter     int at_end;
115518334Speter     int dont_output_data;
115618334Speter{
115718334Speter  register char *name;
115850397Sobrien  unsigned int align;
115918334Speter  tree size_tree;
116018334Speter  int reloc = 0;
116118334Speter  enum in_section saved_in_section;
116218334Speter
116318334Speter  last_assemble_variable_decl = 0;
116418334Speter
116518334Speter  if (GET_CODE (DECL_RTL (decl)) == REG)
116618334Speter    {
116718334Speter      /* Do output symbol info for global register variables, but do nothing
116818334Speter	 else for them.  */
116918334Speter
117018334Speter      if (TREE_ASM_WRITTEN (decl))
117118334Speter	return;
117218334Speter      TREE_ASM_WRITTEN (decl) = 1;
117318334Speter
117452284Sobrien      /* Do no output if -fsyntax-only.  */
117552284Sobrien      if (flag_syntax_only)
117652284Sobrien	return;
117752284Sobrien
117818334Speter#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
117950397Sobrien      /* File-scope global variables are output here.  */
118050397Sobrien      if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
118150397Sobrien	   && top_level)
118250397Sobrien	dbxout_symbol (decl, 0);
118318334Speter#endif
118418334Speter#ifdef SDB_DEBUGGING_INFO
118550397Sobrien      if (write_symbols == SDB_DEBUG && top_level
118650397Sobrien	  /* Leave initialized global vars for end of compilation;
118750397Sobrien	     see comment in compile_file.  */
118850397Sobrien	  && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
118950397Sobrien	sdbout_symbol (decl, 0);
119018334Speter#endif
119118334Speter
119218334Speter      /* Don't output any DWARF debugging information for variables here.
119318334Speter	 In the case of local variables, the information for them is output
119418334Speter	 when we do our recursive traversal of the tree representation for
119518334Speter	 the entire containing function.  In the case of file-scope variables,
119618334Speter	 we output information for all of them at the very end of compilation
119718334Speter	 while we are doing our final traversal of the chain of file-scope
119818334Speter	 declarations.  */
119918334Speter
120018334Speter      return;
120118334Speter    }
120218334Speter
120318334Speter  /* Normally no need to say anything here for external references,
120418334Speter     since assemble_external is called by the language-specific code
120518334Speter     when a declaration is first seen.  */
120618334Speter
120718334Speter  if (DECL_EXTERNAL (decl))
120818334Speter    return;
120918334Speter
121018334Speter  /* Output no assembler code for a function declaration.
121118334Speter     Only definitions of functions output anything.  */
121218334Speter
121318334Speter  if (TREE_CODE (decl) == FUNCTION_DECL)
121418334Speter    return;
121518334Speter
121618334Speter  /* If type was incomplete when the variable was declared,
121718334Speter     see if it is complete now.  */
121818334Speter
121918334Speter  if (DECL_SIZE (decl) == 0)
122018334Speter    layout_decl (decl, 0);
122118334Speter
122218334Speter  /* Still incomplete => don't allocate it; treat the tentative defn
122318334Speter     (which is what it must have been) as an `extern' reference.  */
122418334Speter
122518334Speter  if (!dont_output_data && DECL_SIZE (decl) == 0)
122618334Speter    {
122718334Speter      error_with_file_and_line (DECL_SOURCE_FILE (decl),
122818334Speter				DECL_SOURCE_LINE (decl),
122918334Speter				"storage size of `%s' isn't known",
123018334Speter				IDENTIFIER_POINTER (DECL_NAME (decl)));
123118334Speter      TREE_ASM_WRITTEN (decl) = 1;
123218334Speter      return;
123318334Speter    }
123418334Speter
123518334Speter  /* The first declaration of a variable that comes through this function
123618334Speter     decides whether it is global (in C, has external linkage)
123718334Speter     or local (in C, has internal linkage).  So do nothing more
123818334Speter     if this function has already run.  */
123918334Speter
124018334Speter  if (TREE_ASM_WRITTEN (decl))
124118334Speter    return;
124218334Speter
124318334Speter  TREE_ASM_WRITTEN (decl) = 1;
124418334Speter
124552284Sobrien  /* Do no output if -fsyntax-only.  */
124652284Sobrien  if (flag_syntax_only)
124752284Sobrien    return;
124852284Sobrien
124918334Speter  app_disable ();
125018334Speter
125118334Speter  if (! dont_output_data)
125218334Speter    {
125350397Sobrien      int size;
125450397Sobrien
125518334Speter      if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
125618334Speter	goto finish;
125718334Speter
125818334Speter      /* This is better than explicit arithmetic, since it avoids overflow.  */
125918334Speter      size_tree = size_binop (CEIL_DIV_EXPR,
126050397Sobrien			      DECL_SIZE (decl), size_int (BITS_PER_UNIT));
126118334Speter
126250397Sobrien      size = TREE_INT_CST_LOW (size_tree);
126350397Sobrien      if (TREE_INT_CST_HIGH (size_tree) != 0
126450397Sobrien	  || size != TREE_INT_CST_LOW (size_tree))
126518334Speter	{
126618334Speter	  error_with_decl (decl, "size of variable `%s' is too large");
126718334Speter	  goto finish;
126818334Speter	}
126918334Speter    }
127018334Speter
127118334Speter  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
127218334Speter
127350397Sobrien  if (TREE_PUBLIC (decl) && DECL_NAME (decl)
127450397Sobrien      && ! first_global_object_name
127550397Sobrien      && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
127650397Sobrien				   || DECL_INITIAL (decl) == error_mark_node))
127750397Sobrien      && ! DECL_WEAK (decl)
127850397Sobrien      && ! DECL_ONE_ONLY (decl))
127950397Sobrien    {
128050397Sobrien      char *p;
128150397Sobrien
128250397Sobrien      STRIP_NAME_ENCODING (p, name);
128350397Sobrien      first_global_object_name = permalloc (strlen (p) + 1);
128450397Sobrien      strcpy (first_global_object_name, p);
128550397Sobrien    }
128650397Sobrien
128750397Sobrien  /* Compute the alignment of this data.  */
128850397Sobrien
128950397Sobrien  align = DECL_ALIGN (decl);
129050397Sobrien
129150397Sobrien  /* In the case for initialing an array whose length isn't specified,
129250397Sobrien     where we have not yet been able to do the layout,
129350397Sobrien     figure out the proper alignment now.  */
129450397Sobrien  if (dont_output_data && DECL_SIZE (decl) == 0
129550397Sobrien      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
129650397Sobrien    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
129750397Sobrien
129850397Sobrien  /* Some object file formats have a maximum alignment which they support.
129950397Sobrien     In particular, a.out format supports a maximum alignment of 4.  */
130050397Sobrien#ifndef MAX_OFILE_ALIGNMENT
130150397Sobrien#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
130250397Sobrien#endif
130350397Sobrien  if (align > MAX_OFILE_ALIGNMENT)
130450397Sobrien    {
130550397Sobrien      warning_with_decl (decl,
130650397Sobrien	"alignment of `%s' is greater than maximum object file alignment. Using %d.",
130750397Sobrien                    MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
130850397Sobrien      align = MAX_OFILE_ALIGNMENT;
130950397Sobrien    }
131050397Sobrien
131150397Sobrien  /* On some machines, it is good to increase alignment sometimes.  */
131250397Sobrien#ifdef DATA_ALIGNMENT
131350397Sobrien  align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
131450397Sobrien#endif
131550397Sobrien#ifdef CONSTANT_ALIGNMENT
131650397Sobrien  if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
131750397Sobrien    align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
131850397Sobrien#endif
131950397Sobrien
132050397Sobrien  /* Reset the alignment in case we have made it tighter, so we can benefit
132150397Sobrien     from it in get_pointer_alignment.  */
132250397Sobrien  DECL_ALIGN (decl) = align;
132350397Sobrien
132418334Speter  /* Handle uninitialized definitions.  */
132518334Speter
132650397Sobrien  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
132750397Sobrien      /* If the target can't output uninitialized but not common global data
132850397Sobrien	 in .bss, then we have to use .data.  */
132950397Sobrien#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
133018334Speter      && DECL_COMMON (decl)
133150397Sobrien#endif
133252284Sobrien      && DECL_SECTION_NAME (decl) == 0
133350397Sobrien      && ! dont_output_data)
133418334Speter    {
133518334Speter      int size = TREE_INT_CST_LOW (size_tree);
133618334Speter      int rounded = size;
133718334Speter
133818334Speter      /* Don't allocate zero bytes of common,
133918334Speter	 since that means "undefined external" in the linker.  */
134018334Speter      if (size == 0) rounded = 1;
134118334Speter      /* Round size up to multiple of BIGGEST_ALIGNMENT bits
134218334Speter	 so that each uninitialized object starts on such a boundary.  */
134318334Speter      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
134418334Speter      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
134518334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
134650397Sobrien
134750397Sobrien#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
134850397Sobrien      if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded)
134950397Sobrien         warning_with_decl
135050397Sobrien           (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
135150397Sobrien#endif
135250397Sobrien
135318334Speter#ifdef DBX_DEBUGGING_INFO
135418334Speter      /* File-scope global variables are output here.  */
135518334Speter      if (write_symbols == DBX_DEBUG && top_level)
135618334Speter	dbxout_symbol (decl, 0);
135718334Speter#endif
135818334Speter#ifdef SDB_DEBUGGING_INFO
135918334Speter      if (write_symbols == SDB_DEBUG && top_level
136018334Speter	  /* Leave initialized global vars for end of compilation;
136118334Speter	     see comment in compile_file.  */
136218334Speter	  && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
136318334Speter	sdbout_symbol (decl, 0);
136418334Speter#endif
136518334Speter
136618334Speter      /* Don't output any DWARF debugging information for variables here.
136718334Speter	 In the case of local variables, the information for them is output
136818334Speter	 when we do our recursive traversal of the tree representation for
136918334Speter	 the entire containing function.  In the case of file-scope variables,
137018334Speter	 we output information for all of them at the very end of compilation
137118334Speter	 while we are doing our final traversal of the chain of file-scope
137218334Speter	 declarations.  */
137318334Speter
137450397Sobrien#if 0 /* ??? We should either delete this or add a comment describing what
137550397Sobrien	 it was intended to do and why we shouldn't delete it.  */
137618334Speter      if (flag_shared_data)
137718334Speter	data_section ();
137818334Speter#endif
137950397Sobrien
138050397Sobrien      if (TREE_PUBLIC (decl)
138150397Sobrien#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
138250397Sobrien	  && DECL_COMMON (decl)
138350397Sobrien#endif
138450397Sobrien	  )
138518334Speter	{
138618334Speter#ifdef ASM_OUTPUT_SHARED_COMMON
138718334Speter	  if (flag_shared_data)
138818334Speter	    ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
138918334Speter	  else
139018334Speter#endif
139118334Speter	      {
139250397Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_COMMON
139350397Sobrien		ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size,
139450397Sobrien						   DECL_ALIGN (decl));
139550397Sobrien#else
139618334Speter#ifdef ASM_OUTPUT_ALIGNED_COMMON
139718334Speter		ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
139818334Speter					   DECL_ALIGN (decl));
139918334Speter#else
140018334Speter		ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
140118334Speter#endif
140250397Sobrien#endif
140318334Speter	      }
140418334Speter	}
140550397Sobrien#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
140650397Sobrien      else if (TREE_PUBLIC (decl))
140750397Sobrien	{
140850397Sobrien#ifdef ASM_OUTPUT_SHARED_BSS
140950397Sobrien	  if (flag_shared_data)
141050397Sobrien	    ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
141150397Sobrien	  else
141250397Sobrien#endif
141350397Sobrien	      {
141450397Sobrien#ifdef ASM_OUTPUT_ALIGNED_BSS
141550397Sobrien		ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
141650397Sobrien					DECL_ALIGN (decl));
141750397Sobrien#else
141850397Sobrien		ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
141950397Sobrien#endif
142050397Sobrien	      }
142150397Sobrien	}
142250397Sobrien#endif /* ASM_OUTPUT_BSS || ASM_OUTPUT_ALIGNED_BSS */
142318334Speter      else
142418334Speter	{
142518334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL
142618334Speter	  if (flag_shared_data)
142718334Speter	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
142818334Speter	  else
142918334Speter#endif
143018334Speter	      {
143150397Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
143250397Sobrien		ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size,
143350397Sobrien						  DECL_ALIGN (decl));
143450397Sobrien#else
143518334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
143618334Speter		ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
143718334Speter					  DECL_ALIGN (decl));
143818334Speter#else
143918334Speter		ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
144018334Speter#endif
144150397Sobrien#endif
144218334Speter	      }
144318334Speter	}
144418334Speter      goto finish;
144518334Speter    }
144618334Speter
144750397Sobrien  /* Handle initialized definitions.
144850397Sobrien     Also handle uninitialized global definitions if -fno-common and the
144950397Sobrien     target doesn't support ASM_OUTPUT_BSS.  */
145018334Speter
145118334Speter  /* First make the assembler name(s) global if appropriate.  */
145218334Speter  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
145318334Speter    {
145418334Speter#ifdef ASM_WEAKEN_LABEL
145552284Sobrien      if (DECL_WEAK (decl))
145652284Sobrien	{
145752284Sobrien	  ASM_WEAKEN_LABEL (asm_out_file, name);
145852284Sobrien	   /* Remove this variable from the pending weak list so that
145952284Sobrien	      we do not emit multiple .weak directives for it.  */
146052284Sobrien	  remove_from_pending_weak_list
146152284Sobrien	    (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
146252284Sobrien	}
146318334Speter      else
146418334Speter#endif
146518334Speter      ASM_GLOBALIZE_LABEL (asm_out_file, name);
146618334Speter    }
146718334Speter#if 0
146818334Speter  for (d = equivalents; d; d = TREE_CHAIN (d))
146918334Speter    {
147018334Speter      tree e = TREE_VALUE (d);
147118334Speter      if (TREE_PUBLIC (e) && DECL_NAME (e))
147218334Speter	ASM_GLOBALIZE_LABEL (asm_out_file,
147318334Speter			     XSTR (XEXP (DECL_RTL (e), 0), 0));
147418334Speter    }
147518334Speter#endif
147618334Speter
147718334Speter  /* Output any data that we will need to use the address of.  */
147818334Speter  if (DECL_INITIAL (decl) == error_mark_node)
147918334Speter    reloc = contains_pointers_p (TREE_TYPE (decl));
148018334Speter  else if (DECL_INITIAL (decl))
148118334Speter    reloc = output_addressed_constants (DECL_INITIAL (decl));
148218334Speter
148350397Sobrien#ifdef ASM_OUTPUT_SECTION_NAME
148452284Sobrien  if ((flag_data_sections != 0
148552284Sobrien       && DECL_SECTION_NAME (decl) == NULL_TREE)
148652284Sobrien      || UNIQUE_SECTION_P (decl))
148750397Sobrien    UNIQUE_SECTION (decl, reloc);
148818334Speter#endif
148918334Speter
149050397Sobrien  /* Switch to the appropriate section.  */
149150397Sobrien  variable_section (decl, reloc);
149250397Sobrien
149318334Speter  /* dbxout.c needs to know this.  */
149418334Speter  if (in_text_section ())
149518334Speter    DECL_IN_TEXT_SECTION (decl) = 1;
149618334Speter
149718334Speter  /* Record current section so we can restore it if dbxout.c clobbers it.  */
149818334Speter  saved_in_section = in_section;
149918334Speter
150018334Speter  /* Output the dbx info now that we have chosen the section.  */
150118334Speter
150218334Speter#ifdef DBX_DEBUGGING_INFO
150318334Speter  /* File-scope global variables are output here.  */
150418334Speter  if (write_symbols == DBX_DEBUG && top_level)
150518334Speter    dbxout_symbol (decl, 0);
150618334Speter#endif
150718334Speter#ifdef SDB_DEBUGGING_INFO
150818334Speter  if (write_symbols == SDB_DEBUG && top_level
150918334Speter      /* Leave initialized global vars for end of compilation;
151018334Speter	 see comment in compile_file.  */
151118334Speter      && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
151218334Speter    sdbout_symbol (decl, 0);
151318334Speter#endif
151418334Speter
151518334Speter  /* Don't output any DWARF debugging information for variables here.
151618334Speter     In the case of local variables, the information for them is output
151718334Speter     when we do our recursive traversal of the tree representation for
151818334Speter     the entire containing function.  In the case of file-scope variables,
151918334Speter     we output information for all of them at the very end of compilation
152018334Speter     while we are doing our final traversal of the chain of file-scope
152118334Speter     declarations.  */
152218334Speter
152318334Speter  /* If the debugging output changed sections, reselect the section
152418334Speter     that's supposed to be selected.  */
152518334Speter  if (in_section != saved_in_section)
152650397Sobrien    variable_section (decl, reloc);
152718334Speter
152850397Sobrien  /* Output the alignment of this data.  */
152918334Speter  if (align > BITS_PER_UNIT)
153050397Sobrien    ASM_OUTPUT_ALIGN (asm_out_file,
153150397Sobrien		      floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
153218334Speter
153318334Speter  /* Do any machine/system dependent processing of the object.  */
153418334Speter#ifdef ASM_DECLARE_OBJECT_NAME
153518334Speter  last_assemble_variable_decl = decl;
153618334Speter  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
153718334Speter#else
153818334Speter  /* Standard thing is just output label for the object.  */
153950397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, name);
154018334Speter#endif /* ASM_DECLARE_OBJECT_NAME */
154118334Speter
154218334Speter  if (!dont_output_data)
154318334Speter    {
154418334Speter      if (DECL_INITIAL (decl))
154518334Speter	/* Output the actual data.  */
154618334Speter	output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
154718334Speter      else
154818334Speter	/* Leave space for it.  */
154918334Speter	assemble_zeros (TREE_INT_CST_LOW (size_tree));
155018334Speter    }
155118334Speter
155218334Speter finish:
155318334Speter#ifdef XCOFF_DEBUGGING_INFO
155418334Speter  /* Unfortunately, the IBM assembler cannot handle stabx before the actual
155518334Speter     declaration.  When something like ".stabx  "aa:S-2",aa,133,0" is emitted
155618334Speter     and `aa' hasn't been output yet, the assembler generates a stab entry with
155718334Speter     a value of zero, in addition to creating an unnecessary external entry
155818334Speter     for `aa'.  Hence, we must postpone dbxout_symbol to here at the end.  */
155918334Speter
156018334Speter  /* File-scope global variables are output here.  */
156118334Speter  if (write_symbols == XCOFF_DEBUG && top_level)
156218334Speter    {
156318334Speter      saved_in_section = in_section;
156418334Speter
156518334Speter      dbxout_symbol (decl, 0);
156618334Speter
156718334Speter      if (in_section != saved_in_section)
156850397Sobrien	variable_section (decl, reloc);
156918334Speter    }
157018334Speter#else
157118334Speter  /* There must be a statement after a label.  */
157218334Speter  ;
157318334Speter#endif
157418334Speter}
157518334Speter
157618334Speter/* Return 1 if type TYPE contains any pointers.  */
157718334Speter
157818334Speterstatic int
157918334Spetercontains_pointers_p (type)
158018334Speter     tree type;
158118334Speter{
158218334Speter  switch (TREE_CODE (type))
158318334Speter    {
158418334Speter    case POINTER_TYPE:
158518334Speter    case REFERENCE_TYPE:
158618334Speter      /* I'm not sure whether OFFSET_TYPE needs this treatment,
158718334Speter	 so I'll play safe and return 1.  */
158818334Speter    case OFFSET_TYPE:
158918334Speter      return 1;
159018334Speter
159118334Speter    case RECORD_TYPE:
159218334Speter    case UNION_TYPE:
159318334Speter    case QUAL_UNION_TYPE:
159418334Speter      {
159518334Speter	tree fields;
159618334Speter	/* For a type that has fields, see if the fields have pointers.  */
159718334Speter	for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
159818334Speter	  if (TREE_CODE (fields) == FIELD_DECL
159918334Speter	      && contains_pointers_p (TREE_TYPE (fields)))
160018334Speter	    return 1;
160118334Speter	return 0;
160218334Speter      }
160318334Speter
160418334Speter    case ARRAY_TYPE:
160518334Speter      /* An array type contains pointers if its element type does.  */
160618334Speter      return contains_pointers_p (TREE_TYPE (type));
160718334Speter
160818334Speter    default:
160918334Speter      return 0;
161018334Speter    }
161118334Speter}
161218334Speter
161318334Speter/* Output something to declare an external symbol to the assembler.
161418334Speter   (Most assemblers don't need this, so we normally output nothing.)
161518334Speter   Do nothing if DECL is not external.  */
161618334Speter
161718334Spetervoid
161818334Speterassemble_external (decl)
161952284Sobrien     tree decl ATTRIBUTE_UNUSED;
162018334Speter{
162118334Speter#ifdef ASM_OUTPUT_EXTERNAL
162218334Speter  if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
162318334Speter      && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
162418334Speter    {
162518334Speter      rtx rtl = DECL_RTL (decl);
162618334Speter
162718334Speter      if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
162818334Speter	  && ! SYMBOL_REF_USED (XEXP (rtl, 0)))
162918334Speter	{
163018334Speter	  /* Some systems do require some output.  */
163118334Speter	  SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
163218334Speter	  ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
163318334Speter	}
163418334Speter    }
163518334Speter#endif
163618334Speter}
163718334Speter
163818334Speter/* Similar, for calling a library function FUN.  */
163918334Speter
164018334Spetervoid
164118334Speterassemble_external_libcall (fun)
164252284Sobrien     rtx fun ATTRIBUTE_UNUSED;
164318334Speter{
164418334Speter#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
164550397Sobrien  /* Declare library function name external when first used, if nec.  */
164650397Sobrien  if (! SYMBOL_REF_USED (fun))
164718334Speter    {
164850397Sobrien      SYMBOL_REF_USED (fun) = 1;
164950397Sobrien      ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
165018334Speter    }
165118334Speter#endif
165218334Speter}
165318334Speter
165418334Speter/* Declare the label NAME global.  */
165518334Speter
165618334Spetervoid
165718334Speterassemble_global (name)
165818334Speter     char *name;
165918334Speter{
166018334Speter  ASM_GLOBALIZE_LABEL (asm_out_file, name);
166118334Speter}
166218334Speter
166318334Speter/* Assemble a label named NAME.  */
166418334Speter
166518334Spetervoid
166618334Speterassemble_label (name)
166718334Speter     char *name;
166818334Speter{
166950397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, name);
167018334Speter}
167118334Speter
167218334Speter/* Output to FILE a reference to the assembler name of a C-level name NAME.
167318334Speter   If NAME starts with a *, the rest of NAME is output verbatim.
167418334Speter   Otherwise NAME is transformed in an implementation-defined way
167518334Speter   (usually by the addition of an underscore).
167618334Speter   Many macros in the tm file are defined to call this function.  */
167718334Speter
167818334Spetervoid
167918334Speterassemble_name (file, name)
168018334Speter     FILE *file;
168118334Speter     char *name;
168218334Speter{
168318334Speter  char *real_name;
168450397Sobrien  tree id;
168518334Speter
168618334Speter  STRIP_NAME_ENCODING (real_name, name);
168750397Sobrien  if (flag_prefix_function_name
168850397Sobrien      && ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
168950397Sobrien    real_name = real_name + CHKR_PREFIX_SIZE;
169018334Speter
169150397Sobrien  id = maybe_get_identifier (real_name);
169250397Sobrien  if (id)
169350397Sobrien    TREE_SYMBOL_REFERENCED (id) = 1;
169418334Speter
169518334Speter  if (name[0] == '*')
169650397Sobrien    fputs (&name[1], file);
169718334Speter  else
169850397Sobrien    ASM_OUTPUT_LABELREF (file, name);
169918334Speter}
170018334Speter
170118334Speter/* Allocate SIZE bytes writable static space with a gensym name
170218334Speter   and return an RTX to refer to its address.  */
170318334Speter
170418334Speterrtx
170518334Speterassemble_static_space (size)
170618334Speter     int size;
170718334Speter{
170818334Speter  char name[12];
170918334Speter  char *namestring;
171018334Speter  rtx x;
171118334Speter
171218334Speter#if 0
171318334Speter  if (flag_shared_data)
171418334Speter    data_section ();
171518334Speter#endif
171618334Speter
171718334Speter  ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
171818334Speter  ++const_labelno;
171918334Speter
172018334Speter  namestring = (char *) obstack_alloc (saveable_obstack,
172118334Speter				       strlen (name) + 2);
172218334Speter  strcpy (namestring, name);
172318334Speter
172450397Sobrien  x = gen_rtx_SYMBOL_REF (Pmode, namestring);
172518334Speter
172650397Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
172750397Sobrien  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
172850397Sobrien				 BIGGEST_ALIGNMENT);
172950397Sobrien#else
173018334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
173150397Sobrien  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
173218334Speter#else
173350397Sobrien  {
173450397Sobrien    /* Round size up to multiple of BIGGEST_ALIGNMENT bits
173550397Sobrien       so that each uninitialized object starts on such a boundary.  */
173652284Sobrien    /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL. */
173752284Sobrien    int rounded ATTRIBUTE_UNUSED
173852284Sobrien      = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
173952284Sobrien	 / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
174052284Sobrien	 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
174150397Sobrien    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
174250397Sobrien  }
174318334Speter#endif
174450397Sobrien#endif
174518334Speter  return x;
174618334Speter}
174718334Speter
174818334Speter/* Assemble the static constant template for function entry trampolines.
174918334Speter   This is done at most once per compilation.
175018334Speter   Returns an RTX for the address of the template.  */
175118334Speter
175248743Sobrien#ifdef TRAMPOLINE_TEMPLATE
175318334Speterrtx
175418334Speterassemble_trampoline_template ()
175518334Speter{
175618334Speter  char label[256];
175718334Speter  char *name;
175818334Speter  int align;
175918334Speter
176018334Speter  /* By default, put trampoline templates in read-only data section.  */
176118334Speter
176218334Speter#ifdef TRAMPOLINE_SECTION
176318334Speter  TRAMPOLINE_SECTION ();
176418334Speter#else
176518334Speter  readonly_data_section ();
176618334Speter#endif
176718334Speter
176818334Speter  /* Write the assembler code to define one.  */
176950397Sobrien  align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
177018334Speter  if (align > 0)
177118334Speter    ASM_OUTPUT_ALIGN (asm_out_file, align);
177218334Speter
177318334Speter  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0);
177418334Speter  TRAMPOLINE_TEMPLATE (asm_out_file);
177518334Speter
177618334Speter  /* Record the rtl to refer to it.  */
177718334Speter  ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
177818334Speter  name
177918334Speter    = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
178050397Sobrien  return gen_rtx_SYMBOL_REF (Pmode, name);
178118334Speter}
178248743Sobrien#endif
178318334Speter
178418334Speter/* Assemble the integer constant X into an object of SIZE bytes.
178518334Speter   X must be either a CONST_INT or CONST_DOUBLE.
178618334Speter
178718334Speter   Return 1 if we were able to output the constant, otherwise 0.  If FORCE is
178818334Speter   non-zero, abort if we can't output the constant.  */
178918334Speter
179018334Speterint
179118334Speterassemble_integer (x, size, force)
179218334Speter     rtx x;
179318334Speter     int size;
179418334Speter     int force;
179518334Speter{
179618334Speter  /* First try to use the standard 1, 2, 4, 8, and 16 byte
179750397Sobrien     ASM_OUTPUT... macros.  */
179818334Speter
179918334Speter  switch (size)
180018334Speter    {
180118334Speter#ifdef ASM_OUTPUT_CHAR
180218334Speter    case 1:
180318334Speter      ASM_OUTPUT_CHAR (asm_out_file, x);
180418334Speter      return 1;
180518334Speter#endif
180618334Speter
180718334Speter#ifdef ASM_OUTPUT_SHORT
180818334Speter    case 2:
180918334Speter      ASM_OUTPUT_SHORT (asm_out_file, x);
181018334Speter      return 1;
181118334Speter#endif
181218334Speter
181318334Speter#ifdef ASM_OUTPUT_INT
181418334Speter    case 4:
181518334Speter      ASM_OUTPUT_INT (asm_out_file, x);
181618334Speter      return 1;
181718334Speter#endif
181818334Speter
181918334Speter#ifdef ASM_OUTPUT_DOUBLE_INT
182018334Speter    case 8:
182118334Speter      ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);
182218334Speter      return 1;
182318334Speter#endif
182418334Speter
182518334Speter#ifdef ASM_OUTPUT_QUADRUPLE_INT
182618334Speter    case 16:
182718334Speter      ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x);
182818334Speter      return 1;
182918334Speter#endif
183018334Speter    }
183118334Speter
183218334Speter  /* If we couldn't do it that way, there are two other possibilities: First,
183318334Speter     if the machine can output an explicit byte and this is a 1 byte constant,
183418334Speter     we can use ASM_OUTPUT_BYTE.  */
183518334Speter
183618334Speter#ifdef ASM_OUTPUT_BYTE
183718334Speter  if (size == 1 && GET_CODE (x) == CONST_INT)
183818334Speter    {
183918334Speter      ASM_OUTPUT_BYTE (asm_out_file, INTVAL (x));
184018334Speter      return 1;
184118334Speter    }
184218334Speter#endif
184318334Speter
184418334Speter  /* Finally, if SIZE is larger than a single word, try to output the constant
184518334Speter     one word at a time.  */
184618334Speter
184718334Speter  if (size > UNITS_PER_WORD)
184818334Speter    {
184918334Speter      int i;
185018334Speter      enum machine_mode mode
185118334Speter	= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
185218334Speter      rtx word;
185318334Speter
185418334Speter      for (i = 0; i < size / UNITS_PER_WORD; i++)
185518334Speter	{
185618334Speter	  word = operand_subword (x, i, 0, mode);
185718334Speter
185818334Speter	  if (word == 0)
185918334Speter	    break;
186018334Speter
186118334Speter	  if (! assemble_integer (word, UNITS_PER_WORD, 0))
186218334Speter	    break;
186318334Speter	}
186418334Speter
186518334Speter      if (i == size / UNITS_PER_WORD)
186618334Speter	return 1;
186718334Speter      /* If we output at least one word and then could not finish,
186818334Speter	 there is no valid way to continue.  */
186918334Speter      if (i > 0)
187018334Speter	abort ();
187118334Speter    }
187218334Speter
187318334Speter  if (force)
187418334Speter    abort ();
187518334Speter
187618334Speter  return 0;
187718334Speter}
187818334Speter
187918334Speter/* Assemble the floating-point constant D into an object of size MODE.  */
188018334Speter
188118334Spetervoid
188218334Speterassemble_real (d, mode)
188318334Speter     REAL_VALUE_TYPE d;
188418334Speter     enum machine_mode mode;
188518334Speter{
188618334Speter  jmp_buf output_constant_handler;
188718334Speter
188818334Speter  if (setjmp (output_constant_handler))
188918334Speter    {
189018334Speter      error ("floating point trap outputting a constant");
189118334Speter#ifdef REAL_IS_NOT_DOUBLE
189218334Speter      bzero ((char *) &d, sizeof d);
189318334Speter      d = dconst0;
189418334Speter#else
189518334Speter      d = 0;
189618334Speter#endif
189718334Speter    }
189818334Speter
189918334Speter  set_float_handler (output_constant_handler);
190018334Speter
190118334Speter  switch (mode)
190218334Speter    {
190318334Speter#ifdef ASM_OUTPUT_BYTE_FLOAT
190418334Speter    case QFmode:
190518334Speter      ASM_OUTPUT_BYTE_FLOAT (asm_out_file, d);
190618334Speter      break;
190718334Speter#endif
190818334Speter#ifdef ASM_OUTPUT_SHORT_FLOAT
190918334Speter    case HFmode:
191018334Speter      ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
191118334Speter      break;
191218334Speter#endif
191318334Speter#ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
191418334Speter    case TQFmode:
191518334Speter      ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
191618334Speter      break;
191718334Speter#endif
191818334Speter#ifdef ASM_OUTPUT_FLOAT
191918334Speter    case SFmode:
192018334Speter      ASM_OUTPUT_FLOAT (asm_out_file, d);
192118334Speter      break;
192218334Speter#endif
192318334Speter
192418334Speter#ifdef ASM_OUTPUT_DOUBLE
192518334Speter    case DFmode:
192618334Speter      ASM_OUTPUT_DOUBLE (asm_out_file, d);
192718334Speter      break;
192818334Speter#endif
192918334Speter
193018334Speter#ifdef ASM_OUTPUT_LONG_DOUBLE
193118334Speter    case XFmode:
193218334Speter    case TFmode:
193318334Speter      ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d);
193418334Speter      break;
193518334Speter#endif
193618334Speter
193718334Speter    default:
193818334Speter      abort ();
193918334Speter    }
194018334Speter
194118334Speter  set_float_handler (NULL_PTR);
194218334Speter}
194318334Speter
194418334Speter/* Here we combine duplicate floating constants to make
194518334Speter   CONST_DOUBLE rtx's, and force those out to memory when necessary.  */
194618334Speter
194718334Speter/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
194818334Speter   They are chained through the CONST_DOUBLE_CHAIN.
194918334Speter   A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
195018334Speter   In that case, CONST_DOUBLE_MEM is either a MEM,
195118334Speter   or const0_rtx if no MEM has been made for this CONST_DOUBLE yet.
195218334Speter
195318334Speter   (CONST_DOUBLE_MEM is used only for top-level functions.
195418334Speter   See force_const_mem for explanation.)  */
195518334Speter
195618334Speterstatic rtx const_double_chain;
195718334Speter
195818334Speter/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints.
195918334Speter   For an integer, I0 is the low-order word and I1 is the high-order word.
196018334Speter   For a real number, I0 is the word with the low address
196118334Speter   and I1 is the word with the high address.  */
196218334Speter
196318334Speterrtx
196418334Speterimmed_double_const (i0, i1, mode)
196518334Speter     HOST_WIDE_INT i0, i1;
196618334Speter     enum machine_mode mode;
196718334Speter{
196818334Speter  register rtx r;
196918334Speter
197018334Speter  if (GET_MODE_CLASS (mode) == MODE_INT
197118334Speter      || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
197218334Speter    {
197318334Speter      /* We clear out all bits that don't belong in MODE, unless they and our
197418334Speter	 sign bit are all one.  So we get either a reasonable negative value
197518334Speter	 or a reasonable unsigned value for this mode.  */
197618334Speter      int width = GET_MODE_BITSIZE (mode);
197718334Speter      if (width < HOST_BITS_PER_WIDE_INT
197818334Speter	  && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1)))
197918334Speter	      != ((HOST_WIDE_INT) (-1) << (width - 1))))
198018334Speter	i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0;
198118334Speter      else if (width == HOST_BITS_PER_WIDE_INT
198218334Speter	       && ! (i1 == ~0 && i0 < 0))
198318334Speter	i1 = 0;
198418334Speter      else if (width > 2 * HOST_BITS_PER_WIDE_INT)
198518334Speter	/* We cannot represent this value as a constant.  */
198618334Speter	abort ();
198718334Speter
198818334Speter      /* If this would be an entire word for the target, but is not for
198918334Speter	 the host, then sign-extend on the host so that the number will look
199018334Speter	 the same way on the host that it would on the target.
199118334Speter
199218334Speter	 For example, when building a 64 bit alpha hosted 32 bit sparc
199318334Speter	 targeted compiler, then we want the 32 bit unsigned value -1 to be
199418334Speter	 represented as a 64 bit value -1, and not as 0x00000000ffffffff.
199518334Speter	 The later confuses the sparc backend.  */
199618334Speter
199718334Speter      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
199818334Speter	  && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
199918334Speter	i0 |= ((HOST_WIDE_INT) (-1) << width);
200018334Speter
200118334Speter      /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a CONST_INT.
200218334Speter
200318334Speter	 ??? Strictly speaking, this is wrong if we create a CONST_INT
200418334Speter	 for a large unsigned constant with the size of MODE being
200518334Speter	 HOST_BITS_PER_WIDE_INT and later try to interpret that constant in a
200618334Speter	 wider mode.  In that case we will mis-interpret it as a negative
200718334Speter	 number.
200818334Speter
200918334Speter	 Unfortunately, the only alternative is to make a CONST_DOUBLE
201018334Speter	 for any constant in any mode if it is an unsigned constant larger
201118334Speter	 than the maximum signed integer in an int on the host.  However,
201218334Speter	 doing this will break everyone that always expects to see a CONST_INT
201318334Speter	 for SImode and smaller.
201418334Speter
201518334Speter	 We have always been making CONST_INTs in this case, so nothing new
201618334Speter	 is being broken.  */
201718334Speter
201818334Speter      if (width <= HOST_BITS_PER_WIDE_INT)
201950397Sobrien	i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
202018334Speter
202118334Speter      /* If this integer fits in one word, return a CONST_INT.  */
202218334Speter      if ((i1 == 0 && i0 >= 0)
202318334Speter	  || (i1 == ~0 && i0 < 0))
202418334Speter	return GEN_INT (i0);
202518334Speter
202618334Speter      /* We use VOIDmode for integers.  */
202718334Speter      mode = VOIDmode;
202818334Speter    }
202918334Speter
203018334Speter  /* Search the chain for an existing CONST_DOUBLE with the right value.
203118334Speter     If one is found, return it.  */
203218334Speter
203318334Speter  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
203418334Speter    if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
203518334Speter	&& GET_MODE (r) == mode)
203618334Speter      return r;
203718334Speter
203818334Speter  /* No; make a new one and add it to the chain.
203918334Speter
204018334Speter     We may be called by an optimizer which may be discarding any memory
204118334Speter     allocated during its processing (such as combine and loop).  However,
204218334Speter     we will be leaving this constant on the chain, so we cannot tolerate
204318334Speter     freed memory.  So switch to saveable_obstack for this allocation
204418334Speter     and then switch back if we were in current_obstack.  */
204518334Speter
204618334Speter  push_obstacks_nochange ();
204718334Speter  rtl_in_saveable_obstack ();
204850397Sobrien  r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1);
204918334Speter  pop_obstacks ();
205018334Speter
205118334Speter  /* Don't touch const_double_chain in nested function; see force_const_mem.
205218334Speter     Also, don't touch it if not inside any function.  */
205318334Speter  if (outer_function_chain == 0 && current_function_decl != 0)
205418334Speter    {
205518334Speter      CONST_DOUBLE_CHAIN (r) = const_double_chain;
205618334Speter      const_double_chain = r;
205718334Speter    }
205818334Speter
205918334Speter  /* Store const0_rtx in mem-slot since this CONST_DOUBLE is on the chain.
206018334Speter     Actual use of mem-slot is only through force_const_mem.  */
206118334Speter
206218334Speter  CONST_DOUBLE_MEM (r) = const0_rtx;
206318334Speter
206418334Speter  return r;
206518334Speter}
206618334Speter
206718334Speter/* Return a CONST_DOUBLE for a specified `double' value
206818334Speter   and machine mode.  */
206918334Speter
207018334Speterrtx
207118334Speterimmed_real_const_1 (d, mode)
207218334Speter     REAL_VALUE_TYPE d;
207318334Speter     enum machine_mode mode;
207418334Speter{
207518334Speter  union real_extract u;
207618334Speter  register rtx r;
207718334Speter
207818334Speter  /* Get the desired `double' value as a sequence of ints
207918334Speter     since that is how they are stored in a CONST_DOUBLE.  */
208018334Speter
208118334Speter  u.d = d;
208218334Speter
208318334Speter  /* Detect special cases.  */
208418334Speter
208550397Sobrien  if (REAL_VALUES_IDENTICAL (dconst0, d))
208618334Speter    return CONST0_RTX (mode);
208718334Speter  /* Check for NaN first, because some ports (specifically the i386) do not
208818334Speter     emit correct ieee-fp code by default, and thus will generate a core
208918334Speter     dump here if we pass a NaN to REAL_VALUES_EQUAL and if REAL_VALUES_EQUAL
209018334Speter     does a floating point comparison.  */
209118334Speter  else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
209218334Speter    return CONST1_RTX (mode);
209318334Speter
209450397Sobrien  if (sizeof u == sizeof (HOST_WIDE_INT))
209550397Sobrien    return immed_double_const (u.i[0], 0, mode);
209618334Speter  if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
209718334Speter    return immed_double_const (u.i[0], u.i[1], mode);
209818334Speter
209918334Speter  /* The rest of this function handles the case where
210018334Speter     a float value requires more than 2 ints of space.
210118334Speter     It will be deleted as dead code on machines that don't need it.  */
210218334Speter
210318334Speter  /* Search the chain for an existing CONST_DOUBLE with the right value.
210418334Speter     If one is found, return it.  */
210518334Speter
210618334Speter  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
210718334Speter    if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
210818334Speter	&& GET_MODE (r) == mode)
210918334Speter      return r;
211018334Speter
211118334Speter  /* No; make a new one and add it to the chain.
211218334Speter
211318334Speter     We may be called by an optimizer which may be discarding any memory
211418334Speter     allocated during its processing (such as combine and loop).  However,
211518334Speter     we will be leaving this constant on the chain, so we cannot tolerate
211618334Speter     freed memory.  So switch to saveable_obstack for this allocation
211718334Speter     and then switch back if we were in current_obstack.  */
211818334Speter
211918334Speter  push_obstacks_nochange ();
212018334Speter  rtl_in_saveable_obstack ();
212118334Speter  r = rtx_alloc (CONST_DOUBLE);
212218334Speter  PUT_MODE (r, mode);
212318334Speter  bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
212418334Speter  pop_obstacks ();
212518334Speter
212618334Speter  /* Don't touch const_double_chain in nested function; see force_const_mem.
212718334Speter     Also, don't touch it if not inside any function.  */
212818334Speter  if (outer_function_chain == 0 && current_function_decl != 0)
212918334Speter    {
213018334Speter      CONST_DOUBLE_CHAIN (r) = const_double_chain;
213118334Speter      const_double_chain = r;
213218334Speter    }
213318334Speter
213418334Speter  /* Store const0_rtx in CONST_DOUBLE_MEM since this CONST_DOUBLE is on the
213518334Speter     chain, but has not been allocated memory.  Actual use of CONST_DOUBLE_MEM
213618334Speter     is only through force_const_mem.  */
213718334Speter
213818334Speter  CONST_DOUBLE_MEM (r) = const0_rtx;
213918334Speter
214018334Speter  return r;
214118334Speter}
214218334Speter
214318334Speter/* Return a CONST_DOUBLE rtx for a value specified by EXP,
214418334Speter   which must be a REAL_CST tree node.  */
214518334Speter
214618334Speterrtx
214718334Speterimmed_real_const (exp)
214818334Speter     tree exp;
214918334Speter{
215018334Speter  return immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)));
215118334Speter}
215218334Speter
215318334Speter/* At the end of a function, forget the memory-constants
215418334Speter   previously made for CONST_DOUBLEs.  Mark them as not on real_constant_chain.
215518334Speter   Also clear out real_constant_chain and clear out all the chain-pointers.  */
215618334Speter
215718334Spetervoid
215818334Speterclear_const_double_mem ()
215918334Speter{
216018334Speter  register rtx r, next;
216118334Speter
216218334Speter  /* Don't touch CONST_DOUBLE_MEM for nested functions.
216318334Speter     See force_const_mem for explanation.  */
216418334Speter  if (outer_function_chain != 0)
216518334Speter    return;
216618334Speter
216718334Speter  for (r = const_double_chain; r; r = next)
216818334Speter    {
216918334Speter      next = CONST_DOUBLE_CHAIN (r);
217018334Speter      CONST_DOUBLE_CHAIN (r) = 0;
217118334Speter      CONST_DOUBLE_MEM (r) = cc0_rtx;
217218334Speter    }
217318334Speter  const_double_chain = 0;
217418334Speter}
217518334Speter
217618334Speter/* Given an expression EXP with a constant value,
217718334Speter   reduce it to the sum of an assembler symbol and an integer.
217818334Speter   Store them both in the structure *VALUE.
217918334Speter   Abort if EXP does not reduce.  */
218018334Speter
218118334Speterstruct addr_const
218218334Speter{
218318334Speter  rtx base;
218418334Speter  HOST_WIDE_INT offset;
218518334Speter};
218618334Speter
218718334Speterstatic void
218818334Speterdecode_addr_const (exp, value)
218918334Speter     tree exp;
219018334Speter     struct addr_const *value;
219118334Speter{
219218334Speter  register tree target = TREE_OPERAND (exp, 0);
219318334Speter  register int offset = 0;
219418334Speter  register rtx x;
219518334Speter
219618334Speter  while (1)
219718334Speter    {
219818334Speter      if (TREE_CODE (target) == COMPONENT_REF
219918334Speter	  && (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1)))
220018334Speter	      == INTEGER_CST))
220118334Speter	{
220218334Speter	  offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) / BITS_PER_UNIT;
220318334Speter	  target = TREE_OPERAND (target, 0);
220418334Speter	}
220518334Speter      else if (TREE_CODE (target) == ARRAY_REF)
220618334Speter	{
220718334Speter	  if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST
220818334Speter	      || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST)
220918334Speter	    abort ();
221018334Speter	  offset += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target)))
221118334Speter		      * TREE_INT_CST_LOW (TREE_OPERAND (target, 1)))
221218334Speter		     / BITS_PER_UNIT);
221318334Speter	  target = TREE_OPERAND (target, 0);
221418334Speter	}
221518334Speter      else
221618334Speter	break;
221718334Speter    }
221818334Speter
221918334Speter  switch (TREE_CODE (target))
222018334Speter    {
222118334Speter    case VAR_DECL:
222218334Speter    case FUNCTION_DECL:
222318334Speter      x = DECL_RTL (target);
222418334Speter      break;
222518334Speter
222618334Speter    case LABEL_DECL:
222750397Sobrien      x = gen_rtx_MEM (FUNCTION_MODE,
222850397Sobrien		       gen_rtx_LABEL_REF (VOIDmode,
222950397Sobrien					  label_rtx (TREE_OPERAND (exp, 0))));
223018334Speter      break;
223118334Speter
223218334Speter    case REAL_CST:
223318334Speter    case STRING_CST:
223418334Speter    case COMPLEX_CST:
223518334Speter    case CONSTRUCTOR:
223650397Sobrien    case INTEGER_CST:
223718334Speter      x = TREE_CST_RTL (target);
223818334Speter      break;
223918334Speter
224018334Speter    default:
224118334Speter      abort ();
224218334Speter    }
224318334Speter
224450397Sobrien  if (GET_CODE (x) != MEM)
224550397Sobrien    abort ();
224650397Sobrien  x = XEXP (x, 0);
224718334Speter
224818334Speter  value->base = x;
224918334Speter  value->offset = offset;
225018334Speter}
225118334Speter
225218334Speter/* Uniquize all constants that appear in memory.
225318334Speter   Each constant in memory thus far output is recorded
225418334Speter   in `const_hash_table' with a `struct constant_descriptor'
225518334Speter   that contains a polish representation of the value of
225618334Speter   the constant.
225718334Speter
225818334Speter   We cannot store the trees in the hash table
225918334Speter   because the trees may be temporary.  */
226018334Speter
226118334Speterstruct constant_descriptor
226218334Speter{
226318334Speter  struct constant_descriptor *next;
226418334Speter  char *label;
226518334Speter  char contents[1];
226618334Speter};
226718334Speter
226818334Speter#define HASHBITS 30
226918334Speter#define MAX_HASH_TABLE 1009
227018334Speterstatic struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
227118334Speter
227218334Speter/* Compute a hash code for a constant expression.  */
227318334Speter
227418334Speterstatic int
227518334Speterconst_hash (exp)
227618334Speter     tree exp;
227718334Speter{
227818334Speter  register char *p;
227918334Speter  register int len, hi, i;
228018334Speter  register enum tree_code code = TREE_CODE (exp);
228118334Speter
228250397Sobrien  /* Either set P and LEN to the address and len of something to hash and
228350397Sobrien     exit the switch or return a value.  */
228450397Sobrien
228550397Sobrien  switch (code)
228618334Speter    {
228750397Sobrien    case INTEGER_CST:
228818334Speter      p = (char *) &TREE_INT_CST_LOW (exp);
228918334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
229050397Sobrien      break;
229150397Sobrien
229250397Sobrien    case REAL_CST:
229318334Speter      p = (char *) &TREE_REAL_CST (exp);
229418334Speter      len = sizeof TREE_REAL_CST (exp);
229550397Sobrien      break;
229618334Speter
229750397Sobrien    case STRING_CST:
229850397Sobrien      p = TREE_STRING_POINTER (exp);
229950397Sobrien      len = TREE_STRING_LENGTH (exp);
230050397Sobrien      break;
230118334Speter
230250397Sobrien    case COMPLEX_CST:
230350397Sobrien      return (const_hash (TREE_REALPART (exp)) * 5
230450397Sobrien	      + const_hash (TREE_IMAGPART (exp)));
230518334Speter
230650397Sobrien    case CONSTRUCTOR:
230750397Sobrien      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
230818334Speter	{
230950397Sobrien	  len = int_size_in_bytes (TREE_TYPE (exp));
231050397Sobrien	  p = (char *) alloca (len);
231150397Sobrien	  get_set_constructor_bytes (exp, (unsigned char *) p, len);
231250397Sobrien	  break;
231318334Speter	}
231450397Sobrien      else
231550397Sobrien	{
231650397Sobrien	  register tree link;
231718334Speter
231850397Sobrien	  /* For record type, include the type in the hashing.
231950397Sobrien	     We do not do so for array types
232050397Sobrien	     because (1) the sizes of the elements are sufficient
232150397Sobrien	     and (2) distinct array types can have the same constructor.
232250397Sobrien	     Instead, we include the array size because the constructor could
232350397Sobrien	     be shorter.  */
232450397Sobrien	  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
232550397Sobrien	    hi = ((unsigned long) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
232650397Sobrien	      % MAX_HASH_TABLE;
232750397Sobrien	  else
232850397Sobrien	    hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
232950397Sobrien		  & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
233050397Sobrien
233150397Sobrien	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
233250397Sobrien	    if (TREE_VALUE (link))
233350397Sobrien	      hi
233450397Sobrien		= (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
233550397Sobrien
233650397Sobrien	  return hi;
233750397Sobrien	}
233850397Sobrien
233950397Sobrien    case ADDR_EXPR:
234050397Sobrien      {
234150397Sobrien	struct addr_const value;
234250397Sobrien
234350397Sobrien	decode_addr_const (exp, &value);
234450397Sobrien	if (GET_CODE (value.base) == SYMBOL_REF)
234550397Sobrien	  {
234650397Sobrien	    /* Don't hash the address of the SYMBOL_REF;
234750397Sobrien	       only use the offset and the symbol name.  */
234850397Sobrien	    hi = value.offset;
234950397Sobrien	    p = XSTR (value.base, 0);
235050397Sobrien	    for (i = 0; p[i] != 0; i++)
235150397Sobrien	      hi = ((hi * 613) + (unsigned) (p[i]));
235250397Sobrien	  }
235350397Sobrien	else if (GET_CODE (value.base) == LABEL_REF)
235450397Sobrien	  hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
235550397Sobrien
235650397Sobrien	hi &= (1 << HASHBITS) - 1;
235750397Sobrien	hi %= MAX_HASH_TABLE;
235850397Sobrien      }
235918334Speter      return hi;
236050397Sobrien
236150397Sobrien    case PLUS_EXPR:
236250397Sobrien    case MINUS_EXPR:
236350397Sobrien      return (const_hash (TREE_OPERAND (exp, 0)) * 9
236450397Sobrien	      + const_hash (TREE_OPERAND (exp, 1)));
236550397Sobrien
236650397Sobrien    case NOP_EXPR:
236750397Sobrien    case CONVERT_EXPR:
236850397Sobrien    case NON_LVALUE_EXPR:
236950397Sobrien      return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
237050397Sobrien
237150397Sobrien    default:
237250397Sobrien      abort ();
237318334Speter    }
237418334Speter
237518334Speter  /* Compute hashing function */
237618334Speter  hi = len;
237718334Speter  for (i = 0; i < len; i++)
237850397Sobrien    hi = ((hi * 613) + (unsigned) (p[i]));
237918334Speter
238018334Speter  hi &= (1 << HASHBITS) - 1;
238118334Speter  hi %= MAX_HASH_TABLE;
238218334Speter  return hi;
238318334Speter}
238418334Speter
238518334Speter/* Compare a constant expression EXP with a constant-descriptor DESC.
238618334Speter   Return 1 if DESC describes a constant with the same value as EXP.  */
238718334Speter
238818334Speterstatic int
238918334Spetercompare_constant (exp, desc)
239018334Speter     tree exp;
239118334Speter     struct constant_descriptor *desc;
239218334Speter{
239318334Speter  return 0 != compare_constant_1 (exp, desc->contents);
239418334Speter}
239518334Speter
239618334Speter/* Compare constant expression EXP with a substring P of a constant descriptor.
239718334Speter   If they match, return a pointer to the end of the substring matched.
239818334Speter   If they do not match, return 0.
239918334Speter
240018334Speter   Since descriptors are written in polish prefix notation,
240118334Speter   this function can be used recursively to test one operand of EXP
240218334Speter   against a subdescriptor, and if it succeeds it returns the
240318334Speter   address of the subdescriptor for the next operand.  */
240418334Speter
240518334Speterstatic char *
240618334Spetercompare_constant_1 (exp, p)
240718334Speter     tree exp;
240818334Speter     char *p;
240918334Speter{
241018334Speter  register char *strp;
241118334Speter  register int len;
241218334Speter  register enum tree_code code = TREE_CODE (exp);
241318334Speter
241418334Speter  if (code != (enum tree_code) *p++)
241518334Speter    return 0;
241618334Speter
241750397Sobrien  /* Either set STRP, P and LEN to pointers and length to compare and exit the
241850397Sobrien     switch, or return the result of the comparison.  */
241950397Sobrien
242050397Sobrien  switch (code)
242118334Speter    {
242250397Sobrien    case INTEGER_CST:
242318334Speter      /* Integer constants are the same only if the same width of type.  */
242418334Speter      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
242518334Speter	return 0;
242650397Sobrien
242718334Speter      strp = (char *) &TREE_INT_CST_LOW (exp);
242818334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
242950397Sobrien      break;
243050397Sobrien
243150397Sobrien    case REAL_CST:
243218334Speter      /* Real constants are the same only if the same width of type.  */
243318334Speter      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
243418334Speter	return 0;
243550397Sobrien
243618334Speter      strp = (char *) &TREE_REAL_CST (exp);
243718334Speter      len = sizeof TREE_REAL_CST (exp);
243850397Sobrien      break;
243950397Sobrien
244050397Sobrien    case STRING_CST:
244118334Speter      if (flag_writable_strings)
244218334Speter	return 0;
244350397Sobrien
244450397Sobrien      if (*p++ != TYPE_MODE (TREE_TYPE (exp)))
244550397Sobrien	return 0;
244650397Sobrien
244718334Speter      strp = TREE_STRING_POINTER (exp);
244818334Speter      len = TREE_STRING_LENGTH (exp);
244918334Speter      if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
245018334Speter		sizeof TREE_STRING_LENGTH (exp)))
245118334Speter	return 0;
245250397Sobrien
245318334Speter      p += sizeof TREE_STRING_LENGTH (exp);
245450397Sobrien      break;
245550397Sobrien
245650397Sobrien    case COMPLEX_CST:
245718334Speter      p = compare_constant_1 (TREE_REALPART (exp), p);
245850397Sobrien      if (p == 0)
245918334Speter	return 0;
246018334Speter
246150397Sobrien      return compare_constant_1 (TREE_IMAGPART (exp), p);
246218334Speter
246350397Sobrien    case CONSTRUCTOR:
246450397Sobrien      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
246518334Speter	{
246650397Sobrien	  int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
246750397Sobrien
246850397Sobrien	  strp = (char *) alloca (len);
246950397Sobrien	  get_set_constructor_bytes (exp, (unsigned char *) strp, len);
247050397Sobrien	  if (bcmp ((char *) &xlen, p, sizeof xlen))
247118334Speter	    return 0;
247250397Sobrien
247350397Sobrien	  p += sizeof xlen;
247450397Sobrien	  break;
247518334Speter	}
247650397Sobrien      else
247750397Sobrien	{
247850397Sobrien	  register tree link;
247950397Sobrien	  int length = list_length (CONSTRUCTOR_ELTS (exp));
248050397Sobrien	  tree type;
248150397Sobrien	  int have_purpose = 0;
248218334Speter
248350397Sobrien	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
248450397Sobrien	    if (TREE_PURPOSE (link))
248550397Sobrien	      have_purpose = 1;
248650397Sobrien
248750397Sobrien	  if (bcmp ((char *) &length, p, sizeof length))
248850397Sobrien	    return 0;
248950397Sobrien
249050397Sobrien	  p += sizeof length;
249150397Sobrien
249250397Sobrien	  /* For record constructors, insist that the types match.
249350397Sobrien	     For arrays, just verify both constructors are for arrays.
249450397Sobrien	     Then insist that either both or none have any TREE_PURPOSE
249550397Sobrien	     values.  */
249650397Sobrien	  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
249750397Sobrien	    type = TREE_TYPE (exp);
249850397Sobrien	  else
249950397Sobrien	    type = 0;
250050397Sobrien
250150397Sobrien	  if (bcmp ((char *) &type, p, sizeof type))
250250397Sobrien	    return 0;
250350397Sobrien
250450397Sobrien	  p += sizeof type;
250550397Sobrien
250650397Sobrien	  if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
250750397Sobrien	    return 0;
250850397Sobrien
250950397Sobrien	  p += sizeof have_purpose;
251050397Sobrien
251150397Sobrien	  /* For arrays, insist that the size in bytes match.  */
251250397Sobrien	  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
251318334Speter	    {
251450397Sobrien	      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
251550397Sobrien
251650397Sobrien	      if (bcmp ((char *) &size, p, sizeof size))
251718334Speter		return 0;
251850397Sobrien
251950397Sobrien	      p += sizeof size;
252018334Speter	    }
252150397Sobrien
252250397Sobrien	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
252318334Speter	    {
252450397Sobrien	      if (TREE_VALUE (link))
252550397Sobrien		{
252650397Sobrien		  if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
252750397Sobrien		    return 0;
252850397Sobrien		}
252950397Sobrien	      else
253050397Sobrien		{
253150397Sobrien		  tree zero = 0;
253218334Speter
253350397Sobrien		  if (bcmp ((char *) &zero, p, sizeof zero))
253450397Sobrien		    return 0;
253550397Sobrien
253650397Sobrien		  p += sizeof zero;
253750397Sobrien		}
253850397Sobrien
253950397Sobrien	      if (TREE_PURPOSE (link)
254050397Sobrien		  && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
254150397Sobrien		{
254250397Sobrien		  if (bcmp ((char *) &TREE_PURPOSE (link), p,
254350397Sobrien			    sizeof TREE_PURPOSE (link)))
254450397Sobrien		    return 0;
254550397Sobrien
254650397Sobrien		  p += sizeof TREE_PURPOSE (link);
254750397Sobrien		}
254850397Sobrien	      else if (TREE_PURPOSE (link))
254950397Sobrien		{
255050397Sobrien		  if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0)
255150397Sobrien		    return 0;
255250397Sobrien		}
255350397Sobrien	      else if (have_purpose)
255450397Sobrien		{
255550397Sobrien		  int zero = 0;
255650397Sobrien
255750397Sobrien		  if (bcmp ((char *) &zero, p, sizeof zero))
255850397Sobrien		    return 0;
255950397Sobrien
256050397Sobrien		  p += sizeof zero;
256150397Sobrien		}
256218334Speter	    }
256350397Sobrien
256450397Sobrien	  return p;
256518334Speter	}
256618334Speter
256750397Sobrien    case ADDR_EXPR:
256850397Sobrien      {
256950397Sobrien	struct addr_const value;
257050397Sobrien
257150397Sobrien	decode_addr_const (exp, &value);
257250397Sobrien	strp = (char *) &value.offset;
257350397Sobrien	len = sizeof value.offset;
257450397Sobrien	/* Compare the offset.  */
257550397Sobrien	while (--len >= 0)
257650397Sobrien	  if (*p++ != *strp++)
257750397Sobrien	    return 0;
257850397Sobrien
257950397Sobrien	/* Compare symbol name.  */
258050397Sobrien	strp = XSTR (value.base, 0);
258150397Sobrien	len = strlen (strp) + 1;
258250397Sobrien      }
258350397Sobrien      break;
258450397Sobrien
258550397Sobrien    case PLUS_EXPR:
258650397Sobrien    case MINUS_EXPR:
258752284Sobrien    case RANGE_EXPR:
258818334Speter      p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
258950397Sobrien      if (p == 0)
259050397Sobrien	return 0;
259150397Sobrien
259250397Sobrien      return compare_constant_1 (TREE_OPERAND (exp, 1), p);
259350397Sobrien
259450397Sobrien    case NOP_EXPR:
259550397Sobrien    case CONVERT_EXPR:
259650397Sobrien    case NON_LVALUE_EXPR:
259750397Sobrien      return compare_constant_1 (TREE_OPERAND (exp, 0), p);
259850397Sobrien
259950397Sobrien    default:
260050397Sobrien      abort ();
260118334Speter    }
260218334Speter
260318334Speter  /* Compare constant contents.  */
260418334Speter  while (--len >= 0)
260518334Speter    if (*p++ != *strp++)
260618334Speter      return 0;
260718334Speter
260818334Speter  return p;
260918334Speter}
261018334Speter
261118334Speter/* Construct a constant descriptor for the expression EXP.
261218334Speter   It is up to the caller to enter the descriptor in the hash table.  */
261318334Speter
261418334Speterstatic struct constant_descriptor *
261518334Speterrecord_constant (exp)
261618334Speter     tree exp;
261718334Speter{
261818334Speter  struct constant_descriptor *next = 0;
261918334Speter  char *label = 0;
262018334Speter
262118334Speter  /* Make a struct constant_descriptor.  The first two pointers will
262218334Speter     be filled in later.  Here we just leave space for them.  */
262318334Speter
262418334Speter  obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
262518334Speter  obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
262618334Speter  record_constant_1 (exp);
262718334Speter  return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
262818334Speter}
262918334Speter
263018334Speter/* Add a description of constant expression EXP
263118334Speter   to the object growing in `permanent_obstack'.
263218334Speter   No need to return its address; the caller will get that
263318334Speter   from the obstack when the object is complete.  */
263418334Speter
263518334Speterstatic void
263618334Speterrecord_constant_1 (exp)
263718334Speter     tree exp;
263818334Speter{
263918334Speter  register char *strp;
264018334Speter  register int len;
264118334Speter  register enum tree_code code = TREE_CODE (exp);
264218334Speter
264318334Speter  obstack_1grow (&permanent_obstack, (unsigned int) code);
264418334Speter
264518334Speter  switch (code)
264618334Speter    {
264718334Speter    case INTEGER_CST:
264818334Speter      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
264918334Speter      strp = (char *) &TREE_INT_CST_LOW (exp);
265018334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
265118334Speter      break;
265218334Speter
265318334Speter    case REAL_CST:
265418334Speter      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
265518334Speter      strp = (char *) &TREE_REAL_CST (exp);
265618334Speter      len = sizeof TREE_REAL_CST (exp);
265718334Speter      break;
265818334Speter
265918334Speter    case STRING_CST:
266018334Speter      if (flag_writable_strings)
266118334Speter	return;
266218334Speter
266350397Sobrien      obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
266418334Speter      strp = TREE_STRING_POINTER (exp);
266518334Speter      len = TREE_STRING_LENGTH (exp);
266618334Speter      obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
266718334Speter		    sizeof TREE_STRING_LENGTH (exp));
266818334Speter      break;
266918334Speter
267018334Speter    case COMPLEX_CST:
267118334Speter      record_constant_1 (TREE_REALPART (exp));
267218334Speter      record_constant_1 (TREE_IMAGPART (exp));
267318334Speter      return;
267418334Speter
267518334Speter    case CONSTRUCTOR:
267618334Speter      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
267718334Speter	{
267818334Speter	  int nbytes = int_size_in_bytes (TREE_TYPE (exp));
267918334Speter	  obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
268018334Speter	  obstack_blank (&permanent_obstack, nbytes);
268118334Speter	  get_set_constructor_bytes
268250397Sobrien	    (exp, (unsigned char *) permanent_obstack.next_free-nbytes,
268350397Sobrien	     nbytes);
268418334Speter	  return;
268518334Speter	}
268618334Speter      else
268718334Speter	{
268818334Speter	  register tree link;
268918334Speter	  int length = list_length (CONSTRUCTOR_ELTS (exp));
269018334Speter	  tree type;
269150397Sobrien	  int have_purpose = 0;
269218334Speter
269350397Sobrien	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
269450397Sobrien	    if (TREE_PURPOSE (link))
269550397Sobrien	      have_purpose = 1;
269650397Sobrien
269718334Speter	  obstack_grow (&permanent_obstack, (char *) &length, sizeof length);
269818334Speter
269918334Speter	  /* For record constructors, insist that the types match.
270050397Sobrien	     For arrays, just verify both constructors are for arrays.
270150397Sobrien	     Then insist that either both or none have any TREE_PURPOSE
270250397Sobrien	     values.  */
270318334Speter	  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
270418334Speter	    type = TREE_TYPE (exp);
270518334Speter	  else
270618334Speter	    type = 0;
270718334Speter	  obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
270850397Sobrien	  obstack_grow (&permanent_obstack, (char *) &have_purpose,
270950397Sobrien			sizeof have_purpose);
271018334Speter
271118334Speter	  /* For arrays, insist that the size in bytes match.  */
271218334Speter	  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
271318334Speter	    {
271450397Sobrien	      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
271518334Speter	      obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
271618334Speter	    }
271718334Speter
271818334Speter	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
271918334Speter	    {
272018334Speter	      if (TREE_VALUE (link))
272118334Speter		record_constant_1 (TREE_VALUE (link));
272218334Speter	      else
272318334Speter		{
272418334Speter		  tree zero = 0;
272518334Speter
272618334Speter		  obstack_grow (&permanent_obstack,
272718334Speter				(char *) &zero, sizeof zero);
272818334Speter		}
272950397Sobrien
273050397Sobrien	      if (TREE_PURPOSE (link)
273150397Sobrien		  && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
273250397Sobrien		obstack_grow (&permanent_obstack,
273350397Sobrien			      (char *) &TREE_PURPOSE (link),
273450397Sobrien			      sizeof TREE_PURPOSE (link));
273550397Sobrien	      else if (TREE_PURPOSE (link))
273650397Sobrien		record_constant_1 (TREE_PURPOSE (link));
273750397Sobrien	      else if (have_purpose)
273850397Sobrien		{
273950397Sobrien		  int zero = 0;
274050397Sobrien
274150397Sobrien		  obstack_grow (&permanent_obstack,
274250397Sobrien				(char *) &zero, sizeof zero);
274350397Sobrien		}
274418334Speter	    }
274518334Speter	}
274618334Speter      return;
274718334Speter
274818334Speter    case ADDR_EXPR:
274918334Speter      {
275018334Speter	struct addr_const value;
275118334Speter
275218334Speter	decode_addr_const (exp, &value);
275318334Speter	/* Record the offset.  */
275418334Speter	obstack_grow (&permanent_obstack,
275518334Speter		      (char *) &value.offset, sizeof value.offset);
275618334Speter	/* Record the symbol name.  */
275718334Speter	obstack_grow (&permanent_obstack, XSTR (value.base, 0),
275818334Speter		      strlen (XSTR (value.base, 0)) + 1);
275918334Speter      }
276018334Speter      return;
276118334Speter
276218334Speter    case PLUS_EXPR:
276318334Speter    case MINUS_EXPR:
276452284Sobrien    case RANGE_EXPR:
276518334Speter      record_constant_1 (TREE_OPERAND (exp, 0));
276618334Speter      record_constant_1 (TREE_OPERAND (exp, 1));
276718334Speter      return;
276818334Speter
276918334Speter    case NOP_EXPR:
277018334Speter    case CONVERT_EXPR:
277118334Speter    case NON_LVALUE_EXPR:
277218334Speter      record_constant_1 (TREE_OPERAND (exp, 0));
277318334Speter      return;
277418334Speter
277518334Speter    default:
277618334Speter      abort ();
277718334Speter    }
277818334Speter
277918334Speter  /* Record constant contents.  */
278018334Speter  obstack_grow (&permanent_obstack, strp, len);
278118334Speter}
278218334Speter
278318334Speter/* Record a list of constant expressions that were passed to
278418334Speter   output_constant_def but that could not be output right away.  */
278518334Speter
278618334Speterstruct deferred_constant
278718334Speter{
278818334Speter  struct deferred_constant *next;
278918334Speter  tree exp;
279018334Speter  int reloc;
279118334Speter  int labelno;
279218334Speter};
279318334Speter
279418334Speterstatic struct deferred_constant *deferred_constants;
279518334Speter
279650397Sobrien/* Another list of constants which should be output after the
279750397Sobrien   function.  */
279850397Sobrienstatic struct deferred_constant *after_function_constants;
279950397Sobrien
280018334Speter/* Nonzero means defer output of addressed subconstants
280118334Speter   (i.e., those for which output_constant_def is called.)  */
280218334Speterstatic int defer_addressed_constants_flag;
280318334Speter
280418334Speter/* Start deferring output of subconstants.  */
280518334Speter
280618334Spetervoid
280718334Speterdefer_addressed_constants ()
280818334Speter{
280918334Speter  defer_addressed_constants_flag++;
281018334Speter}
281118334Speter
281218334Speter/* Stop deferring output of subconstants,
281318334Speter   and output now all those that have been deferred.  */
281418334Speter
281518334Spetervoid
281618334Speteroutput_deferred_addressed_constants ()
281718334Speter{
281818334Speter  struct deferred_constant *p, *next;
281918334Speter
282018334Speter  defer_addressed_constants_flag--;
282118334Speter
282218334Speter  if (defer_addressed_constants_flag > 0)
282318334Speter    return;
282418334Speter
282518334Speter  for (p = deferred_constants; p; p = next)
282618334Speter    {
282718334Speter      output_constant_def_contents (p->exp, p->reloc, p->labelno);
282818334Speter      next = p->next;
282918334Speter      free (p);
283018334Speter    }
283118334Speter
283218334Speter  deferred_constants = 0;
283318334Speter}
283418334Speter
283550397Sobrien/* Output any constants which should appear after a function.  */
283650397Sobrien
283750397Sobrienstatic void
283850397Sobrienoutput_after_function_constants ()
283950397Sobrien{
284050397Sobrien  struct deferred_constant *p, *next;
284150397Sobrien
284250397Sobrien  for (p = after_function_constants; p; p = next)
284350397Sobrien    {
284450397Sobrien      output_constant_def_contents (p->exp, p->reloc, p->labelno);
284550397Sobrien      next = p->next;
284650397Sobrien      free (p);
284750397Sobrien    }
284850397Sobrien
284950397Sobrien  after_function_constants = 0;
285050397Sobrien}
285150397Sobrien
285218334Speter/* Make a copy of the whole tree structure for a constant.
285318334Speter   This handles the same types of nodes that compare_constant
285418334Speter   and record_constant handle.  */
285518334Speter
285618334Speterstatic tree
285718334Spetercopy_constant (exp)
285818334Speter     tree exp;
285918334Speter{
286018334Speter  switch (TREE_CODE (exp))
286118334Speter    {
286218334Speter    case ADDR_EXPR:
286318334Speter      /* For ADDR_EXPR, we do not want to copy the decl whose address
286418334Speter	 is requested.  We do want to copy constants though.  */
286518334Speter      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
286618334Speter	return build1 (TREE_CODE (exp), TREE_TYPE (exp),
286718334Speter		       copy_constant (TREE_OPERAND (exp, 0)));
286818334Speter      else
286918334Speter	return copy_node (exp);
287018334Speter
287118334Speter    case INTEGER_CST:
287218334Speter    case REAL_CST:
287318334Speter    case STRING_CST:
287418334Speter      return copy_node (exp);
287518334Speter
287618334Speter    case COMPLEX_CST:
287750397Sobrien      return build_complex (TREE_TYPE (exp),
287850397Sobrien			    copy_constant (TREE_REALPART (exp)),
287918334Speter			    copy_constant (TREE_IMAGPART (exp)));
288018334Speter
288118334Speter    case PLUS_EXPR:
288218334Speter    case MINUS_EXPR:
288318334Speter      return build (TREE_CODE (exp), TREE_TYPE (exp),
288418334Speter		    copy_constant (TREE_OPERAND (exp, 0)),
288518334Speter		    copy_constant (TREE_OPERAND (exp, 1)));
288618334Speter
288718334Speter    case NOP_EXPR:
288818334Speter    case CONVERT_EXPR:
288950397Sobrien    case NON_LVALUE_EXPR:
289018334Speter      return build1 (TREE_CODE (exp), TREE_TYPE (exp),
289118334Speter		     copy_constant (TREE_OPERAND (exp, 0)));
289218334Speter
289318334Speter    case CONSTRUCTOR:
289418334Speter      {
289518334Speter	tree copy = copy_node (exp);
289618334Speter	tree list = copy_list (CONSTRUCTOR_ELTS (exp));
289718334Speter	tree tail;
289818334Speter
289918334Speter	CONSTRUCTOR_ELTS (copy) = list;
290018334Speter	for (tail = list; tail; tail = TREE_CHAIN (tail))
290118334Speter	  TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
290218334Speter	if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
290318334Speter	  for (tail = list; tail; tail = TREE_CHAIN (tail))
290418334Speter	    TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
290518334Speter
290618334Speter	return copy;
290718334Speter      }
290818334Speter
290918334Speter    default:
291018334Speter      abort ();
291118334Speter    }
291218334Speter}
291318334Speter
291418334Speter/* Return an rtx representing a reference to constant data in memory
291518334Speter   for the constant expression EXP.
291618334Speter
291718334Speter   If assembler code for such a constant has already been output,
291818334Speter   return an rtx to refer to it.
291918334Speter   Otherwise, output such a constant in memory (or defer it for later)
292018334Speter   and generate an rtx for it.
292118334Speter
292218334Speter   The TREE_CST_RTL of EXP is set up to point to that rtx.
292318334Speter   The const_hash_table records which constants already have label strings.  */
292418334Speter
292518334Speterrtx
292618334Speteroutput_constant_def (exp)
292718334Speter     tree exp;
292818334Speter{
292918334Speter  register int hash;
293018334Speter  register struct constant_descriptor *desc;
293118334Speter  char label[256];
293218334Speter  char *found = 0;
293318334Speter  int reloc;
293418334Speter  register rtx def;
293518334Speter
293618334Speter  if (TREE_CST_RTL (exp))
293718334Speter    return TREE_CST_RTL (exp);
293818334Speter
293918334Speter  /* Make sure any other constants whose addresses appear in EXP
294018334Speter     are assigned label numbers.  */
294118334Speter
294218334Speter  reloc = output_addressed_constants (exp);
294318334Speter
294418334Speter  /* Compute hash code of EXP.  Search the descriptors for that hash code
294518334Speter     to see if any of them describes EXP.  If yes, the descriptor records
294618334Speter     the label number already assigned.  */
294718334Speter
294818334Speter  hash = const_hash (exp) % MAX_HASH_TABLE;
294918334Speter
295018334Speter  for (desc = const_hash_table[hash]; desc; desc = desc->next)
295118334Speter    if (compare_constant (exp, desc))
295218334Speter      {
295318334Speter	found = desc->label;
295418334Speter	break;
295518334Speter      }
295618334Speter
295718334Speter  if (found == 0)
295818334Speter    {
295918334Speter      /* No constant equal to EXP is known to have been output.
296018334Speter	 Make a constant descriptor to enter EXP in the hash table.
296118334Speter	 Assign the label number and record it in the descriptor for
296218334Speter	 future calls to this function to find.  */
296318334Speter
296418334Speter      /* Create a string containing the label name, in LABEL.  */
296518334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
296618334Speter
296718334Speter      desc = record_constant (exp);
296818334Speter      desc->next = const_hash_table[hash];
296918334Speter      desc->label
297018334Speter	= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
297118334Speter      const_hash_table[hash] = desc;
297218334Speter    }
297318334Speter  else
297418334Speter    {
297518334Speter      /* Create a string containing the label name, in LABEL.  */
297618334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
297718334Speter    }
297818334Speter
297918334Speter  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
298018334Speter
298118334Speter  push_obstacks_nochange ();
298218334Speter  if (TREE_PERMANENT (exp))
298318334Speter    end_temporary_allocation ();
298418334Speter
298550397Sobrien  def = gen_rtx_SYMBOL_REF (Pmode, desc->label);
298618334Speter
298718334Speter  TREE_CST_RTL (exp)
298850397Sobrien    = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), def);
298918334Speter  RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
299018334Speter  if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
299152284Sobrien    MEM_SET_IN_STRUCT_P (TREE_CST_RTL (exp), 1);
299218334Speter
299318334Speter  pop_obstacks ();
299418334Speter
299518334Speter  /* Optionally set flags or add text to the name to record information
299618334Speter     such as that it is a function name.  If the name is changed, the macro
299718334Speter     ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
299818334Speter#ifdef ENCODE_SECTION_INFO
299918334Speter  ENCODE_SECTION_INFO (exp);
300018334Speter#endif
300118334Speter
300218334Speter  /* If this is the first time we've seen this particular constant,
300318334Speter     output it (or defer its output for later).  */
300418334Speter  if (found == 0)
300518334Speter    {
300650397Sobrien      int after_function = 0;
300750397Sobrien
300850397Sobrien#ifdef CONSTANT_AFTER_FUNCTION_P
300950397Sobrien      if (current_function_decl != 0
301050397Sobrien	  && CONSTANT_AFTER_FUNCTION_P (exp))
301150397Sobrien	after_function = 1;
301250397Sobrien#endif
301350397Sobrien
301450397Sobrien      if (defer_addressed_constants_flag || after_function)
301518334Speter	{
301618334Speter	  struct deferred_constant *p;
301718334Speter	  p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
301818334Speter
301918334Speter	  push_obstacks_nochange ();
302018334Speter	  suspend_momentary ();
302118334Speter	  p->exp = copy_constant (exp);
302218334Speter	  pop_obstacks ();
302318334Speter	  p->reloc = reloc;
302418334Speter	  p->labelno = const_labelno++;
302550397Sobrien	  if (after_function)
302650397Sobrien	    {
302750397Sobrien	      p->next = after_function_constants;
302850397Sobrien	      after_function_constants = p;
302950397Sobrien	    }
303050397Sobrien	  else
303150397Sobrien	    {
303250397Sobrien	      p->next = deferred_constants;
303350397Sobrien	      deferred_constants = p;
303450397Sobrien	    }
303518334Speter	}
303618334Speter      else
303752284Sobrien	{
303852284Sobrien	  /* Do no output if -fsyntax-only.  */
303952284Sobrien	  if (! flag_syntax_only)
304052284Sobrien	    output_constant_def_contents (exp, reloc, const_labelno);
304152284Sobrien	  ++const_labelno;
304252284Sobrien	}
304318334Speter    }
304418334Speter
304518334Speter  return TREE_CST_RTL (exp);
304618334Speter}
304718334Speter
304818334Speter/* Now output assembler code to define the label for EXP,
304918334Speter   and follow it with the data of EXP.  */
305018334Speter
305118334Speterstatic void
305218334Speteroutput_constant_def_contents (exp, reloc, labelno)
305318334Speter     tree exp;
305418334Speter     int reloc;
305518334Speter     int labelno;
305618334Speter{
305718334Speter  int align;
305818334Speter
305918334Speter  if (IN_NAMED_SECTION (exp))
306050397Sobrien    named_section (exp, NULL, reloc);
306118334Speter  else
306218334Speter    {
306318334Speter      /* First switch to text section, except for writable strings.  */
306418334Speter#ifdef SELECT_SECTION
306518334Speter      SELECT_SECTION (exp, reloc);
306618334Speter#else
306718334Speter      if (((TREE_CODE (exp) == STRING_CST) && flag_writable_strings)
306818334Speter	  || (flag_pic && reloc))
306918334Speter	data_section ();
307018334Speter      else
307118334Speter	readonly_data_section ();
307218334Speter#endif
307318334Speter    }
307418334Speter
307518334Speter  /* Align the location counter as required by EXP's data type.  */
307618334Speter  align = TYPE_ALIGN (TREE_TYPE (exp));
307718334Speter#ifdef CONSTANT_ALIGNMENT
307818334Speter  align = CONSTANT_ALIGNMENT (exp, align);
307918334Speter#endif
308018334Speter
308118334Speter  if (align > BITS_PER_UNIT)
308250397Sobrien    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
308318334Speter
308418334Speter  /* Output the label itself.  */
308518334Speter  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
308618334Speter
308718334Speter  /* Output the value of EXP.  */
308818334Speter  output_constant (exp,
308918334Speter		   (TREE_CODE (exp) == STRING_CST
309018334Speter		    ? TREE_STRING_LENGTH (exp)
309118334Speter		    : int_size_in_bytes (TREE_TYPE (exp))));
309218334Speter
309318334Speter}
309418334Speter
309518334Speter/* Similar hash facility for making memory-constants
309618334Speter   from constant rtl-expressions.  It is used on RISC machines
309718334Speter   where immediate integer arguments and constant addresses are restricted
309818334Speter   so that such constants must be stored in memory.
309918334Speter
310018334Speter   This pool of constants is reinitialized for each function
310118334Speter   so each function gets its own constants-pool that comes right before it.
310218334Speter
310318334Speter   All structures allocated here are discarded when functions are saved for
310418334Speter   inlining, so they do not need to be allocated permanently.  */
310518334Speter
310618334Speter#define MAX_RTX_HASH_TABLE 61
310718334Speterstatic struct constant_descriptor **const_rtx_hash_table;
310818334Speter
310918334Speter/* Structure to represent sufficient information about a constant so that
311018334Speter   it can be output when the constant pool is output, so that function
311118334Speter   integration can be done, and to simplify handling on machines that reference
311218334Speter   constant pool as base+displacement.  */
311318334Speter
311418334Speterstruct pool_constant
311518334Speter{
311618334Speter  struct constant_descriptor *desc;
311718334Speter  struct pool_constant *next;
311818334Speter  enum machine_mode mode;
311918334Speter  rtx constant;
312018334Speter  int labelno;
312118334Speter  int align;
312218334Speter  int offset;
312350397Sobrien  int mark;
312418334Speter};
312518334Speter
312618334Speter/* Pointers to first and last constant in pool.  */
312718334Speter
312818334Speterstatic struct pool_constant *first_pool, *last_pool;
312918334Speter
313018334Speter/* Current offset in constant pool (does not include any machine-specific
313118334Speter   header.  */
313218334Speter
313318334Speterstatic int pool_offset;
313418334Speter
313518334Speter/* Structure used to maintain hash table mapping symbols used to their
313618334Speter   corresponding constants.  */
313718334Speter
313818334Speterstruct pool_sym
313918334Speter{
314018334Speter  char *label;
314118334Speter  struct pool_constant *pool;
314218334Speter  struct pool_sym *next;
314318334Speter};
314418334Speter
314518334Speterstatic struct pool_sym **const_rtx_sym_hash_table;
314618334Speter
314718334Speter/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
314818334Speter   The argument is XSTR (... , 0)  */
314918334Speter
315018334Speter#define SYMHASH(LABEL)	\
315150397Sobrien  ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1))  % MAX_RTX_HASH_TABLE)
315218334Speter
315318334Speter/* Initialize constant pool hashing for next function.  */
315418334Speter
315518334Spetervoid
315618334Speterinit_const_rtx_hash_table ()
315718334Speter{
315818334Speter  const_rtx_hash_table
315918334Speter    = ((struct constant_descriptor **)
316018334Speter       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
316118334Speter  const_rtx_sym_hash_table
316218334Speter    = ((struct pool_sym **)
316318334Speter       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
316418334Speter  bzero ((char *) const_rtx_hash_table,
316518334Speter	 MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
316618334Speter  bzero ((char *) const_rtx_sym_hash_table,
316718334Speter	 MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
316818334Speter
316918334Speter  first_pool = last_pool = 0;
317018334Speter  pool_offset = 0;
317118334Speter}
317218334Speter
317318334Speter/* Save and restore status for a nested function.  */
317418334Speter
317518334Spetervoid
317650397Sobriensave_varasm_status (p, context)
317718334Speter     struct function *p;
317850397Sobrien     tree context;
317918334Speter{
318018334Speter  p->const_rtx_hash_table = const_rtx_hash_table;
318118334Speter  p->const_rtx_sym_hash_table = const_rtx_sym_hash_table;
318218334Speter  p->first_pool = first_pool;
318318334Speter  p->last_pool = last_pool;
318418334Speter  p->pool_offset = pool_offset;
318550397Sobrien  p->const_double_chain = const_double_chain;
318650397Sobrien
318750397Sobrien  /* If we are pushing to toplevel, we can't reuse const_double_chain.  */
318850397Sobrien  if (context == NULL_TREE)
318950397Sobrien    const_double_chain = 0;
319018334Speter}
319118334Speter
319218334Spetervoid
319318334Speterrestore_varasm_status (p)
319418334Speter     struct function *p;
319518334Speter{
319618334Speter  const_rtx_hash_table = p->const_rtx_hash_table;
319718334Speter  const_rtx_sym_hash_table = p->const_rtx_sym_hash_table;
319818334Speter  first_pool = p->first_pool;
319918334Speter  last_pool = p->last_pool;
320018334Speter  pool_offset = p->pool_offset;
320150397Sobrien  const_double_chain = p->const_double_chain;
320218334Speter}
320318334Speter
320418334Speterenum kind { RTX_DOUBLE, RTX_INT };
320518334Speter
320618334Speterstruct rtx_const
320718334Speter{
320818334Speter#ifdef ONLY_INT_FIELDS
320918334Speter  unsigned int kind : 16;
321018334Speter  unsigned int mode : 16;
321118334Speter#else
321218334Speter  enum kind kind : 16;
321318334Speter  enum machine_mode mode : 16;
321418334Speter#endif
321518334Speter  union {
321618334Speter    union real_extract du;
321718334Speter    struct addr_const addr;
321818334Speter    struct {HOST_WIDE_INT high, low;} di;
321918334Speter  } un;
322018334Speter};
322118334Speter
322218334Speter/* Express an rtx for a constant integer (perhaps symbolic)
322318334Speter   as the sum of a symbol or label plus an explicit integer.
322418334Speter   They are stored into VALUE.  */
322518334Speter
322618334Speterstatic void
322718334Speterdecode_rtx_const (mode, x, value)
322818334Speter     enum machine_mode mode;
322918334Speter     rtx x;
323018334Speter     struct rtx_const *value;
323118334Speter{
323218334Speter  /* Clear the whole structure, including any gaps.  */
323318334Speter
323418334Speter  {
323518334Speter    int *p = (int *) value;
323618334Speter    int *end = (int *) (value + 1);
323718334Speter    while (p < end)
323818334Speter      *p++ = 0;
323918334Speter  }
324018334Speter
324150397Sobrien  value->kind = RTX_INT;	/* Most usual kind.  */
324218334Speter  value->mode = mode;
324318334Speter
324418334Speter  switch (GET_CODE (x))
324518334Speter    {
324618334Speter    case CONST_DOUBLE:
324718334Speter      value->kind = RTX_DOUBLE;
324818334Speter      if (GET_MODE (x) != VOIDmode)
324918334Speter	{
325018334Speter	  value->mode = GET_MODE (x);
325118334Speter	  bcopy ((char *) &CONST_DOUBLE_LOW (x),
325218334Speter		 (char *) &value->un.du, sizeof value->un.du);
325318334Speter	}
325418334Speter      else
325518334Speter	{
325618334Speter	  value->un.di.low = CONST_DOUBLE_LOW (x);
325718334Speter	  value->un.di.high = CONST_DOUBLE_HIGH (x);
325818334Speter	}
325918334Speter      break;
326018334Speter
326118334Speter    case CONST_INT:
326218334Speter      value->un.addr.offset = INTVAL (x);
326318334Speter      break;
326418334Speter
326518334Speter    case SYMBOL_REF:
326618334Speter    case LABEL_REF:
326718334Speter    case PC:
326818334Speter      value->un.addr.base = x;
326918334Speter      break;
327018334Speter
327118334Speter    case CONST:
327218334Speter      x = XEXP (x, 0);
327318334Speter      if (GET_CODE (x) == PLUS)
327418334Speter	{
327518334Speter	  value->un.addr.base = XEXP (x, 0);
327618334Speter	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
327718334Speter	    abort ();
327818334Speter	  value->un.addr.offset = INTVAL (XEXP (x, 1));
327918334Speter	}
328018334Speter      else if (GET_CODE (x) == MINUS)
328118334Speter	{
328218334Speter	  value->un.addr.base = XEXP (x, 0);
328318334Speter	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
328418334Speter	    abort ();
328518334Speter	  value->un.addr.offset = - INTVAL (XEXP (x, 1));
328618334Speter	}
328718334Speter      else
328818334Speter	abort ();
328918334Speter      break;
329018334Speter
329118334Speter    default:
329218334Speter      abort ();
329318334Speter    }
329418334Speter
329518334Speter  if (value->kind == RTX_INT && value->un.addr.base != 0)
329618334Speter    switch (GET_CODE (value->un.addr.base))
329718334Speter      {
329818334Speter      case SYMBOL_REF:
329918334Speter      case LABEL_REF:
330018334Speter	/* Use the string's address, not the SYMBOL_REF's address,
330118334Speter	   for the sake of addresses of library routines.
330218334Speter	   For a LABEL_REF, compare labels.  */
330318334Speter	value->un.addr.base = XEXP (value->un.addr.base, 0);
330450397Sobrien
330550397Sobrien      default:
330650397Sobrien	break;
330718334Speter      }
330818334Speter}
330918334Speter
331018334Speter/* Given a MINUS expression, simplify it if both sides
331118334Speter   include the same symbol.  */
331218334Speter
331318334Speterrtx
331418334Spetersimplify_subtraction (x)
331518334Speter     rtx x;
331618334Speter{
331718334Speter  struct rtx_const val0, val1;
331818334Speter
331918334Speter  decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
332018334Speter  decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
332118334Speter
332218334Speter  if (val0.un.addr.base == val1.un.addr.base)
332318334Speter    return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
332418334Speter  return x;
332518334Speter}
332618334Speter
332718334Speter/* Compute a hash code for a constant RTL expression.  */
332818334Speter
332918334Speterstatic int
333018334Speterconst_hash_rtx (mode, x)
333118334Speter     enum machine_mode mode;
333218334Speter     rtx x;
333318334Speter{
333450397Sobrien  register int hi;
333550397Sobrien  register size_t i;
333618334Speter
333718334Speter  struct rtx_const value;
333818334Speter  decode_rtx_const (mode, x, &value);
333918334Speter
334018334Speter  /* Compute hashing function */
334118334Speter  hi = 0;
334218334Speter  for (i = 0; i < sizeof value / sizeof (int); i++)
334318334Speter    hi += ((int *) &value)[i];
334418334Speter
334518334Speter  hi &= (1 << HASHBITS) - 1;
334618334Speter  hi %= MAX_RTX_HASH_TABLE;
334718334Speter  return hi;
334818334Speter}
334918334Speter
335018334Speter/* Compare a constant rtl object X with a constant-descriptor DESC.
335118334Speter   Return 1 if DESC describes a constant with the same value as X.  */
335218334Speter
335318334Speterstatic int
335418334Spetercompare_constant_rtx (mode, x, desc)
335518334Speter     enum machine_mode mode;
335618334Speter     rtx x;
335718334Speter     struct constant_descriptor *desc;
335818334Speter{
335918334Speter  register int *p = (int *) desc->contents;
336018334Speter  register int *strp;
336118334Speter  register int len;
336218334Speter  struct rtx_const value;
336318334Speter
336418334Speter  decode_rtx_const (mode, x, &value);
336518334Speter  strp = (int *) &value;
336618334Speter  len = sizeof value / sizeof (int);
336718334Speter
336818334Speter  /* Compare constant contents.  */
336918334Speter  while (--len >= 0)
337018334Speter    if (*p++ != *strp++)
337118334Speter      return 0;
337218334Speter
337318334Speter  return 1;
337418334Speter}
337518334Speter
337618334Speter/* Construct a constant descriptor for the rtl-expression X.
337718334Speter   It is up to the caller to enter the descriptor in the hash table.  */
337818334Speter
337918334Speterstatic struct constant_descriptor *
338018334Speterrecord_constant_rtx (mode, x)
338118334Speter     enum machine_mode mode;
338218334Speter     rtx x;
338318334Speter{
338418334Speter  struct constant_descriptor *ptr;
338518334Speter  char *label;
338618334Speter  struct rtx_const value;
338718334Speter
338818334Speter  decode_rtx_const (mode, x, &value);
338918334Speter
339018334Speter  /* Put these things in the saveable obstack so we can ensure it won't
339118334Speter     be freed if we are called from combine or some other phase that discards
339218334Speter     memory allocated from function_obstack (current_obstack).  */
339318334Speter  obstack_grow (saveable_obstack, &ptr, sizeof ptr);
339418334Speter  obstack_grow (saveable_obstack, &label, sizeof label);
339518334Speter
339618334Speter  /* Record constant contents.  */
339718334Speter  obstack_grow (saveable_obstack, &value, sizeof value);
339818334Speter
339918334Speter  return (struct constant_descriptor *) obstack_finish (saveable_obstack);
340018334Speter}
340118334Speter
340218334Speter/* Given a constant rtx X, make (or find) a memory constant for its value
340318334Speter   and return a MEM rtx to refer to it in memory.  */
340418334Speter
340518334Speterrtx
340618334Speterforce_const_mem (mode, x)
340718334Speter     enum machine_mode mode;
340818334Speter     rtx x;
340918334Speter{
341018334Speter  register int hash;
341118334Speter  register struct constant_descriptor *desc;
341218334Speter  char label[256];
341318334Speter  char *found = 0;
341418334Speter  rtx def;
341518334Speter
341618334Speter  /* If we want this CONST_DOUBLE in the same mode as it is in memory
341718334Speter     (this will always be true for floating CONST_DOUBLEs that have been
341818334Speter     placed in memory, but not for VOIDmode (integer) CONST_DOUBLEs),
341918334Speter     use the previous copy.  Otherwise, make a new one.  Note that in
342018334Speter     the unlikely event that this same CONST_DOUBLE is used in two different
342118334Speter     modes in an alternating fashion, we will allocate a lot of different
342218334Speter     memory locations, but this should be extremely rare.  */
342318334Speter
342418334Speter  /* Don't use CONST_DOUBLE_MEM in a nested function.
342518334Speter     Nested functions have their own constant pools,
342618334Speter     so they can't share the same values in CONST_DOUBLE_MEM
342718334Speter     with the containing function.  */
342818334Speter  if (outer_function_chain == 0)
342918334Speter    if (GET_CODE (x) == CONST_DOUBLE
343018334Speter	&& GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
343118334Speter	&& GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
343218334Speter      return CONST_DOUBLE_MEM (x);
343318334Speter
343418334Speter  /* Compute hash code of X.  Search the descriptors for that hash code
343518334Speter     to see if any of them describes X.  If yes, the descriptor records
343618334Speter     the label number already assigned.  */
343718334Speter
343818334Speter  hash = const_hash_rtx (mode, x);
343918334Speter
344018334Speter  for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
344118334Speter    if (compare_constant_rtx (mode, x, desc))
344218334Speter      {
344318334Speter	found = desc->label;
344418334Speter	break;
344518334Speter      }
344618334Speter
344718334Speter  if (found == 0)
344818334Speter    {
344918334Speter      register struct pool_constant *pool;
345018334Speter      register struct pool_sym *sym;
345118334Speter      int align;
345218334Speter
345318334Speter      /* No constant equal to X is known to have been output.
345418334Speter	 Make a constant descriptor to enter X in the hash table.
345518334Speter	 Assign the label number and record it in the descriptor for
345618334Speter	 future calls to this function to find.  */
345718334Speter
345818334Speter      desc = record_constant_rtx (mode, x);
345918334Speter      desc->next = const_rtx_hash_table[hash];
346018334Speter      const_rtx_hash_table[hash] = desc;
346118334Speter
346218334Speter      /* Align the location counter as required by EXP's data type.  */
346318334Speter      align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
346418334Speter      if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
346518334Speter	align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
346650397Sobrien#ifdef CONSTANT_ALIGNMENT
346750397Sobrien      align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
346850397Sobrien				 align * BITS_PER_UNIT) / BITS_PER_UNIT;
346950397Sobrien#endif
347018334Speter
347118334Speter      pool_offset += align - 1;
347218334Speter      pool_offset &= ~ (align - 1);
347318334Speter
347418334Speter      /* If RTL is not being placed into the saveable obstack, make a
347550397Sobrien	 copy of X that is in the saveable obstack in case we are
347650397Sobrien	 being called from combine or some other phase that discards
347750397Sobrien	 memory it allocates.  We used to only do this if it is a
347850397Sobrien	 CONST; however, reload can allocate a CONST_INT when
347950397Sobrien	 eliminating registers.  */
348018334Speter      if (rtl_obstack != saveable_obstack
348150397Sobrien	  && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
348218334Speter	{
348318334Speter	  push_obstacks_nochange ();
348418334Speter	  rtl_in_saveable_obstack ();
348518334Speter
348650397Sobrien	  if (GET_CODE (x) == CONST)
348750397Sobrien	    x = gen_rtx_CONST (GET_MODE (x),
348850397Sobrien			       gen_rtx_PLUS (GET_MODE (x),
348950397Sobrien					     XEXP (XEXP (x, 0), 0),
349050397Sobrien					     XEXP (XEXP (x, 0), 1)));
349150397Sobrien	  else
349250397Sobrien	    x = GEN_INT (INTVAL (x));
349350397Sobrien
349418334Speter	  pop_obstacks ();
349518334Speter	}
349618334Speter
349718334Speter      /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
349818334Speter
349918334Speter      pool = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
350018334Speter      pool->desc = desc;
350118334Speter      pool->constant = x;
350218334Speter      pool->mode = mode;
350318334Speter      pool->labelno = const_labelno;
350418334Speter      pool->align = align;
350518334Speter      pool->offset = pool_offset;
350650397Sobrien      pool->mark = 1;
350718334Speter      pool->next = 0;
350818334Speter
350918334Speter      if (last_pool == 0)
351018334Speter	first_pool = pool;
351118334Speter      else
351218334Speter	last_pool->next = pool;
351318334Speter
351418334Speter      last_pool = pool;
351518334Speter      pool_offset += GET_MODE_SIZE (mode);
351618334Speter
351718334Speter      /* Create a string containing the label name, in LABEL.  */
351818334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
351918334Speter
352018334Speter      ++const_labelno;
352118334Speter
352218334Speter      desc->label = found
352318334Speter	= (char *) obstack_copy0 (saveable_obstack, label, strlen (label));
352418334Speter
352518334Speter      /* Add label to symbol hash table.  */
352618334Speter      hash = SYMHASH (found);
352718334Speter      sym = (struct pool_sym *) savealloc (sizeof (struct pool_sym));
352818334Speter      sym->label = found;
352918334Speter      sym->pool = pool;
353018334Speter      sym->next = const_rtx_sym_hash_table[hash];
353118334Speter      const_rtx_sym_hash_table[hash] = sym;
353218334Speter    }
353318334Speter
353418334Speter  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
353518334Speter
353650397Sobrien  def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
353718334Speter
353818334Speter  RTX_UNCHANGING_P (def) = 1;
353918334Speter  /* Mark the symbol_ref as belonging to this constants pool.  */
354018334Speter  CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
354118334Speter  current_function_uses_const_pool = 1;
354218334Speter
354318334Speter  if (outer_function_chain == 0)
354418334Speter    if (GET_CODE (x) == CONST_DOUBLE)
354518334Speter      {
354618334Speter	if (CONST_DOUBLE_MEM (x) == cc0_rtx)
354718334Speter	  {
354818334Speter	    CONST_DOUBLE_CHAIN (x) = const_double_chain;
354918334Speter	    const_double_chain = x;
355018334Speter	  }
355118334Speter	CONST_DOUBLE_MEM (x) = def;
355218334Speter      }
355318334Speter
355418334Speter  return def;
355518334Speter}
355618334Speter
355718334Speter/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
355818334Speter   the corresponding pool_constant structure.  */
355918334Speter
356018334Speterstatic struct pool_constant *
356118334Speterfind_pool_constant (addr)
356218334Speter     rtx addr;
356318334Speter{
356418334Speter  struct pool_sym *sym;
356518334Speter  char *label = XSTR (addr, 0);
356618334Speter
356718334Speter  for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
356818334Speter    if (sym->label == label)
356918334Speter      return sym->pool;
357018334Speter
357118334Speter  abort ();
357218334Speter}
357318334Speter
357418334Speter/* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
357518334Speter
357618334Speterrtx
357718334Speterget_pool_constant (addr)
357818334Speter     rtx addr;
357918334Speter{
358018334Speter  return (find_pool_constant (addr))->constant;
358118334Speter}
358218334Speter
358318334Speter/* Similar, return the mode.  */
358418334Speter
358518334Speterenum machine_mode
358618334Speterget_pool_mode (addr)
358718334Speter     rtx addr;
358818334Speter{
358918334Speter  return (find_pool_constant (addr))->mode;
359018334Speter}
359118334Speter
359218334Speter/* Similar, return the offset in the constant pool.  */
359318334Speter
359418334Speterint
359518334Speterget_pool_offset (addr)
359618334Speter     rtx addr;
359718334Speter{
359818334Speter  return (find_pool_constant (addr))->offset;
359918334Speter}
360018334Speter
360118334Speter/* Return the size of the constant pool.  */
360218334Speter
360318334Speterint
360418334Speterget_pool_size ()
360518334Speter{
360618334Speter  return pool_offset;
360718334Speter}
360818334Speter
360918334Speter/* Write all the constants in the constant pool.  */
361018334Speter
361118334Spetervoid
361218334Speteroutput_constant_pool (fnname, fndecl)
361352284Sobrien  char *fnname ATTRIBUTE_UNUSED;
361452284Sobrien  tree fndecl ATTRIBUTE_UNUSED;
361518334Speter{
361618334Speter  struct pool_constant *pool;
361718334Speter  rtx x;
361818334Speter  union real_extract u;
361918334Speter
362050397Sobrien  /* It is possible for gcc to call force_const_mem and then to later
362150397Sobrien     discard the instructions which refer to the constant.  In such a
362250397Sobrien     case we do not need to output the constant.  */
362352284Sobrien  mark_constant_pool ();
362450397Sobrien
362518334Speter#ifdef ASM_OUTPUT_POOL_PROLOGUE
362618334Speter  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
362718334Speter#endif
362818334Speter
362918334Speter  for (pool = first_pool; pool; pool = pool->next)
363018334Speter    {
363118334Speter      x = pool->constant;
363218334Speter
363350397Sobrien      if (! pool->mark)
363450397Sobrien	continue;
363550397Sobrien
363618334Speter      /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
363718334Speter	 whose CODE_LABEL has been deleted.  This can occur if a jump table
363818334Speter	 is eliminated by optimization.  If so, write a constant of zero
363918334Speter	 instead.  Note that this can also happen by turning the
364018334Speter	 CODE_LABEL into a NOTE.  */
364118334Speter      if (((GET_CODE (x) == LABEL_REF
364218334Speter	    && (INSN_DELETED_P (XEXP (x, 0))
364318334Speter		|| GET_CODE (XEXP (x, 0)) == NOTE)))
364418334Speter	  || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
364518334Speter	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
364618334Speter	      && (INSN_DELETED_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
364718334Speter		  || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == NOTE)))
364818334Speter	x = const0_rtx;
364918334Speter
365018334Speter      /* First switch to correct section.  */
365118334Speter#ifdef SELECT_RTX_SECTION
365218334Speter      SELECT_RTX_SECTION (pool->mode, x);
365318334Speter#else
365418334Speter      readonly_data_section ();
365518334Speter#endif
365618334Speter
365718334Speter#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
365818334Speter      ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
365918334Speter				     pool->align, pool->labelno, done);
366018334Speter#endif
366118334Speter
366218334Speter      if (pool->align > 1)
366352284Sobrien	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (pool->align));
366418334Speter
366518334Speter      /* Output the label.  */
366618334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
366718334Speter
366818334Speter      /* Output the value of the constant itself.  */
366918334Speter      switch (GET_MODE_CLASS (pool->mode))
367018334Speter	{
367118334Speter	case MODE_FLOAT:
367218334Speter	  if (GET_CODE (x) != CONST_DOUBLE)
367318334Speter	    abort ();
367418334Speter
367518334Speter	  bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
367618334Speter	  assemble_real (u.d, pool->mode);
367718334Speter	  break;
367818334Speter
367918334Speter	case MODE_INT:
368018334Speter	case MODE_PARTIAL_INT:
368118334Speter	  assemble_integer (x, GET_MODE_SIZE (pool->mode), 1);
368218334Speter	  break;
368318334Speter
368418334Speter	default:
368518334Speter	  abort ();
368618334Speter	}
368718334Speter
368850397Sobrien#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
368918334Speter    done: ;
369050397Sobrien#endif
369150397Sobrien
369218334Speter    }
369318334Speter
369450397Sobrien#ifdef ASM_OUTPUT_POOL_EPILOGUE
369550397Sobrien  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
369650397Sobrien#endif
369750397Sobrien
369818334Speter  /* Done with this pool.  */
369918334Speter  first_pool = last_pool = 0;
370018334Speter}
370150397Sobrien
370250397Sobrien/* Look through the instructions for this function, and mark all the
370350397Sobrien   entries in the constant pool which are actually being used.  */
370450397Sobrien
370550397Sobrienstatic void
370650397Sobrienmark_constant_pool ()
370750397Sobrien{
370850397Sobrien  register rtx insn;
370950397Sobrien  struct pool_constant *pool;
371050397Sobrien
371150397Sobrien  if (first_pool == 0)
371250397Sobrien    return;
371350397Sobrien
371450397Sobrien  for (pool = first_pool; pool; pool = pool->next)
371550397Sobrien    pool->mark = 0;
371650397Sobrien
371750397Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
371850397Sobrien    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
371950397Sobrien      mark_constants (PATTERN (insn));
372050397Sobrien
372150397Sobrien  for (insn = current_function_epilogue_delay_list;
372250397Sobrien       insn;
372350397Sobrien       insn = XEXP (insn, 1))
372450397Sobrien    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
372550397Sobrien      mark_constants (PATTERN (insn));
372652284Sobrien
372752284Sobrien  /* It's possible that the only reference to a symbol is in a symbol
372852284Sobrien     that's in the constant pool.  This happens in Fortran under some
372952284Sobrien     situations.  (When the constant contains the address of another
373052284Sobrien     constant, and only the first is used directly in an insn.)
373152284Sobrien     This is potentially suboptimal if there's ever a possibility of
373252284Sobrien     backwards (in pool order) 2'd level references.  However, it's
373352284Sobrien     not clear that 2'd level references can happen. */
373452284Sobrien  for (pool = first_pool; pool; pool = pool->next)
373552284Sobrien    {
373652284Sobrien      struct pool_sym *sym;
373752284Sobrien      char *label;
373852284Sobrien
373952284Sobrien      /* skip unmarked entries; no insn refers to them. */
374052284Sobrien      if (!pool->mark)
374152284Sobrien	  continue;
374252284Sobrien
374352284Sobrien      label = XSTR (pool->constant, 0);
374452284Sobrien
374552284Sobrien      /* Be sure the symbol's value is marked. */
374652284Sobrien      for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym;
374752284Sobrien           sym = sym->next)
374852284Sobrien	  if (sym->label == label)
374952284Sobrien	    sym->pool->mark = 1;
375052284Sobrien      /* If we didn't find it, there's something truly wrong here, but it
375152284Sobrien	 will be announced by the assembler. */
375252284Sobrien    }
375350397Sobrien}
375450397Sobrien
375550397Sobrienstatic void
375650397Sobrienmark_constants (x)
375750397Sobrien     register rtx x;
375850397Sobrien{
375950397Sobrien  register int i;
376050397Sobrien  register char *format_ptr;
376150397Sobrien
376250397Sobrien  if (x == 0)
376350397Sobrien    return;
376450397Sobrien
376550397Sobrien  if (GET_CODE (x) == SYMBOL_REF)
376650397Sobrien    {
376750397Sobrien      if (CONSTANT_POOL_ADDRESS_P (x))
376850397Sobrien	find_pool_constant (x)->mark = 1;
376950397Sobrien      return;
377050397Sobrien    }
377150397Sobrien  /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
377250397Sobrien     a MEM, but does not constitute a use of that MEM.  This is particularly
377350397Sobrien     important inside a nested function, because CONST_DOUBLE_MEM may be
377450397Sobrien     a reference to a MEM in the parent's constant pool.  See the comment
377550397Sobrien     in force_const_mem.  */
377650397Sobrien  else if (GET_CODE (x) == CONST_DOUBLE)
377750397Sobrien    return;
377850397Sobrien
377950397Sobrien  /* Insns may appear inside a SEQUENCE.  Only check the patterns of
378050397Sobrien     insns, not any notes that may be attached.  We don't want to mark
378150397Sobrien     a constant just because it happens to appear in a REG_EQUIV note.  */
378250397Sobrien  if (GET_RTX_CLASS (GET_CODE (x)) == 'i')
378350397Sobrien    {
378450397Sobrien      mark_constants (PATTERN (x));
378550397Sobrien      return;
378650397Sobrien    }
378750397Sobrien
378850397Sobrien  format_ptr = GET_RTX_FORMAT (GET_CODE (x));
378950397Sobrien
379050397Sobrien  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
379150397Sobrien    {
379250397Sobrien      switch (*format_ptr++)
379350397Sobrien	{
379450397Sobrien	case 'e':
379550397Sobrien	  mark_constants (XEXP (x, i));
379650397Sobrien	  break;
379750397Sobrien
379850397Sobrien	case 'E':
379950397Sobrien	  if (XVEC (x, i) != 0)
380050397Sobrien	    {
380150397Sobrien	      register int j;
380250397Sobrien
380350397Sobrien	      for (j = 0; j < XVECLEN (x, i); j++)
380450397Sobrien		mark_constants (XVECEXP (x, i, j));
380550397Sobrien	    }
380650397Sobrien	  break;
380750397Sobrien
380850397Sobrien	case 'S':
380950397Sobrien	case 's':
381050397Sobrien	case '0':
381150397Sobrien	case 'i':
381250397Sobrien	case 'w':
381350397Sobrien	case 'n':
381450397Sobrien	case 'u':
381550397Sobrien	  break;
381650397Sobrien
381750397Sobrien	default:
381850397Sobrien	  abort ();
381950397Sobrien	}
382050397Sobrien    }
382150397Sobrien}
382218334Speter
382318334Speter/* Find all the constants whose addresses are referenced inside of EXP,
382418334Speter   and make sure assembler code with a label has been output for each one.
382518334Speter   Indicate whether an ADDR_EXPR has been encountered.  */
382618334Speter
382718334Speterstatic int
382818334Speteroutput_addressed_constants (exp)
382918334Speter     tree exp;
383018334Speter{
383118334Speter  int reloc = 0;
383218334Speter
383318334Speter  switch (TREE_CODE (exp))
383418334Speter    {
383518334Speter    case ADDR_EXPR:
383618334Speter      {
383718334Speter	register tree constant = TREE_OPERAND (exp, 0);
383818334Speter
383918334Speter	while (TREE_CODE (constant) == COMPONENT_REF)
384018334Speter	  {
384118334Speter	    constant = TREE_OPERAND (constant, 0);
384218334Speter	  }
384318334Speter
384418334Speter	if (TREE_CODE_CLASS (TREE_CODE (constant)) == 'c'
384518334Speter	    || TREE_CODE (constant) == CONSTRUCTOR)
384618334Speter	  /* No need to do anything here
384718334Speter	     for addresses of variables or functions.  */
384818334Speter	  output_constant_def (constant);
384918334Speter      }
385018334Speter      reloc = 1;
385118334Speter      break;
385218334Speter
385318334Speter    case PLUS_EXPR:
385418334Speter    case MINUS_EXPR:
385518334Speter      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
385618334Speter      reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
385718334Speter      break;
385818334Speter
385918334Speter    case NOP_EXPR:
386018334Speter    case CONVERT_EXPR:
386118334Speter    case NON_LVALUE_EXPR:
386218334Speter      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
386318334Speter      break;
386418334Speter
386518334Speter    case CONSTRUCTOR:
386618334Speter      {
386718334Speter	register tree link;
386818334Speter	for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
386918334Speter	  if (TREE_VALUE (link) != 0)
387018334Speter	    reloc |= output_addressed_constants (TREE_VALUE (link));
387118334Speter      }
387218334Speter      break;
387318334Speter
387450397Sobrien    default:
387518334Speter      break;
387618334Speter    }
387718334Speter  return reloc;
387818334Speter}
387918334Speter
388018334Speter/* Output assembler code for constant EXP to FILE, with no label.
388118334Speter   This includes the pseudo-op such as ".int" or ".byte", and a newline.
388218334Speter   Assumes output_addressed_constants has been done on EXP already.
388318334Speter
388418334Speter   Generate exactly SIZE bytes of assembler data, padding at the end
388518334Speter   with zeros if necessary.  SIZE must always be specified.
388618334Speter
388718334Speter   SIZE is important for structure constructors,
388818334Speter   since trailing members may have been omitted from the constructor.
388918334Speter   It is also important for initialization of arrays from string constants
389018334Speter   since the full length of the string constant might not be wanted.
389118334Speter   It is also needed for initialization of unions, where the initializer's
389218334Speter   type is just one member, and that may not be as long as the union.
389318334Speter
389418334Speter   There a case in which we would fail to output exactly SIZE bytes:
389518334Speter   for a structure constructor that wants to produce more than SIZE bytes.
389618334Speter   But such constructors will never be generated for any possible input.  */
389718334Speter
389818334Spetervoid
389918334Speteroutput_constant (exp, size)
390018334Speter     register tree exp;
390118334Speter     register int size;
390218334Speter{
390318334Speter  register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
390418334Speter
390552284Sobrien  /* Some front-ends use constants other than the standard
390652284Sobrien     language-indepdent varieties, but which may still be output
390752284Sobrien     directly.  Give the front-end a chance to convert EXP to a
390852284Sobrien     language-independent representation.  */
390952284Sobrien  if (lang_expand_constant)
391052284Sobrien    exp = (*lang_expand_constant) (exp);
391152284Sobrien
391252284Sobrien  if (size == 0 || flag_syntax_only)
391318334Speter    return;
391418334Speter
391518334Speter  /* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
391618334Speter     That way we get the constant (we hope) inside it.  Also, strip off any
391718334Speter     NOP_EXPR that converts between two record, union, array, or set types.  */
391818334Speter  while ((TREE_CODE (exp) == NOP_EXPR
391918334Speter	  && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
392018334Speter	      || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
392118334Speter	 || TREE_CODE (exp) == NON_LVALUE_EXPR)
392218334Speter    exp = TREE_OPERAND (exp, 0);
392318334Speter
392418334Speter  /* Allow a constructor with no elements for any data type.
392518334Speter     This means to fill the space with zeros.  */
392618334Speter  if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
392718334Speter    {
392850397Sobrien      assemble_zeros (size);
392918334Speter      return;
393018334Speter    }
393118334Speter
393218334Speter  switch (code)
393318334Speter    {
393418334Speter    case CHAR_TYPE:
393518334Speter    case BOOLEAN_TYPE:
393618334Speter    case INTEGER_TYPE:
393718334Speter    case ENUMERAL_TYPE:
393818334Speter    case POINTER_TYPE:
393918334Speter    case REFERENCE_TYPE:
394018334Speter      /* ??? What about       (int)((float)(int)&foo + 4)    */
394118334Speter      while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
394218334Speter	     || TREE_CODE (exp) == NON_LVALUE_EXPR)
394318334Speter	exp = TREE_OPERAND (exp, 0);
394418334Speter
394518334Speter      if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
394618334Speter					   EXPAND_INITIALIZER),
394718334Speter			      size, 0))
394818334Speter	error ("initializer for integer value is too complicated");
394918334Speter      size = 0;
395018334Speter      break;
395118334Speter
395218334Speter    case REAL_TYPE:
395318334Speter      if (TREE_CODE (exp) != REAL_CST)
395418334Speter	error ("initializer for floating value is not a floating constant");
395518334Speter
395618334Speter      assemble_real (TREE_REAL_CST (exp),
395718334Speter		     mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0));
395818334Speter      size = 0;
395918334Speter      break;
396018334Speter
396118334Speter    case COMPLEX_TYPE:
396218334Speter      output_constant (TREE_REALPART (exp), size / 2);
396318334Speter      output_constant (TREE_IMAGPART (exp), size / 2);
396418334Speter      size -= (size / 2) * 2;
396518334Speter      break;
396618334Speter
396718334Speter    case ARRAY_TYPE:
396818334Speter      if (TREE_CODE (exp) == CONSTRUCTOR)
396918334Speter	{
397018334Speter	  output_constructor (exp, size);
397118334Speter	  return;
397218334Speter	}
397318334Speter      else if (TREE_CODE (exp) == STRING_CST)
397418334Speter	{
397518334Speter	  int excess = 0;
397618334Speter
397718334Speter	  if (size > TREE_STRING_LENGTH (exp))
397818334Speter	    {
397918334Speter	      excess = size - TREE_STRING_LENGTH (exp);
398018334Speter	      size = TREE_STRING_LENGTH (exp);
398118334Speter	    }
398218334Speter
398318334Speter	  assemble_string (TREE_STRING_POINTER (exp), size);
398418334Speter	  size = excess;
398518334Speter	}
398618334Speter      else
398718334Speter	abort ();
398818334Speter      break;
398918334Speter
399018334Speter    case RECORD_TYPE:
399118334Speter    case UNION_TYPE:
399218334Speter      if (TREE_CODE (exp) == CONSTRUCTOR)
399318334Speter	output_constructor (exp, size);
399418334Speter      else
399518334Speter	abort ();
399618334Speter      return;
399718334Speter
399818334Speter    case SET_TYPE:
399918334Speter      if (TREE_CODE (exp) == INTEGER_CST)
400018334Speter	assemble_integer (expand_expr (exp, NULL_RTX,
400118334Speter				       VOIDmode, EXPAND_INITIALIZER),
400218334Speter			  size, 1);
400318334Speter      else if (TREE_CODE (exp) == CONSTRUCTOR)
400418334Speter	{
400518334Speter	  unsigned char *buffer = (unsigned char *) alloca (size);
400618334Speter	  if (get_set_constructor_bytes (exp, buffer, size))
400718334Speter	    abort ();
400818334Speter	  assemble_string ((char *) buffer, size);
400918334Speter	}
401018334Speter      else
401118334Speter	error ("unknown set constructor type");
401218334Speter      return;
401350397Sobrien
401450397Sobrien    default:
401550397Sobrien      break; /* ??? */
401618334Speter    }
401718334Speter
401818334Speter  if (size > 0)
401918334Speter    assemble_zeros (size);
402018334Speter}
402118334Speter
402218334Speter
402318334Speter/* Subroutine of output_constant, used for CONSTRUCTORs
402418334Speter   (aggregate constants).
402518334Speter   Generate at least SIZE bytes, padding if necessary.  */
402618334Speter
402718334Speterstatic void
402818334Speteroutput_constructor (exp, size)
402918334Speter     tree exp;
403018334Speter     int size;
403118334Speter{
403218334Speter  register tree link, field = 0;
403318334Speter  HOST_WIDE_INT min_index = 0;
403418334Speter  /* Number of bytes output or skipped so far.
403518334Speter     In other words, current position within the constructor.  */
403618334Speter  int total_bytes = 0;
403718334Speter  /* Non-zero means BYTE contains part of a byte, to be output.  */
403818334Speter  int byte_buffer_in_use = 0;
403918334Speter  register int byte;
404018334Speter
404118334Speter  if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
404218334Speter    abort ();
404318334Speter
404418334Speter  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
404518334Speter    field = TYPE_FIELDS (TREE_TYPE (exp));
404618334Speter
404718334Speter  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
404818334Speter      && TYPE_DOMAIN (TREE_TYPE (exp)) != 0)
404918334Speter    min_index
405018334Speter      = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (exp))));
405118334Speter
405218334Speter  /* As LINK goes through the elements of the constant,
405318334Speter     FIELD goes through the structure fields, if the constant is a structure.
405418334Speter     if the constant is a union, then we override this,
405518334Speter     by getting the field from the TREE_LIST element.
405652284Sobrien     But the constant could also be an array.  Then FIELD is zero.
405752284Sobrien
405852284Sobrien     There is always a maximum of one element in the chain LINK for unions
405952284Sobrien     (even if the initializer in a source program incorrectly contains
406052284Sobrien     more one). */
406118334Speter  for (link = CONSTRUCTOR_ELTS (exp);
406218334Speter       link;
406318334Speter       link = TREE_CHAIN (link),
406418334Speter       field = field ? TREE_CHAIN (field) : 0)
406518334Speter    {
406618334Speter      tree val = TREE_VALUE (link);
406718334Speter      tree index = 0;
406818334Speter
406918334Speter      /* the element in a union constructor specifies the proper field.  */
407018334Speter
407118334Speter      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
407218334Speter	  || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
407318334Speter	{
407418334Speter	  /* if available, use the type given by link */
407518334Speter	  if (TREE_PURPOSE (link) != 0)
407618334Speter	    field = TREE_PURPOSE (link);
407718334Speter	}
407818334Speter
407918334Speter      if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
408018334Speter	index = TREE_PURPOSE (link);
408118334Speter
408218334Speter      /* Eliminate the marker that makes a cast not be an lvalue.  */
408318334Speter      if (val != 0)
408418334Speter	STRIP_NOPS (val);
408518334Speter
408650397Sobrien      if (index && TREE_CODE (index) == RANGE_EXPR)
408718334Speter	{
408850397Sobrien	  register int fieldsize
408950397Sobrien	    = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
409050397Sobrien	  HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
409150397Sobrien	  HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
409250397Sobrien	  HOST_WIDE_INT index;
409350397Sobrien	  for (index = lo_index; index <= hi_index; index++)
409450397Sobrien	    {
409550397Sobrien	      /* Output the element's initial value.  */
409650397Sobrien	      if (val == 0)
409750397Sobrien		assemble_zeros (fieldsize);
409850397Sobrien	      else
409950397Sobrien		output_constant (val, fieldsize);
410050397Sobrien
410150397Sobrien	      /* Count its size.  */
410250397Sobrien	      total_bytes += fieldsize;
410350397Sobrien	    }
410450397Sobrien	}
410550397Sobrien      else if (field == 0 || !DECL_BIT_FIELD (field))
410650397Sobrien	{
410718334Speter	  /* An element that is not a bit-field.  */
410818334Speter
410918334Speter	  register int fieldsize;
411018334Speter	  /* Since this structure is static,
411118334Speter	     we know the positions are constant.  */
411218334Speter	  int bitpos = (field ? (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
411318334Speter				 / BITS_PER_UNIT)
411418334Speter			: 0);
411518334Speter	  if (index != 0)
411618334Speter	    bitpos = (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (val)))
411718334Speter		      / BITS_PER_UNIT
411818334Speter		      * (TREE_INT_CST_LOW (index) - min_index));
411918334Speter
412018334Speter	  /* Output any buffered-up bit-fields preceding this element.  */
412118334Speter	  if (byte_buffer_in_use)
412218334Speter	    {
412318334Speter	      ASM_OUTPUT_BYTE (asm_out_file, byte);
412418334Speter	      total_bytes++;
412518334Speter	      byte_buffer_in_use = 0;
412618334Speter	    }
412718334Speter
412818334Speter	  /* Advance to offset of this element.
412918334Speter	     Note no alignment needed in an array, since that is guaranteed
413018334Speter	     if each element has the proper size.  */
413118334Speter	  if ((field != 0 || index != 0) && bitpos != total_bytes)
413218334Speter	    {
413350397Sobrien	      assemble_zeros (bitpos - total_bytes);
413418334Speter	      total_bytes = bitpos;
413518334Speter	    }
413618334Speter
413718334Speter	  /* Determine size this element should occupy.  */
413818334Speter	  if (field)
413918334Speter	    {
414018334Speter	      if (TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
414118334Speter		abort ();
414218334Speter	      if (TREE_INT_CST_LOW (DECL_SIZE (field)) > 100000)
414318334Speter		{
414418334Speter		  /* This avoids overflow trouble.  */
414518334Speter		  tree size_tree = size_binop (CEIL_DIV_EXPR,
414618334Speter					       DECL_SIZE (field),
414718334Speter					       size_int (BITS_PER_UNIT));
414818334Speter		  fieldsize = TREE_INT_CST_LOW (size_tree);
414918334Speter		}
415018334Speter	      else
415118334Speter		{
415218334Speter		  fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field));
415318334Speter		  fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
415418334Speter		}
415518334Speter	    }
415618334Speter	  else
415718334Speter	    fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
415818334Speter
415918334Speter	  /* Output the element's initial value.  */
416018334Speter	  if (val == 0)
416118334Speter	    assemble_zeros (fieldsize);
416218334Speter	  else
416318334Speter	    output_constant (val, fieldsize);
416418334Speter
416518334Speter	  /* Count its size.  */
416618334Speter	  total_bytes += fieldsize;
416718334Speter	}
416818334Speter      else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
416918334Speter	error ("invalid initial value for member `%s'",
417018334Speter	       IDENTIFIER_POINTER (DECL_NAME (field)));
417118334Speter      else
417218334Speter	{
417318334Speter	  /* Element that is a bit-field.  */
417418334Speter
417518334Speter	  int next_offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
417618334Speter	  int end_offset
417718334Speter	    = (next_offset + TREE_INT_CST_LOW (DECL_SIZE (field)));
417818334Speter
417918334Speter	  if (val == 0)
418018334Speter	    val = integer_zero_node;
418118334Speter
418218334Speter	  /* If this field does not start in this (or, next) byte,
418318334Speter	     skip some bytes.  */
418418334Speter	  if (next_offset / BITS_PER_UNIT != total_bytes)
418518334Speter	    {
418618334Speter	      /* Output remnant of any bit field in previous bytes.  */
418718334Speter	      if (byte_buffer_in_use)
418818334Speter		{
418918334Speter		  ASM_OUTPUT_BYTE (asm_out_file, byte);
419018334Speter		  total_bytes++;
419118334Speter		  byte_buffer_in_use = 0;
419218334Speter		}
419318334Speter
419418334Speter	      /* If still not at proper byte, advance to there.  */
419518334Speter	      if (next_offset / BITS_PER_UNIT != total_bytes)
419618334Speter		{
419718334Speter		  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
419818334Speter		  total_bytes = next_offset / BITS_PER_UNIT;
419918334Speter		}
420018334Speter	    }
420118334Speter
420218334Speter	  if (! byte_buffer_in_use)
420318334Speter	    byte = 0;
420418334Speter
420518334Speter	  /* We must split the element into pieces that fall within
420618334Speter	     separate bytes, and combine each byte with previous or
420718334Speter	     following bit-fields.  */
420818334Speter
420918334Speter	  /* next_offset is the offset n fbits from the beginning of
421018334Speter	     the structure to the next bit of this element to be processed.
421118334Speter	     end_offset is the offset of the first bit past the end of
421218334Speter	     this element.  */
421318334Speter	  while (next_offset < end_offset)
421418334Speter	    {
421518334Speter	      int this_time;
421618334Speter	      int shift;
421718334Speter	      HOST_WIDE_INT value;
421818334Speter	      int next_byte = next_offset / BITS_PER_UNIT;
421918334Speter	      int next_bit = next_offset % BITS_PER_UNIT;
422018334Speter
422118334Speter	      /* Advance from byte to byte
422218334Speter		 within this element when necessary.  */
422318334Speter	      while (next_byte != total_bytes)
422418334Speter		{
422518334Speter		  ASM_OUTPUT_BYTE (asm_out_file, byte);
422618334Speter		  total_bytes++;
422718334Speter		  byte = 0;
422818334Speter		}
422918334Speter
423018334Speter	      /* Number of bits we can process at once
423118334Speter		 (all part of the same byte).  */
423218334Speter	      this_time = MIN (end_offset - next_offset,
423318334Speter			       BITS_PER_UNIT - next_bit);
423418334Speter	      if (BYTES_BIG_ENDIAN)
423518334Speter		{
423618334Speter		  /* On big-endian machine, take the most significant bits
423718334Speter		     first (of the bits that are significant)
423818334Speter		     and put them into bytes from the most significant end.  */
423918334Speter		  shift = end_offset - next_offset - this_time;
424018334Speter		  /* Don't try to take a bunch of bits that cross
424118334Speter		     the word boundary in the INTEGER_CST.  */
424218334Speter		  if (shift < HOST_BITS_PER_WIDE_INT
424318334Speter		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
424418334Speter		    {
424518334Speter		      this_time -= (HOST_BITS_PER_WIDE_INT - shift);
424618334Speter		      shift = HOST_BITS_PER_WIDE_INT;
424718334Speter		    }
424818334Speter
424918334Speter		  /* Now get the bits from the appropriate constant word.  */
425018334Speter		  if (shift < HOST_BITS_PER_WIDE_INT)
425118334Speter		    {
425218334Speter		      value = TREE_INT_CST_LOW (val);
425318334Speter		    }
425418334Speter		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
425518334Speter		    {
425618334Speter		      value = TREE_INT_CST_HIGH (val);
425718334Speter		      shift -= HOST_BITS_PER_WIDE_INT;
425818334Speter		    }
425918334Speter		  else
426018334Speter		    abort ();
426118334Speter		  byte |= (((value >> shift)
426218334Speter			    & (((HOST_WIDE_INT) 1 << this_time) - 1))
426318334Speter			   << (BITS_PER_UNIT - this_time - next_bit));
426418334Speter		}
426518334Speter	      else
426618334Speter		{
426718334Speter		  /* On little-endian machines,
426818334Speter		     take first the least significant bits of the value
426918334Speter		     and pack them starting at the least significant
427018334Speter		     bits of the bytes.  */
427118334Speter		  shift = (next_offset
427218334Speter			   - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
427318334Speter		  /* Don't try to take a bunch of bits that cross
427418334Speter		     the word boundary in the INTEGER_CST.  */
427518334Speter		  if (shift < HOST_BITS_PER_WIDE_INT
427618334Speter		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
427718334Speter		    {
427818334Speter		      this_time -= (HOST_BITS_PER_WIDE_INT - shift);
427918334Speter		      shift = HOST_BITS_PER_WIDE_INT;
428018334Speter		    }
428118334Speter
428218334Speter		  /* Now get the bits from the appropriate constant word.  */
428350397Sobrien		  if (shift < HOST_BITS_PER_WIDE_INT)
428418334Speter		    value = TREE_INT_CST_LOW (val);
428518334Speter		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
428618334Speter		    {
428718334Speter		      value = TREE_INT_CST_HIGH (val);
428818334Speter		      shift -= HOST_BITS_PER_WIDE_INT;
428918334Speter		    }
429018334Speter		  else
429118334Speter		    abort ();
429218334Speter		  byte |= (((value >> shift)
429318334Speter			    & (((HOST_WIDE_INT) 1 << this_time) - 1))
429418334Speter			   << next_bit);
429518334Speter		}
429618334Speter	      next_offset += this_time;
429718334Speter	      byte_buffer_in_use = 1;
429818334Speter	    }
429918334Speter	}
430018334Speter    }
430118334Speter  if (byte_buffer_in_use)
430218334Speter    {
430318334Speter      ASM_OUTPUT_BYTE (asm_out_file, byte);
430418334Speter      total_bytes++;
430518334Speter    }
430618334Speter  if (total_bytes < size)
430718334Speter    assemble_zeros (size - total_bytes);
430818334Speter}
430918334Speter
431052284Sobrien#ifdef HANDLE_PRAGMA_WEAK
431152284Sobrien/* Add function NAME to the weak symbols list.  VALUE is a weak alias
431252284Sobrien   associatd with NAME.  */
431352284Sobrien
431452284Sobrienint
431552284Sobrienadd_weak (name, value)
431652284Sobrien     char *name;
431752284Sobrien     char *value;
431818334Speter{
431952284Sobrien  struct weak_syms *weak;
432018334Speter
432152284Sobrien  weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms));
432218334Speter
432352284Sobrien  if (weak == NULL)
432452284Sobrien    return 0;
432518334Speter
432652284Sobrien  weak->next = weak_decls;
432752284Sobrien  weak->name = name;
432852284Sobrien  weak->value = value;
432952284Sobrien  weak_decls = weak;
433052284Sobrien
433152284Sobrien  return 1;
433252284Sobrien}
433318334Speter#endif /* HANDLE_PRAGMA_WEAK */
433418334Speter
433518334Speter/* Declare DECL to be a weak symbol.  */
433618334Speter
433718334Spetervoid
433818334Speterdeclare_weak (decl)
433918334Speter     tree decl;
434018334Speter{
434118334Speter  if (! TREE_PUBLIC (decl))
434218334Speter    error_with_decl (decl, "weak declaration of `%s' must be public");
434318334Speter  else if (TREE_ASM_WRITTEN (decl))
434418334Speter    error_with_decl (decl, "weak declaration of `%s' must precede definition");
434518334Speter  else if (SUPPORTS_WEAK)
434618334Speter    DECL_WEAK (decl) = 1;
434750397Sobrien#ifdef HANDLE_PRAGMA_WEAK
434852284Sobrien   add_weak (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
434950397Sobrien#endif
435018334Speter}
435118334Speter
435218334Speter/* Emit any pending weak declarations.  */
435318334Speter
435452284Sobrien#ifdef HANDLE_PRAGMA_WEAK
435552284Sobrienstruct weak_syms * weak_decls;
435652284Sobrien#endif
435752284Sobrien
435818334Spetervoid
435918334Speterweak_finish ()
436018334Speter{
436118334Speter#ifdef HANDLE_PRAGMA_WEAK
436218334Speter  if (HANDLE_PRAGMA_WEAK)
436318334Speter    {
436418334Speter      struct weak_syms *t;
436518334Speter      for (t = weak_decls; t; t = t->next)
436618334Speter	{
436752284Sobrien	  if (t->name)
436852284Sobrien	    {
436952284Sobrien	      ASM_WEAKEN_LABEL (asm_out_file, t->name);
437052284Sobrien	      if (t->value)
437152284Sobrien		ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
437252284Sobrien	    }
437318334Speter	}
437418334Speter    }
437518334Speter#endif
437618334Speter}
437718334Speter
437852284Sobrien/* Remove NAME from the pending list of weak symbols.  This prevents
437952284Sobrien   the compiler from emitting multiple .weak directives which confuses
438052284Sobrien   some assemblers.  */
438152284Sobrienstatic void
438252284Sobrienremove_from_pending_weak_list (name)
438352284Sobrien     char *name;
438452284Sobrien{
438552284Sobrien#ifdef HANDLE_PRAGMA_WEAK
438652284Sobrien  if (HANDLE_PRAGMA_WEAK)
438752284Sobrien    {
438852284Sobrien      struct weak_syms *t;
438952284Sobrien      for (t = weak_decls; t; t = t->next)
439052284Sobrien	{
439152284Sobrien	  if (t->name && strcmp (name, t->name) == 0)
439252284Sobrien	    t->name = NULL;
439352284Sobrien	}
439452284Sobrien    }
439552284Sobrien#endif
439652284Sobrien}
439752284Sobrien
439818334Spetervoid
439918334Speterassemble_alias (decl, target)
440052284Sobrien     tree decl, target ATTRIBUTE_UNUSED;
440118334Speter{
440218334Speter  char *name;
440318334Speter
440450397Sobrien  make_decl_rtl (decl, (char *) 0, 1);
440518334Speter  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
440618334Speter
440750397Sobrien#ifdef ASM_OUTPUT_DEF
440818334Speter  /* Make name accessible from other files, if appropriate.  */
440918334Speter
441018334Speter  if (TREE_PUBLIC (decl))
441118334Speter    {
441218334Speter#ifdef ASM_WEAKEN_LABEL
441318334Speter      if (DECL_WEAK (decl))
441452284Sobrien 	{
441552284Sobrien	  ASM_WEAKEN_LABEL (asm_out_file, name);
441652284Sobrien	  /* Remove this function from the pending weak list so that
441752284Sobrien	     we do not emit multiple .weak directives for it.  */
441852284Sobrien	  remove_from_pending_weak_list
441952284Sobrien	    (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
442052284Sobrien	}
442118334Speter      else
442218334Speter#endif
442318334Speter	ASM_GLOBALIZE_LABEL (asm_out_file, name);
442418334Speter    }
442518334Speter
442618334Speter  ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
442718334Speter  TREE_ASM_WRITTEN (decl) = 1;
442818334Speter#else
442950397Sobrien#ifdef ASM_OUTPUT_WEAK_ALIAS
443050397Sobrien  if (! DECL_WEAK (decl))
443150397Sobrien    warning ("only weak aliases are supported in this configuration");
443250397Sobrien
443350397Sobrien  ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
443450397Sobrien  TREE_ASM_WRITTEN (decl) = 1;
443550397Sobrien#else
443650397Sobrien  warning ("alias definitions not supported in this configuration; ignored");
443718334Speter#endif
443850397Sobrien#endif
443918334Speter}
444050397Sobrien
444150397Sobrien/* This determines whether or not we support link-once semantics.  */
444250397Sobrien#ifndef SUPPORTS_ONE_ONLY
444350397Sobrien#ifdef MAKE_DECL_ONE_ONLY
444450397Sobrien#define SUPPORTS_ONE_ONLY 1
444550397Sobrien#else
444650397Sobrien#define SUPPORTS_ONE_ONLY 0
444750397Sobrien#endif
444850397Sobrien#endif
444950397Sobrien
445050397Sobrien/* Returns 1 if the target configuration supports defining public symbols
445150397Sobrien   so that one of them will be chosen at link time instead of generating a
445250397Sobrien   multiply-defined symbol error, whether through the use of weak symbols or
445350397Sobrien   a target-specific mechanism for having duplicates discarded.  */
445450397Sobrien
445550397Sobrienint
445650397Sobriensupports_one_only ()
445750397Sobrien{
445850397Sobrien  if (SUPPORTS_ONE_ONLY)
445950397Sobrien    return 1;
446050397Sobrien  return SUPPORTS_WEAK;
446150397Sobrien}
446250397Sobrien
446350397Sobrien/* Set up DECL as a public symbol that can be defined in multiple
446450397Sobrien   translation units without generating a linker error.  */
446550397Sobrien
446650397Sobrienvoid
446750397Sobrienmake_decl_one_only (decl)
446850397Sobrien     tree decl;
446950397Sobrien{
447050397Sobrien  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
447150397Sobrien    abort ();
447250397Sobrien
447350397Sobrien  TREE_PUBLIC (decl) = 1;
447450397Sobrien
447550397Sobrien  if (TREE_CODE (decl) == VAR_DECL
447650397Sobrien      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
447750397Sobrien    DECL_COMMON (decl) = 1;
447850397Sobrien  else if (SUPPORTS_ONE_ONLY)
447950397Sobrien    {
448050397Sobrien#ifdef MAKE_DECL_ONE_ONLY
448150397Sobrien      MAKE_DECL_ONE_ONLY (decl);
448250397Sobrien#endif
448350397Sobrien      DECL_ONE_ONLY (decl) = 1;
448450397Sobrien    }
448550397Sobrien  else if (SUPPORTS_WEAK)
448650397Sobrien    DECL_WEAK (decl) = 1;
448750397Sobrien  else
448850397Sobrien    abort ();
448950397Sobrien}
4490