varasm.c revision 18334
118334Speter/* Output variables, constants and external declarations, for GNU compiler.
218334Speter   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 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
2918334Speter#include <stdio.h>
3018334Speter#include <setjmp.h>
3118334Speter/* #include <stab.h> */
3218334Speter#include "config.h"
3318334Speter#include "rtl.h"
3418334Speter#include "tree.h"
3518334Speter#include "flags.h"
3618334Speter#include "function.h"
3718334Speter#include "expr.h"
3818334Speter#include "output.h"
3918334Speter#include "hard-reg-set.h"
4018334Speter#include "regs.h"
4118334Speter#include "defaults.h"
4218334Speter#include "real.h"
4318334Speter#include "bytecode.h"
4418334Speter
4518334Speter#include "obstack.h"
4618334Speter#include "c-pragma.h"
4718334Speter
4818334Speter#ifdef XCOFF_DEBUGGING_INFO
4918334Speter#include "xcoffout.h"
5018334Speter#endif
5118334Speter
5218334Speter#include <ctype.h>
5318334Speter
5418334Speter#ifndef ASM_STABS_OP
5518334Speter#define ASM_STABS_OP ".stabs"
5618334Speter#endif
5718334Speter
5818334Speter/* This macro gets just the user-specified name
5918334Speter   out of the string in a SYMBOL_REF.  On most machines,
6018334Speter   we discard the * if any and that's all.  */
6118334Speter#ifndef STRIP_NAME_ENCODING
6218334Speter#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
6318334Speter  (VAR) = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'))
6418334Speter#endif
6518334Speter
6618334Speter/* File in which assembler code is being written.  */
6718334Speter
6818334Speterextern FILE *asm_out_file;
6918334Speter
7018334Speter/* The (assembler) name of the first globally-visible object output.  */
7118334Speterchar *first_global_object_name;
7218334Speter
7318334Speterextern struct obstack *current_obstack;
7418334Speterextern struct obstack *saveable_obstack;
7518334Speterextern struct obstack *rtl_obstack;
7618334Speterextern struct obstack permanent_obstack;
7718334Speter#define obstack_chunk_alloc xmalloc
7818334Speter
7918334Speter/* Number for making the label on the next
8018334Speter   constant that is stored in memory.  */
8118334Speter
8218334Speterint const_labelno;
8318334Speter
8418334Speter/* Number for making the label on the next
8518334Speter   static variable internal to a function.  */
8618334Speter
8718334Speterint var_labelno;
8818334Speter
8918334Speter/* Carry information from ASM_DECLARE_OBJECT_NAME
9018334Speter   to ASM_FINISH_DECLARE_OBJECT.  */
9118334Speter
9218334Speterint size_directive_output;
9318334Speter
9418334Speter/* The last decl for which assemble_variable was called,
9518334Speter   if it did ASM_DECLARE_OBJECT_NAME.
9618334Speter   If the last call to assemble_variable didn't do that,
9718334Speter   this holds 0.  */
9818334Speter
9918334Spetertree last_assemble_variable_decl;
10018334Speter
10118334Speter
10218334Speter#ifdef HANDLE_PRAGMA_WEAK
10318334Speter/* Any weak symbol declarations waiting to be emitted.  */
10418334Speter
10518334Speterstruct weak_syms
10618334Speter{
10718334Speter  struct weak_syms *next;
10818334Speter  char *name;
10918334Speter  char *value;
11018334Speter};
11118334Speter
11218334Speterstatic struct weak_syms *weak_decls;
11318334Speter#endif
11418334Speter
11518334Speter/* Nonzero if at least one function definition has been seen.  */
11618334Speter
11718334Speterstatic int function_defined;
11818334Speter
11918334Speterstruct addr_const;
12018334Speterstruct constant_descriptor;
12118334Speterstruct rtx_const;
12218334Speterstruct pool_constant;
12318334Speter
12418334Speterstatic void bc_make_decl_rtl		PROTO((tree, char *, int));
12518334Speterstatic char *strip_reg_name		PROTO((char *));
12618334Speterstatic void bc_output_ascii		PROTO((FILE *, char *, int));
12718334Speterstatic int contains_pointers_p		PROTO((tree));
12818334Speterstatic void decode_addr_const		PROTO((tree, struct addr_const *));
12918334Speterstatic int const_hash			PROTO((tree));
13018334Speterstatic int compare_constant		PROTO((tree,
13118334Speter					       struct constant_descriptor *));
13218334Speterstatic char *compare_constant_1		PROTO((tree, char *));
13318334Speterstatic struct constant_descriptor *record_constant PROTO((tree));
13418334Speterstatic void record_constant_1		PROTO((tree));
13518334Speterstatic tree copy_constant		PROTO((tree));
13618334Speterstatic void output_constant_def_contents  PROTO((tree, int, int));
13718334Speterstatic void decode_rtx_const		PROTO((enum machine_mode, rtx,
13818334Speter					       struct rtx_const *));
13918334Speterstatic int const_hash_rtx		PROTO((enum machine_mode, rtx));
14018334Speterstatic int compare_constant_rtx		PROTO((enum machine_mode, rtx,
14118334Speter					       struct constant_descriptor *));
14218334Speterstatic struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
14318334Speter							      rtx));
14418334Speterstatic struct pool_constant *find_pool_constant PROTO((rtx));
14518334Speterstatic int output_addressed_constants	PROTO((tree));
14618334Speterstatic void bc_assemble_integer		PROTO((tree, int));
14718334Speterstatic void output_constructor		PROTO((tree, int));
14818334Speter
14918334Speter#ifdef EXTRA_SECTIONS
15018334Speterstatic enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section
15118334Speter  = no_section;
15218334Speter#else
15318334Speterstatic enum in_section {no_section, in_text, in_data, in_named} in_section
15418334Speter  = no_section;
15518334Speter#endif
15618334Speter
15718334Speter/* Return a non-zero value if DECL has a section attribute.  */
15818334Speter#define IN_NAMED_SECTION(DECL) \
15918334Speter  ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
16018334Speter   && DECL_SECTION_NAME (DECL) != NULL_TREE)
16118334Speter
16218334Speter/* Text of section name when in_section == in_named.  */
16318334Speterstatic char *in_named_name;
16418334Speter
16518334Speter/* Define functions like text_section for any extra sections.  */
16618334Speter#ifdef EXTRA_SECTION_FUNCTIONS
16718334SpeterEXTRA_SECTION_FUNCTIONS
16818334Speter#endif
16918334Speter
17018334Speter/* Tell assembler to switch to text section.  */
17118334Speter
17218334Spetervoid
17318334Spetertext_section ()
17418334Speter{
17518334Speter  if (in_section != in_text)
17618334Speter    {
17718334Speter      if (output_bytecode)
17818334Speter	bc_text ();
17918334Speter      else
18018334Speter	fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
18118334Speter
18218334Speter      in_section = in_text;
18318334Speter    }
18418334Speter}
18518334Speter
18618334Speter/* Tell assembler to switch to data section.  */
18718334Speter
18818334Spetervoid
18918334Speterdata_section ()
19018334Speter{
19118334Speter  if (in_section != in_data)
19218334Speter    {
19318334Speter      if (output_bytecode)
19418334Speter	bc_data ();
19518334Speter      else
19618334Speter	{
19718334Speter	  if (flag_shared_data)
19818334Speter	    {
19918334Speter#ifdef SHARED_SECTION_ASM_OP
20018334Speter	      fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
20118334Speter#else
20218334Speter	      fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
20318334Speter#endif
20418334Speter	    }
20518334Speter	  else
20618334Speter	    fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
20718334Speter	}
20818334Speter
20918334Speter      in_section = in_data;
21018334Speter    }
21118334Speter}
21218334Speter
21318334Speter/* Tell assembler to switch to read-only data section.  This is normally
21418334Speter   the text section.  */
21518334Speter
21618334Spetervoid
21718334Speterreadonly_data_section ()
21818334Speter{
21918334Speter#ifdef READONLY_DATA_SECTION
22018334Speter  READONLY_DATA_SECTION ();  /* Note this can call data_section.  */
22118334Speter#else
22218334Speter  text_section ();
22318334Speter#endif
22418334Speter}
22518334Speter
22618334Speter/* Determine if we're in the text section. */
22718334Speter
22818334Speterint
22918334Speterin_text_section ()
23018334Speter{
23118334Speter  return in_section == in_text;
23218334Speter}
23318334Speter
23418334Speter/* Tell assembler to change to section NAME for DECL.
23518334Speter   If DECL is NULL, just switch to section NAME.
23618334Speter   If NAME is NULL, get the name from DECL.  */
23718334Speter
23818334Spetervoid
23918334Speternamed_section (decl, name)
24018334Speter     tree decl;
24118334Speter     char *name;
24218334Speter{
24318334Speter  if (decl != NULL_TREE
24418334Speter      && (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL))
24518334Speter    abort ();
24618334Speter  if (name == NULL)
24718334Speter    name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
24818334Speter
24918334Speter  if (in_section != in_named || strcmp (name, in_named_name))
25018334Speter    {
25118334Speter      in_named_name = name;
25218334Speter      in_section = in_named;
25318334Speter
25418334Speter#ifdef ASM_OUTPUT_SECTION_NAME
25518334Speter      ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name);
25618334Speter#else
25718334Speter      /* Section attributes are not supported if this macro isn't provided -
25818334Speter	 some host formats don't support them at all.  The front-end should
25918334Speter	 already have flagged this as an error.  */
26018334Speter      abort ();
26118334Speter#endif
26218334Speter    }
26318334Speter}
26418334Speter
26518334Speter/* Switch to the section for function DECL.
26618334Speter
26718334Speter   If DECL is NULL_TREE, switch to the text section.
26818334Speter   ??? It's not clear that we will ever be passed NULL_TREE, but it's
26918334Speter   safer to handle it.  */
27018334Speter
27118334Spetervoid
27218334Speterfunction_section (decl)
27318334Speter     tree decl;
27418334Speter{
27518334Speter  if (decl != NULL_TREE
27618334Speter      && DECL_SECTION_NAME (decl) != NULL_TREE)
27718334Speter    named_section (decl, (char *) 0);
27818334Speter else
27918334Speter   text_section ();
28018334Speter}
28118334Speter
28218334Speter/* Create the rtl to represent a function, for a function definition.
28318334Speter   DECL is a FUNCTION_DECL node which describes which function.
28418334Speter   The rtl is stored into DECL.  */
28518334Speter
28618334Spetervoid
28718334Spetermake_function_rtl (decl)
28818334Speter     tree decl;
28918334Speter{
29018334Speter  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
29118334Speter
29218334Speter  if (output_bytecode)
29318334Speter    {
29418334Speter      if (DECL_RTL (decl) == 0)
29518334Speter	DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
29618334Speter
29718334Speter      /* Record that at least one function has been defined.  */
29818334Speter      function_defined = 1;
29918334Speter      return;
30018334Speter    }
30118334Speter
30218334Speter  /* Rename a nested function to avoid conflicts.  */
30318334Speter  if (decl_function_context (decl) != 0
30418334Speter      && DECL_INITIAL (decl) != 0
30518334Speter      && DECL_RTL (decl) == 0)
30618334Speter    {
30718334Speter      char *label;
30818334Speter
30918334Speter      name = IDENTIFIER_POINTER (DECL_NAME (decl));
31018334Speter      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
31118334Speter      name = obstack_copy0 (saveable_obstack, label, strlen (label));
31218334Speter      var_labelno++;
31318334Speter    }
31418334Speter
31518334Speter  if (DECL_RTL (decl) == 0)
31618334Speter    {
31718334Speter      DECL_RTL (decl)
31818334Speter	= gen_rtx (MEM, DECL_MODE (decl),
31918334Speter		   gen_rtx (SYMBOL_REF, Pmode, name));
32018334Speter
32118334Speter      /* Optionally set flags or add text to the name to record information
32218334Speter	 such as that it is a function name.  If the name is changed, the macro
32318334Speter	 ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
32418334Speter#ifdef ENCODE_SECTION_INFO
32518334Speter      ENCODE_SECTION_INFO (decl);
32618334Speter#endif
32718334Speter    }
32818334Speter
32918334Speter  /* Record at least one function has been defined.  */
33018334Speter  function_defined = 1;
33118334Speter}
33218334Speter
33318334Speter/* Create the DECL_RTL for a declaration for a static or external
33418334Speter   variable or static or external function.
33518334Speter   ASMSPEC, if not 0, is the string which the user specified
33618334Speter   as the assembler symbol name.
33718334Speter   TOP_LEVEL is nonzero if this is a file-scope variable.
33818334Speter   This is never called for PARM_DECLs.  */
33918334Speter
34018334Speterstatic void
34118334Speterbc_make_decl_rtl (decl, asmspec, top_level)
34218334Speter     tree decl;
34318334Speter     char *asmspec;
34418334Speter     int top_level;
34518334Speter{
34618334Speter  register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));
34718334Speter
34818334Speter  if (DECL_RTL (decl) == 0)
34918334Speter    {
35018334Speter      /* Print an error message for register variables.  */
35118334Speter      if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
35218334Speter	error ("function declared `register'");
35318334Speter      else if (DECL_REGISTER (decl))
35418334Speter	error ("global register variables not supported in the interpreter");
35518334Speter
35618334Speter      /* Handle ordinary static variables and functions.  */
35718334Speter      if (DECL_RTL (decl) == 0)
35818334Speter	{
35918334Speter	  /* Can't use just the variable's own name for a variable
36018334Speter	     whose scope is less than the whole file.
36118334Speter	     Concatenate a distinguishing number.  */
36218334Speter	  if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
36318334Speter	    {
36418334Speter	      char *label;
36518334Speter
36618334Speter	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
36718334Speter	      name = obstack_copy0 (saveable_obstack, label, strlen (label));
36818334Speter	      var_labelno++;
36918334Speter	    }
37018334Speter
37118334Speter	  DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
37218334Speter	}
37318334Speter    }
37418334Speter}
37518334Speter
37618334Speter/* Given NAME, a putative register name, discard any customary prefixes.  */
37718334Speter
37818334Speterstatic char *
37918334Speterstrip_reg_name (name)
38018334Speter     char *name;
38118334Speter{
38218334Speter#ifdef REGISTER_PREFIX
38318334Speter  if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
38418334Speter    name += strlen (REGISTER_PREFIX);
38518334Speter#endif
38618334Speter  if (name[0] == '%' || name[0] == '#')
38718334Speter    name++;
38818334Speter  return name;
38918334Speter}
39018334Speter
39118334Speter/* Decode an `asm' spec for a declaration as a register name.
39218334Speter   Return the register number, or -1 if nothing specified,
39318334Speter   or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
39418334Speter   or -3 if ASMSPEC is `cc' and is not recognized,
39518334Speter   or -4 if ASMSPEC is `memory' and is not recognized.
39618334Speter   Accept an exact spelling or a decimal number.
39718334Speter   Prefixes such as % are optional.  */
39818334Speter
39918334Speterint
40018334Speterdecode_reg_name (asmspec)
40118334Speter     char *asmspec;
40218334Speter{
40318334Speter  if (asmspec != 0)
40418334Speter    {
40518334Speter      int i;
40618334Speter
40718334Speter      /* Get rid of confusing prefixes.  */
40818334Speter      asmspec = strip_reg_name (asmspec);
40918334Speter
41018334Speter      /* Allow a decimal number as a "register name".  */
41118334Speter      for (i = strlen (asmspec) - 1; i >= 0; i--)
41218334Speter	if (! (asmspec[i] >= '0' && asmspec[i] <= '9'))
41318334Speter	  break;
41418334Speter      if (asmspec[0] != 0 && i < 0)
41518334Speter	{
41618334Speter	  i = atoi (asmspec);
41718334Speter	  if (i < FIRST_PSEUDO_REGISTER && i >= 0)
41818334Speter	    return i;
41918334Speter	  else
42018334Speter	    return -2;
42118334Speter	}
42218334Speter
42318334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
42418334Speter	if (reg_names[i][0]
42518334Speter	    && ! strcmp (asmspec, strip_reg_name (reg_names[i])))
42618334Speter	  return i;
42718334Speter
42818334Speter#ifdef ADDITIONAL_REGISTER_NAMES
42918334Speter      {
43018334Speter	static struct { char *name; int number; } table[]
43118334Speter	  = ADDITIONAL_REGISTER_NAMES;
43218334Speter
43318334Speter	for (i = 0; i < sizeof (table) / sizeof (table[0]); i++)
43418334Speter	  if (! strcmp (asmspec, table[i].name))
43518334Speter	    return table[i].number;
43618334Speter      }
43718334Speter#endif /* ADDITIONAL_REGISTER_NAMES */
43818334Speter
43918334Speter      if (!strcmp (asmspec, "memory"))
44018334Speter	return -4;
44118334Speter
44218334Speter      if (!strcmp (asmspec, "cc"))
44318334Speter	return -3;
44418334Speter
44518334Speter      return -2;
44618334Speter    }
44718334Speter
44818334Speter  return -1;
44918334Speter}
45018334Speter
45118334Speter/* Create the DECL_RTL for a declaration for a static or external variable
45218334Speter   or static or external function.
45318334Speter   ASMSPEC, if not 0, is the string which the user specified
45418334Speter   as the assembler symbol name.
45518334Speter   TOP_LEVEL is nonzero if this is a file-scope variable.
45618334Speter
45718334Speter   This is never called for PARM_DECL nodes.  */
45818334Speter
45918334Spetervoid
46018334Spetermake_decl_rtl (decl, asmspec, top_level)
46118334Speter     tree decl;
46218334Speter     char *asmspec;
46318334Speter     int top_level;
46418334Speter{
46518334Speter  register char *name = 0;
46618334Speter  int reg_number;
46718334Speter
46818334Speter  if (output_bytecode)
46918334Speter    {
47018334Speter      bc_make_decl_rtl (decl, asmspec, top_level);
47118334Speter      return;
47218334Speter    }
47318334Speter
47418334Speter  reg_number = decode_reg_name (asmspec);
47518334Speter
47618334Speter  if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
47718334Speter    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
47818334Speter
47918334Speter  if (reg_number == -2)
48018334Speter    {
48118334Speter      /* ASMSPEC is given, and not the name of a register.  */
48218334Speter      name = (char *) obstack_alloc (saveable_obstack,
48318334Speter				     strlen (asmspec) + 2);
48418334Speter      name[0] = '*';
48518334Speter      strcpy (&name[1], asmspec);
48618334Speter    }
48718334Speter
48818334Speter  /* For a duplicate declaration, we can be called twice on the
48918334Speter     same DECL node.  Don't discard the RTL already made.  */
49018334Speter  if (DECL_RTL (decl) == 0)
49118334Speter    {
49218334Speter      DECL_RTL (decl) = 0;
49318334Speter
49418334Speter      /* First detect errors in declaring global registers.  */
49518334Speter      if (DECL_REGISTER (decl) && reg_number == -1)
49618334Speter	error_with_decl (decl,
49718334Speter			 "register name not specified for `%s'");
49818334Speter      else if (DECL_REGISTER (decl) && reg_number < 0)
49918334Speter	error_with_decl (decl,
50018334Speter			 "invalid register name for `%s'");
50118334Speter      else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl))
50218334Speter	error_with_decl (decl,
50318334Speter			 "register name given for non-register variable `%s'");
50418334Speter      else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
50518334Speter	error ("function declared `register'");
50618334Speter      else if (DECL_REGISTER (decl) && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
50718334Speter	error_with_decl (decl, "data type of `%s' isn't suitable for a register");
50818334Speter      else if (DECL_REGISTER (decl)
50918334Speter	       && ! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
51018334Speter	error_with_decl (decl, "register number for `%s' isn't suitable for the data type");
51118334Speter      /* Now handle properly declared static register variables.  */
51218334Speter      else if (DECL_REGISTER (decl))
51318334Speter	{
51418334Speter	  int nregs;
51518334Speter#if 0 /* yylex should print the warning for this */
51618334Speter	  if (pedantic)
51718334Speter	    pedwarn ("ANSI C forbids global register variables");
51818334Speter#endif
51918334Speter	  if (DECL_INITIAL (decl) != 0 && top_level)
52018334Speter	    {
52118334Speter	      DECL_INITIAL (decl) = 0;
52218334Speter	      error ("global register variable has initial value");
52318334Speter	    }
52418334Speter	  if (fixed_regs[reg_number] == 0
52518334Speter	      && function_defined && top_level)
52618334Speter	    error ("global register variable follows a function definition");
52718334Speter	  if (TREE_THIS_VOLATILE (decl))
52818334Speter	    warning ("volatile register variables don't work as you might wish");
52918334Speter
53018334Speter	  /* If the user specified one of the eliminables registers here,
53118334Speter	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
53218334Speter	     confused with that register and be eliminated.  Although this
53318334Speter	     usage is somewhat suspect, we nevertheless use the following
53418334Speter	     kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
53518334Speter
53618334Speter	  DECL_RTL (decl)
53718334Speter	    = gen_rtx (REG, DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
53818334Speter	  REGNO (DECL_RTL (decl)) = reg_number;
53918334Speter	  REG_USERVAR_P (DECL_RTL (decl)) = 1;
54018334Speter
54118334Speter	  if (top_level)
54218334Speter	    {
54318334Speter	      /* Make this register global, so not usable for anything
54418334Speter		 else.  */
54518334Speter	      nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
54618334Speter	      while (nregs > 0)
54718334Speter		globalize_reg (reg_number + --nregs);
54818334Speter	    }
54918334Speter	}
55018334Speter      /* Specifying a section attribute on an uninitialized variable does not
55118334Speter	 (and cannot) cause it to be put in the given section.  The linker
55218334Speter	 can only put initialized objects in specific sections, everything
55318334Speter	 else goes in bss for the linker to sort out later (otherwise the
55418334Speter	 linker would give a duplicate definition error for each compilation
55518334Speter	 unit that behaved thusly).  So warn the user.  */
55618334Speter      else if (TREE_CODE (decl) == VAR_DECL
55718334Speter	       && DECL_SECTION_NAME (decl) != NULL_TREE
55818334Speter	       && DECL_INITIAL (decl) == NULL_TREE
55918334Speter	       && DECL_COMMON (decl)
56018334Speter	       && ! flag_no_common)
56118334Speter	{
56218334Speter	  warning_with_decl (decl,
56318334Speter			     "section attribute ignored for uninitialized variable `%s'");
56418334Speter	  /* Remove the section name so subsequent declarations won't see it.
56518334Speter	     We are ignoring it, remember.  */
56618334Speter	  DECL_SECTION_NAME (decl) = NULL_TREE;
56718334Speter	}
56818334Speter
56918334Speter      /* Now handle ordinary static variables and functions (in memory).
57018334Speter	 Also handle vars declared register invalidly.  */
57118334Speter      if (DECL_RTL (decl) == 0)
57218334Speter	{
57318334Speter	  /* Can't use just the variable's own name for a variable
57418334Speter	     whose scope is less than the whole file.
57518334Speter	     Concatenate a distinguishing number.  */
57618334Speter	  if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
57718334Speter	    {
57818334Speter	      char *label;
57918334Speter
58018334Speter	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
58118334Speter	      name = obstack_copy0 (saveable_obstack, label, strlen (label));
58218334Speter	      var_labelno++;
58318334Speter	    }
58418334Speter
58518334Speter	  if (name == 0)
58618334Speter	    abort ();
58718334Speter
58818334Speter	  DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl),
58918334Speter				     gen_rtx (SYMBOL_REF, Pmode, name));
59018334Speter
59118334Speter	  /* If this variable is to be treated as volatile, show its
59218334Speter	     tree node has side effects.  If it has side effects, either
59318334Speter	     because of this test or from TREE_THIS_VOLATILE also
59418334Speter	     being set, show the MEM is volatile.  */
59518334Speter	  if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
59618334Speter	      && TREE_PUBLIC (decl))
59718334Speter	    TREE_SIDE_EFFECTS (decl) = 1;
59818334Speter	  if (TREE_SIDE_EFFECTS (decl))
59918334Speter	    MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
60018334Speter
60118334Speter	  if (TREE_READONLY (decl))
60218334Speter	    RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
60318334Speter	  MEM_IN_STRUCT_P (DECL_RTL (decl))
60418334Speter	    = AGGREGATE_TYPE_P (TREE_TYPE (decl));
60518334Speter
60618334Speter	  /* Optionally set flags or add text to the name to record information
60718334Speter	     such as that it is a function name.
60818334Speter	     If the name is changed, the macro ASM_OUTPUT_LABELREF
60918334Speter	     will have to know how to strip this information.  */
61018334Speter#ifdef ENCODE_SECTION_INFO
61118334Speter	  ENCODE_SECTION_INFO (decl);
61218334Speter#endif
61318334Speter	}
61418334Speter    }
61518334Speter  /* If the old RTL had the wrong mode, fix the mode.  */
61618334Speter  else if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
61718334Speter    {
61818334Speter      rtx rtl = DECL_RTL (decl);
61918334Speter      PUT_MODE (rtl, DECL_MODE (decl));
62018334Speter    }
62118334Speter}
62218334Speter
62318334Speter/* Make the rtl for variable VAR be volatile.
62418334Speter   Use this only for static variables.  */
62518334Speter
62618334Spetervoid
62718334Spetermake_var_volatile (var)
62818334Speter     tree var;
62918334Speter{
63018334Speter  if (GET_CODE (DECL_RTL (var)) != MEM)
63118334Speter    abort ();
63218334Speter
63318334Speter  MEM_VOLATILE_P (DECL_RTL (var)) = 1;
63418334Speter}
63518334Speter
63618334Speter/* Output alignment directive to align for constant expression EXP.  */
63718334Speter
63818334Spetervoid
63918334Speterassemble_constant_align (exp)
64018334Speter     tree exp;
64118334Speter{
64218334Speter  int align;
64318334Speter
64418334Speter  /* Align the location counter as required by EXP's data type.  */
64518334Speter  align = TYPE_ALIGN (TREE_TYPE (exp));
64618334Speter#ifdef CONSTANT_ALIGNMENT
64718334Speter  align = CONSTANT_ALIGNMENT (exp, align);
64818334Speter#endif
64918334Speter
65018334Speter  if (align > BITS_PER_UNIT)
65118334Speter    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
65218334Speter}
65318334Speter
65418334Speter/* Output a string of literal assembler code
65518334Speter   for an `asm' keyword used between functions.  */
65618334Speter
65718334Spetervoid
65818334Speterassemble_asm (string)
65918334Speter     tree string;
66018334Speter{
66118334Speter  if (output_bytecode)
66218334Speter    {
66318334Speter      error ("asm statements not allowed in interpreter");
66418334Speter      return;
66518334Speter    }
66618334Speter
66718334Speter  app_enable ();
66818334Speter
66918334Speter  if (TREE_CODE (string) == ADDR_EXPR)
67018334Speter    string = TREE_OPERAND (string, 0);
67118334Speter
67218334Speter  fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
67318334Speter}
67418334Speter
67518334Speter#if 0 /* This should no longer be needed, because
67618334Speter	 flag_gnu_linker should be 0 on these systems,
67718334Speter	 which should prevent any output
67818334Speter	 if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent.  */
67918334Speter#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))
68018334Speter#ifndef ASM_OUTPUT_CONSTRUCTOR
68118334Speter#define ASM_OUTPUT_CONSTRUCTOR(file, name)
68218334Speter#endif
68318334Speter#ifndef ASM_OUTPUT_DESTRUCTOR
68418334Speter#define ASM_OUTPUT_DESTRUCTOR(file, name)
68518334Speter#endif
68618334Speter#endif
68718334Speter#endif /* 0 */
68818334Speter
68918334Speter/* Record an element in the table of global destructors.
69018334Speter   How this is done depends on what sort of assembler and linker
69118334Speter   are in use.
69218334Speter
69318334Speter   NAME should be the name of a global function to be called
69418334Speter   at exit time.  This name is output using assemble_name.  */
69518334Speter
69618334Spetervoid
69718334Speterassemble_destructor (name)
69818334Speter     char *name;
69918334Speter{
70018334Speter#ifdef ASM_OUTPUT_DESTRUCTOR
70118334Speter  ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
70218334Speter#else
70318334Speter  if (flag_gnu_linker)
70418334Speter    {
70518334Speter      /* Now tell GNU LD that this is part of the static destructor set.  */
70618334Speter      /* This code works for any machine provided you use GNU as/ld.  */
70718334Speter      fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
70818334Speter      assemble_name (asm_out_file, name);
70918334Speter      fputc ('\n', asm_out_file);
71018334Speter    }
71118334Speter#endif
71218334Speter}
71318334Speter
71418334Speter/* Likewise for global constructors.  */
71518334Speter
71618334Spetervoid
71718334Speterassemble_constructor (name)
71818334Speter     char *name;
71918334Speter{
72018334Speter#ifdef ASM_OUTPUT_CONSTRUCTOR
72118334Speter  ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
72218334Speter#else
72318334Speter  if (flag_gnu_linker)
72418334Speter    {
72518334Speter      /* Now tell GNU LD that this is part of the static constructor set.  */
72618334Speter      /* This code works for any machine provided you use GNU as/ld.  */
72718334Speter      fprintf (asm_out_file, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
72818334Speter      assemble_name (asm_out_file, name);
72918334Speter      fputc ('\n', asm_out_file);
73018334Speter    }
73118334Speter#endif
73218334Speter}
73318334Speter
73418334Speter/* Likewise for entries we want to record for garbage collection.
73518334Speter   Garbage collection is still under development.  */
73618334Speter
73718334Spetervoid
73818334Speterassemble_gc_entry (name)
73918334Speter     char *name;
74018334Speter{
74118334Speter#ifdef ASM_OUTPUT_GC_ENTRY
74218334Speter  ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
74318334Speter#else
74418334Speter  if (flag_gnu_linker)
74518334Speter    {
74618334Speter      /* Now tell GNU LD that this is part of the static constructor set.  */
74718334Speter      fprintf (asm_out_file, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
74818334Speter      assemble_name (asm_out_file, name);
74918334Speter      fputc ('\n', asm_out_file);
75018334Speter    }
75118334Speter#endif
75218334Speter}
75318334Speter
75418334Speter/* Output assembler code for the constant pool of a function and associated
75518334Speter   with defining the name of the function.  DECL describes the function.
75618334Speter   NAME is the function's name.  For the constant pool, we use the current
75718334Speter   constant pool data.  */
75818334Speter
75918334Spetervoid
76018334Speterassemble_start_function (decl, fnname)
76118334Speter     tree decl;
76218334Speter     char *fnname;
76318334Speter{
76418334Speter  int align;
76518334Speter
76618334Speter  /* The following code does not need preprocessing in the assembler.  */
76718334Speter
76818334Speter  app_disable ();
76918334Speter
77018334Speter  output_constant_pool (fnname, decl);
77118334Speter
77218334Speter  function_section (decl);
77318334Speter
77418334Speter  /* Tell assembler to move to target machine's alignment for functions.  */
77518334Speter  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
77618334Speter  if (align > 0)
77718334Speter    {
77818334Speter      if (output_bytecode)
77918334Speter	BC_OUTPUT_ALIGN (asm_out_file, align);
78018334Speter      else
78118334Speter	ASM_OUTPUT_ALIGN (asm_out_file, align);
78218334Speter    }
78318334Speter
78418334Speter#ifdef ASM_OUTPUT_FUNCTION_PREFIX
78518334Speter  ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
78618334Speter#endif
78718334Speter
78818334Speter#ifdef SDB_DEBUGGING_INFO
78918334Speter  /* Output SDB definition of the function.  */
79018334Speter  if (write_symbols == SDB_DEBUG)
79118334Speter    sdbout_mark_begin_function ();
79218334Speter#endif
79318334Speter
79418334Speter#ifdef DBX_DEBUGGING_INFO
79518334Speter  /* Output DBX definition of the function.  */
79618334Speter  if (write_symbols == DBX_DEBUG)
79718334Speter    dbxout_begin_function (decl);
79818334Speter#endif
79918334Speter
80018334Speter  /* Make function name accessible from other files, if appropriate.  */
80118334Speter
80218334Speter  if (TREE_PUBLIC (decl))
80318334Speter    {
80418334Speter      if (!first_global_object_name)
80518334Speter	{
80618334Speter	  char *p;
80718334Speter
80818334Speter	  STRIP_NAME_ENCODING (p, fnname);
80918334Speter	  first_global_object_name = permalloc (strlen (p) + 1);
81018334Speter	  strcpy (first_global_object_name, p);
81118334Speter	}
81218334Speter
81318334Speter#ifdef ASM_WEAKEN_LABEL
81418334Speter      if (DECL_WEAK (decl))
81518334Speter	ASM_WEAKEN_LABEL (asm_out_file, fnname);
81618334Speter      else
81718334Speter#endif
81818334Speter      if (output_bytecode)
81918334Speter	BC_GLOBALIZE_LABEL (asm_out_file, fnname);
82018334Speter      else
82118334Speter	ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
82218334Speter    }
82318334Speter
82418334Speter  /* Do any machine/system dependent processing of the function name */
82518334Speter#ifdef ASM_DECLARE_FUNCTION_NAME
82618334Speter  ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
82718334Speter#else
82818334Speter  /* Standard thing is just output label for the function.  */
82918334Speter  if (output_bytecode)
83018334Speter    BC_OUTPUT_LABEL (asm_out_file, fnname);
83118334Speter  else
83218334Speter    ASM_OUTPUT_LABEL (asm_out_file, fnname);
83318334Speter#endif /* ASM_DECLARE_FUNCTION_NAME */
83418334Speter}
83518334Speter
83618334Speter/* Output assembler code associated with defining the size of the
83718334Speter   function.  DECL describes the function.  NAME is the function's name.  */
83818334Speter
83918334Spetervoid
84018334Speterassemble_end_function (decl, fnname)
84118334Speter     tree decl;
84218334Speter     char *fnname;
84318334Speter{
84418334Speter#ifdef ASM_DECLARE_FUNCTION_SIZE
84518334Speter  ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
84618334Speter#endif
84718334Speter}
84818334Speter
84918334Speter/* Assemble code to leave SIZE bytes of zeros.  */
85018334Speter
85118334Spetervoid
85218334Speterassemble_zeros (size)
85318334Speter     int size;
85418334Speter{
85518334Speter  if (output_bytecode)
85618334Speter    {
85718334Speter      bc_emit_const_skip (size);
85818334Speter      return;
85918334Speter    }
86018334Speter
86118334Speter#ifdef ASM_NO_SKIP_IN_TEXT
86218334Speter  /* The `space' pseudo in the text section outputs nop insns rather than 0s,
86318334Speter     so we must output 0s explicitly in the text section.  */
86418334Speter  if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
86518334Speter    {
86618334Speter      int i;
86718334Speter
86818334Speter      for (i = 0; i < size - 20; i += 20)
86918334Speter	{
87018334Speter#ifdef ASM_BYTE_OP
87118334Speter	  fprintf (asm_out_file,
87218334Speter		   "%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);
87318334Speter#else
87418334Speter	  fprintf (asm_out_file,
87518334Speter		   "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
87618334Speter#endif
87718334Speter	}
87818334Speter      if (i < size)
87918334Speter        {
88018334Speter#ifdef ASM_BYTE_OP
88118334Speter	  fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);
88218334Speter#else
88318334Speter	  fprintf (asm_out_file, "\tbyte 0");
88418334Speter#endif
88518334Speter	  i++;
88618334Speter	  for (; i < size; i++)
88718334Speter	    fprintf (asm_out_file, ",0");
88818334Speter	  fprintf (asm_out_file, "\n");
88918334Speter	}
89018334Speter    }
89118334Speter  else
89218334Speter#endif
89318334Speter    if (size > 0)
89418334Speter      {
89518334Speter	if (output_bytecode)
89618334Speter	  BC_OUTPUT_SKIP (asm_out_file, size);
89718334Speter	else
89818334Speter	  ASM_OUTPUT_SKIP (asm_out_file, size);
89918334Speter      }
90018334Speter}
90118334Speter
90218334Speter/* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
90318334Speter
90418334Spetervoid
90518334Speterassemble_align (align)
90618334Speter     int align;
90718334Speter{
90818334Speter  if (align > BITS_PER_UNIT)
90918334Speter    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
91018334Speter}
91118334Speter
91218334Speter/* Assemble a string constant with the specified C string as contents.  */
91318334Speter
91418334Spetervoid
91518334Speterassemble_string (p, size)
91618334Speter     char *p;
91718334Speter     int size;
91818334Speter{
91918334Speter  register int i;
92018334Speter  int pos = 0;
92118334Speter  int maximum = 2000;
92218334Speter
92318334Speter  if (output_bytecode)
92418334Speter    {
92518334Speter      bc_emit (p, size);
92618334Speter      return;
92718334Speter    }
92818334Speter
92918334Speter  /* If the string is very long, split it up.  */
93018334Speter
93118334Speter  while (pos < size)
93218334Speter    {
93318334Speter      int thissize = size - pos;
93418334Speter      if (thissize > maximum)
93518334Speter	thissize = maximum;
93618334Speter
93718334Speter      if (output_bytecode)
93818334Speter	bc_output_ascii (asm_out_file, p, thissize);
93918334Speter      else
94018334Speter	{
94118334Speter	  ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
94218334Speter	}
94318334Speter
94418334Speter      pos += thissize;
94518334Speter      p += thissize;
94618334Speter    }
94718334Speter}
94818334Speter
94918334Speterstatic void
95018334Speterbc_output_ascii (file, p, size)
95118334Speter     FILE *file;
95218334Speter     char *p;
95318334Speter     int size;
95418334Speter{
95518334Speter  BC_OUTPUT_ASCII (file, p, size);
95618334Speter}
95718334Speter
95818334Speter/* Assemble everything that is needed for a variable or function declaration.
95918334Speter   Not used for automatic variables, and not used for function definitions.
96018334Speter   Should not be called for variables of incomplete structure type.
96118334Speter
96218334Speter   TOP_LEVEL is nonzero if this variable has file scope.
96318334Speter   AT_END is nonzero if this is the special handling, at end of compilation,
96418334Speter   to define things that have had only tentative definitions.
96518334Speter   DONT_OUTPUT_DATA if nonzero means don't actually output the
96618334Speter   initial value (that will be done by the caller).  */
96718334Speter
96818334Spetervoid
96918334Speterassemble_variable (decl, top_level, at_end, dont_output_data)
97018334Speter     tree decl;
97118334Speter     int top_level;
97218334Speter     int at_end;
97318334Speter     int dont_output_data;
97418334Speter{
97518334Speter  register char *name;
97618334Speter  int align;
97718334Speter  tree size_tree;
97818334Speter  int reloc = 0;
97918334Speter  enum in_section saved_in_section;
98018334Speter
98118334Speter  last_assemble_variable_decl = 0;
98218334Speter
98318334Speter  if (output_bytecode)
98418334Speter    return;
98518334Speter
98618334Speter  if (GET_CODE (DECL_RTL (decl)) == REG)
98718334Speter    {
98818334Speter      /* Do output symbol info for global register variables, but do nothing
98918334Speter	 else for them.  */
99018334Speter
99118334Speter      if (TREE_ASM_WRITTEN (decl))
99218334Speter	return;
99318334Speter      TREE_ASM_WRITTEN (decl) = 1;
99418334Speter
99518334Speter      if (!output_bytecode)
99618334Speter	{
99718334Speter#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
99818334Speter	  /* File-scope global variables are output here.  */
99918334Speter	  if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
100018334Speter	      && top_level)
100118334Speter	    dbxout_symbol (decl, 0);
100218334Speter#endif
100318334Speter#ifdef SDB_DEBUGGING_INFO
100418334Speter	  if (write_symbols == SDB_DEBUG && top_level
100518334Speter	      /* Leave initialized global vars for end of compilation;
100618334Speter		 see comment in compile_file.  */
100718334Speter	      && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
100818334Speter	    sdbout_symbol (decl, 0);
100918334Speter#endif
101018334Speter	}
101118334Speter
101218334Speter      /* Don't output any DWARF debugging information for variables here.
101318334Speter	 In the case of local variables, the information for them is output
101418334Speter	 when we do our recursive traversal of the tree representation for
101518334Speter	 the entire containing function.  In the case of file-scope variables,
101618334Speter	 we output information for all of them at the very end of compilation
101718334Speter	 while we are doing our final traversal of the chain of file-scope
101818334Speter	 declarations.  */
101918334Speter
102018334Speter      return;
102118334Speter    }
102218334Speter
102318334Speter  /* Normally no need to say anything here for external references,
102418334Speter     since assemble_external is called by the language-specific code
102518334Speter     when a declaration is first seen.  */
102618334Speter
102718334Speter  if (DECL_EXTERNAL (decl))
102818334Speter    return;
102918334Speter
103018334Speter  /* Output no assembler code for a function declaration.
103118334Speter     Only definitions of functions output anything.  */
103218334Speter
103318334Speter  if (TREE_CODE (decl) == FUNCTION_DECL)
103418334Speter    return;
103518334Speter
103618334Speter  /* If type was incomplete when the variable was declared,
103718334Speter     see if it is complete now.  */
103818334Speter
103918334Speter  if (DECL_SIZE (decl) == 0)
104018334Speter    layout_decl (decl, 0);
104118334Speter
104218334Speter  /* Still incomplete => don't allocate it; treat the tentative defn
104318334Speter     (which is what it must have been) as an `extern' reference.  */
104418334Speter
104518334Speter  if (!dont_output_data && DECL_SIZE (decl) == 0)
104618334Speter    {
104718334Speter      error_with_file_and_line (DECL_SOURCE_FILE (decl),
104818334Speter				DECL_SOURCE_LINE (decl),
104918334Speter				"storage size of `%s' isn't known",
105018334Speter				IDENTIFIER_POINTER (DECL_NAME (decl)));
105118334Speter      TREE_ASM_WRITTEN (decl) = 1;
105218334Speter      return;
105318334Speter    }
105418334Speter
105518334Speter  /* The first declaration of a variable that comes through this function
105618334Speter     decides whether it is global (in C, has external linkage)
105718334Speter     or local (in C, has internal linkage).  So do nothing more
105818334Speter     if this function has already run.  */
105918334Speter
106018334Speter  if (TREE_ASM_WRITTEN (decl))
106118334Speter    return;
106218334Speter
106318334Speter  TREE_ASM_WRITTEN (decl) = 1;
106418334Speter
106518334Speter  app_disable ();
106618334Speter
106718334Speter  if (! dont_output_data)
106818334Speter    {
106918334Speter      if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
107018334Speter	goto finish;
107118334Speter
107218334Speter      /* This is better than explicit arithmetic, since it avoids overflow.  */
107318334Speter      size_tree = size_binop (CEIL_DIV_EXPR,
107418334Speter			  DECL_SIZE (decl), size_int (BITS_PER_UNIT));
107518334Speter
107618334Speter      if (TREE_INT_CST_HIGH (size_tree) != 0)
107718334Speter	{
107818334Speter	  error_with_decl (decl, "size of variable `%s' is too large");
107918334Speter	  goto finish;
108018334Speter	}
108118334Speter    }
108218334Speter
108318334Speter  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
108418334Speter
108518334Speter  /* Handle uninitialized definitions.  */
108618334Speter
108718334Speter  /* ANSI specifies that a tentative definition which is not merged with
108818334Speter     a non-tentative definition behaves exactly like a definition with an
108918334Speter     initializer equal to zero.  (Section 3.7.2)
109018334Speter     -fno-common gives strict ANSI behavior.  Usually you don't want it.
109118334Speter     This matters only for variables with external linkage.  */
109218334Speter  if ((! flag_no_common || ! TREE_PUBLIC (decl))
109318334Speter      && DECL_COMMON (decl)
109418334Speter      && ! dont_output_data
109518334Speter      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
109618334Speter    {
109718334Speter      int size = TREE_INT_CST_LOW (size_tree);
109818334Speter      int rounded = size;
109918334Speter
110018334Speter      if (TREE_INT_CST_HIGH (size_tree) != 0)
110118334Speter	error_with_decl (decl, "size of variable `%s' is too large");
110218334Speter      /* Don't allocate zero bytes of common,
110318334Speter	 since that means "undefined external" in the linker.  */
110418334Speter      if (size == 0) rounded = 1;
110518334Speter      /* Round size up to multiple of BIGGEST_ALIGNMENT bits
110618334Speter	 so that each uninitialized object starts on such a boundary.  */
110718334Speter      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
110818334Speter      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
110918334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
111018334Speter
111118334Speter#ifdef DBX_DEBUGGING_INFO
111218334Speter      /* File-scope global variables are output here.  */
111318334Speter      if (write_symbols == DBX_DEBUG && top_level)
111418334Speter	dbxout_symbol (decl, 0);
111518334Speter#endif
111618334Speter#ifdef SDB_DEBUGGING_INFO
111718334Speter      if (write_symbols == SDB_DEBUG && top_level
111818334Speter	  /* Leave initialized global vars for end of compilation;
111918334Speter	     see comment in compile_file.  */
112018334Speter	  && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
112118334Speter	sdbout_symbol (decl, 0);
112218334Speter#endif
112318334Speter
112418334Speter      /* Don't output any DWARF debugging information for variables here.
112518334Speter	 In the case of local variables, the information for them is output
112618334Speter	 when we do our recursive traversal of the tree representation for
112718334Speter	 the entire containing function.  In the case of file-scope variables,
112818334Speter	 we output information for all of them at the very end of compilation
112918334Speter	 while we are doing our final traversal of the chain of file-scope
113018334Speter	 declarations.  */
113118334Speter
113218334Speter#if 0
113318334Speter      if (flag_shared_data)
113418334Speter	data_section ();
113518334Speter#endif
113618334Speter      if (TREE_PUBLIC (decl))
113718334Speter	{
113818334Speter#ifdef ASM_OUTPUT_SHARED_COMMON
113918334Speter	  if (flag_shared_data)
114018334Speter	    ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
114118334Speter	  else
114218334Speter#endif
114318334Speter	    if (output_bytecode)
114418334Speter	      {
114518334Speter		BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
114618334Speter	      }
114718334Speter	    else
114818334Speter	      {
114918334Speter#ifdef ASM_OUTPUT_ALIGNED_COMMON
115018334Speter		ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
115118334Speter					   DECL_ALIGN (decl));
115218334Speter#else
115318334Speter		ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
115418334Speter#endif
115518334Speter	      }
115618334Speter	}
115718334Speter      else
115818334Speter	{
115918334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL
116018334Speter	  if (flag_shared_data)
116118334Speter	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
116218334Speter	  else
116318334Speter#endif
116418334Speter	    if (output_bytecode)
116518334Speter	      {
116618334Speter		BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
116718334Speter	      }
116818334Speter	    else
116918334Speter	      {
117018334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
117118334Speter		ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
117218334Speter					  DECL_ALIGN (decl));
117318334Speter#else
117418334Speter		ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
117518334Speter#endif
117618334Speter	      }
117718334Speter	}
117818334Speter      goto finish;
117918334Speter    }
118018334Speter
118118334Speter  /* Handle initialized definitions.  */
118218334Speter
118318334Speter  /* First make the assembler name(s) global if appropriate.  */
118418334Speter  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
118518334Speter    {
118618334Speter      if (!first_global_object_name)
118718334Speter	{
118818334Speter	  char *p;
118918334Speter
119018334Speter	  STRIP_NAME_ENCODING (p, name);
119118334Speter	  first_global_object_name = permalloc (strlen (p) + 1);
119218334Speter	  strcpy (first_global_object_name, p);
119318334Speter	}
119418334Speter
119518334Speter#ifdef ASM_WEAKEN_LABEL
119618334Speter      if (DECL_WEAK (decl))
119718334Speter	ASM_WEAKEN_LABEL (asm_out_file, name);
119818334Speter      else
119918334Speter#endif
120018334Speter      ASM_GLOBALIZE_LABEL (asm_out_file, name);
120118334Speter    }
120218334Speter#if 0
120318334Speter  for (d = equivalents; d; d = TREE_CHAIN (d))
120418334Speter    {
120518334Speter      tree e = TREE_VALUE (d);
120618334Speter      if (TREE_PUBLIC (e) && DECL_NAME (e))
120718334Speter	ASM_GLOBALIZE_LABEL (asm_out_file,
120818334Speter			     XSTR (XEXP (DECL_RTL (e), 0), 0));
120918334Speter    }
121018334Speter#endif
121118334Speter
121218334Speter  /* Output any data that we will need to use the address of.  */
121318334Speter  if (DECL_INITIAL (decl) == error_mark_node)
121418334Speter    reloc = contains_pointers_p (TREE_TYPE (decl));
121518334Speter  else if (DECL_INITIAL (decl))
121618334Speter    reloc = output_addressed_constants (DECL_INITIAL (decl));
121718334Speter
121818334Speter  /* Switch to the proper section for this data.  */
121918334Speter  if (IN_NAMED_SECTION (decl))
122018334Speter    named_section (decl, NULL);
122118334Speter  else
122218334Speter    {
122318334Speter      /* C++ can have const variables that get initialized from constructors,
122418334Speter	 and thus can not be in a readonly section.  We prevent this by
122518334Speter	 verifying that the initial value is constant for objects put in a
122618334Speter	 readonly section.
122718334Speter
122818334Speter	 error_mark_node is used by the C front end to indicate that the
122918334Speter	 initializer has not been seen yet.  In this case, we assume that
123018334Speter	 the initializer must be constant.  */
123118334Speter#ifdef SELECT_SECTION
123218334Speter      SELECT_SECTION (decl, reloc);
123318334Speter#else
123418334Speter      if (TREE_READONLY (decl)
123518334Speter	  && ! TREE_THIS_VOLATILE (decl)
123618334Speter	  && DECL_INITIAL (decl)
123718334Speter	  && (DECL_INITIAL (decl) == error_mark_node
123818334Speter	      || TREE_CONSTANT (DECL_INITIAL (decl)))
123918334Speter	  && ! (flag_pic && reloc))
124018334Speter	readonly_data_section ();
124118334Speter      else
124218334Speter	data_section ();
124318334Speter#endif
124418334Speter    }
124518334Speter
124618334Speter  /* dbxout.c needs to know this.  */
124718334Speter  if (in_text_section ())
124818334Speter    DECL_IN_TEXT_SECTION (decl) = 1;
124918334Speter
125018334Speter  /* Record current section so we can restore it if dbxout.c clobbers it.  */
125118334Speter  saved_in_section = in_section;
125218334Speter
125318334Speter  /* Output the dbx info now that we have chosen the section.  */
125418334Speter
125518334Speter#ifdef DBX_DEBUGGING_INFO
125618334Speter  /* File-scope global variables are output here.  */
125718334Speter  if (write_symbols == DBX_DEBUG && top_level)
125818334Speter    dbxout_symbol (decl, 0);
125918334Speter#endif
126018334Speter#ifdef SDB_DEBUGGING_INFO
126118334Speter  if (write_symbols == SDB_DEBUG && top_level
126218334Speter      /* Leave initialized global vars for end of compilation;
126318334Speter	 see comment in compile_file.  */
126418334Speter      && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
126518334Speter    sdbout_symbol (decl, 0);
126618334Speter#endif
126718334Speter
126818334Speter  /* Don't output any DWARF debugging information for variables here.
126918334Speter     In the case of local variables, the information for them is output
127018334Speter     when we do our recursive traversal of the tree representation for
127118334Speter     the entire containing function.  In the case of file-scope variables,
127218334Speter     we output information for all of them at the very end of compilation
127318334Speter     while we are doing our final traversal of the chain of file-scope
127418334Speter     declarations.  */
127518334Speter
127618334Speter  /* If the debugging output changed sections, reselect the section
127718334Speter     that's supposed to be selected.  */
127818334Speter  if (in_section != saved_in_section)
127918334Speter    {
128018334Speter      /* Switch to the proper section for this data.  */
128118334Speter#ifdef SELECT_SECTION
128218334Speter      SELECT_SECTION (decl, reloc);
128318334Speter#else
128418334Speter      if (TREE_READONLY (decl)
128518334Speter	  && ! TREE_THIS_VOLATILE (decl)
128618334Speter	  && DECL_INITIAL (decl)
128718334Speter	  && (DECL_INITIAL (decl) == error_mark_node
128818334Speter	      || TREE_CONSTANT (DECL_INITIAL (decl)))
128918334Speter	  && ! (flag_pic && reloc))
129018334Speter	readonly_data_section ();
129118334Speter      else
129218334Speter	data_section ();
129318334Speter#endif
129418334Speter    }
129518334Speter
129618334Speter  /* Compute and output the alignment of this data.  */
129718334Speter
129818334Speter  align = DECL_ALIGN (decl);
129918334Speter  /* In the case for initialing an array whose length isn't specified,
130018334Speter     where we have not yet been able to do the layout,
130118334Speter     figure out the proper alignment now.  */
130218334Speter  if (dont_output_data && DECL_SIZE (decl) == 0
130318334Speter      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
130418334Speter    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
130518334Speter
130618334Speter  /* Some object file formats have a maximum alignment which they support.
130718334Speter     In particular, a.out format supports a maximum alignment of 4.  */
130818334Speter#ifndef MAX_OFILE_ALIGNMENT
130918334Speter#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
131018334Speter#endif
131118334Speter  if (align > MAX_OFILE_ALIGNMENT)
131218334Speter    {
131318334Speter      warning_with_decl (decl,
131418334Speter	  "alignment of `%s' is greater than maximum object file alignment");
131518334Speter      align = MAX_OFILE_ALIGNMENT;
131618334Speter    }
131718334Speter#ifdef DATA_ALIGNMENT
131818334Speter  /* On some machines, it is good to increase alignment sometimes.  */
131918334Speter  align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
132018334Speter#endif
132118334Speter#ifdef CONSTANT_ALIGNMENT
132218334Speter  if (DECL_INITIAL (decl))
132318334Speter    align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
132418334Speter#endif
132518334Speter
132618334Speter  /* Reset the alignment in case we have made it tighter, so we can benefit
132718334Speter     from it in get_pointer_alignment.  */
132818334Speter  DECL_ALIGN (decl) = align;
132918334Speter
133018334Speter  if (align > BITS_PER_UNIT)
133118334Speter    {
133218334Speter      if (output_bytecode)
133318334Speter	BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
133418334Speter      else
133518334Speter	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
133618334Speter    }
133718334Speter
133818334Speter  /* Do any machine/system dependent processing of the object.  */
133918334Speter#ifdef ASM_DECLARE_OBJECT_NAME
134018334Speter  last_assemble_variable_decl = decl;
134118334Speter  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
134218334Speter#else
134318334Speter  /* Standard thing is just output label for the object.  */
134418334Speter  if (output_bytecode)
134518334Speter    BC_OUTPUT_LABEL (asm_out_file, name);
134618334Speter  else
134718334Speter    ASM_OUTPUT_LABEL (asm_out_file, name);
134818334Speter#endif /* ASM_DECLARE_OBJECT_NAME */
134918334Speter
135018334Speter  if (!dont_output_data)
135118334Speter    {
135218334Speter      if (DECL_INITIAL (decl))
135318334Speter	/* Output the actual data.  */
135418334Speter	output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
135518334Speter      else
135618334Speter	/* Leave space for it.  */
135718334Speter	assemble_zeros (TREE_INT_CST_LOW (size_tree));
135818334Speter    }
135918334Speter
136018334Speter finish:
136118334Speter#ifdef XCOFF_DEBUGGING_INFO
136218334Speter  /* Unfortunately, the IBM assembler cannot handle stabx before the actual
136318334Speter     declaration.  When something like ".stabx  "aa:S-2",aa,133,0" is emitted
136418334Speter     and `aa' hasn't been output yet, the assembler generates a stab entry with
136518334Speter     a value of zero, in addition to creating an unnecessary external entry
136618334Speter     for `aa'.  Hence, we must postpone dbxout_symbol to here at the end.  */
136718334Speter
136818334Speter  /* File-scope global variables are output here.  */
136918334Speter  if (write_symbols == XCOFF_DEBUG && top_level)
137018334Speter    {
137118334Speter      saved_in_section = in_section;
137218334Speter
137318334Speter      dbxout_symbol (decl, 0);
137418334Speter
137518334Speter      if (in_section != saved_in_section)
137618334Speter	{
137718334Speter	  /* Switch to the proper section for this data.  */
137818334Speter#ifdef SELECT_SECTION
137918334Speter	  SELECT_SECTION (decl, reloc);
138018334Speter#else
138118334Speter	  if (TREE_READONLY (decl)
138218334Speter	      && ! TREE_THIS_VOLATILE (decl)
138318334Speter	      && DECL_INITIAL (decl)
138418334Speter	      && (DECL_INITIAL (decl) == error_mark_node
138518334Speter		  || TREE_CONSTANT (DECL_INITIAL (decl)))
138618334Speter	      && ! (flag_pic && reloc))
138718334Speter	    readonly_data_section ();
138818334Speter	  else
138918334Speter	    data_section ();
139018334Speter#endif
139118334Speter	}
139218334Speter    }
139318334Speter#else
139418334Speter  /* There must be a statement after a label.  */
139518334Speter  ;
139618334Speter#endif
139718334Speter}
139818334Speter
139918334Speter/* Return 1 if type TYPE contains any pointers.  */
140018334Speter
140118334Speterstatic int
140218334Spetercontains_pointers_p (type)
140318334Speter     tree type;
140418334Speter{
140518334Speter  switch (TREE_CODE (type))
140618334Speter    {
140718334Speter    case POINTER_TYPE:
140818334Speter    case REFERENCE_TYPE:
140918334Speter      /* I'm not sure whether OFFSET_TYPE needs this treatment,
141018334Speter	 so I'll play safe and return 1.  */
141118334Speter    case OFFSET_TYPE:
141218334Speter      return 1;
141318334Speter
141418334Speter    case RECORD_TYPE:
141518334Speter    case UNION_TYPE:
141618334Speter    case QUAL_UNION_TYPE:
141718334Speter      {
141818334Speter	tree fields;
141918334Speter	/* For a type that has fields, see if the fields have pointers.  */
142018334Speter	for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
142118334Speter	  if (TREE_CODE (fields) == FIELD_DECL
142218334Speter	      && contains_pointers_p (TREE_TYPE (fields)))
142318334Speter	    return 1;
142418334Speter	return 0;
142518334Speter      }
142618334Speter
142718334Speter    case ARRAY_TYPE:
142818334Speter      /* An array type contains pointers if its element type does.  */
142918334Speter      return contains_pointers_p (TREE_TYPE (type));
143018334Speter
143118334Speter    default:
143218334Speter      return 0;
143318334Speter    }
143418334Speter}
143518334Speter
143618334Speter/* Output text storage for constructor CONSTR. */
143718334Speter
143818334Spetervoid
143918334Speterbc_output_constructor (constr, size)
144018334Speter     tree constr;
144118334Speter     int size;
144218334Speter{
144318334Speter  int i;
144418334Speter
144518334Speter  /* Must always be a literal; non-literal constructors are handled
144618334Speter     differently. */
144718334Speter
144818334Speter  if (!TREE_CONSTANT (constr))
144918334Speter    abort ();
145018334Speter
145118334Speter  /* Always const */
145218334Speter  text_section ();
145318334Speter
145418334Speter  /* Align */
145518334Speter  for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++)
145618334Speter    ;
145718334Speter
145818334Speter  if (i > 0)
145918334Speter    BC_OUTPUT_ALIGN (asm_out_file, i);
146018334Speter
146118334Speter  /* Output data */
146218334Speter  output_constant (constr, size);
146318334Speter}
146418334Speter
146518334Speter/* Create storage for constructor CONSTR. */
146618334Speter
146718334Spetervoid
146818334Speterbc_output_data_constructor (constr)
146918334Speter    tree constr;
147018334Speter{
147118334Speter  int i;
147218334Speter
147318334Speter  /* Put in data section */
147418334Speter  data_section ();
147518334Speter
147618334Speter  /* Align */
147718334Speter  for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
147818334Speter  if (i > 0)
147918334Speter    BC_OUTPUT_ALIGN (asm_out_file, i);
148018334Speter
148118334Speter  /* The constructor is filled in at runtime. */
148218334Speter  BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
148318334Speter}
148418334Speter
148518334Speter/* Output something to declare an external symbol to the assembler.
148618334Speter   (Most assemblers don't need this, so we normally output nothing.)
148718334Speter   Do nothing if DECL is not external.  */
148818334Speter
148918334Spetervoid
149018334Speterassemble_external (decl)
149118334Speter     tree decl;
149218334Speter{
149318334Speter  if (output_bytecode)
149418334Speter    return;
149518334Speter
149618334Speter#ifdef ASM_OUTPUT_EXTERNAL
149718334Speter  if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
149818334Speter      && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
149918334Speter    {
150018334Speter      rtx rtl = DECL_RTL (decl);
150118334Speter
150218334Speter      if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
150318334Speter	  && ! SYMBOL_REF_USED (XEXP (rtl, 0)))
150418334Speter	{
150518334Speter	  /* Some systems do require some output.  */
150618334Speter	  SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
150718334Speter	  ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
150818334Speter	}
150918334Speter    }
151018334Speter#endif
151118334Speter}
151218334Speter
151318334Speter/* Similar, for calling a library function FUN.  */
151418334Speter
151518334Spetervoid
151618334Speterassemble_external_libcall (fun)
151718334Speter     rtx fun;
151818334Speter{
151918334Speter#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
152018334Speter  if (!output_bytecode)
152118334Speter    {
152218334Speter      /* Declare library function name external when first used, if nec.  */
152318334Speter      if (! SYMBOL_REF_USED (fun))
152418334Speter	{
152518334Speter	  SYMBOL_REF_USED (fun) = 1;
152618334Speter	  ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
152718334Speter	}
152818334Speter    }
152918334Speter#endif
153018334Speter}
153118334Speter
153218334Speter/* Declare the label NAME global.  */
153318334Speter
153418334Spetervoid
153518334Speterassemble_global (name)
153618334Speter     char *name;
153718334Speter{
153818334Speter  ASM_GLOBALIZE_LABEL (asm_out_file, name);
153918334Speter}
154018334Speter
154118334Speter/* Assemble a label named NAME.  */
154218334Speter
154318334Spetervoid
154418334Speterassemble_label (name)
154518334Speter     char *name;
154618334Speter{
154718334Speter  if (output_bytecode)
154818334Speter    BC_OUTPUT_LABEL (asm_out_file, name);
154918334Speter  else
155018334Speter    ASM_OUTPUT_LABEL (asm_out_file, name);
155118334Speter}
155218334Speter
155318334Speter/* Output to FILE a reference to the assembler name of a C-level name NAME.
155418334Speter   If NAME starts with a *, the rest of NAME is output verbatim.
155518334Speter   Otherwise NAME is transformed in an implementation-defined way
155618334Speter   (usually by the addition of an underscore).
155718334Speter   Many macros in the tm file are defined to call this function.  */
155818334Speter
155918334Spetervoid
156018334Speterassemble_name (file, name)
156118334Speter     FILE *file;
156218334Speter     char *name;
156318334Speter{
156418334Speter  char *real_name;
156518334Speter  int save_warn_id_clash = warn_id_clash;
156618334Speter
156718334Speter  STRIP_NAME_ENCODING (real_name, name);
156818334Speter
156918334Speter  /* Don't warn about an identifier name length clash on this name, since
157018334Speter     it can be a user symbol suffixed by a number.  */
157118334Speter  warn_id_clash = 0;
157218334Speter  TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
157318334Speter  warn_id_clash = save_warn_id_clash;
157418334Speter
157518334Speter  if (name[0] == '*')
157618334Speter    {
157718334Speter      if (output_bytecode)
157818334Speter	bc_emit_labelref (name, 0);
157918334Speter      else
158018334Speter	fputs (&name[1], file);
158118334Speter    }
158218334Speter  else
158318334Speter    {
158418334Speter      if (output_bytecode)
158518334Speter	BC_OUTPUT_LABELREF (file, name);
158618334Speter      else
158718334Speter	ASM_OUTPUT_LABELREF (file, name);
158818334Speter    }
158918334Speter}
159018334Speter
159118334Speter/* Allocate SIZE bytes writable static space with a gensym name
159218334Speter   and return an RTX to refer to its address.  */
159318334Speter
159418334Speterrtx
159518334Speterassemble_static_space (size)
159618334Speter     int size;
159718334Speter{
159818334Speter  char name[12];
159918334Speter  char *namestring;
160018334Speter  rtx x;
160118334Speter  /* Round size up to multiple of BIGGEST_ALIGNMENT bits
160218334Speter     so that each uninitialized object starts on such a boundary.  */
160318334Speter  int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
160418334Speter		 / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
160518334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
160618334Speter
160718334Speter#if 0
160818334Speter  if (flag_shared_data)
160918334Speter    data_section ();
161018334Speter#endif
161118334Speter
161218334Speter  ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
161318334Speter  ++const_labelno;
161418334Speter
161518334Speter  namestring = (char *) obstack_alloc (saveable_obstack,
161618334Speter				       strlen (name) + 2);
161718334Speter  strcpy (namestring, name);
161818334Speter
161918334Speter  if (output_bytecode)
162018334Speter    x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0);
162118334Speter  else
162218334Speter    x = gen_rtx (SYMBOL_REF, Pmode, namestring);
162318334Speter
162418334Speter  if (output_bytecode)
162518334Speter    {
162618334Speter      BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
162718334Speter    }
162818334Speter  else
162918334Speter    {
163018334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
163118334Speter      ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
163218334Speter#else
163318334Speter      ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
163418334Speter#endif
163518334Speter    }
163618334Speter  return x;
163718334Speter}
163818334Speter
163918334Speter/* Assemble the static constant template for function entry trampolines.
164018334Speter   This is done at most once per compilation.
164118334Speter   Returns an RTX for the address of the template.  */
164218334Speter
164318334Speterrtx
164418334Speterassemble_trampoline_template ()
164518334Speter{
164618334Speter  char label[256];
164718334Speter  char *name;
164818334Speter  int align;
164918334Speter
165018334Speter  /* Shouldn't get here */
165118334Speter  if (output_bytecode)
165218334Speter    abort ();
165318334Speter
165418334Speter  /* By default, put trampoline templates in read-only data section.  */
165518334Speter
165618334Speter#ifdef TRAMPOLINE_SECTION
165718334Speter  TRAMPOLINE_SECTION ();
165818334Speter#else
165918334Speter  readonly_data_section ();
166018334Speter#endif
166118334Speter
166218334Speter  /* Write the assembler code to define one.  */
166318334Speter  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
166418334Speter  if (align > 0)
166518334Speter    ASM_OUTPUT_ALIGN (asm_out_file, align);
166618334Speter
166718334Speter  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0);
166818334Speter  TRAMPOLINE_TEMPLATE (asm_out_file);
166918334Speter
167018334Speter  /* Record the rtl to refer to it.  */
167118334Speter  ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
167218334Speter  name
167318334Speter    = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
167418334Speter  return gen_rtx (SYMBOL_REF, Pmode, name);
167518334Speter}
167618334Speter
167718334Speter/* Assemble the integer constant X into an object of SIZE bytes.
167818334Speter   X must be either a CONST_INT or CONST_DOUBLE.
167918334Speter
168018334Speter   Return 1 if we were able to output the constant, otherwise 0.  If FORCE is
168118334Speter   non-zero, abort if we can't output the constant.  */
168218334Speter
168318334Speterint
168418334Speterassemble_integer (x, size, force)
168518334Speter     rtx x;
168618334Speter     int size;
168718334Speter     int force;
168818334Speter{
168918334Speter  /* First try to use the standard 1, 2, 4, 8, and 16 byte
169018334Speter     ASM_OUTPUT... macros. */
169118334Speter
169218334Speter  switch (size)
169318334Speter    {
169418334Speter#ifdef ASM_OUTPUT_CHAR
169518334Speter    case 1:
169618334Speter      ASM_OUTPUT_CHAR (asm_out_file, x);
169718334Speter      return 1;
169818334Speter#endif
169918334Speter
170018334Speter#ifdef ASM_OUTPUT_SHORT
170118334Speter    case 2:
170218334Speter      ASM_OUTPUT_SHORT (asm_out_file, x);
170318334Speter      return 1;
170418334Speter#endif
170518334Speter
170618334Speter#ifdef ASM_OUTPUT_INT
170718334Speter    case 4:
170818334Speter      ASM_OUTPUT_INT (asm_out_file, x);
170918334Speter      return 1;
171018334Speter#endif
171118334Speter
171218334Speter#ifdef ASM_OUTPUT_DOUBLE_INT
171318334Speter    case 8:
171418334Speter      ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);
171518334Speter      return 1;
171618334Speter#endif
171718334Speter
171818334Speter#ifdef ASM_OUTPUT_QUADRUPLE_INT
171918334Speter    case 16:
172018334Speter      ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x);
172118334Speter      return 1;
172218334Speter#endif
172318334Speter    }
172418334Speter
172518334Speter  /* If we couldn't do it that way, there are two other possibilities: First,
172618334Speter     if the machine can output an explicit byte and this is a 1 byte constant,
172718334Speter     we can use ASM_OUTPUT_BYTE.  */
172818334Speter
172918334Speter#ifdef ASM_OUTPUT_BYTE
173018334Speter  if (size == 1 && GET_CODE (x) == CONST_INT)
173118334Speter    {
173218334Speter      ASM_OUTPUT_BYTE (asm_out_file, INTVAL (x));
173318334Speter      return 1;
173418334Speter    }
173518334Speter#endif
173618334Speter
173718334Speter  /* Finally, if SIZE is larger than a single word, try to output the constant
173818334Speter     one word at a time.  */
173918334Speter
174018334Speter  if (size > UNITS_PER_WORD)
174118334Speter    {
174218334Speter      int i;
174318334Speter      enum machine_mode mode
174418334Speter	= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
174518334Speter      rtx word;
174618334Speter
174718334Speter      for (i = 0; i < size / UNITS_PER_WORD; i++)
174818334Speter	{
174918334Speter	  word = operand_subword (x, i, 0, mode);
175018334Speter
175118334Speter	  if (word == 0)
175218334Speter	    break;
175318334Speter
175418334Speter	  if (! assemble_integer (word, UNITS_PER_WORD, 0))
175518334Speter	    break;
175618334Speter	}
175718334Speter
175818334Speter      if (i == size / UNITS_PER_WORD)
175918334Speter	return 1;
176018334Speter      /* If we output at least one word and then could not finish,
176118334Speter	 there is no valid way to continue.  */
176218334Speter      if (i > 0)
176318334Speter	abort ();
176418334Speter    }
176518334Speter
176618334Speter  if (force)
176718334Speter    abort ();
176818334Speter
176918334Speter  return 0;
177018334Speter}
177118334Speter
177218334Speter/* Assemble the floating-point constant D into an object of size MODE.  */
177318334Speter
177418334Spetervoid
177518334Speterassemble_real (d, mode)
177618334Speter     REAL_VALUE_TYPE d;
177718334Speter     enum machine_mode mode;
177818334Speter{
177918334Speter  jmp_buf output_constant_handler;
178018334Speter
178118334Speter  if (setjmp (output_constant_handler))
178218334Speter    {
178318334Speter      error ("floating point trap outputting a constant");
178418334Speter#ifdef REAL_IS_NOT_DOUBLE
178518334Speter      bzero ((char *) &d, sizeof d);
178618334Speter      d = dconst0;
178718334Speter#else
178818334Speter      d = 0;
178918334Speter#endif
179018334Speter    }
179118334Speter
179218334Speter  set_float_handler (output_constant_handler);
179318334Speter
179418334Speter  switch (mode)
179518334Speter    {
179618334Speter#ifdef ASM_OUTPUT_BYTE_FLOAT
179718334Speter    case QFmode:
179818334Speter      ASM_OUTPUT_BYTE_FLOAT (asm_out_file, d);
179918334Speter      break;
180018334Speter#endif
180118334Speter#ifdef ASM_OUTPUT_SHORT_FLOAT
180218334Speter    case HFmode:
180318334Speter      ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
180418334Speter      break;
180518334Speter#endif
180618334Speter#ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
180718334Speter    case TQFmode:
180818334Speter      ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
180918334Speter      break;
181018334Speter#endif
181118334Speter#ifdef ASM_OUTPUT_FLOAT
181218334Speter    case SFmode:
181318334Speter      ASM_OUTPUT_FLOAT (asm_out_file, d);
181418334Speter      break;
181518334Speter#endif
181618334Speter
181718334Speter#ifdef ASM_OUTPUT_DOUBLE
181818334Speter    case DFmode:
181918334Speter      ASM_OUTPUT_DOUBLE (asm_out_file, d);
182018334Speter      break;
182118334Speter#endif
182218334Speter
182318334Speter#ifdef ASM_OUTPUT_LONG_DOUBLE
182418334Speter    case XFmode:
182518334Speter    case TFmode:
182618334Speter      ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d);
182718334Speter      break;
182818334Speter#endif
182918334Speter
183018334Speter    default:
183118334Speter      abort ();
183218334Speter    }
183318334Speter
183418334Speter  set_float_handler (NULL_PTR);
183518334Speter}
183618334Speter
183718334Speter/* Here we combine duplicate floating constants to make
183818334Speter   CONST_DOUBLE rtx's, and force those out to memory when necessary.  */
183918334Speter
184018334Speter/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
184118334Speter   They are chained through the CONST_DOUBLE_CHAIN.
184218334Speter   A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
184318334Speter   In that case, CONST_DOUBLE_MEM is either a MEM,
184418334Speter   or const0_rtx if no MEM has been made for this CONST_DOUBLE yet.
184518334Speter
184618334Speter   (CONST_DOUBLE_MEM is used only for top-level functions.
184718334Speter   See force_const_mem for explanation.)  */
184818334Speter
184918334Speterstatic rtx const_double_chain;
185018334Speter
185118334Speter/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints.
185218334Speter   For an integer, I0 is the low-order word and I1 is the high-order word.
185318334Speter   For a real number, I0 is the word with the low address
185418334Speter   and I1 is the word with the high address.  */
185518334Speter
185618334Speterrtx
185718334Speterimmed_double_const (i0, i1, mode)
185818334Speter     HOST_WIDE_INT i0, i1;
185918334Speter     enum machine_mode mode;
186018334Speter{
186118334Speter  register rtx r;
186218334Speter  int in_current_obstack;
186318334Speter
186418334Speter  if (GET_MODE_CLASS (mode) == MODE_INT
186518334Speter      || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
186618334Speter    {
186718334Speter      /* We clear out all bits that don't belong in MODE, unless they and our
186818334Speter	 sign bit are all one.  So we get either a reasonable negative value
186918334Speter	 or a reasonable unsigned value for this mode.  */
187018334Speter      int width = GET_MODE_BITSIZE (mode);
187118334Speter      if (width < HOST_BITS_PER_WIDE_INT
187218334Speter	  && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1)))
187318334Speter	      != ((HOST_WIDE_INT) (-1) << (width - 1))))
187418334Speter	i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0;
187518334Speter      else if (width == HOST_BITS_PER_WIDE_INT
187618334Speter	       && ! (i1 == ~0 && i0 < 0))
187718334Speter	i1 = 0;
187818334Speter      else if (width > 2 * HOST_BITS_PER_WIDE_INT)
187918334Speter	/* We cannot represent this value as a constant.  */
188018334Speter	abort ();
188118334Speter
188218334Speter      /* If this would be an entire word for the target, but is not for
188318334Speter	 the host, then sign-extend on the host so that the number will look
188418334Speter	 the same way on the host that it would on the target.
188518334Speter
188618334Speter	 For example, when building a 64 bit alpha hosted 32 bit sparc
188718334Speter	 targeted compiler, then we want the 32 bit unsigned value -1 to be
188818334Speter	 represented as a 64 bit value -1, and not as 0x00000000ffffffff.
188918334Speter	 The later confuses the sparc backend.  */
189018334Speter
189118334Speter      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
189218334Speter	  && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
189318334Speter	i0 |= ((HOST_WIDE_INT) (-1) << width);
189418334Speter
189518334Speter      /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a CONST_INT.
189618334Speter
189718334Speter	 ??? Strictly speaking, this is wrong if we create a CONST_INT
189818334Speter	 for a large unsigned constant with the size of MODE being
189918334Speter	 HOST_BITS_PER_WIDE_INT and later try to interpret that constant in a
190018334Speter	 wider mode.  In that case we will mis-interpret it as a negative
190118334Speter	 number.
190218334Speter
190318334Speter	 Unfortunately, the only alternative is to make a CONST_DOUBLE
190418334Speter	 for any constant in any mode if it is an unsigned constant larger
190518334Speter	 than the maximum signed integer in an int on the host.  However,
190618334Speter	 doing this will break everyone that always expects to see a CONST_INT
190718334Speter	 for SImode and smaller.
190818334Speter
190918334Speter	 We have always been making CONST_INTs in this case, so nothing new
191018334Speter	 is being broken.  */
191118334Speter
191218334Speter      if (width <= HOST_BITS_PER_WIDE_INT)
191318334Speter	i1 = (i0 < 0) ? ~0 : 0;
191418334Speter
191518334Speter      /* If this integer fits in one word, return a CONST_INT.  */
191618334Speter      if ((i1 == 0 && i0 >= 0)
191718334Speter	  || (i1 == ~0 && i0 < 0))
191818334Speter	return GEN_INT (i0);
191918334Speter
192018334Speter      /* We use VOIDmode for integers.  */
192118334Speter      mode = VOIDmode;
192218334Speter    }
192318334Speter
192418334Speter  /* Search the chain for an existing CONST_DOUBLE with the right value.
192518334Speter     If one is found, return it.  */
192618334Speter
192718334Speter  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
192818334Speter    if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
192918334Speter	&& GET_MODE (r) == mode)
193018334Speter      return r;
193118334Speter
193218334Speter  /* No; make a new one and add it to the chain.
193318334Speter
193418334Speter     We may be called by an optimizer which may be discarding any memory
193518334Speter     allocated during its processing (such as combine and loop).  However,
193618334Speter     we will be leaving this constant on the chain, so we cannot tolerate
193718334Speter     freed memory.  So switch to saveable_obstack for this allocation
193818334Speter     and then switch back if we were in current_obstack.  */
193918334Speter
194018334Speter  push_obstacks_nochange ();
194118334Speter  rtl_in_saveable_obstack ();
194218334Speter  r = gen_rtx (CONST_DOUBLE, mode, 0, i0, i1);
194318334Speter  pop_obstacks ();
194418334Speter
194518334Speter  /* Don't touch const_double_chain in nested function; see force_const_mem.
194618334Speter     Also, don't touch it if not inside any function.  */
194718334Speter  if (outer_function_chain == 0 && current_function_decl != 0)
194818334Speter    {
194918334Speter      CONST_DOUBLE_CHAIN (r) = const_double_chain;
195018334Speter      const_double_chain = r;
195118334Speter    }
195218334Speter
195318334Speter  /* Store const0_rtx in mem-slot since this CONST_DOUBLE is on the chain.
195418334Speter     Actual use of mem-slot is only through force_const_mem.  */
195518334Speter
195618334Speter  CONST_DOUBLE_MEM (r) = const0_rtx;
195718334Speter
195818334Speter  return r;
195918334Speter}
196018334Speter
196118334Speter/* Return a CONST_DOUBLE for a specified `double' value
196218334Speter   and machine mode.  */
196318334Speter
196418334Speterrtx
196518334Speterimmed_real_const_1 (d, mode)
196618334Speter     REAL_VALUE_TYPE d;
196718334Speter     enum machine_mode mode;
196818334Speter{
196918334Speter  union real_extract u;
197018334Speter  register rtx r;
197118334Speter  int in_current_obstack;
197218334Speter
197318334Speter  /* Get the desired `double' value as a sequence of ints
197418334Speter     since that is how they are stored in a CONST_DOUBLE.  */
197518334Speter
197618334Speter  u.d = d;
197718334Speter
197818334Speter  /* Detect special cases.  */
197918334Speter
198018334Speter  /* Avoid REAL_VALUES_EQUAL here in order to distinguish minus zero.  */
198118334Speter  if (!bcmp ((char *) &dconst0, (char *) &d, sizeof d))
198218334Speter    return CONST0_RTX (mode);
198318334Speter  /* Check for NaN first, because some ports (specifically the i386) do not
198418334Speter     emit correct ieee-fp code by default, and thus will generate a core
198518334Speter     dump here if we pass a NaN to REAL_VALUES_EQUAL and if REAL_VALUES_EQUAL
198618334Speter     does a floating point comparison.  */
198718334Speter  else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
198818334Speter    return CONST1_RTX (mode);
198918334Speter
199018334Speter  if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
199118334Speter    return immed_double_const (u.i[0], u.i[1], mode);
199218334Speter
199318334Speter  /* The rest of this function handles the case where
199418334Speter     a float value requires more than 2 ints of space.
199518334Speter     It will be deleted as dead code on machines that don't need it.  */
199618334Speter
199718334Speter  /* Search the chain for an existing CONST_DOUBLE with the right value.
199818334Speter     If one is found, return it.  */
199918334Speter
200018334Speter  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
200118334Speter    if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
200218334Speter	&& GET_MODE (r) == mode)
200318334Speter      return r;
200418334Speter
200518334Speter  /* No; make a new one and add it to the chain.
200618334Speter
200718334Speter     We may be called by an optimizer which may be discarding any memory
200818334Speter     allocated during its processing (such as combine and loop).  However,
200918334Speter     we will be leaving this constant on the chain, so we cannot tolerate
201018334Speter     freed memory.  So switch to saveable_obstack for this allocation
201118334Speter     and then switch back if we were in current_obstack.  */
201218334Speter
201318334Speter  push_obstacks_nochange ();
201418334Speter  rtl_in_saveable_obstack ();
201518334Speter  r = rtx_alloc (CONST_DOUBLE);
201618334Speter  PUT_MODE (r, mode);
201718334Speter  bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
201818334Speter  pop_obstacks ();
201918334Speter
202018334Speter  /* Don't touch const_double_chain in nested function; see force_const_mem.
202118334Speter     Also, don't touch it if not inside any function.  */
202218334Speter  if (outer_function_chain == 0 && current_function_decl != 0)
202318334Speter    {
202418334Speter      CONST_DOUBLE_CHAIN (r) = const_double_chain;
202518334Speter      const_double_chain = r;
202618334Speter    }
202718334Speter
202818334Speter  /* Store const0_rtx in CONST_DOUBLE_MEM since this CONST_DOUBLE is on the
202918334Speter     chain, but has not been allocated memory.  Actual use of CONST_DOUBLE_MEM
203018334Speter     is only through force_const_mem.  */
203118334Speter
203218334Speter  CONST_DOUBLE_MEM (r) = const0_rtx;
203318334Speter
203418334Speter  return r;
203518334Speter}
203618334Speter
203718334Speter/* Return a CONST_DOUBLE rtx for a value specified by EXP,
203818334Speter   which must be a REAL_CST tree node.  */
203918334Speter
204018334Speterrtx
204118334Speterimmed_real_const (exp)
204218334Speter     tree exp;
204318334Speter{
204418334Speter  return immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)));
204518334Speter}
204618334Speter
204718334Speter/* At the end of a function, forget the memory-constants
204818334Speter   previously made for CONST_DOUBLEs.  Mark them as not on real_constant_chain.
204918334Speter   Also clear out real_constant_chain and clear out all the chain-pointers.  */
205018334Speter
205118334Spetervoid
205218334Speterclear_const_double_mem ()
205318334Speter{
205418334Speter  register rtx r, next;
205518334Speter
205618334Speter  /* Don't touch CONST_DOUBLE_MEM for nested functions.
205718334Speter     See force_const_mem for explanation.  */
205818334Speter  if (outer_function_chain != 0)
205918334Speter    return;
206018334Speter
206118334Speter  for (r = const_double_chain; r; r = next)
206218334Speter    {
206318334Speter      next = CONST_DOUBLE_CHAIN (r);
206418334Speter      CONST_DOUBLE_CHAIN (r) = 0;
206518334Speter      CONST_DOUBLE_MEM (r) = cc0_rtx;
206618334Speter    }
206718334Speter  const_double_chain = 0;
206818334Speter}
206918334Speter
207018334Speter/* Given an expression EXP with a constant value,
207118334Speter   reduce it to the sum of an assembler symbol and an integer.
207218334Speter   Store them both in the structure *VALUE.
207318334Speter   Abort if EXP does not reduce.  */
207418334Speter
207518334Speterstruct addr_const
207618334Speter{
207718334Speter  rtx base;
207818334Speter  HOST_WIDE_INT offset;
207918334Speter};
208018334Speter
208118334Speterstatic void
208218334Speterdecode_addr_const (exp, value)
208318334Speter     tree exp;
208418334Speter     struct addr_const *value;
208518334Speter{
208618334Speter  register tree target = TREE_OPERAND (exp, 0);
208718334Speter  register int offset = 0;
208818334Speter  register rtx x;
208918334Speter
209018334Speter  while (1)
209118334Speter    {
209218334Speter      if (TREE_CODE (target) == COMPONENT_REF
209318334Speter	  && (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1)))
209418334Speter	      == INTEGER_CST))
209518334Speter	{
209618334Speter	  offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) / BITS_PER_UNIT;
209718334Speter	  target = TREE_OPERAND (target, 0);
209818334Speter	}
209918334Speter      else if (TREE_CODE (target) == ARRAY_REF)
210018334Speter	{
210118334Speter	  if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST
210218334Speter	      || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST)
210318334Speter	    abort ();
210418334Speter	  offset += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target)))
210518334Speter		      * TREE_INT_CST_LOW (TREE_OPERAND (target, 1)))
210618334Speter		     / BITS_PER_UNIT);
210718334Speter	  target = TREE_OPERAND (target, 0);
210818334Speter	}
210918334Speter      else
211018334Speter	break;
211118334Speter    }
211218334Speter
211318334Speter  switch (TREE_CODE (target))
211418334Speter    {
211518334Speter    case VAR_DECL:
211618334Speter    case FUNCTION_DECL:
211718334Speter      x = DECL_RTL (target);
211818334Speter      break;
211918334Speter
212018334Speter    case LABEL_DECL:
212118334Speter      if (output_bytecode)
212218334Speter	/* FIXME: this may not be correct, check it */
212318334Speter	x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0);
212418334Speter      else
212518334Speter	x = gen_rtx (MEM, FUNCTION_MODE,
212618334Speter		     gen_rtx (LABEL_REF, VOIDmode,
212718334Speter			      label_rtx (TREE_OPERAND (exp, 0))));
212818334Speter      break;
212918334Speter
213018334Speter    case REAL_CST:
213118334Speter    case STRING_CST:
213218334Speter    case COMPLEX_CST:
213318334Speter    case CONSTRUCTOR:
213418334Speter      x = TREE_CST_RTL (target);
213518334Speter      break;
213618334Speter
213718334Speter    default:
213818334Speter      abort ();
213918334Speter    }
214018334Speter
214118334Speter  if (!output_bytecode)
214218334Speter    {
214318334Speter      if (GET_CODE (x) != MEM)
214418334Speter	abort ();
214518334Speter      x = XEXP (x, 0);
214618334Speter    }
214718334Speter
214818334Speter  value->base = x;
214918334Speter  value->offset = offset;
215018334Speter}
215118334Speter
215218334Speter/* Uniquize all constants that appear in memory.
215318334Speter   Each constant in memory thus far output is recorded
215418334Speter   in `const_hash_table' with a `struct constant_descriptor'
215518334Speter   that contains a polish representation of the value of
215618334Speter   the constant.
215718334Speter
215818334Speter   We cannot store the trees in the hash table
215918334Speter   because the trees may be temporary.  */
216018334Speter
216118334Speterstruct constant_descriptor
216218334Speter{
216318334Speter  struct constant_descriptor *next;
216418334Speter  char *label;
216518334Speter  char contents[1];
216618334Speter};
216718334Speter
216818334Speter#define HASHBITS 30
216918334Speter#define MAX_HASH_TABLE 1009
217018334Speterstatic struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
217118334Speter
217218334Speter/* Compute a hash code for a constant expression.  */
217318334Speter
217418334Speterstatic int
217518334Speterconst_hash (exp)
217618334Speter     tree exp;
217718334Speter{
217818334Speter  register char *p;
217918334Speter  register int len, hi, i;
218018334Speter  register enum tree_code code = TREE_CODE (exp);
218118334Speter
218218334Speter  if (code == INTEGER_CST)
218318334Speter    {
218418334Speter      p = (char *) &TREE_INT_CST_LOW (exp);
218518334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
218618334Speter    }
218718334Speter  else if (code == REAL_CST)
218818334Speter    {
218918334Speter      p = (char *) &TREE_REAL_CST (exp);
219018334Speter      len = sizeof TREE_REAL_CST (exp);
219118334Speter    }
219218334Speter  else if (code == STRING_CST)
219318334Speter    p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp);
219418334Speter  else if (code == COMPLEX_CST)
219518334Speter    return const_hash (TREE_REALPART (exp)) * 5
219618334Speter      + const_hash (TREE_IMAGPART (exp));
219718334Speter  else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
219818334Speter    {
219918334Speter      len = int_size_in_bytes (TREE_TYPE (exp));
220018334Speter      p = (char*) alloca (len);
220118334Speter      get_set_constructor_bytes (exp, (unsigned char *) p, len);
220218334Speter    }
220318334Speter  else if (code == CONSTRUCTOR)
220418334Speter    {
220518334Speter      register tree link;
220618334Speter
220718334Speter      /* For record type, include the type in the hashing.
220818334Speter	 We do not do so for array types
220918334Speter	 because (1) the sizes of the elements are sufficient
221018334Speter	 and (2) distinct array types can have the same constructor.
221118334Speter	 Instead, we include the array size because the constructor could
221218334Speter	 be shorter.  */
221318334Speter      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
221418334Speter	hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
221518334Speter	  % MAX_HASH_TABLE;
221618334Speter      else
221718334Speter	hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
221818334Speter	       & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
221918334Speter
222018334Speter      for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
222118334Speter	if (TREE_VALUE (link))
222218334Speter	  hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
222318334Speter
222418334Speter      return hi;
222518334Speter    }
222618334Speter  else if (code == ADDR_EXPR)
222718334Speter    {
222818334Speter      struct addr_const value;
222918334Speter      decode_addr_const (exp, &value);
223018334Speter      if (GET_CODE (value.base) == SYMBOL_REF)
223118334Speter	{
223218334Speter	  /* Don't hash the address of the SYMBOL_REF;
223318334Speter	     only use the offset and the symbol name.  */
223418334Speter	  hi = value.offset;
223518334Speter	  p = XSTR (value.base, 0);
223618334Speter	  for (i = 0; p[i] != 0; i++)
223718334Speter	    hi = ((hi * 613) + (unsigned)(p[i]));
223818334Speter	}
223918334Speter      else if (GET_CODE (value.base) == LABEL_REF)
224018334Speter	hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
224118334Speter
224218334Speter      hi &= (1 << HASHBITS) - 1;
224318334Speter      hi %= MAX_HASH_TABLE;
224418334Speter      return hi;
224518334Speter    }
224618334Speter  else if (code == PLUS_EXPR || code == MINUS_EXPR)
224718334Speter    return const_hash (TREE_OPERAND (exp, 0)) * 9
224818334Speter      +  const_hash (TREE_OPERAND (exp, 1));
224918334Speter  else if (code == NOP_EXPR || code == CONVERT_EXPR)
225018334Speter    return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
225118334Speter
225218334Speter  /* Compute hashing function */
225318334Speter  hi = len;
225418334Speter  for (i = 0; i < len; i++)
225518334Speter    hi = ((hi * 613) + (unsigned)(p[i]));
225618334Speter
225718334Speter  hi &= (1 << HASHBITS) - 1;
225818334Speter  hi %= MAX_HASH_TABLE;
225918334Speter  return hi;
226018334Speter}
226118334Speter
226218334Speter/* Compare a constant expression EXP with a constant-descriptor DESC.
226318334Speter   Return 1 if DESC describes a constant with the same value as EXP.  */
226418334Speter
226518334Speterstatic int
226618334Spetercompare_constant (exp, desc)
226718334Speter     tree exp;
226818334Speter     struct constant_descriptor *desc;
226918334Speter{
227018334Speter  return 0 != compare_constant_1 (exp, desc->contents);
227118334Speter}
227218334Speter
227318334Speter/* Compare constant expression EXP with a substring P of a constant descriptor.
227418334Speter   If they match, return a pointer to the end of the substring matched.
227518334Speter   If they do not match, return 0.
227618334Speter
227718334Speter   Since descriptors are written in polish prefix notation,
227818334Speter   this function can be used recursively to test one operand of EXP
227918334Speter   against a subdescriptor, and if it succeeds it returns the
228018334Speter   address of the subdescriptor for the next operand.  */
228118334Speter
228218334Speterstatic char *
228318334Spetercompare_constant_1 (exp, p)
228418334Speter     tree exp;
228518334Speter     char *p;
228618334Speter{
228718334Speter  register char *strp;
228818334Speter  register int len;
228918334Speter  register enum tree_code code = TREE_CODE (exp);
229018334Speter
229118334Speter  if (code != (enum tree_code) *p++)
229218334Speter    return 0;
229318334Speter
229418334Speter  if (code == INTEGER_CST)
229518334Speter    {
229618334Speter      /* Integer constants are the same only if the same width of type.  */
229718334Speter      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
229818334Speter	return 0;
229918334Speter      strp = (char *) &TREE_INT_CST_LOW (exp);
230018334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
230118334Speter    }
230218334Speter  else if (code == REAL_CST)
230318334Speter    {
230418334Speter      /* Real constants are the same only if the same width of type.  */
230518334Speter      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
230618334Speter	return 0;
230718334Speter      strp = (char *) &TREE_REAL_CST (exp);
230818334Speter      len = sizeof TREE_REAL_CST (exp);
230918334Speter    }
231018334Speter  else if (code == STRING_CST)
231118334Speter    {
231218334Speter      if (flag_writable_strings)
231318334Speter	return 0;
231418334Speter      strp = TREE_STRING_POINTER (exp);
231518334Speter      len = TREE_STRING_LENGTH (exp);
231618334Speter      if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
231718334Speter		sizeof TREE_STRING_LENGTH (exp)))
231818334Speter	return 0;
231918334Speter      p += sizeof TREE_STRING_LENGTH (exp);
232018334Speter    }
232118334Speter  else if (code == COMPLEX_CST)
232218334Speter    {
232318334Speter      p = compare_constant_1 (TREE_REALPART (exp), p);
232418334Speter      if (p == 0) return 0;
232518334Speter      p = compare_constant_1 (TREE_IMAGPART (exp), p);
232618334Speter      return p;
232718334Speter    }
232818334Speter  else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
232918334Speter    {
233018334Speter      len = int_size_in_bytes (TREE_TYPE (exp));
233118334Speter      strp = (char*) alloca (len);
233218334Speter      get_set_constructor_bytes (exp, (unsigned char *) strp, len);
233318334Speter    }
233418334Speter  else if (code == CONSTRUCTOR)
233518334Speter    {
233618334Speter      register tree link;
233718334Speter      int length = list_length (CONSTRUCTOR_ELTS (exp));
233818334Speter      tree type;
233918334Speter
234018334Speter      if (bcmp ((char *) &length, p, sizeof length))
234118334Speter	return 0;
234218334Speter      p += sizeof length;
234318334Speter
234418334Speter      /* For record constructors, insist that the types match.
234518334Speter	 For arrays, just verify both constructors are for arrays.  */
234618334Speter      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
234718334Speter	type = TREE_TYPE (exp);
234818334Speter      else
234918334Speter	type = 0;
235018334Speter      if (bcmp ((char *) &type, p, sizeof type))
235118334Speter	return 0;
235218334Speter      p += sizeof type;
235318334Speter
235418334Speter      /* For arrays, insist that the size in bytes match.  */
235518334Speter      if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
235618334Speter	{
235718334Speter	  int size = int_size_in_bytes (TREE_TYPE (exp));
235818334Speter	  if (bcmp ((char *) &size, p, sizeof size))
235918334Speter	    return 0;
236018334Speter	  p += sizeof size;
236118334Speter	}
236218334Speter
236318334Speter      for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
236418334Speter	{
236518334Speter	  if (TREE_VALUE (link))
236618334Speter	    {
236718334Speter	      if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
236818334Speter		return 0;
236918334Speter	    }
237018334Speter	  else
237118334Speter	    {
237218334Speter	      tree zero = 0;
237318334Speter
237418334Speter	      if (bcmp ((char *) &zero, p, sizeof zero))
237518334Speter		return 0;
237618334Speter	      p += sizeof zero;
237718334Speter	    }
237818334Speter	}
237918334Speter
238018334Speter      return p;
238118334Speter    }
238218334Speter  else if (code == ADDR_EXPR)
238318334Speter    {
238418334Speter      struct addr_const value;
238518334Speter      decode_addr_const (exp, &value);
238618334Speter      strp = (char *) &value.offset;
238718334Speter      len = sizeof value.offset;
238818334Speter      /* Compare the offset.  */
238918334Speter      while (--len >= 0)
239018334Speter	if (*p++ != *strp++)
239118334Speter	  return 0;
239218334Speter      /* Compare symbol name.  */
239318334Speter      strp = XSTR (value.base, 0);
239418334Speter      len = strlen (strp) + 1;
239518334Speter    }
239618334Speter  else if (code == PLUS_EXPR || code == MINUS_EXPR)
239718334Speter    {
239818334Speter      p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
239918334Speter      if (p == 0) return 0;
240018334Speter      p = compare_constant_1 (TREE_OPERAND (exp, 1), p);
240118334Speter      return p;
240218334Speter    }
240318334Speter  else if (code == NOP_EXPR || code == CONVERT_EXPR)
240418334Speter    {
240518334Speter      p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
240618334Speter      return p;
240718334Speter    }
240818334Speter
240918334Speter  /* Compare constant contents.  */
241018334Speter  while (--len >= 0)
241118334Speter    if (*p++ != *strp++)
241218334Speter      return 0;
241318334Speter
241418334Speter  return p;
241518334Speter}
241618334Speter
241718334Speter/* Construct a constant descriptor for the expression EXP.
241818334Speter   It is up to the caller to enter the descriptor in the hash table.  */
241918334Speter
242018334Speterstatic struct constant_descriptor *
242118334Speterrecord_constant (exp)
242218334Speter     tree exp;
242318334Speter{
242418334Speter  struct constant_descriptor *next = 0;
242518334Speter  char *label = 0;
242618334Speter
242718334Speter  /* Make a struct constant_descriptor.  The first two pointers will
242818334Speter     be filled in later.  Here we just leave space for them.  */
242918334Speter
243018334Speter  obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
243118334Speter  obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
243218334Speter  record_constant_1 (exp);
243318334Speter  return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
243418334Speter}
243518334Speter
243618334Speter/* Add a description of constant expression EXP
243718334Speter   to the object growing in `permanent_obstack'.
243818334Speter   No need to return its address; the caller will get that
243918334Speter   from the obstack when the object is complete.  */
244018334Speter
244118334Speterstatic void
244218334Speterrecord_constant_1 (exp)
244318334Speter     tree exp;
244418334Speter{
244518334Speter  register char *strp;
244618334Speter  register int len;
244718334Speter  register enum tree_code code = TREE_CODE (exp);
244818334Speter
244918334Speter  obstack_1grow (&permanent_obstack, (unsigned int) code);
245018334Speter
245118334Speter  switch (code)
245218334Speter    {
245318334Speter    case INTEGER_CST:
245418334Speter      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
245518334Speter      strp = (char *) &TREE_INT_CST_LOW (exp);
245618334Speter      len = 2 * sizeof TREE_INT_CST_LOW (exp);
245718334Speter      break;
245818334Speter
245918334Speter    case REAL_CST:
246018334Speter      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
246118334Speter      strp = (char *) &TREE_REAL_CST (exp);
246218334Speter      len = sizeof TREE_REAL_CST (exp);
246318334Speter      break;
246418334Speter
246518334Speter    case STRING_CST:
246618334Speter      if (flag_writable_strings)
246718334Speter	return;
246818334Speter
246918334Speter      strp = TREE_STRING_POINTER (exp);
247018334Speter      len = TREE_STRING_LENGTH (exp);
247118334Speter      obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
247218334Speter		    sizeof TREE_STRING_LENGTH (exp));
247318334Speter      break;
247418334Speter
247518334Speter    case COMPLEX_CST:
247618334Speter      record_constant_1 (TREE_REALPART (exp));
247718334Speter      record_constant_1 (TREE_IMAGPART (exp));
247818334Speter      return;
247918334Speter
248018334Speter    case CONSTRUCTOR:
248118334Speter      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
248218334Speter	{
248318334Speter	  int nbytes = int_size_in_bytes (TREE_TYPE (exp));
248418334Speter	  obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
248518334Speter	  obstack_blank (&permanent_obstack, nbytes);
248618334Speter	  get_set_constructor_bytes
248718334Speter	    (exp, (unsigned char *) permanent_obstack.next_free, nbytes);
248818334Speter	  return;
248918334Speter	}
249018334Speter      else
249118334Speter	{
249218334Speter	  register tree link;
249318334Speter	  int length = list_length (CONSTRUCTOR_ELTS (exp));
249418334Speter	  tree type;
249518334Speter
249618334Speter	  obstack_grow (&permanent_obstack, (char *) &length, sizeof length);
249718334Speter
249818334Speter	  /* For record constructors, insist that the types match.
249918334Speter	     For arrays, just verify both constructors are for arrays.  */
250018334Speter	  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
250118334Speter	    type = TREE_TYPE (exp);
250218334Speter	  else
250318334Speter	    type = 0;
250418334Speter	  obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
250518334Speter
250618334Speter	  /* For arrays, insist that the size in bytes match.  */
250718334Speter	  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
250818334Speter	    {
250918334Speter	      int size = int_size_in_bytes (TREE_TYPE (exp));
251018334Speter	      obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
251118334Speter	    }
251218334Speter
251318334Speter	  for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
251418334Speter	    {
251518334Speter	      if (TREE_VALUE (link))
251618334Speter		record_constant_1 (TREE_VALUE (link));
251718334Speter	      else
251818334Speter		{
251918334Speter		  tree zero = 0;
252018334Speter
252118334Speter		  obstack_grow (&permanent_obstack,
252218334Speter				(char *) &zero, sizeof zero);
252318334Speter		}
252418334Speter	    }
252518334Speter	}
252618334Speter      return;
252718334Speter
252818334Speter    case ADDR_EXPR:
252918334Speter      {
253018334Speter	struct addr_const value;
253118334Speter
253218334Speter	decode_addr_const (exp, &value);
253318334Speter	/* Record the offset.  */
253418334Speter	obstack_grow (&permanent_obstack,
253518334Speter		      (char *) &value.offset, sizeof value.offset);
253618334Speter	/* Record the symbol name.  */
253718334Speter	obstack_grow (&permanent_obstack, XSTR (value.base, 0),
253818334Speter		      strlen (XSTR (value.base, 0)) + 1);
253918334Speter      }
254018334Speter      return;
254118334Speter
254218334Speter    case PLUS_EXPR:
254318334Speter    case MINUS_EXPR:
254418334Speter      record_constant_1 (TREE_OPERAND (exp, 0));
254518334Speter      record_constant_1 (TREE_OPERAND (exp, 1));
254618334Speter      return;
254718334Speter
254818334Speter    case NOP_EXPR:
254918334Speter    case CONVERT_EXPR:
255018334Speter    case NON_LVALUE_EXPR:
255118334Speter      record_constant_1 (TREE_OPERAND (exp, 0));
255218334Speter      return;
255318334Speter
255418334Speter    default:
255518334Speter      abort ();
255618334Speter    }
255718334Speter
255818334Speter  /* Record constant contents.  */
255918334Speter  obstack_grow (&permanent_obstack, strp, len);
256018334Speter}
256118334Speter
256218334Speter/* Record a list of constant expressions that were passed to
256318334Speter   output_constant_def but that could not be output right away.  */
256418334Speter
256518334Speterstruct deferred_constant
256618334Speter{
256718334Speter  struct deferred_constant *next;
256818334Speter  tree exp;
256918334Speter  int reloc;
257018334Speter  int labelno;
257118334Speter};
257218334Speter
257318334Speterstatic struct deferred_constant *deferred_constants;
257418334Speter
257518334Speter/* Nonzero means defer output of addressed subconstants
257618334Speter   (i.e., those for which output_constant_def is called.)  */
257718334Speterstatic int defer_addressed_constants_flag;
257818334Speter
257918334Speter/* Start deferring output of subconstants.  */
258018334Speter
258118334Spetervoid
258218334Speterdefer_addressed_constants ()
258318334Speter{
258418334Speter  defer_addressed_constants_flag++;
258518334Speter}
258618334Speter
258718334Speter/* Stop deferring output of subconstants,
258818334Speter   and output now all those that have been deferred.  */
258918334Speter
259018334Spetervoid
259118334Speteroutput_deferred_addressed_constants ()
259218334Speter{
259318334Speter  struct deferred_constant *p, *next;
259418334Speter
259518334Speter  defer_addressed_constants_flag--;
259618334Speter
259718334Speter  if (defer_addressed_constants_flag > 0)
259818334Speter    return;
259918334Speter
260018334Speter  for (p = deferred_constants; p; p = next)
260118334Speter    {
260218334Speter      output_constant_def_contents (p->exp, p->reloc, p->labelno);
260318334Speter      next = p->next;
260418334Speter      free (p);
260518334Speter    }
260618334Speter
260718334Speter  deferred_constants = 0;
260818334Speter}
260918334Speter
261018334Speter/* Make a copy of the whole tree structure for a constant.
261118334Speter   This handles the same types of nodes that compare_constant
261218334Speter   and record_constant handle.  */
261318334Speter
261418334Speterstatic tree
261518334Spetercopy_constant (exp)
261618334Speter     tree exp;
261718334Speter{
261818334Speter  switch (TREE_CODE (exp))
261918334Speter    {
262018334Speter    case ADDR_EXPR:
262118334Speter      /* For ADDR_EXPR, we do not want to copy the decl whose address
262218334Speter	 is requested.  We do want to copy constants though.  */
262318334Speter      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
262418334Speter	return build1 (TREE_CODE (exp), TREE_TYPE (exp),
262518334Speter		       copy_constant (TREE_OPERAND (exp, 0)));
262618334Speter      else
262718334Speter	return copy_node (exp);
262818334Speter
262918334Speter    case INTEGER_CST:
263018334Speter    case REAL_CST:
263118334Speter    case STRING_CST:
263218334Speter      return copy_node (exp);
263318334Speter
263418334Speter    case COMPLEX_CST:
263518334Speter      return build_complex (copy_constant (TREE_REALPART (exp)),
263618334Speter			    copy_constant (TREE_IMAGPART (exp)));
263718334Speter
263818334Speter    case PLUS_EXPR:
263918334Speter    case MINUS_EXPR:
264018334Speter      return build (TREE_CODE (exp), TREE_TYPE (exp),
264118334Speter		    copy_constant (TREE_OPERAND (exp, 0)),
264218334Speter		    copy_constant (TREE_OPERAND (exp, 1)));
264318334Speter
264418334Speter    case NOP_EXPR:
264518334Speter    case CONVERT_EXPR:
264618334Speter      return build1 (TREE_CODE (exp), TREE_TYPE (exp),
264718334Speter		     copy_constant (TREE_OPERAND (exp, 0)));
264818334Speter
264918334Speter    case CONSTRUCTOR:
265018334Speter      {
265118334Speter	tree copy = copy_node (exp);
265218334Speter	tree list = copy_list (CONSTRUCTOR_ELTS (exp));
265318334Speter	tree tail;
265418334Speter
265518334Speter	CONSTRUCTOR_ELTS (copy) = list;
265618334Speter	for (tail = list; tail; tail = TREE_CHAIN (tail))
265718334Speter	  TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
265818334Speter	if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
265918334Speter	  for (tail = list; tail; tail = TREE_CHAIN (tail))
266018334Speter	    TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
266118334Speter
266218334Speter	return copy;
266318334Speter      }
266418334Speter
266518334Speter    default:
266618334Speter      abort ();
266718334Speter    }
266818334Speter}
266918334Speter
267018334Speter/* Return an rtx representing a reference to constant data in memory
267118334Speter   for the constant expression EXP.
267218334Speter
267318334Speter   If assembler code for such a constant has already been output,
267418334Speter   return an rtx to refer to it.
267518334Speter   Otherwise, output such a constant in memory (or defer it for later)
267618334Speter   and generate an rtx for it.
267718334Speter
267818334Speter   The TREE_CST_RTL of EXP is set up to point to that rtx.
267918334Speter   The const_hash_table records which constants already have label strings.  */
268018334Speter
268118334Speterrtx
268218334Speteroutput_constant_def (exp)
268318334Speter     tree exp;
268418334Speter{
268518334Speter  register int hash;
268618334Speter  register struct constant_descriptor *desc;
268718334Speter  char label[256];
268818334Speter  char *found = 0;
268918334Speter  int reloc;
269018334Speter  register rtx def;
269118334Speter
269218334Speter  if (TREE_CODE (exp) == INTEGER_CST)
269318334Speter    abort ();			/* No TREE_CST_RTL slot in these.  */
269418334Speter
269518334Speter  if (TREE_CST_RTL (exp))
269618334Speter    return TREE_CST_RTL (exp);
269718334Speter
269818334Speter  /* Make sure any other constants whose addresses appear in EXP
269918334Speter     are assigned label numbers.  */
270018334Speter
270118334Speter  reloc = output_addressed_constants (exp);
270218334Speter
270318334Speter  /* Compute hash code of EXP.  Search the descriptors for that hash code
270418334Speter     to see if any of them describes EXP.  If yes, the descriptor records
270518334Speter     the label number already assigned.  */
270618334Speter
270718334Speter  hash = const_hash (exp) % MAX_HASH_TABLE;
270818334Speter
270918334Speter  for (desc = const_hash_table[hash]; desc; desc = desc->next)
271018334Speter    if (compare_constant (exp, desc))
271118334Speter      {
271218334Speter	found = desc->label;
271318334Speter	break;
271418334Speter      }
271518334Speter
271618334Speter  if (found == 0)
271718334Speter    {
271818334Speter      /* No constant equal to EXP is known to have been output.
271918334Speter	 Make a constant descriptor to enter EXP in the hash table.
272018334Speter	 Assign the label number and record it in the descriptor for
272118334Speter	 future calls to this function to find.  */
272218334Speter
272318334Speter      /* Create a string containing the label name, in LABEL.  */
272418334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
272518334Speter
272618334Speter      desc = record_constant (exp);
272718334Speter      desc->next = const_hash_table[hash];
272818334Speter      desc->label
272918334Speter	= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
273018334Speter      const_hash_table[hash] = desc;
273118334Speter    }
273218334Speter  else
273318334Speter    {
273418334Speter      /* Create a string containing the label name, in LABEL.  */
273518334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
273618334Speter    }
273718334Speter
273818334Speter  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
273918334Speter
274018334Speter  push_obstacks_nochange ();
274118334Speter  if (TREE_PERMANENT (exp))
274218334Speter    end_temporary_allocation ();
274318334Speter
274418334Speter  def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
274518334Speter
274618334Speter  TREE_CST_RTL (exp)
274718334Speter    = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
274818334Speter  RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
274918334Speter  if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
275018334Speter    MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
275118334Speter
275218334Speter  pop_obstacks ();
275318334Speter
275418334Speter  /* Optionally set flags or add text to the name to record information
275518334Speter     such as that it is a function name.  If the name is changed, the macro
275618334Speter     ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
275718334Speter#ifdef ENCODE_SECTION_INFO
275818334Speter  ENCODE_SECTION_INFO (exp);
275918334Speter#endif
276018334Speter
276118334Speter  /* If this is the first time we've seen this particular constant,
276218334Speter     output it (or defer its output for later).  */
276318334Speter  if (found == 0)
276418334Speter    {
276518334Speter      if (defer_addressed_constants_flag)
276618334Speter	{
276718334Speter	  struct deferred_constant *p;
276818334Speter	  p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
276918334Speter
277018334Speter	  push_obstacks_nochange ();
277118334Speter	  suspend_momentary ();
277218334Speter	  p->exp = copy_constant (exp);
277318334Speter	  pop_obstacks ();
277418334Speter	  p->reloc = reloc;
277518334Speter	  p->labelno = const_labelno++;
277618334Speter	  p->next = deferred_constants;
277718334Speter	  deferred_constants = p;
277818334Speter	}
277918334Speter      else
278018334Speter	output_constant_def_contents (exp, reloc, const_labelno++);
278118334Speter    }
278218334Speter
278318334Speter  return TREE_CST_RTL (exp);
278418334Speter}
278518334Speter
278618334Speter/* Now output assembler code to define the label for EXP,
278718334Speter   and follow it with the data of EXP.  */
278818334Speter
278918334Speterstatic void
279018334Speteroutput_constant_def_contents (exp, reloc, labelno)
279118334Speter     tree exp;
279218334Speter     int reloc;
279318334Speter     int labelno;
279418334Speter{
279518334Speter  int align;
279618334Speter
279718334Speter  if (IN_NAMED_SECTION (exp))
279818334Speter    named_section (exp, NULL);
279918334Speter  else
280018334Speter    {
280118334Speter      /* First switch to text section, except for writable strings.  */
280218334Speter#ifdef SELECT_SECTION
280318334Speter      SELECT_SECTION (exp, reloc);
280418334Speter#else
280518334Speter      if (((TREE_CODE (exp) == STRING_CST) && flag_writable_strings)
280618334Speter	  || (flag_pic && reloc))
280718334Speter	data_section ();
280818334Speter      else
280918334Speter	readonly_data_section ();
281018334Speter#endif
281118334Speter    }
281218334Speter
281318334Speter  /* Align the location counter as required by EXP's data type.  */
281418334Speter  align = TYPE_ALIGN (TREE_TYPE (exp));
281518334Speter#ifdef CONSTANT_ALIGNMENT
281618334Speter  align = CONSTANT_ALIGNMENT (exp, align);
281718334Speter#endif
281818334Speter
281918334Speter  if (align > BITS_PER_UNIT)
282018334Speter    {
282118334Speter      if (!output_bytecode)
282218334Speter	{
282318334Speter	  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
282418334Speter	}
282518334Speter      else
282618334Speter	{
282718334Speter	  BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
282818334Speter	}
282918334Speter    }
283018334Speter
283118334Speter  /* Output the label itself.  */
283218334Speter  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
283318334Speter
283418334Speter  /* Output the value of EXP.  */
283518334Speter  output_constant (exp,
283618334Speter		   (TREE_CODE (exp) == STRING_CST
283718334Speter		    ? TREE_STRING_LENGTH (exp)
283818334Speter		    : int_size_in_bytes (TREE_TYPE (exp))));
283918334Speter
284018334Speter}
284118334Speter
284218334Speter/* Similar hash facility for making memory-constants
284318334Speter   from constant rtl-expressions.  It is used on RISC machines
284418334Speter   where immediate integer arguments and constant addresses are restricted
284518334Speter   so that such constants must be stored in memory.
284618334Speter
284718334Speter   This pool of constants is reinitialized for each function
284818334Speter   so each function gets its own constants-pool that comes right before it.
284918334Speter
285018334Speter   All structures allocated here are discarded when functions are saved for
285118334Speter   inlining, so they do not need to be allocated permanently.  */
285218334Speter
285318334Speter#define MAX_RTX_HASH_TABLE 61
285418334Speterstatic struct constant_descriptor **const_rtx_hash_table;
285518334Speter
285618334Speter/* Structure to represent sufficient information about a constant so that
285718334Speter   it can be output when the constant pool is output, so that function
285818334Speter   integration can be done, and to simplify handling on machines that reference
285918334Speter   constant pool as base+displacement.  */
286018334Speter
286118334Speterstruct pool_constant
286218334Speter{
286318334Speter  struct constant_descriptor *desc;
286418334Speter  struct pool_constant *next;
286518334Speter  enum machine_mode mode;
286618334Speter  rtx constant;
286718334Speter  int labelno;
286818334Speter  int align;
286918334Speter  int offset;
287018334Speter};
287118334Speter
287218334Speter/* Pointers to first and last constant in pool.  */
287318334Speter
287418334Speterstatic struct pool_constant *first_pool, *last_pool;
287518334Speter
287618334Speter/* Current offset in constant pool (does not include any machine-specific
287718334Speter   header.  */
287818334Speter
287918334Speterstatic int pool_offset;
288018334Speter
288118334Speter/* Structure used to maintain hash table mapping symbols used to their
288218334Speter   corresponding constants.  */
288318334Speter
288418334Speterstruct pool_sym
288518334Speter{
288618334Speter  char *label;
288718334Speter  struct pool_constant *pool;
288818334Speter  struct pool_sym *next;
288918334Speter};
289018334Speter
289118334Speterstatic struct pool_sym **const_rtx_sym_hash_table;
289218334Speter
289318334Speter/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
289418334Speter   The argument is XSTR (... , 0)  */
289518334Speter
289618334Speter#define SYMHASH(LABEL)	\
289718334Speter  ((((HOST_WIDE_INT) (LABEL)) & ((1 << HASHBITS) - 1))  % MAX_RTX_HASH_TABLE)
289818334Speter
289918334Speter/* Initialize constant pool hashing for next function.  */
290018334Speter
290118334Spetervoid
290218334Speterinit_const_rtx_hash_table ()
290318334Speter{
290418334Speter  const_rtx_hash_table
290518334Speter    = ((struct constant_descriptor **)
290618334Speter       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
290718334Speter  const_rtx_sym_hash_table
290818334Speter    = ((struct pool_sym **)
290918334Speter       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
291018334Speter  bzero ((char *) const_rtx_hash_table,
291118334Speter	 MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
291218334Speter  bzero ((char *) const_rtx_sym_hash_table,
291318334Speter	 MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
291418334Speter
291518334Speter  first_pool = last_pool = 0;
291618334Speter  pool_offset = 0;
291718334Speter}
291818334Speter
291918334Speter/* Save and restore status for a nested function.  */
292018334Speter
292118334Spetervoid
292218334Spetersave_varasm_status (p)
292318334Speter     struct function *p;
292418334Speter{
292518334Speter  p->const_rtx_hash_table = const_rtx_hash_table;
292618334Speter  p->const_rtx_sym_hash_table = const_rtx_sym_hash_table;
292718334Speter  p->first_pool = first_pool;
292818334Speter  p->last_pool = last_pool;
292918334Speter  p->pool_offset = pool_offset;
293018334Speter}
293118334Speter
293218334Spetervoid
293318334Speterrestore_varasm_status (p)
293418334Speter     struct function *p;
293518334Speter{
293618334Speter  const_rtx_hash_table = p->const_rtx_hash_table;
293718334Speter  const_rtx_sym_hash_table = p->const_rtx_sym_hash_table;
293818334Speter  first_pool = p->first_pool;
293918334Speter  last_pool = p->last_pool;
294018334Speter  pool_offset = p->pool_offset;
294118334Speter}
294218334Speter
294318334Speterenum kind { RTX_DOUBLE, RTX_INT };
294418334Speter
294518334Speterstruct rtx_const
294618334Speter{
294718334Speter#ifdef ONLY_INT_FIELDS
294818334Speter  unsigned int kind : 16;
294918334Speter  unsigned int mode : 16;
295018334Speter#else
295118334Speter  enum kind kind : 16;
295218334Speter  enum machine_mode mode : 16;
295318334Speter#endif
295418334Speter  union {
295518334Speter    union real_extract du;
295618334Speter    struct addr_const addr;
295718334Speter    struct {HOST_WIDE_INT high, low;} di;
295818334Speter  } un;
295918334Speter};
296018334Speter
296118334Speter/* Express an rtx for a constant integer (perhaps symbolic)
296218334Speter   as the sum of a symbol or label plus an explicit integer.
296318334Speter   They are stored into VALUE.  */
296418334Speter
296518334Speterstatic void
296618334Speterdecode_rtx_const (mode, x, value)
296718334Speter     enum machine_mode mode;
296818334Speter     rtx x;
296918334Speter     struct rtx_const *value;
297018334Speter{
297118334Speter  /* Clear the whole structure, including any gaps.  */
297218334Speter
297318334Speter  {
297418334Speter    int *p = (int *) value;
297518334Speter    int *end = (int *) (value + 1);
297618334Speter    while (p < end)
297718334Speter      *p++ = 0;
297818334Speter  }
297918334Speter
298018334Speter  value->kind = RTX_INT;	/* Most usual kind. */
298118334Speter  value->mode = mode;
298218334Speter
298318334Speter  switch (GET_CODE (x))
298418334Speter    {
298518334Speter    case CONST_DOUBLE:
298618334Speter      value->kind = RTX_DOUBLE;
298718334Speter      if (GET_MODE (x) != VOIDmode)
298818334Speter	{
298918334Speter	  value->mode = GET_MODE (x);
299018334Speter	  bcopy ((char *) &CONST_DOUBLE_LOW (x),
299118334Speter		 (char *) &value->un.du, sizeof value->un.du);
299218334Speter	}
299318334Speter      else
299418334Speter	{
299518334Speter	  value->un.di.low = CONST_DOUBLE_LOW (x);
299618334Speter	  value->un.di.high = CONST_DOUBLE_HIGH (x);
299718334Speter	}
299818334Speter      break;
299918334Speter
300018334Speter    case CONST_INT:
300118334Speter      value->un.addr.offset = INTVAL (x);
300218334Speter      break;
300318334Speter
300418334Speter    case SYMBOL_REF:
300518334Speter    case LABEL_REF:
300618334Speter    case PC:
300718334Speter      value->un.addr.base = x;
300818334Speter      break;
300918334Speter
301018334Speter    case CONST:
301118334Speter      x = XEXP (x, 0);
301218334Speter      if (GET_CODE (x) == PLUS)
301318334Speter	{
301418334Speter	  value->un.addr.base = XEXP (x, 0);
301518334Speter	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
301618334Speter	    abort ();
301718334Speter	  value->un.addr.offset = INTVAL (XEXP (x, 1));
301818334Speter	}
301918334Speter      else if (GET_CODE (x) == MINUS)
302018334Speter	{
302118334Speter	  value->un.addr.base = XEXP (x, 0);
302218334Speter	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
302318334Speter	    abort ();
302418334Speter	  value->un.addr.offset = - INTVAL (XEXP (x, 1));
302518334Speter	}
302618334Speter      else
302718334Speter	abort ();
302818334Speter      break;
302918334Speter
303018334Speter    default:
303118334Speter      abort ();
303218334Speter    }
303318334Speter
303418334Speter  if (value->kind == RTX_INT && value->un.addr.base != 0)
303518334Speter    switch (GET_CODE (value->un.addr.base))
303618334Speter      {
303718334Speter      case SYMBOL_REF:
303818334Speter      case LABEL_REF:
303918334Speter	/* Use the string's address, not the SYMBOL_REF's address,
304018334Speter	   for the sake of addresses of library routines.
304118334Speter	   For a LABEL_REF, compare labels.  */
304218334Speter	value->un.addr.base = XEXP (value->un.addr.base, 0);
304318334Speter      }
304418334Speter}
304518334Speter
304618334Speter/* Given a MINUS expression, simplify it if both sides
304718334Speter   include the same symbol.  */
304818334Speter
304918334Speterrtx
305018334Spetersimplify_subtraction (x)
305118334Speter     rtx x;
305218334Speter{
305318334Speter  struct rtx_const val0, val1;
305418334Speter
305518334Speter  decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
305618334Speter  decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
305718334Speter
305818334Speter  if (val0.un.addr.base == val1.un.addr.base)
305918334Speter    return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
306018334Speter  return x;
306118334Speter}
306218334Speter
306318334Speter/* Compute a hash code for a constant RTL expression.  */
306418334Speter
306518334Speterstatic int
306618334Speterconst_hash_rtx (mode, x)
306718334Speter     enum machine_mode mode;
306818334Speter     rtx x;
306918334Speter{
307018334Speter  register int hi, i;
307118334Speter
307218334Speter  struct rtx_const value;
307318334Speter  decode_rtx_const (mode, x, &value);
307418334Speter
307518334Speter  /* Compute hashing function */
307618334Speter  hi = 0;
307718334Speter  for (i = 0; i < sizeof value / sizeof (int); i++)
307818334Speter    hi += ((int *) &value)[i];
307918334Speter
308018334Speter  hi &= (1 << HASHBITS) - 1;
308118334Speter  hi %= MAX_RTX_HASH_TABLE;
308218334Speter  return hi;
308318334Speter}
308418334Speter
308518334Speter/* Compare a constant rtl object X with a constant-descriptor DESC.
308618334Speter   Return 1 if DESC describes a constant with the same value as X.  */
308718334Speter
308818334Speterstatic int
308918334Spetercompare_constant_rtx (mode, x, desc)
309018334Speter     enum machine_mode mode;
309118334Speter     rtx x;
309218334Speter     struct constant_descriptor *desc;
309318334Speter{
309418334Speter  register int *p = (int *) desc->contents;
309518334Speter  register int *strp;
309618334Speter  register int len;
309718334Speter  struct rtx_const value;
309818334Speter
309918334Speter  decode_rtx_const (mode, x, &value);
310018334Speter  strp = (int *) &value;
310118334Speter  len = sizeof value / sizeof (int);
310218334Speter
310318334Speter  /* Compare constant contents.  */
310418334Speter  while (--len >= 0)
310518334Speter    if (*p++ != *strp++)
310618334Speter      return 0;
310718334Speter
310818334Speter  return 1;
310918334Speter}
311018334Speter
311118334Speter/* Construct a constant descriptor for the rtl-expression X.
311218334Speter   It is up to the caller to enter the descriptor in the hash table.  */
311318334Speter
311418334Speterstatic struct constant_descriptor *
311518334Speterrecord_constant_rtx (mode, x)
311618334Speter     enum machine_mode mode;
311718334Speter     rtx x;
311818334Speter{
311918334Speter  struct constant_descriptor *ptr;
312018334Speter  char *label;
312118334Speter  struct rtx_const value;
312218334Speter
312318334Speter  decode_rtx_const (mode, x, &value);
312418334Speter
312518334Speter  /* Put these things in the saveable obstack so we can ensure it won't
312618334Speter     be freed if we are called from combine or some other phase that discards
312718334Speter     memory allocated from function_obstack (current_obstack).  */
312818334Speter  obstack_grow (saveable_obstack, &ptr, sizeof ptr);
312918334Speter  obstack_grow (saveable_obstack, &label, sizeof label);
313018334Speter
313118334Speter  /* Record constant contents.  */
313218334Speter  obstack_grow (saveable_obstack, &value, sizeof value);
313318334Speter
313418334Speter  return (struct constant_descriptor *) obstack_finish (saveable_obstack);
313518334Speter}
313618334Speter
313718334Speter/* Given a constant rtx X, make (or find) a memory constant for its value
313818334Speter   and return a MEM rtx to refer to it in memory.  */
313918334Speter
314018334Speterrtx
314118334Speterforce_const_mem (mode, x)
314218334Speter     enum machine_mode mode;
314318334Speter     rtx x;
314418334Speter{
314518334Speter  register int hash;
314618334Speter  register struct constant_descriptor *desc;
314718334Speter  char label[256];
314818334Speter  char *found = 0;
314918334Speter  rtx def;
315018334Speter
315118334Speter  /* If we want this CONST_DOUBLE in the same mode as it is in memory
315218334Speter     (this will always be true for floating CONST_DOUBLEs that have been
315318334Speter     placed in memory, but not for VOIDmode (integer) CONST_DOUBLEs),
315418334Speter     use the previous copy.  Otherwise, make a new one.  Note that in
315518334Speter     the unlikely event that this same CONST_DOUBLE is used in two different
315618334Speter     modes in an alternating fashion, we will allocate a lot of different
315718334Speter     memory locations, but this should be extremely rare.  */
315818334Speter
315918334Speter  /* Don't use CONST_DOUBLE_MEM in a nested function.
316018334Speter     Nested functions have their own constant pools,
316118334Speter     so they can't share the same values in CONST_DOUBLE_MEM
316218334Speter     with the containing function.  */
316318334Speter  if (outer_function_chain == 0)
316418334Speter    if (GET_CODE (x) == CONST_DOUBLE
316518334Speter	&& GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
316618334Speter	&& GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
316718334Speter      return CONST_DOUBLE_MEM (x);
316818334Speter
316918334Speter  /* Compute hash code of X.  Search the descriptors for that hash code
317018334Speter     to see if any of them describes X.  If yes, the descriptor records
317118334Speter     the label number already assigned.  */
317218334Speter
317318334Speter  hash = const_hash_rtx (mode, x);
317418334Speter
317518334Speter  for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
317618334Speter    if (compare_constant_rtx (mode, x, desc))
317718334Speter      {
317818334Speter	found = desc->label;
317918334Speter	break;
318018334Speter      }
318118334Speter
318218334Speter  if (found == 0)
318318334Speter    {
318418334Speter      register struct pool_constant *pool;
318518334Speter      register struct pool_sym *sym;
318618334Speter      int align;
318718334Speter
318818334Speter      /* No constant equal to X is known to have been output.
318918334Speter	 Make a constant descriptor to enter X in the hash table.
319018334Speter	 Assign the label number and record it in the descriptor for
319118334Speter	 future calls to this function to find.  */
319218334Speter
319318334Speter      desc = record_constant_rtx (mode, x);
319418334Speter      desc->next = const_rtx_hash_table[hash];
319518334Speter      const_rtx_hash_table[hash] = desc;
319618334Speter
319718334Speter      /* Align the location counter as required by EXP's data type.  */
319818334Speter      align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
319918334Speter      if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
320018334Speter	align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
320118334Speter
320218334Speter      pool_offset += align - 1;
320318334Speter      pool_offset &= ~ (align - 1);
320418334Speter
320518334Speter      /* If RTL is not being placed into the saveable obstack, make a
320618334Speter	 copy of X that is in the saveable obstack in case we are being
320718334Speter	 called from combine or some other phase that discards memory
320818334Speter	 it allocates.  We need only do this if it is a CONST, since
320918334Speter	 no other RTX should be allocated in this situation. */
321018334Speter      if (rtl_obstack != saveable_obstack
321118334Speter	  && GET_CODE (x) == CONST)
321218334Speter	{
321318334Speter	  push_obstacks_nochange ();
321418334Speter	  rtl_in_saveable_obstack ();
321518334Speter
321618334Speter	  x = gen_rtx (CONST, GET_MODE (x),
321718334Speter		       gen_rtx (PLUS, GET_MODE (x),
321818334Speter				XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
321918334Speter	  pop_obstacks ();
322018334Speter	}
322118334Speter
322218334Speter      /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
322318334Speter
322418334Speter      pool = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
322518334Speter      pool->desc = desc;
322618334Speter      pool->constant = x;
322718334Speter      pool->mode = mode;
322818334Speter      pool->labelno = const_labelno;
322918334Speter      pool->align = align;
323018334Speter      pool->offset = pool_offset;
323118334Speter      pool->next = 0;
323218334Speter
323318334Speter      if (last_pool == 0)
323418334Speter	first_pool = pool;
323518334Speter      else
323618334Speter	last_pool->next = pool;
323718334Speter
323818334Speter      last_pool = pool;
323918334Speter      pool_offset += GET_MODE_SIZE (mode);
324018334Speter
324118334Speter      /* Create a string containing the label name, in LABEL.  */
324218334Speter      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
324318334Speter
324418334Speter      ++const_labelno;
324518334Speter
324618334Speter      desc->label = found
324718334Speter	= (char *) obstack_copy0 (saveable_obstack, label, strlen (label));
324818334Speter
324918334Speter      /* Add label to symbol hash table.  */
325018334Speter      hash = SYMHASH (found);
325118334Speter      sym = (struct pool_sym *) savealloc (sizeof (struct pool_sym));
325218334Speter      sym->label = found;
325318334Speter      sym->pool = pool;
325418334Speter      sym->next = const_rtx_sym_hash_table[hash];
325518334Speter      const_rtx_sym_hash_table[hash] = sym;
325618334Speter    }
325718334Speter
325818334Speter  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
325918334Speter
326018334Speter  def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, found));
326118334Speter
326218334Speter  RTX_UNCHANGING_P (def) = 1;
326318334Speter  /* Mark the symbol_ref as belonging to this constants pool.  */
326418334Speter  CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
326518334Speter  current_function_uses_const_pool = 1;
326618334Speter
326718334Speter  if (outer_function_chain == 0)
326818334Speter    if (GET_CODE (x) == CONST_DOUBLE)
326918334Speter      {
327018334Speter	if (CONST_DOUBLE_MEM (x) == cc0_rtx)
327118334Speter	  {
327218334Speter	    CONST_DOUBLE_CHAIN (x) = const_double_chain;
327318334Speter	    const_double_chain = x;
327418334Speter	  }
327518334Speter	CONST_DOUBLE_MEM (x) = def;
327618334Speter      }
327718334Speter
327818334Speter  return def;
327918334Speter}
328018334Speter
328118334Speter/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
328218334Speter   the corresponding pool_constant structure.  */
328318334Speter
328418334Speterstatic struct pool_constant *
328518334Speterfind_pool_constant (addr)
328618334Speter     rtx addr;
328718334Speter{
328818334Speter  struct pool_sym *sym;
328918334Speter  char *label = XSTR (addr, 0);
329018334Speter
329118334Speter  for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
329218334Speter    if (sym->label == label)
329318334Speter      return sym->pool;
329418334Speter
329518334Speter  abort ();
329618334Speter}
329718334Speter
329818334Speter/* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
329918334Speter
330018334Speterrtx
330118334Speterget_pool_constant (addr)
330218334Speter     rtx addr;
330318334Speter{
330418334Speter  return (find_pool_constant (addr))->constant;
330518334Speter}
330618334Speter
330718334Speter/* Similar, return the mode.  */
330818334Speter
330918334Speterenum machine_mode
331018334Speterget_pool_mode (addr)
331118334Speter     rtx addr;
331218334Speter{
331318334Speter  return (find_pool_constant (addr))->mode;
331418334Speter}
331518334Speter
331618334Speter/* Similar, return the offset in the constant pool.  */
331718334Speter
331818334Speterint
331918334Speterget_pool_offset (addr)
332018334Speter     rtx addr;
332118334Speter{
332218334Speter  return (find_pool_constant (addr))->offset;
332318334Speter}
332418334Speter
332518334Speter/* Return the size of the constant pool.  */
332618334Speter
332718334Speterint
332818334Speterget_pool_size ()
332918334Speter{
333018334Speter  return pool_offset;
333118334Speter}
333218334Speter
333318334Speter/* Write all the constants in the constant pool.  */
333418334Speter
333518334Spetervoid
333618334Speteroutput_constant_pool (fnname, fndecl)
333718334Speter     char *fnname;
333818334Speter     tree fndecl;
333918334Speter{
334018334Speter  struct pool_constant *pool;
334118334Speter  rtx x;
334218334Speter  union real_extract u;
334318334Speter
334418334Speter#ifdef ASM_OUTPUT_POOL_PROLOGUE
334518334Speter  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
334618334Speter#endif
334718334Speter
334818334Speter  for (pool = first_pool; pool; pool = pool->next)
334918334Speter    {
335018334Speter      x = pool->constant;
335118334Speter
335218334Speter      /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
335318334Speter	 whose CODE_LABEL has been deleted.  This can occur if a jump table
335418334Speter	 is eliminated by optimization.  If so, write a constant of zero
335518334Speter	 instead.  Note that this can also happen by turning the
335618334Speter	 CODE_LABEL into a NOTE.  */
335718334Speter      if (((GET_CODE (x) == LABEL_REF
335818334Speter	    && (INSN_DELETED_P (XEXP (x, 0))
335918334Speter		|| GET_CODE (XEXP (x, 0)) == NOTE)))
336018334Speter	  || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
336118334Speter	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
336218334Speter	      && (INSN_DELETED_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
336318334Speter		  || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == NOTE)))
336418334Speter	x = const0_rtx;
336518334Speter
336618334Speter      /* First switch to correct section.  */
336718334Speter#ifdef SELECT_RTX_SECTION
336818334Speter      SELECT_RTX_SECTION (pool->mode, x);
336918334Speter#else
337018334Speter      readonly_data_section ();
337118334Speter#endif
337218334Speter
337318334Speter#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
337418334Speter      ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
337518334Speter				     pool->align, pool->labelno, done);
337618334Speter#endif
337718334Speter
337818334Speter      if (pool->align > 1)
337918334Speter	ASM_OUTPUT_ALIGN (asm_out_file, exact_log2 (pool->align));
338018334Speter
338118334Speter      /* Output the label.  */
338218334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
338318334Speter
338418334Speter      /* Output the value of the constant itself.  */
338518334Speter      switch (GET_MODE_CLASS (pool->mode))
338618334Speter	{
338718334Speter	case MODE_FLOAT:
338818334Speter	  if (GET_CODE (x) != CONST_DOUBLE)
338918334Speter	    abort ();
339018334Speter
339118334Speter	  bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
339218334Speter	  assemble_real (u.d, pool->mode);
339318334Speter	  break;
339418334Speter
339518334Speter	case MODE_INT:
339618334Speter	case MODE_PARTIAL_INT:
339718334Speter	  assemble_integer (x, GET_MODE_SIZE (pool->mode), 1);
339818334Speter	  break;
339918334Speter
340018334Speter	default:
340118334Speter	  abort ();
340218334Speter	}
340318334Speter
340418334Speter    done: ;
340518334Speter    }
340618334Speter
340718334Speter  /* Done with this pool.  */
340818334Speter  first_pool = last_pool = 0;
340918334Speter}
341018334Speter
341118334Speter/* Find all the constants whose addresses are referenced inside of EXP,
341218334Speter   and make sure assembler code with a label has been output for each one.
341318334Speter   Indicate whether an ADDR_EXPR has been encountered.  */
341418334Speter
341518334Speterstatic int
341618334Speteroutput_addressed_constants (exp)
341718334Speter     tree exp;
341818334Speter{
341918334Speter  int reloc = 0;
342018334Speter
342118334Speter  switch (TREE_CODE (exp))
342218334Speter    {
342318334Speter    case ADDR_EXPR:
342418334Speter      {
342518334Speter	register tree constant = TREE_OPERAND (exp, 0);
342618334Speter
342718334Speter	while (TREE_CODE (constant) == COMPONENT_REF)
342818334Speter	  {
342918334Speter	    constant = TREE_OPERAND (constant, 0);
343018334Speter	  }
343118334Speter
343218334Speter	if (TREE_CODE_CLASS (TREE_CODE (constant)) == 'c'
343318334Speter	    || TREE_CODE (constant) == CONSTRUCTOR)
343418334Speter	  /* No need to do anything here
343518334Speter	     for addresses of variables or functions.  */
343618334Speter	  output_constant_def (constant);
343718334Speter      }
343818334Speter      reloc = 1;
343918334Speter      break;
344018334Speter
344118334Speter    case PLUS_EXPR:
344218334Speter    case MINUS_EXPR:
344318334Speter      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
344418334Speter      reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
344518334Speter      break;
344618334Speter
344718334Speter    case NOP_EXPR:
344818334Speter    case CONVERT_EXPR:
344918334Speter    case NON_LVALUE_EXPR:
345018334Speter      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
345118334Speter      break;
345218334Speter
345318334Speter    case CONSTRUCTOR:
345418334Speter      {
345518334Speter	register tree link;
345618334Speter	for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
345718334Speter	  if (TREE_VALUE (link) != 0)
345818334Speter	    reloc |= output_addressed_constants (TREE_VALUE (link));
345918334Speter      }
346018334Speter      break;
346118334Speter
346218334Speter    case ERROR_MARK:
346318334Speter      break;
346418334Speter    }
346518334Speter  return reloc;
346618334Speter}
346718334Speter
346818334Speter/* Output assembler code for constant EXP to FILE, with no label.
346918334Speter   This includes the pseudo-op such as ".int" or ".byte", and a newline.
347018334Speter   Assumes output_addressed_constants has been done on EXP already.
347118334Speter
347218334Speter   Generate exactly SIZE bytes of assembler data, padding at the end
347318334Speter   with zeros if necessary.  SIZE must always be specified.
347418334Speter
347518334Speter   SIZE is important for structure constructors,
347618334Speter   since trailing members may have been omitted from the constructor.
347718334Speter   It is also important for initialization of arrays from string constants
347818334Speter   since the full length of the string constant might not be wanted.
347918334Speter   It is also needed for initialization of unions, where the initializer's
348018334Speter   type is just one member, and that may not be as long as the union.
348118334Speter
348218334Speter   There a case in which we would fail to output exactly SIZE bytes:
348318334Speter   for a structure constructor that wants to produce more than SIZE bytes.
348418334Speter   But such constructors will never be generated for any possible input.  */
348518334Speter
348618334Spetervoid
348718334Speteroutput_constant (exp, size)
348818334Speter     register tree exp;
348918334Speter     register int size;
349018334Speter{
349118334Speter  register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
349218334Speter  rtx x;
349318334Speter
349418334Speter  if (size == 0)
349518334Speter    return;
349618334Speter
349718334Speter  /* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
349818334Speter     That way we get the constant (we hope) inside it.  Also, strip off any
349918334Speter     NOP_EXPR that converts between two record, union, array, or set types.  */
350018334Speter  while ((TREE_CODE (exp) == NOP_EXPR
350118334Speter	  && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
350218334Speter	      || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
350318334Speter	 || TREE_CODE (exp) == NON_LVALUE_EXPR)
350418334Speter    exp = TREE_OPERAND (exp, 0);
350518334Speter
350618334Speter  /* Allow a constructor with no elements for any data type.
350718334Speter     This means to fill the space with zeros.  */
350818334Speter  if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
350918334Speter    {
351018334Speter      if (output_bytecode)
351118334Speter	bc_emit_const_skip (size);
351218334Speter      else
351318334Speter	assemble_zeros (size);
351418334Speter      return;
351518334Speter    }
351618334Speter
351718334Speter  switch (code)
351818334Speter    {
351918334Speter    case CHAR_TYPE:
352018334Speter    case BOOLEAN_TYPE:
352118334Speter    case INTEGER_TYPE:
352218334Speter    case ENUMERAL_TYPE:
352318334Speter    case POINTER_TYPE:
352418334Speter    case REFERENCE_TYPE:
352518334Speter      /* ??? What about       (int)((float)(int)&foo + 4)    */
352618334Speter      while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
352718334Speter	     || TREE_CODE (exp) == NON_LVALUE_EXPR)
352818334Speter	exp = TREE_OPERAND (exp, 0);
352918334Speter
353018334Speter      if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
353118334Speter					   EXPAND_INITIALIZER),
353218334Speter			      size, 0))
353318334Speter	error ("initializer for integer value is too complicated");
353418334Speter      size = 0;
353518334Speter      break;
353618334Speter
353718334Speter    case REAL_TYPE:
353818334Speter      if (TREE_CODE (exp) != REAL_CST)
353918334Speter	error ("initializer for floating value is not a floating constant");
354018334Speter
354118334Speter      assemble_real (TREE_REAL_CST (exp),
354218334Speter		     mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0));
354318334Speter      size = 0;
354418334Speter      break;
354518334Speter
354618334Speter    case COMPLEX_TYPE:
354718334Speter      output_constant (TREE_REALPART (exp), size / 2);
354818334Speter      output_constant (TREE_IMAGPART (exp), size / 2);
354918334Speter      size -= (size / 2) * 2;
355018334Speter      break;
355118334Speter
355218334Speter    case ARRAY_TYPE:
355318334Speter      if (TREE_CODE (exp) == CONSTRUCTOR)
355418334Speter	{
355518334Speter	  output_constructor (exp, size);
355618334Speter	  return;
355718334Speter	}
355818334Speter      else if (TREE_CODE (exp) == STRING_CST)
355918334Speter	{
356018334Speter	  int excess = 0;
356118334Speter
356218334Speter	  if (size > TREE_STRING_LENGTH (exp))
356318334Speter	    {
356418334Speter	      excess = size - TREE_STRING_LENGTH (exp);
356518334Speter	      size = TREE_STRING_LENGTH (exp);
356618334Speter	    }
356718334Speter
356818334Speter	  assemble_string (TREE_STRING_POINTER (exp), size);
356918334Speter	  size = excess;
357018334Speter	}
357118334Speter      else
357218334Speter	abort ();
357318334Speter      break;
357418334Speter
357518334Speter    case RECORD_TYPE:
357618334Speter    case UNION_TYPE:
357718334Speter      if (TREE_CODE (exp) == CONSTRUCTOR)
357818334Speter	output_constructor (exp, size);
357918334Speter      else
358018334Speter	abort ();
358118334Speter      return;
358218334Speter
358318334Speter    case SET_TYPE:
358418334Speter      if (TREE_CODE (exp) == INTEGER_CST)
358518334Speter	assemble_integer (expand_expr (exp, NULL_RTX,
358618334Speter				       VOIDmode, EXPAND_INITIALIZER),
358718334Speter			  size, 1);
358818334Speter      else if (TREE_CODE (exp) == CONSTRUCTOR)
358918334Speter	{
359018334Speter	  unsigned char *buffer = (unsigned char *) alloca (size);
359118334Speter	  if (get_set_constructor_bytes (exp, buffer, size))
359218334Speter	    abort ();
359318334Speter	  assemble_string ((char *) buffer, size);
359418334Speter	}
359518334Speter      else
359618334Speter	error ("unknown set constructor type");
359718334Speter      return;
359818334Speter    }
359918334Speter
360018334Speter  if (size > 0)
360118334Speter    assemble_zeros (size);
360218334Speter}
360318334Speter
360418334Speter/* Bytecode specific code to output assembler for integer. */
360518334Speter
360618334Speterstatic void
360718334Speterbc_assemble_integer (exp, size)
360818334Speter    tree exp;
360918334Speter    int size;
361018334Speter{
361118334Speter  tree const_part;
361218334Speter  tree addr_part;
361318334Speter  tree tmp;
361418334Speter
361518334Speter  /* FIXME: is this fold() business going to be as good as the
361618334Speter     expand_expr() using EXPAND_SUM above in the RTL case?  I
361718334Speter     hate RMS.
361818334Speter     FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
361918334Speter
362018334Speter  exp = fold (exp);
362118334Speter
362218334Speter  while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
362318334Speter    exp = TREE_OPERAND (exp, 0);
362418334Speter  if (TREE_CODE (exp) == INTEGER_CST)
362518334Speter    {
362618334Speter      const_part = exp;
362718334Speter      addr_part = 0;
362818334Speter    }
362918334Speter  else if (TREE_CODE (exp) == PLUS_EXPR)
363018334Speter    {
363118334Speter      const_part = TREE_OPERAND (exp, 0);
363218334Speter      while (TREE_CODE (const_part) == NOP_EXPR
363318334Speter	     || TREE_CODE (const_part) == CONVERT_EXPR)
363418334Speter	const_part = TREE_OPERAND (const_part, 0);
363518334Speter      addr_part = TREE_OPERAND (exp, 1);
363618334Speter      while (TREE_CODE (addr_part) == NOP_EXPR
363718334Speter	     || TREE_CODE (addr_part) == CONVERT_EXPR)
363818334Speter	addr_part = TREE_OPERAND (addr_part, 0);
363918334Speter      if (TREE_CODE (const_part) != INTEGER_CST)
364018334Speter	tmp = const_part, const_part = addr_part, addr_part = tmp;
364118334Speter      if (TREE_CODE (const_part) != INTEGER_CST
364218334Speter	  || TREE_CODE (addr_part) != ADDR_EXPR)
364318334Speter	abort ();		/* FIXME: we really haven't considered
364418334Speter				   all the possible cases here.  */
364518334Speter    }
364618334Speter  else if (TREE_CODE (exp) == ADDR_EXPR)
364718334Speter    {
364818334Speter      const_part = integer_zero_node;
364918334Speter      addr_part = exp;
365018334Speter    }
365118334Speter  else
365218334Speter    abort ();		/* FIXME: ditto previous.  */
365318334Speter
365418334Speter  if (addr_part == 0)
365518334Speter    {
365618334Speter      if (size == 1)
365718334Speter	{
365818334Speter	  char c = TREE_INT_CST_LOW (const_part);
365918334Speter	  bc_emit (&c, 1);
366018334Speter	  size -= 1;
366118334Speter	}
366218334Speter      else if (size == 2)
366318334Speter	{
366418334Speter	  short s = TREE_INT_CST_LOW (const_part);
366518334Speter	  bc_emit ((char *) &s, 2);
366618334Speter	  size -= 2;
366718334Speter	}
366818334Speter      else if (size == 4)
366918334Speter	{
367018334Speter	  int i = TREE_INT_CST_LOW (const_part);
367118334Speter	  bc_emit ((char *) &i, 4);
367218334Speter	  size -= 4;
367318334Speter	}
367418334Speter      else if (size == 8)
367518334Speter	{
367618334Speter	  if (WORDS_BIG_ENDIAN)
367718334Speter	    {
367818334Speter	      int i = TREE_INT_CST_HIGH (const_part);
367918334Speter	      bc_emit ((char *) &i, 4);
368018334Speter	      i = TREE_INT_CST_LOW (const_part);
368118334Speter	      bc_emit ((char *) &i, 4);
368218334Speter	    }
368318334Speter	  else
368418334Speter	    {
368518334Speter	      int i = TREE_INT_CST_LOW (const_part);
368618334Speter	      bc_emit ((char *) &i, 4);
368718334Speter	      i = TREE_INT_CST_HIGH (const_part);
368818334Speter	      bc_emit ((char *) &i, 4);
368918334Speter	    }
369018334Speter	  size -= 8;
369118334Speter	}
369218334Speter    }
369318334Speter  else
369418334Speter    if (size == 4
369518334Speter	&& TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
369618334Speter      bc_emit_labelref (IDENTIFIER_POINTER
369718334Speter			(DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0))),
369818334Speter			TREE_INT_CST_LOW (const_part));
369918334Speter    else
370018334Speter      abort ();		/* FIXME: there may be more cases.  */
370118334Speter}
370218334Speter
370318334Speter/* Subroutine of output_constant, used for CONSTRUCTORs
370418334Speter   (aggregate constants).
370518334Speter   Generate at least SIZE bytes, padding if necessary.  */
370618334Speter
370718334Speterstatic void
370818334Speteroutput_constructor (exp, size)
370918334Speter     tree exp;
371018334Speter     int size;
371118334Speter{
371218334Speter  register tree link, field = 0;
371318334Speter  HOST_WIDE_INT min_index = 0;
371418334Speter  /* Number of bytes output or skipped so far.
371518334Speter     In other words, current position within the constructor.  */
371618334Speter  int total_bytes = 0;
371718334Speter  /* Non-zero means BYTE contains part of a byte, to be output.  */
371818334Speter  int byte_buffer_in_use = 0;
371918334Speter  register int byte;
372018334Speter
372118334Speter  if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
372218334Speter    abort ();
372318334Speter
372418334Speter  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
372518334Speter    field = TYPE_FIELDS (TREE_TYPE (exp));
372618334Speter
372718334Speter  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
372818334Speter      && TYPE_DOMAIN (TREE_TYPE (exp)) != 0)
372918334Speter    min_index
373018334Speter      = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (exp))));
373118334Speter
373218334Speter  /* As LINK goes through the elements of the constant,
373318334Speter     FIELD goes through the structure fields, if the constant is a structure.
373418334Speter     if the constant is a union, then we override this,
373518334Speter     by getting the field from the TREE_LIST element.
373618334Speter     But the constant could also be an array.  Then FIELD is zero.  */
373718334Speter  for (link = CONSTRUCTOR_ELTS (exp);
373818334Speter       link;
373918334Speter       link = TREE_CHAIN (link),
374018334Speter       field = field ? TREE_CHAIN (field) : 0)
374118334Speter    {
374218334Speter      tree val = TREE_VALUE (link);
374318334Speter      tree index = 0;
374418334Speter
374518334Speter      /* the element in a union constructor specifies the proper field.  */
374618334Speter
374718334Speter      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
374818334Speter	  || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
374918334Speter	{
375018334Speter	  /* if available, use the type given by link */
375118334Speter	  if (TREE_PURPOSE (link) != 0)
375218334Speter	    field = TREE_PURPOSE (link);
375318334Speter	}
375418334Speter
375518334Speter      if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
375618334Speter	index = TREE_PURPOSE (link);
375718334Speter
375818334Speter      /* Eliminate the marker that makes a cast not be an lvalue.  */
375918334Speter      if (val != 0)
376018334Speter	STRIP_NOPS (val);
376118334Speter
376218334Speter      if (field == 0 || !DECL_BIT_FIELD (field))
376318334Speter	{
376418334Speter	  /* An element that is not a bit-field.  */
376518334Speter
376618334Speter	  register int fieldsize;
376718334Speter	  /* Since this structure is static,
376818334Speter	     we know the positions are constant.  */
376918334Speter	  int bitpos = (field ? (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
377018334Speter				 / BITS_PER_UNIT)
377118334Speter			: 0);
377218334Speter	  if (index != 0)
377318334Speter	    bitpos = (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (val)))
377418334Speter		      / BITS_PER_UNIT
377518334Speter		      * (TREE_INT_CST_LOW (index) - min_index));
377618334Speter
377718334Speter	  /* Output any buffered-up bit-fields preceding this element.  */
377818334Speter	  if (byte_buffer_in_use)
377918334Speter	    {
378018334Speter	      ASM_OUTPUT_BYTE (asm_out_file, byte);
378118334Speter	      total_bytes++;
378218334Speter	      byte_buffer_in_use = 0;
378318334Speter	    }
378418334Speter
378518334Speter	  /* Advance to offset of this element.
378618334Speter	     Note no alignment needed in an array, since that is guaranteed
378718334Speter	     if each element has the proper size.  */
378818334Speter	  if ((field != 0 || index != 0) && bitpos != total_bytes)
378918334Speter	    {
379018334Speter	      if (!output_bytecode)
379118334Speter		assemble_zeros (bitpos - total_bytes);
379218334Speter	      else
379318334Speter		bc_emit_const_skip (bitpos - total_bytes);
379418334Speter	      total_bytes = bitpos;
379518334Speter	    }
379618334Speter
379718334Speter	  /* Determine size this element should occupy.  */
379818334Speter	  if (field)
379918334Speter	    {
380018334Speter	      if (TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
380118334Speter		abort ();
380218334Speter	      if (TREE_INT_CST_LOW (DECL_SIZE (field)) > 100000)
380318334Speter		{
380418334Speter		  /* This avoids overflow trouble.  */
380518334Speter		  tree size_tree = size_binop (CEIL_DIV_EXPR,
380618334Speter					       DECL_SIZE (field),
380718334Speter					       size_int (BITS_PER_UNIT));
380818334Speter		  fieldsize = TREE_INT_CST_LOW (size_tree);
380918334Speter		}
381018334Speter	      else
381118334Speter		{
381218334Speter		  fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field));
381318334Speter		  fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
381418334Speter		}
381518334Speter	    }
381618334Speter	  else
381718334Speter	    fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
381818334Speter
381918334Speter	  /* Output the element's initial value.  */
382018334Speter	  if (val == 0)
382118334Speter	    assemble_zeros (fieldsize);
382218334Speter	  else
382318334Speter	    output_constant (val, fieldsize);
382418334Speter
382518334Speter	  /* Count its size.  */
382618334Speter	  total_bytes += fieldsize;
382718334Speter	}
382818334Speter      else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
382918334Speter	error ("invalid initial value for member `%s'",
383018334Speter	       IDENTIFIER_POINTER (DECL_NAME (field)));
383118334Speter      else
383218334Speter	{
383318334Speter	  /* Element that is a bit-field.  */
383418334Speter
383518334Speter	  int next_offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
383618334Speter	  int end_offset
383718334Speter	    = (next_offset + TREE_INT_CST_LOW (DECL_SIZE (field)));
383818334Speter
383918334Speter	  if (val == 0)
384018334Speter	    val = integer_zero_node;
384118334Speter
384218334Speter	  /* If this field does not start in this (or, next) byte,
384318334Speter	     skip some bytes.  */
384418334Speter	  if (next_offset / BITS_PER_UNIT != total_bytes)
384518334Speter	    {
384618334Speter	      /* Output remnant of any bit field in previous bytes.  */
384718334Speter	      if (byte_buffer_in_use)
384818334Speter		{
384918334Speter		  ASM_OUTPUT_BYTE (asm_out_file, byte);
385018334Speter		  total_bytes++;
385118334Speter		  byte_buffer_in_use = 0;
385218334Speter		}
385318334Speter
385418334Speter	      /* If still not at proper byte, advance to there.  */
385518334Speter	      if (next_offset / BITS_PER_UNIT != total_bytes)
385618334Speter		{
385718334Speter		  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
385818334Speter		  total_bytes = next_offset / BITS_PER_UNIT;
385918334Speter		}
386018334Speter	    }
386118334Speter
386218334Speter	  if (! byte_buffer_in_use)
386318334Speter	    byte = 0;
386418334Speter
386518334Speter	  /* We must split the element into pieces that fall within
386618334Speter	     separate bytes, and combine each byte with previous or
386718334Speter	     following bit-fields.  */
386818334Speter
386918334Speter	  /* next_offset is the offset n fbits from the beginning of
387018334Speter	     the structure to the next bit of this element to be processed.
387118334Speter	     end_offset is the offset of the first bit past the end of
387218334Speter	     this element.  */
387318334Speter	  while (next_offset < end_offset)
387418334Speter	    {
387518334Speter	      int this_time;
387618334Speter	      int shift;
387718334Speter	      HOST_WIDE_INT value;
387818334Speter	      int next_byte = next_offset / BITS_PER_UNIT;
387918334Speter	      int next_bit = next_offset % BITS_PER_UNIT;
388018334Speter
388118334Speter	      /* Advance from byte to byte
388218334Speter		 within this element when necessary.  */
388318334Speter	      while (next_byte != total_bytes)
388418334Speter		{
388518334Speter		  ASM_OUTPUT_BYTE (asm_out_file, byte);
388618334Speter		  total_bytes++;
388718334Speter		  byte = 0;
388818334Speter		}
388918334Speter
389018334Speter	      /* Number of bits we can process at once
389118334Speter		 (all part of the same byte).  */
389218334Speter	      this_time = MIN (end_offset - next_offset,
389318334Speter			       BITS_PER_UNIT - next_bit);
389418334Speter	      if (BYTES_BIG_ENDIAN)
389518334Speter		{
389618334Speter		  /* On big-endian machine, take the most significant bits
389718334Speter		     first (of the bits that are significant)
389818334Speter		     and put them into bytes from the most significant end.  */
389918334Speter		  shift = end_offset - next_offset - this_time;
390018334Speter		  /* Don't try to take a bunch of bits that cross
390118334Speter		     the word boundary in the INTEGER_CST.  */
390218334Speter		  if (shift < HOST_BITS_PER_WIDE_INT
390318334Speter		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
390418334Speter		    {
390518334Speter		      this_time -= (HOST_BITS_PER_WIDE_INT - shift);
390618334Speter		      shift = HOST_BITS_PER_WIDE_INT;
390718334Speter		    }
390818334Speter
390918334Speter		  /* Now get the bits from the appropriate constant word.  */
391018334Speter		  if (shift < HOST_BITS_PER_WIDE_INT)
391118334Speter		    {
391218334Speter		      value = TREE_INT_CST_LOW (val);
391318334Speter		    }
391418334Speter		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
391518334Speter		    {
391618334Speter		      value = TREE_INT_CST_HIGH (val);
391718334Speter		      shift -= HOST_BITS_PER_WIDE_INT;
391818334Speter		    }
391918334Speter		  else
392018334Speter		    abort ();
392118334Speter		  byte |= (((value >> shift)
392218334Speter			    & (((HOST_WIDE_INT) 1 << this_time) - 1))
392318334Speter			   << (BITS_PER_UNIT - this_time - next_bit));
392418334Speter		}
392518334Speter	      else
392618334Speter		{
392718334Speter		  /* On little-endian machines,
392818334Speter		     take first the least significant bits of the value
392918334Speter		     and pack them starting at the least significant
393018334Speter		     bits of the bytes.  */
393118334Speter		  shift = (next_offset
393218334Speter			   - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
393318334Speter		  /* Don't try to take a bunch of bits that cross
393418334Speter		     the word boundary in the INTEGER_CST.  */
393518334Speter		  if (shift < HOST_BITS_PER_WIDE_INT
393618334Speter		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
393718334Speter		    {
393818334Speter		      this_time -= (HOST_BITS_PER_WIDE_INT - shift);
393918334Speter		      shift = HOST_BITS_PER_WIDE_INT;
394018334Speter		    }
394118334Speter
394218334Speter		  /* Now get the bits from the appropriate constant word.  */
394318334Speter		  if (shift < HOST_BITS_PER_INT)
394418334Speter		    value = TREE_INT_CST_LOW (val);
394518334Speter		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
394618334Speter		    {
394718334Speter		      value = TREE_INT_CST_HIGH (val);
394818334Speter		      shift -= HOST_BITS_PER_WIDE_INT;
394918334Speter		    }
395018334Speter		  else
395118334Speter		    abort ();
395218334Speter		  byte |= (((value >> shift)
395318334Speter			    & (((HOST_WIDE_INT) 1 << this_time) - 1))
395418334Speter			   << next_bit);
395518334Speter		}
395618334Speter	      next_offset += this_time;
395718334Speter	      byte_buffer_in_use = 1;
395818334Speter	    }
395918334Speter	}
396018334Speter    }
396118334Speter  if (byte_buffer_in_use)
396218334Speter    {
396318334Speter      ASM_OUTPUT_BYTE (asm_out_file, byte);
396418334Speter      total_bytes++;
396518334Speter    }
396618334Speter  if (total_bytes < size)
396718334Speter    assemble_zeros (size - total_bytes);
396818334Speter}
396918334Speter
397018334Speter/* Output asm to handle ``#pragma weak'' */
397118334Spetervoid
397218334Speterhandle_pragma_weak (what, name, value)
397318334Speter     enum pragma_state what;
397418334Speter     char *name, *value;
397518334Speter{
397618334Speter#ifdef HANDLE_PRAGMA_WEAK
397718334Speter  if (what == ps_name || what == ps_value)
397818334Speter    {
397918334Speter      struct weak_syms *weak =
398018334Speter	(struct weak_syms *)permalloc (sizeof (struct weak_syms));
398118334Speter      weak->next = weak_decls;
398218334Speter      weak->name = permalloc (strlen (name) + 1);
398318334Speter      strcpy (weak->name, name);
398418334Speter
398518334Speter      if (what != ps_value)
398618334Speter	weak->value = NULL_PTR;
398718334Speter
398818334Speter      else
398918334Speter	{
399018334Speter	  weak->value = permalloc (strlen (value) + 1);
399118334Speter	  strcpy (weak->value, value);
399218334Speter	}
399318334Speter
399418334Speter      weak_decls = weak;
399518334Speter    }
399618334Speter  else if (! (what == ps_done || what == ps_start))
399718334Speter    warning ("malformed `#pragma weak'");
399818334Speter#endif /* HANDLE_PRAGMA_WEAK */
399918334Speter}
400018334Speter
400118334Speter/* Declare DECL to be a weak symbol.  */
400218334Speter
400318334Spetervoid
400418334Speterdeclare_weak (decl)
400518334Speter     tree decl;
400618334Speter{
400718334Speter  if (! TREE_PUBLIC (decl))
400818334Speter    error_with_decl (decl, "weak declaration of `%s' must be public");
400918334Speter  else if (TREE_ASM_WRITTEN (decl))
401018334Speter    error_with_decl (decl, "weak declaration of `%s' must precede definition");
401118334Speter  else if (SUPPORTS_WEAK)
401218334Speter    DECL_WEAK (decl) = 1;
401318334Speter}
401418334Speter
401518334Speter/* Emit any pending weak declarations.  */
401618334Speter
401718334Spetervoid
401818334Speterweak_finish ()
401918334Speter{
402018334Speter#ifdef HANDLE_PRAGMA_WEAK
402118334Speter  if (HANDLE_PRAGMA_WEAK)
402218334Speter    {
402318334Speter      struct weak_syms *t;
402418334Speter      for (t = weak_decls; t; t = t->next)
402518334Speter	{
402618334Speter	  ASM_WEAKEN_LABEL (asm_out_file, t->name);
402718334Speter	  if (t->value)
402818334Speter	    ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
402918334Speter	}
403018334Speter    }
403118334Speter#endif
403218334Speter}
403318334Speter
403418334Spetervoid
403518334Speterassemble_alias (decl, target)
403618334Speter     tree decl, target;
403718334Speter{
403818334Speter#ifdef ASM_OUTPUT_DEF
403918334Speter  char *name;
404018334Speter
404118334Speter  make_decl_rtl (decl, (char*)0, 1);
404218334Speter  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
404318334Speter
404418334Speter  /* Make name accessible from other files, if appropriate.  */
404518334Speter
404618334Speter  if (TREE_PUBLIC (decl))
404718334Speter    {
404818334Speter#ifdef ASM_WEAKEN_LABEL
404918334Speter      if (DECL_WEAK (decl))
405018334Speter	ASM_WEAKEN_LABEL (asm_out_file, name);
405118334Speter      else
405218334Speter#endif
405318334Speter      if (output_bytecode)
405418334Speter	BC_GLOBALIZE_LABEL (asm_out_file, name);
405518334Speter      else
405618334Speter	ASM_GLOBALIZE_LABEL (asm_out_file, name);
405718334Speter    }
405818334Speter
405918334Speter  ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
406018334Speter  TREE_ASM_WRITTEN (decl) = 1;
406118334Speter#else
406218334Speter  warning ("alias definitions not supported in this configuration");
406318334Speter#endif
406418334Speter}
4065