aboutsummaryrefslogtreecommitdiff
path: root/gcc/varasm.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard@codesourcery.com>2006-02-18 22:06:53 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2006-02-18 22:06:53 +0000
commitaacd3885eb07280eed4558f0dacad4d977052dc2 (patch)
treeb8f39049c93e479153dfa0a8aa3f5539993a4a56 /gcc/varasm.c
parentdcf966bd82b34172175ca8ff4aa39f91729a9dbb (diff)
downloadgcc-aacd3885eb07280eed4558f0dacad4d977052dc2.zip
gcc-aacd3885eb07280eed4558f0dacad4d977052dc2.tar.gz
gcc-aacd3885eb07280eed4558f0dacad4d977052dc2.tar.bz2
re PR target/9703 ([arm] Accessing data through constant pool more times could be solved in less instructions)
* cselib.c (cselib_init): Change RTX_SIZE to RTX_CODE_SIZE. * emit-rtl.c (copy_rtx_if_shared_1): Use shallow_copy_rtx. (copy_insn_1): Likewise. Don't copy each field individually. Reindent. * read-rtl.c (apply_macro_to_rtx): Use RTX_CODE_SIZE instead of RTX_SIZE. * reload1.c (eliminate_regs): Use shallow_copy_rtx. * rtl.c (rtx_size): Rename variable to... (rtx_code_size): ...this. (rtx_size): New function. (rtx_alloc_stat): Use RTX_CODE_SIZE instead of RTX_SIZE. (copy_rtx): Use shallow_copy_rtx. Don't copy each field individually. Reindent. (shallow_copy_rtx_stat): Use rtx_size instead of RTX_SIZE. * rtl.h (rtx_code_size): New variable. (rtx_size): Change from a variable to a function. (RTX_SIZE): Rename to... (RTX_CODE_SIZE): ...this. PR target/9703 PR tree-optimization/17106 * doc/tm.texi (TARGET_USE_BLOCKS_FOR_CONSTANT_P): Document. (Anchored Addresses): New section. * doc/invoke.texi (-fsection-anchors): Document. * doc/rtl.texi (SYMBOL_REF_IN_BLOCK_P, SYMBOL_FLAG_IN_BLOCK): Likewise. (SYMBOL_REF_ANCHOR_P, SYMBOL_FLAG_ANCHOR): Likewise. (SYMBOL_REF_BLOCK, SYMBOL_REF_BLOCK_OFFSET): Likewise. * hooks.c (hook_bool_mode_rtx_false): New function. * hooks.h (hook_bool_mode_rtx_false): Declare. * gengtype.c (create_optional_field): New function. (adjust_field_rtx_def): Add the "block_sym" field for SYMBOL_REFs when SYMBOL_REF_IN_BLOCK_P is true. * target.h (output_anchor, use_blocks_for_constant_p): New hooks. (min_anchor_offset, max_anchor_offset): Likewise. (use_anchors_for_symbol_p): New hook. * toplev.c (compile_file): Call output_object_blocks. (target_supports_section_anchors_p): New function. (process_options): Check that -fsection-anchors is only used on targets that support it and when -funit-at-a-time is in effect. * tree-ssa-loop-ivopts.c (prepare_decl_rtl): Only create DECL_RTL if the decl doesn't have one. * dwarf2out.c: Remove instantiations of VEC(rtx,gc). * expr.c (emit_move_multi_word, emit_move_insn): Pass the result of force_const_mem through use_anchored_address. (expand_expr_constant): New function. (expand_expr_addr_expr_1): Call it. Use the same modifier when calling expand_expr for INDIRECT_REF. (expand_expr_real_1): Pass DECL_RTL through use_anchored_address for all modifiers except EXPAND_INITIALIZER. Use expand_expr_constant. * expr.h (use_anchored_address): Declare. * loop-unroll.c: Don't declare rtx vectors here. * explow.c: Include output.h. (validize_mem): Call use_anchored_address. (use_anchored_address): New function. * common.opt (-fsection-anchors): New switch. * varasm.c (object_block_htab, anchor_labelno): New variables. (hash_section, object_block_entry_eq, object_block_entry_hash) (use_object_blocks_p, get_block_for_section, create_block_symbol) (use_blocks_for_decl_p, change_symbol_section): New functions. (get_variable_section): New function, split out from assemble_variable. (make_decl_rtl): Create a block symbol if use_object_blocks_p and use_blocks_for_decl_p say so. Use change_symbol_section if the symbol has already been created. (assemble_variable_contents): New function, split out from... (assemble_variable): ...here. Don't output any code for block symbols; just pass them to place_block_symbol. Use get_variable_section and assemble_variable_contents. (get_constant_alignment, get_constant_section, get_constant_size): New functions, split from output_constant_def_contents. (build_constant_desc): Create a block symbol if use_object_blocks_p says so. Or into SYMBOL_REF_FLAGS. (assemble_constant_contents): New function, split from... (output_constant_def_contents): ...here. Don't output any code for block symbols; just pass them to place_section_symbol. Use get_constant_section and get_constant_alignment. (force_const_mem): Create a block symbol if use_object_blocks_p and use_blocks_for_constant_p say so. Or into SYMBOL_REF_FLAGS. (output_constant_pool_1): Add an explicit alignment argument. Don't switch sections here. (output_constant_pool): Adjust call to output_constant_pool_1. Switch sections here instead. Don't output anything for block symbols; just pass them to place_block_symbol. (init_varasm_once): Initialize object_block_htab. (default_encode_section_info): Keep the old SYMBOL_FLAG_IN_BLOCK. (default_asm_output_anchor, default_use_aenchors_for_symbol_p) (place_block_symbol, get_section_anchor, output_object_block) (output_object_block_htab, output_object_blocks): New functions. * target-def.h (TARGET_ASM_OUTPUT_ANCHOR): New macro. (TARGET_ASM_OUT): Include it. (TARGET_USE_BLOCKS_FOR_CONSTANT_P): New macro. (TARGET_MIN_ANCHOR_OFFSET, TARGET_MAX_ANCHOR_OFFSET): New macros. (TARGET_USE_ANCHORS_FOR_SYMBOL_P): New macro. (TARGET_INITIALIZER): Include them. * rtl.c (rtl_check_failed_block_symbol): New function. * rtl.h: Include vec.h. Declare heap and gc rtx vectors. (block_symbol, object_block): New structures. (rtx_def): Add a block_symbol field to the union. (BLOCK_SYMBOL_CHECK): New macro. (rtl_check_failed_block_symbol): Declare. (SYMBOL_FLAG_IN_BLOCK, SYMBOL_FLAG_ANCHOR): New SYMBOL_REF flags. (SYMBOL_REF_IN_BLOCK_P, SYMBOL_REF_ANCHOR_P): New predicates. (SYMBOL_FLAG_MACH_DEP_SHIFT): Bump by 2. (SYMBOL_REF_BLOCK, SYMBOL_REF_BLOCK_OFFSET): New accessors. * output.h (output_section_symbols): Declare. (object_block): Name structure. (place_section_symbol, get_section_anchor, default_asm_output_anchor) (default_use_anchors_for_symbol_p): Declare. * Makefile.in (RTL_BASE_H): Add vec.h. (explow.o): Depend on output.h. * config/rs6000/rs6000.c (TARGET_MIN_ANCHOR_OFFSET): Override default. (TARGET_MAX_ANCHOR_OFFSET): Likewise. (TARGET_USE_BLOCKS_FOR_CONSTANT_P): Likewise. (rs6000_use_blocks_for_constant_p): New function. From-SVN: r111254
Diffstat (limited to 'gcc/varasm.c')
-rw-r--r--gcc/varasm.c709
1 files changed, 619 insertions, 90 deletions
diff --git a/gcc/varasm.c b/gcc/varasm.c
index bddf1ad..9801b1f 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -184,6 +184,12 @@ static GTY(()) section *unnamed_sections;
/* Hash table of named sections. */
static GTY((param_is (section))) htab_t section_htab;
+/* A table of object_blocks, indexed by section. */
+static GTY((param_is (struct object_block))) htab_t object_block_htab;
+
+/* The next number to use for internal anchor labels. */
+static GTY(()) int anchor_labelno;
+
/* Helper routines for maintaining section_htab. */
static int
@@ -202,6 +208,34 @@ section_entry_hash (const void *p)
return htab_hash_string (old->named.name);
}
+/* Return a hash value for section SECT. */
+
+static hashval_t
+hash_section (section *sect)
+{
+ if (sect->common.flags & SECTION_NAMED)
+ return htab_hash_string (sect->named.name);
+ return sect->common.flags;
+}
+
+/* Helper routines for maintaining object_block_htab. */
+
+static int
+object_block_entry_eq (const void *p1, const void *p2)
+{
+ const struct object_block *old = p1;
+ const section *new = p2;
+
+ return old->sect == new;
+}
+
+static hashval_t
+object_block_entry_hash (const void *p)
+{
+ const struct object_block *old = p;
+ return hash_section (old->sect);
+}
+
/* Return a new unnamed section with the given fields. */
section *
@@ -256,6 +290,66 @@ get_section (const char *name, unsigned int flags, tree decl)
return sect;
}
+/* Return true if the current compilation mode benefits from having
+ objects grouped into blocks. */
+
+static bool
+use_object_blocks_p (void)
+{
+ return flag_section_anchors;
+}
+
+/* Return the object_block structure for section SECT. Create a new
+ structure if we haven't created one already. */
+
+static struct object_block *
+get_block_for_section (section *sect)
+{
+ struct object_block *block;
+ void **slot;
+
+ slot = htab_find_slot_with_hash (object_block_htab, sect,
+ hash_section (sect), INSERT);
+ block = (struct object_block *) *slot;
+ if (block == NULL)
+ {
+ block = (struct object_block *)
+ ggc_alloc_cleared (sizeof (struct object_block));
+ block->sect = sect;
+ *slot = block;
+ }
+ return block;
+}
+
+/* Create a symbol with label LABEL and place it at byte offset
+ OFFSET in BLOCK. OFFSET can be negative if the symbol's offset
+ is not yet known. LABEL must be a garbage-collected string. */
+
+static rtx
+create_block_symbol (const char *label, struct object_block *block,
+ HOST_WIDE_INT offset)
+{
+ rtx symbol;
+ unsigned int size;
+
+ /* Create the extended SYMBOL_REF. */
+ size = RTX_HDR_SIZE + sizeof (struct block_symbol);
+ symbol = ggc_alloc_zone (size, &rtl_zone);
+
+ /* Initialize the normal SYMBOL_REF fields. */
+ memset (symbol, 0, size);
+ PUT_CODE (symbol, SYMBOL_REF);
+ PUT_MODE (symbol, Pmode);
+ XSTR (symbol, 0) = label;
+ SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_IN_BLOCK;
+
+ /* Initialize the block_symbol stuff. */
+ SYMBOL_REF_BLOCK (symbol) = block;
+ SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+ return symbol;
+}
+
static void
initialize_cold_section_name (void)
{
@@ -705,6 +799,83 @@ decode_reg_name (const char *asmspec)
return -1;
}
+/* Return true if it is possible to put DECL in an object_block. */
+
+static bool
+use_blocks_for_decl_p (tree decl)
+{
+ /* Only data DECLs can be placed into object blocks. */
+ if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
+ return false;
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ /* The object must be defined in this translation unit. */
+ if (DECL_EXTERNAL (decl))
+ return false;
+
+ /* There's no point using object blocks for something that is
+ isolated by definition. */
+ if (DECL_ONE_ONLY (decl))
+ return false;
+
+ /* Symbols that use .common cannot be put into blocks. */
+ if (DECL_COMMON (decl) && DECL_INITIAL (decl) == NULL)
+ return false;
+ }
+
+ /* We can only calculate block offsets if the decl has a known
+ constant size. */
+ if (DECL_SIZE_UNIT (decl) == NULL)
+ return false;
+ if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+ return false;
+
+ /* Detect decls created by dw2_force_const_mem. Such decls are
+ special because DECL_INITIAL doesn't specify the decl's true value.
+ dw2_output_indirect_constants will instead call assemble_variable
+ with dont_output_data set to 1 and then print the contents itself. */
+ if (DECL_INITIAL (decl) == decl)
+ return false;
+
+ return true;
+}
+
+/* Make sure block symbol SYMBOL is in section SECT, moving it to a
+ different block if necessary. */
+
+static void
+change_symbol_section (rtx symbol, section *sect)
+{
+ if (sect != SYMBOL_REF_BLOCK (symbol)->sect)
+ {
+ gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
+ SYMBOL_REF_BLOCK (symbol) = get_block_for_section (sect);
+ }
+}
+
+/* Return the section into which the given VAR_DECL or CONST_DECL
+ should be placed. */
+
+static section *
+get_variable_section (tree decl)
+{
+ int reloc;
+
+ if (DECL_INITIAL (decl) == error_mark_node)
+ reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+ else if (DECL_INITIAL (decl))
+ reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+ else
+ reloc = 0;
+
+ resolve_unique_section (decl, reloc, flag_data_sections);
+ if (IN_NAMED_SECTION (decl))
+ return get_named_section (decl, NULL, reloc);
+ else
+ return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+}
+
/* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL. DECL should
have static storage duration. In other words, it should not be an
automatic variable, including PARM_DECLs.
@@ -741,9 +912,9 @@ make_decl_rtl (tree decl)
if (DECL_RTL_SET_P (decl))
{
/* If the old RTL had the wrong mode, fix the mode. */
- if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
- SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
- DECL_MODE (decl), 0));
+ x = DECL_RTL (decl);
+ if (GET_MODE (x) != DECL_MODE (decl))
+ SET_DECL_RTL (decl, adjust_address_nv (x, DECL_MODE (decl), 0));
if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
return;
@@ -758,6 +929,13 @@ make_decl_rtl (tree decl)
decl attribute overrides another. */
targetm.encode_section_info (decl, DECL_RTL (decl), false);
+ /* If the old address was assigned to an object block, see whether
+ that block is still in the right section. */
+ if (MEM_P (x)
+ && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && SYMBOL_REF_IN_BLOCK_P (XEXP (x, 0)))
+ change_symbol_section (XEXP (x, 0), get_variable_section (decl));
+
/* Make this function static known to the mudflap runtime. */
if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
mudflap_enqueue_decl (decl);
@@ -854,7 +1032,13 @@ make_decl_rtl (tree decl)
if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
DECL_COMMON (decl) = 0;
- x = gen_rtx_SYMBOL_REF (Pmode, name);
+ if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
+ {
+ section *sect = get_variable_section (decl);
+ x = create_block_symbol (name, get_block_for_section (sect), -1);
+ }
+ else
+ x = gen_rtx_SYMBOL_REF (Pmode, name);
SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
SET_SYMBOL_REF_DECL (x, decl);
@@ -1407,6 +1591,38 @@ asm_emit_uninitialised (tree decl, const char *name,
return true;
}
+/* A subroutine of assemble_variable. Output the label and contents of
+ DECL, whose address is a SYMBOL_REF with name NAME. DONT_OUTPUT_DATA
+ is as for assemble_variable. */
+
+static void
+assemble_variable_contents (tree decl, const char *name,
+ bool dont_output_data)
+{
+ /* Do any machine/system dependent processing of the object. */
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (asm_out_file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+
+ if (!dont_output_data)
+ {
+ if (DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node
+ && !initializer_zerop (DECL_INITIAL (decl)))
+ /* Output the actual data. */
+ output_constant (DECL_INITIAL (decl),
+ tree_low_cst (DECL_SIZE_UNIT (decl), 1),
+ DECL_ALIGN (decl));
+ else
+ /* Leave space for it. */
+ assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+ }
+}
+
/* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions.
Should not be called for variables of incomplete structure type.
@@ -1423,8 +1639,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
{
const char *name;
unsigned int align;
- int reloc = 0;
rtx decl_rtl;
+ bool in_block_p;
if (lang_hooks.decls.prepare_assemble_variable)
lang_hooks.decls.prepare_assemble_variable (decl);
@@ -1494,6 +1710,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
return;
}
+ gcc_assert (MEM_P (decl_rtl));
+ gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
+ in_block_p = SYMBOL_REF_IN_BLOCK_P (XEXP (decl_rtl, 0));
name = XSTR (XEXP (decl_rtl, 0), 0);
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
notice_global_symbol (decl);
@@ -1563,6 +1782,10 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
#endif
}
}
+ /* Do not handle decls as common if they will be assigned a
+ specific section position. */
+ else if (in_block_p)
+ ;
else if (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node
|| (flag_zero_initialized_in_bss
@@ -1605,47 +1828,27 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
globalize_decl (decl);
/* Output any data that we will need to use the address of. */
- if (DECL_INITIAL (decl) == error_mark_node)
- reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
- else if (DECL_INITIAL (decl))
- {
- reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
- output_addressed_constants (DECL_INITIAL (decl));
- }
-
- /* Switch to the appropriate section. */
- resolve_unique_section (decl, reloc, flag_data_sections);
- variable_section (decl, reloc);
+ if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+ output_addressed_constants (DECL_INITIAL (decl));
/* dbxout.c needs to know this. */
if (in_section && (in_section->common.flags & SECTION_CODE) != 0)
DECL_IN_TEXT_SECTION (decl) = 1;
- /* Output the alignment of this data. */
- if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
-
- /* Do any machine/system dependent processing of the object. */
-#ifdef ASM_DECLARE_OBJECT_NAME
- last_assemble_variable_decl = decl;
- ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
-#else
- /* Standard thing is just output label for the object. */
- ASM_OUTPUT_LABEL (asm_out_file, name);
-#endif /* ASM_DECLARE_OBJECT_NAME */
-
- if (!dont_output_data)
+ /* If the decl is part of an object_block, make sure that the decl
+ has been positioned within its block, but do not write out its
+ definition yet. output_object_blocks will do that later. */
+ if (in_block_p)
{
- if (DECL_INITIAL (decl)
- && DECL_INITIAL (decl) != error_mark_node
- && !initializer_zerop (DECL_INITIAL (decl)))
- /* Output the actual data. */
- output_constant (DECL_INITIAL (decl),
- tree_low_cst (DECL_SIZE_UNIT (decl), 1),
- align);
- else
- /* Leave space for it. */
- assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+ gcc_assert (!dont_output_data);
+ place_block_symbol (XEXP (decl_rtl, 0));
+ }
+ else
+ {
+ switch_to_section (get_variable_section (decl));
+ if (align > BITS_PER_UNIT)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
+ assemble_variable_contents (decl, name, dont_output_data);
}
}
@@ -2554,6 +2757,46 @@ copy_constant (tree exp)
}
}
+/* Return the alignment of constant EXP in bits. */
+
+static unsigned int
+get_constant_alignment (tree exp)
+{
+ unsigned int align;
+
+ align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+ align = CONSTANT_ALIGNMENT (exp, align);
+#endif
+ return align;
+}
+
+/* Return the section into which constant EXP should be placed. */
+
+static section *
+get_constant_section (tree exp)
+{
+ if (IN_NAMED_SECTION (exp))
+ return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
+ else
+ return targetm.asm_out.select_section (exp,
+ compute_reloc_for_constant (exp),
+ get_constant_alignment (exp));
+}
+
+/* Return the size of constant EXP in bytes. */
+
+static HOST_WIDE_INT
+get_constant_size (tree exp)
+{
+ HOST_WIDE_INT size;
+
+ size = int_size_in_bytes (TREE_TYPE (exp));
+ if (TREE_CODE (exp) == STRING_CST)
+ size = MAX (TREE_STRING_LENGTH (exp), size);
+ return size;
+}
+
/* Subroutine of output_constant_def:
No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
@@ -2582,8 +2825,15 @@ build_constant_desc (tree exp)
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
- symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
- SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+ if (use_object_blocks_p ())
+ {
+ section *sect = get_constant_section (exp);
+ symbol = create_block_symbol (ggc_strdup (label),
+ get_block_for_section (sect), -1);
+ }
+ else
+ symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+ SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
SET_SYMBOL_REF_DECL (symbol, desc->value);
TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
@@ -2676,54 +2926,57 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
output_constant_def_contents (symbol);
}
+/* Subroutine of output_constant_def_contents. Output the definition
+ of constant EXP, which is pointed to by label LABEL. ALIGN is the
+ constant's alignment in bits. */
+
+static void
+assemble_constant_contents (tree exp, const char *label, unsigned int align)
+{
+ HOST_WIDE_INT size;
+
+ size = get_constant_size (exp);
+
+ /* Do any machine/system dependent processing of the constant. */
+#ifdef ASM_DECLARE_CONSTANT_NAME
+ ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
+#else
+ /* Standard thing is just output label for the constant. */
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+#endif /* ASM_DECLARE_CONSTANT_NAME */
+
+ /* Output the value of EXP. */
+ output_constant (exp, size, align);
+}
+
/* We must output the constant data referred to by SYMBOL; do so. */
static void
output_constant_def_contents (rtx symbol)
{
tree exp = SYMBOL_REF_DECL (symbol);
- const char *label = XSTR (symbol, 0);
- HOST_WIDE_INT size;
+ unsigned int align;
/* Make sure any other constants whose addresses appear in EXP
are assigned label numbers. */
- int reloc = compute_reloc_for_constant (exp);
-
- /* Align the location counter as required by EXP's data type. */
- unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
- align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-
output_addressed_constants (exp);
/* We are no longer deferring this constant. */
TREE_ASM_WRITTEN (exp) = 1;
- if (IN_NAMED_SECTION (exp))
- switch_to_section (get_named_section (exp, NULL, reloc));
+ /* If the constant is part of an object block, make sure that the
+ decl has been positioned within its block, but do not write out
+ its definition yet. output_object_blocks will do that later. */
+ if (SYMBOL_REF_IN_BLOCK_P (symbol))
+ place_block_symbol (symbol);
else
- switch_to_section (targetm.asm_out.select_section (exp, reloc, align));
-
- if (align > BITS_PER_UNIT)
{
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ switch_to_section (get_constant_section (exp));
+ align = get_constant_alignment (exp);
+ if (align > BITS_PER_UNIT)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ assemble_constant_contents (exp, XSTR (symbol, 0), align);
}
-
- size = int_size_in_bytes (TREE_TYPE (exp));
- if (TREE_CODE (exp) == STRING_CST)
- size = MAX (TREE_STRING_LENGTH (exp), size);
-
- /* Do any machine/system dependent processing of the constant. */
-#ifdef ASM_DECLARE_CONSTANT_NAME
- ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
-#else
- /* Standard thing is just output label for the constant. */
- ASM_OUTPUT_LABEL (asm_out_file, label);
-#endif /* ASM_DECLARE_CONSTANT_NAME */
-
- /* Output the value of EXP. */
- output_constant (exp, size, align);
if (flag_mudflap)
mudflap_enqueue_constant (exp);
}
@@ -2987,8 +3240,16 @@ force_const_mem (enum machine_mode mode, rtx x)
/* Construct the SYMBOL_REF. Make sure to mark it as belonging to
the constants pool. */
- desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
- SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+ if (use_object_blocks_p () && targetm.use_blocks_for_constant_p (mode, x))
+ {
+ section *sect = targetm.asm_out.select_rtx_section (mode, x, align);
+ symbol = create_block_symbol (ggc_strdup (label),
+ get_block_for_section (sect), -1);
+ }
+ else
+ symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+ desc->sym = symbol;
+ SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
CONSTANT_POOL_ADDRESS_P (symbol) = 1;
SET_SYMBOL_REF_CONSTANT (symbol, desc);
current_function_uses_const_pool = 1;
@@ -3090,15 +3351,15 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
}
}
-/* Worker function for output_constant_pool. Emit POOL. */
+/* Worker function for output_constant_pool. Emit constant DESC,
+ giving it ALIGN bits of alignment. */
static void
-output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+output_constant_pool_1 (struct constant_descriptor_rtx *desc,
+ unsigned int align)
{
rtx x, tmp;
- if (!desc->mark)
- return;
x = desc->constant;
/* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
@@ -3131,29 +3392,25 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
break;
}
- /* First switch to correct section. */
- switch_to_section (targetm.asm_out.select_rtx_section (desc->mode, x,
- desc->align));
-
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
- desc->align, desc->labelno, done);
+ align, desc->labelno, done);
#endif
- assemble_align (desc->align);
+ assemble_align (align);
/* Output the label. */
targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
/* Output the data. */
- output_constant_pool_2 (desc->mode, x, desc->align);
+ output_constant_pool_2 (desc->mode, x, align);
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
sections have proper size. */
- if (desc->align > GET_MODE_BITSIZE (desc->mode)
+ if (align > GET_MODE_BITSIZE (desc->mode)
&& in_section
&& (in_section->common.flags & SECTION_MERGE))
- assemble_align (desc->align);
+ assemble_align (align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done:
@@ -3265,7 +3522,21 @@ output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
#endif
for (desc = pool->first; desc ; desc = desc->next)
- output_constant_pool_1 (desc);
+ if (desc->mark)
+ {
+ /* If the constant is part of an object_block, make sure that
+ the constant has been positioned within its block, but do not
+ write out its definition yet. output_object_blocks will do
+ that later. */
+ if (SYMBOL_REF_IN_BLOCK_P (desc->sym))
+ place_block_symbol (desc->sym);
+ else
+ {
+ switch_to_section (targetm.asm_out.select_rtx_section
+ (desc->mode, desc->constant, desc->align));
+ output_constant_pool_1 (desc, desc->align);
+ }
+ }
#ifdef ASM_OUTPUT_POOL_EPILOGUE
ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
@@ -4805,6 +5076,8 @@ init_varasm_once (void)
{
section_htab = htab_create_ggc (31, section_entry_hash,
section_entry_eq, NULL);
+ object_block_htab = htab_create_ggc (31, object_block_entry_hash,
+ object_block_entry_eq, NULL);
const_desc_htab = htab_create_ggc (1009, const_desc_hash,
const_desc_eq, NULL);
@@ -5413,7 +5686,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
if (GET_CODE (symbol) != SYMBOL_REF)
return;
- flags = 0;
+ flags = SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_IN_BLOCK;
if (TREE_CODE (decl) == FUNCTION_DECL)
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
@@ -5440,6 +5713,59 @@ default_strip_name_encoding (const char *str)
return str + (*str == '*');
}
+#ifdef ASM_OUTPUT_DEF
+/* The default implementation of TARGET_ASM_OUTPUT_ANCHOR. Define the
+ anchor relative to ".", the current section position. */
+
+void
+default_asm_output_anchor (rtx symbol)
+{
+ char buffer[100];
+
+ sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC,
+ SYMBOL_REF_BLOCK_OFFSET (symbol));
+ ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
+}
+#endif
+
+/* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P. */
+
+bool
+default_use_anchors_for_symbol_p (rtx symbol)
+{
+ section *sect;
+ tree decl;
+
+ /* Don't use anchors for mergeable sections. The linker might move
+ the objects around. */
+ sect = SYMBOL_REF_BLOCK (symbol)->sect;
+ if (sect->common.flags & SECTION_MERGE)
+ return false;
+
+ /* Don't use anchors for small data sections. The small data register
+ acts as an anchor for such sections. */
+ if (sect->common.flags & SECTION_SMALL)
+ return false;
+
+ decl = SYMBOL_REF_DECL (symbol);
+ if (decl && DECL_P (decl))
+ {
+ /* Don't use section anchors for decls that might be defined by
+ other modules. */
+ if (!targetm.binds_local_p (decl))
+ return false;
+
+ /* Don't use section anchors for decls that will be placed in a
+ small data section. */
+ /* ??? Ideally, this check would be redundant with the SECTION_SMALL
+ one above. The problem is that we only use SECTION_SMALL for
+ sections that should be marked as small in the section directive. */
+ if (targetm.in_small_data_p (decl))
+ return false;
+ }
+ return true;
+}
+
/* Assume ELF-ish defaults, since that's pretty much the most liberal
wrt cross-module name binding. */
@@ -5620,4 +5946,207 @@ switch_to_section (section *new_section)
new_section->common.flags |= SECTION_DECLARED;
}
+/* If block symbol SYMBOL has not yet been assigned an offset, place
+ it at the end of its block. */
+
+void
+place_block_symbol (rtx symbol)
+{
+ unsigned HOST_WIDE_INT size, mask, offset;
+ struct constant_descriptor_rtx *desc;
+ unsigned int alignment;
+ struct object_block *block;
+ tree decl;
+
+ if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
+ return;
+
+ /* Work out the symbol's size and alignment. */
+ if (CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ desc = SYMBOL_REF_CONSTANT (symbol);
+ alignment = desc->align;
+ size = GET_MODE_SIZE (desc->mode);
+ }
+ else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ alignment = get_constant_alignment (decl);
+ size = get_constant_size (decl);
+ }
+ else
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ alignment = DECL_ALIGN (decl);
+ size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ }
+
+ /* Calculate the object's offset from the start of the block. */
+ block = SYMBOL_REF_BLOCK (symbol);
+ mask = alignment / BITS_PER_UNIT - 1;
+ offset = (block->size + mask) & ~mask;
+ SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+ /* Record the block's new alignment and size. */
+ block->alignment = MAX (block->alignment, alignment);
+ block->size = offset + size;
+
+ VEC_safe_push (rtx, gc, block->objects, symbol);
+}
+
+/* Return the anchor that should be used to address byte offset OFFSET
+ from the first object in BLOCK. MODEL is the TLS model used
+ to access it. */
+
+rtx
+get_section_anchor (struct object_block *block, HOST_WIDE_INT offset,
+ enum tls_model model)
+{
+ char label[100];
+ unsigned int begin, middle, end;
+ unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
+ rtx anchor;
+
+ /* Work out the anchor's offset. Use an offset of 0 for the first
+ anchor so that we don't pessimize the case where we take the address
+ of a variable at the beginning of the block. This is particularly
+ useful when a block has only one variable assigned to it.
+
+ We try to place anchors RANGE bytes apart, so there can then be
+ anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
+ a ptr_mode offset. With some target settings, the lowest such
+ anchor might be out of range for the lowest ptr_mode offset;
+ likewise the highest anchor for the highest offset. Use anchors
+ at the extreme ends of the ptr_mode range in such cases.
+
+ All arithmetic uses unsigned integers in order to avoid
+ signed overflow. */
+ max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
+ min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
+ range = max_offset - min_offset + 1;
+ if (range == 0)
+ offset = 0;
+ else
+ {
+ bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
+ if (offset < 0)
+ {
+ delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
+ delta -= delta % range;
+ if (delta > bias)
+ delta = bias;
+ offset = (HOST_WIDE_INT) (-delta);
+ }
+ else
+ {
+ delta = (unsigned HOST_WIDE_INT) offset - min_offset;
+ delta -= delta % range;
+ if (delta > bias - 1)
+ delta = bias - 1;
+ offset = (HOST_WIDE_INT) delta;
+ }
+ }
+
+ /* Do a binary search to see if there's already an anchor we can use.
+ Set BEGIN to the new anchor's index if not. */
+ begin = 0;
+ end = VEC_length (rtx, block->anchors);
+ while (begin != end)
+ {
+ middle = (end + begin) / 2;
+ anchor = VEC_index (rtx, block->anchors, middle);
+ if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset)
+ end = middle;
+ else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset)
+ begin = middle + 1;
+ else if (SYMBOL_REF_TLS_MODEL (anchor) > model)
+ end = middle;
+ else if (SYMBOL_REF_TLS_MODEL (anchor) < model)
+ begin = middle + 1;
+ else
+ return anchor;
+ }
+
+ /* Create a new anchor with a unique label. */
+ ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++);
+ anchor = create_block_symbol (ggc_strdup (label), block, offset);
+ SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR;
+ SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT;
+
+ /* Insert it at index BEGIN. */
+ VEC_safe_insert (rtx, gc, block->anchors, begin, anchor);
+ return anchor;
+}
+
+/* Output the objects in BLOCK. */
+
+static void
+output_object_block (struct object_block *block)
+{
+ struct constant_descriptor_rtx *desc;
+ unsigned int i;
+ HOST_WIDE_INT offset;
+ tree decl;
+ rtx symbol;
+
+ if (block->objects == NULL)
+ return;
+
+ /* Switch to the section and make sure that the first byte is
+ suitably aligned. */
+ switch_to_section (block->sect);
+ assemble_align (block->alignment);
+
+ /* Define the values of all anchors relative to the current section
+ position. */
+ for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
+ targetm.asm_out.output_anchor (symbol);
+
+ /* Output the objects themselves. */
+ offset = 0;
+ for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
+ {
+ /* Move to the object's offset, padding with zeros if necessary. */
+ assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
+ offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
+ if (CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ desc = SYMBOL_REF_CONSTANT (symbol);
+ output_constant_pool_1 (desc, 1);
+ offset += GET_MODE_SIZE (desc->mode);
+ }
+ else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ assemble_constant_contents (decl, XSTR (symbol, 0),
+ get_constant_alignment (decl));
+ offset += get_constant_size (decl);
+ }
+ else
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ assemble_variable_contents (decl, XSTR (symbol, 0), false);
+ offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ }
+ }
+}
+
+/* A htab_traverse callback used to call output_object_block for
+ each member of object_block_htab. */
+
+static int
+output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ output_object_block ((struct object_block *) (*slot));
+ return 1;
+}
+
+/* Output the definitions of all object_blocks. */
+
+void
+output_object_blocks (void)
+{
+ htab_traverse (object_block_htab, output_object_block_htab, NULL);
+}
+
#include "gt-varasm.h"