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