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