Index: gcc/config/rs6000/rs6000.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/rs6000/rs6000.c,v retrieving revision 1.368 diff -u -p -r1.368 rs6000.c --- gcc/config/rs6000/rs6000.c 23 Aug 2002 18:02:22 -0000 1.368 +++ gcc/config/rs6000/rs6000.c 30 Aug 2002 18:08:39 -0000 @@ -196,9 +196,11 @@ static unsigned int rs6000_elf_section_t int)); static void rs6000_elf_asm_out_constructor PARAMS ((rtx, int)); static void rs6000_elf_asm_out_destructor PARAMS ((rtx, int)); -static void rs6000_elf_select_section PARAMS ((tree, int, - unsigned HOST_WIDE_INT)); -static void rs6000_elf_unique_section PARAMS ((tree, int)); +static bool rs6000_in_small_data_p PARAMS ((tree)); + +void rs6000_elf_select_section PARAMS ((tree, int, + unsigned HOST_WIDE_INT)); +void rs6000_elf_unique_section PARAMS ((tree, int)); static void rs6000_elf_select_rtx_section PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT)); static void rs6000_elf_encode_section_info PARAMS ((tree, int)); @@ -308,7 +310,8 @@ static const char alt_reg_names[][8] = #define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes - +#undef TARGET_IN_SMALL_DATA_P +#define TARGET_IN_SMALL_DATA_P rs6000_in_small_data_p #undef TARGET_ASM_ALIGNED_DI_OP #define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP @@ -6503,7 +6506,7 @@ mtcrf_operation (op, mode) maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp))); if (GET_CODE (unspec) != UNSPEC - || XINT (unspec, 1) != 20 + || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR || XVECLEN (unspec, 0) != 2 || XVECEXP (unspec, 0, 0) != src_reg || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT @@ -9633,7 +9636,7 @@ get_TOC_alias_set () } /* This retuns nonzero if the current function uses the TOC. This is - determined by the presence of (unspec ... 7), which is generated by + determined by the presence of (unspec ... UNSPEC_TOCADR), which is generated by the various load_toc_* patterns. */ int @@ -9650,7 +9653,7 @@ uses_TOC () if (GET_CODE (pat) == PARALLEL) for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == UNSPEC - && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == 7) + && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == UNSPEC_TOCADR) return 1; } return 0; @@ -10845,7 +10848,7 @@ rs6000_emit_epilogue (sibcall) RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i)); RTVEC_ELT (p, ndx) = gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i), - gen_rtx_UNSPEC (CCmode, r, 20)); + gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR)); ndx++; } emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); @@ -12416,137 +12419,293 @@ rs6000_elf_select_rtx_section (mode, x, default_elf_select_rtx_section (mode, x, align); } -/* A C statement or statements to switch to the appropriate - section for output of DECL. DECL is either a `VAR_DECL' node - or a constant of some sort. RELOC indicates whether forming - the initial value of DECL requires link-time relocations. */ -static void -rs6000_elf_select_section (decl, reloc, align) +static bool +rs6000_in_small_data_p (decl) tree decl; - int reloc; - unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED; { - int size = int_size_in_bytes (TREE_TYPE (decl)); - bool needs_sdata; - bool readonly; - static void (* const sec_funcs[4]) PARAMS ((void)) = { - &readonly_data_section, - &sdata2_section, - &data_section, - &sdata_section - }; + /* We want to merge strings, so we never consider them small data. */ + if (TREE_CODE (decl) == STRING_CST) + return false; - needs_sdata = (size > 0 - && size <= g_switch_value - && rs6000_sdata != SDATA_NONE - && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl))); + if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl)) + { + const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); + if (strcmp (section, ".sdata") == 0 + || strcmp (section, ".sdata2") == 0 + || strcmp (section, ".sbss") == 0) + return true; + } + else + { + int size = int_size_in_bytes (TREE_TYPE (decl)); + return (size > 0 + && size <= g_switch_value + && rs6000_sdata != SDATA_NONE + && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl))); + } +} - if (TREE_CODE (decl) == STRING_CST) - readonly = !flag_writable_strings; +/* A helper function for default_elf_select_section and + default_elf_unique_section. Categorizes the DECL. */ + +enum rs6000_section_category +{ + SECCAT_TEXT, + + SECCAT_RODATA, + SECCAT_RODATA_MERGE_STR, + SECCAT_RODATA_MERGE_STR_INIT, + SECCAT_RODATA_MERGE_CONST, + + SECCAT_DATA, + + /* To optimize loading of shared programs, define following subsections + of data section: + _REL Contains data that has relocations, so they get grouped + together and dynamic linker will visit fewer pages in memory. + _RO Contains data that is otherwise read-only. This is useful + with prelinking as most relocations won't be dynamically + linked and thus stay read only. + _LOCAL Marks data containing relocations only to local objects. + These relocations will get fully resolved by prelinking. */ + SECCAT_DATA_REL, + SECCAT_DATA_REL_LOCAL, + SECCAT_DATA_REL_RO, + SECCAT_DATA_REL_RO_LOCAL, + + SECCAT_SDATA, + SECCAT_SDATA2, + SECCAT_TDATA, + + SECCAT_BSS, + SECCAT_SBSS, + SECCAT_TBSS +}; + +static enum rs6000_section_category rs6000_categorize_decl_for_section PARAMS ((tree, int, int)); + +static enum rs6000_section_category +rs6000_categorize_decl_for_section (decl, reloc, pic) + tree decl; + int reloc; + int pic; +{ + enum rs6000_section_category ret; + + if (TREE_CODE (decl) == FUNCTION_DECL) + return SECCAT_TEXT; + else if (TREE_CODE (decl) == STRING_CST) + { + if (flag_writable_strings) + return SECCAT_DATA; + else + return SECCAT_RODATA_MERGE_STR; + } else if (TREE_CODE (decl) == VAR_DECL) - readonly = (!((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc) - && TREE_READONLY (decl) - && !TREE_SIDE_EFFECTS (decl) - && DECL_INITIAL (decl) - && DECL_INITIAL (decl) != error_mark_node - && TREE_CONSTANT (DECL_INITIAL (decl))); + { + if (DECL_INITIAL (decl) == NULL + || DECL_INITIAL (decl) == error_mark_node) + ret = SECCAT_BSS; + else if (! TREE_READONLY (decl) + || TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (DECL_INITIAL (decl))) + { + if (pic && (reloc & 2)) + ret = SECCAT_DATA_REL; + else if (pic && reloc) + ret = SECCAT_DATA_REL_LOCAL; + else + ret = SECCAT_DATA; + } + else if (pic && (reloc & 2)) + ret = SECCAT_DATA_REL_RO; + else if (pic && reloc) + ret = SECCAT_DATA_REL_RO_LOCAL; + else if (flag_merge_constants < 2) + /* C and C++ don't allow different variables to share the same + location. -fmerge-all-constants allows even that (at the + expense of not conforming). */ + ret = SECCAT_RODATA; + else if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST) + ret = SECCAT_RODATA_MERGE_STR_INIT; + else + ret = SECCAT_RODATA_MERGE_CONST; + } else if (TREE_CODE (decl) == CONSTRUCTOR) - readonly = (!((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc) - && !TREE_SIDE_EFFECTS (decl) - && TREE_CONSTANT (decl)); + { + if ((pic && reloc) + || TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (decl)) + ret = SECCAT_DATA; + else + ret = SECCAT_RODATA; + } else - readonly = !((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc); + ret = SECCAT_RODATA; - if (needs_sdata && rs6000_sdata != SDATA_EABI) - readonly = false; - - (*sec_funcs[(readonly ? 0 : 2) + (needs_sdata ? 1 : 0)])(); + /* There are no read-only thread-local sections. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) + { + if (ret == SECCAT_BSS) + ret = SECCAT_TBSS; + else + ret = SECCAT_TDATA; + } + + /* If the target uses small data sections, select it. */ + else if ((*targetm.in_small_data_p) (decl)) + { + if (ret == SECCAT_BSS) + ret = SECCAT_SBSS; + else + ret = SECCAT_SDATA; + } + + /* With EABI we put small readonly data into .sdata2. */ + if (ret == SECCAT_RODATA && rs6000_sdata == SDATA_EABI + && (*targetm.in_small_data_p) (decl)) + ret = SECCAT_SDATA2; + + return ret; } -/* A C statement to build up a unique section name, expressed as a - STRING_CST node, and assign it to DECL_SECTION_NAME (decl). - RELOC indicates whether the initial value of EXP requires - link-time relocations. If you do not define this macro, GCC will use - the symbol name prefixed by `.' as the section name. Note - this - macro can now be called for uninitialized data items as well as - initialised data and functions. */ +/* Select a section based on the above categorization. */ -static void +void +rs6000_elf_select_section (decl, reloc, align) + tree decl; + int reloc; + unsigned HOST_WIDE_INT align; +{ + bool pic = flag_pic || DEFAULT_ABI == ABI_AIX; + + switch (rs6000_categorize_decl_for_section (decl, reloc, pic)) + { + case SECCAT_TEXT: + /* We're not supposed to be called on FUNCTION_DECLs. */ + abort (); + case SECCAT_RODATA: + readonly_data_section (); + break; + case SECCAT_RODATA_MERGE_STR: + mergeable_string_section (decl, align, 0); + break; + case SECCAT_RODATA_MERGE_STR_INIT: + mergeable_string_section (DECL_INITIAL (decl), align, 0); + break; + case SECCAT_RODATA_MERGE_CONST: + mergeable_constant_section (DECL_MODE (decl), align, 0); + break; + case SECCAT_DATA: + data_section (); + break; + case SECCAT_DATA_REL: + named_section (NULL_TREE, ".data.rel", reloc); + break; + case SECCAT_DATA_REL_LOCAL: + named_section (NULL_TREE, ".data.rel.local", reloc); + break; + case SECCAT_DATA_REL_RO: + named_section (NULL_TREE, ".data.rel.ro", reloc); + break; + case SECCAT_DATA_REL_RO_LOCAL: + named_section (NULL_TREE, ".data.rel.ro.local", reloc); + break; + case SECCAT_SDATA: + named_section (NULL_TREE, ".sdata", reloc); + break; + case SECCAT_SDATA2: + named_section (NULL_TREE, ".sdata2", reloc); + break; + case SECCAT_TDATA: + named_section (NULL_TREE, ".tdata", reloc); + break; + case SECCAT_BSS: +#ifdef BSS_SECTION_ASM_OP + bss_section (); +#else + named_section (NULL_TREE, ".bss", reloc); +#endif + break; + case SECCAT_SBSS: + named_section (NULL_TREE, ".sbss", reloc); + break; + case SECCAT_TBSS: + named_section (NULL_TREE, ".tbss", reloc); + break; + default: + abort (); + } +} + +/* Construct a unique section name based on the decl name and the + categorization performed above. */ + +void rs6000_elf_unique_section (decl, reloc) tree decl; int reloc; { - int len; - int sec; - const char *name; + bool one_only = DECL_ONE_ONLY (decl); + bool pic = flag_pic || DEFAULT_ABI == ABI_AIX; + const char *prefix, *name; + size_t nlen, plen; char *string; - const char *prefix; - static const char *const prefixes[7][2] = - { - { ".rodata.", ".gnu.linkonce.r." }, - { ".sdata2.", ".gnu.linkonce.s2." }, - { ".data.", ".gnu.linkonce.d." }, - { ".sdata.", ".gnu.linkonce.s." }, - { ".bss.", ".gnu.linkonce.b." }, - { ".sbss.", ".gnu.linkonce.sb." }, - { ".text.", ".gnu.linkonce.t." } - }; - - if (TREE_CODE (decl) == FUNCTION_DECL) - sec = 6; - else + switch (rs6000_categorize_decl_for_section (decl, reloc, pic)) { - bool readonly; - bool needs_sdata; - int size; - - if (TREE_CODE (decl) == STRING_CST) - readonly = !flag_writable_strings; - else if (TREE_CODE (decl) == VAR_DECL) - readonly = (!((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc) - && TREE_READONLY (decl) - && !TREE_SIDE_EFFECTS (decl) - && TREE_CONSTANT (DECL_INITIAL (decl))); - else - readonly = !((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc); - - size = int_size_in_bytes (TREE_TYPE (decl)); - needs_sdata = (size > 0 - && size <= g_switch_value - && rs6000_sdata != SDATA_NONE - && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl))); - - if (DECL_INITIAL (decl) == NULL - || DECL_INITIAL (decl) == error_mark_node) - sec = 4; - else if (!readonly) - sec = 2; - else - sec = 0; - - if (needs_sdata) - { - /* .sdata2 is only for EABI. */ - if (sec == 0 && rs6000_sdata != SDATA_EABI) - sec = 2; - sec += 1; - } + case SECCAT_TEXT: + prefix = one_only ? ".gnu.linkonce.t." : ".text."; + break; + case SECCAT_RODATA: + case SECCAT_RODATA_MERGE_STR: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_CONST: + prefix = one_only ? ".gnu.linkonce.r." : ".rodata."; + break; + case SECCAT_DATA: + case SECCAT_DATA_REL: + case SECCAT_DATA_REL_LOCAL: + case SECCAT_DATA_REL_RO: + case SECCAT_DATA_REL_RO_LOCAL: + prefix = one_only ? ".gnu.linkonce.d." : ".data."; + break; + case SECCAT_SDATA: + prefix = one_only ? ".gnu.linkonce.s." : ".sdata."; + break; + case SECCAT_SDATA2: + prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2."; + break; + case SECCAT_BSS: + prefix = one_only ? ".gnu.linkonce.b." : ".bss."; + break; + case SECCAT_SBSS: + prefix = one_only ? ".gnu.linkonce.sb." : ".sbss."; + break; + case SECCAT_TDATA: + prefix = one_only ? ".gnu.linkonce.td." : ".tdata."; + break; + case SECCAT_TBSS: + prefix = one_only ? ".gnu.linkonce.tb." : ".tbss."; + break; + default: + abort (); } + plen = strlen (prefix); name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - name = (*targetm.strip_name_encoding) (name); - prefix = prefixes[sec][DECL_ONE_ONLY (decl)]; - len = strlen (name) + strlen (prefix); - string = alloca (len + 1); - - sprintf (string, "%s%s", prefix, name); - - DECL_SECTION_NAME (decl) = build_string (len, string); + name = (* targetm.strip_name_encoding) (name); + nlen = strlen (name); + + string = alloca (nlen + plen + 1); + memcpy (string, prefix, plen); + memcpy (string + plen, name, nlen + 1); + + DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); } - + /* If we are referencing a function that is static or is known to be in this file, make the SYMBOL_REF special. We can use this to indicate that we can branch to this function without emitting a no-op after the