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
This commit is contained in:
Richard Sandiford 2006-02-18 22:06:53 +00:00 committed by Richard Sandiford
parent dcf966bd82
commit aacd3885eb
27 changed files with 1298 additions and 226 deletions

View File

@ -1,3 +1,119 @@
2005-02-18 Richard Sandiford <richard@codesourcery.com>
* 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.
2006-02-18 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* doc/install.texi (hppa*-hp-hpux*): Update for 4.1.0.

View File

@ -735,7 +735,7 @@ HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H)
LANGHOOKS_DEF_H = langhooks-def.h $(HOOKS_H)
TARGET_DEF_H = target-def.h $(HOOKS_H)
RTL_BASE_H = rtl.h rtl.def $(MACHMODE_H) reg-notes.def insn-notes.def \
input.h real.h statistics.h
input.h real.h statistics.h vec.h
RTL_H = $(RTL_BASE_H) genrtl.h
PARAMS_H = params.h params.def
BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def
@ -2198,7 +2198,8 @@ expmed.o : expmed.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_
toplev.h $(TM_P_H) langhooks.h
explow.o : explow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(FLAGS_H) hard-reg-set.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) \
toplev.h $(FUNCTION_H) $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h target.h
toplev.h $(FUNCTION_H) $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h target.h \
output.h
optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(FLAGS_H) insn-config.h $(EXPR_H) $(OPTABS_H) libfuncs.h \
$(RECOG_H) reload.h toplev.h $(GGC_H) real.h $(TM_P_H) except.h \

View File

@ -787,6 +787,10 @@ fsched-stalled-insns-dep=
Common RejectNegative Joined UInteger
-fsched-stalled-insns-dep=<number> Set dependence distance checking in premature scheduling of queued insns
fsection-anchors
Common Report Var(flag_section_anchors)
Access data in the same section from shared anchor points
frtl-abstract-sequences
Common Report Var(flag_rtl_seqabstr)
Perform sequence abstraction optimization on RTL

View File

@ -623,6 +623,7 @@ static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
static void rs6000_elf_encode_section_info (tree, rtx, int)
ATTRIBUTE_UNUSED;
#endif
static bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx);
#if TARGET_XCOFF
static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
static void rs6000_xcoff_asm_init_sections (void);
@ -1021,6 +1022,20 @@ static const char alt_reg_names[][8] =
#define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
#endif
/* Use a 32-bit anchor range. This leads to sequences like:
addis tmp,anchor,high
add dest,tmp,low
where tmp itself acts as an anchor, and can be shared between
accesses to the same 64k page. */
#undef TARGET_MIN_ANCHOR_OFFSET
#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1
#undef TARGET_MAX_ANCHOR_OFFSET
#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff
#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
#define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
struct gcc_target targetm = TARGET_INITIALIZER;
@ -17648,7 +17663,14 @@ rs6000_elf_in_small_data_p (tree decl)
}
#endif /* USING_ELFOS_H */
/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P. */
static bool
rs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x)
{
return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode);
}
/* Return a REG that occurs in ADDR with coefficient 1.
ADDR can be effectively incremented by incrementing REG.

View File

@ -1453,8 +1453,7 @@ cselib_init (bool record_memory)
sizeof (struct elt_loc_list), 10);
cselib_val_pool = create_alloc_pool ("cselib_val_list",
sizeof (cselib_val), 10);
value_pool = create_alloc_pool ("value",
RTX_SIZE (VALUE), 100);
value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100);
cselib_record_memory = record_memory;
/* This is only created once. */
if (! callmem)

View File

@ -333,7 +333,7 @@ Objective-C and Objective-C++ Dialects}.
-fsched-stalled-insns=@var{n} -fsched-stalled-insns-dep=@var{n} @gol
-fsched2-use-superblocks @gol
-fsched2-use-traces -freschedule-modulo-scheduled-loops @gol
-fsignaling-nans -fsingle-precision-constant @gol
-fsection-anchors -fsignaling-nans -fsingle-precision-constant @gol
-fstack-protector -fstack-protector-all @gol
-fstrength-reduce -fstrict-aliasing -ftracer -fthread-jumps @gol
-funroll-all-loops -funroll-loops -fpeel-loops @gol
@ -5773,6 +5773,35 @@ If a guard check fails, an error message is printed and the program exits.
@item -fstack-protector-all
Like @option{-fstack-protector} except that all functions are protected.
@item -fsection-anchors
@opindex fsection-anchors
Try to reduce the number of symbolic address calculations by using
shared ``anchor'' symbols to address nearby objects. This transformation
can help to reduce the number of GOT entries and GOT accesses on some
targets.
For example, the implementation of the following function @code{foo}:
@smallexample
static int a, b, c;
int foo (void) @{ return a + b + c; @}
@end smallexample
would usually calculate the addresses of all three variables, but if you
compile it with @option{-fsection-anchors}, it will access the variables
from a common anchor point instead. The effect is similar to the
following pseudocode (which isn't valid C):
@smallexample
int foo (void)
@{
register int *xr = &x;
return xr[&a - &x] + xr[&b - &x] + xr[&c - &x];
@}
@end smallexample
Not all targets support this option.
@item --param @var{name}=@var{value}
@opindex param
In some places, GCC uses various constants to control the amount of

View File

@ -501,11 +501,40 @@ See @code{TARGET_IN_SMALL_DATA_P}.
This is a multi-bit field accessor that returns the @code{tls_model}
to be used for a thread-local storage symbol. It returns zero for
non-thread-local symbols.
@findex SYMBOL_REF_IN_BLOCK_P
@findex SYMBOL_FLAG_IN_BLOCK
@item SYMBOL_FLAG_IN_BLOCK
Set if the symbol has been assigned to an @code{object_block} structure.
@code{SYMBOL_REF_BLOCK} and @code{SYMBOL_REF_BLOCK_OFFSET} provide more
information about such symbols.
@findex SYMBOL_REF_ANCHOR_P
@findex SYMBOL_FLAG_ANCHOR
@cindex @option{-fsection-anchors}
@item SYMBOL_FLAG_ANCHOR
Set if the symbol is used as a section anchor. ``Section anchors''
are symbols that have a known position within an @code{object_block}
and that can be used to access nearby members of that block.
They are used to implement @option{-fsection-anchors}.
If this flag is set, then @code{SYMBOL_FLAG_IN_BLOCK} will be too.
@end table
Bits beginning with @code{SYMBOL_FLAG_MACH_DEP} are available for
the target's use.
@end table
@findex SYMBOL_REF_BLOCK
@item SYMBOL_REF_BLOCK (@var{x})
If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the @samp{object_block}
structure to which the symbol belongs. The value is always nonnull.
@findex SYMBOL_REF_BLOCK_OFFSET
@item SYMBOL_REF_BLOCK_OFFSET (@var{x})
If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the offset of @var{x}
from the first object in @samp{SYMBOL_REF_BLOCK (@var{x})}. The value is
negative if @var{x} has not yet been assigned an offset.
@end table
@node Flags

View File

@ -38,6 +38,7 @@ through the macros defined in the @file{.h} file.
* Trampolines:: Code set up at run time to enter a nested function.
* Library Calls:: Controlling how library routines are implicitly called.
* Addressing Modes:: Defining addressing modes valid for memory operands.
* Anchored Addresses:: Defining how @option{-fsection-anchors} should work.
* Condition Code:: Defining how insns update the condition code.
* Costs:: Defining relative costs of different operations.
* Scheduling:: Adjusting the behavior of the instruction scheduler.
@ -5207,6 +5208,14 @@ holding the constant. This restriction is often true of addresses
of TLS symbols for various targets.
@end deftypefn
@deftypefn {Target Hook} bool TARGET_USE_BLOCKS_FOR_CONSTANT_P (enum machine_mode @var{mode}, rtx @var{x})
This hook should return true if pool entries for constant @var{x} can
be placed in an @code{object_block} structure. @var{mode} is the mode
of @var{x}.
The default version returns false for all constants.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD (void)
This hook should return the DECL of a function @var{f} that given an
address @var{addr} as an argument returns a mask @var{m} that can be
@ -5236,6 +5245,76 @@ the argument @var{OFF} to @code{REALIGN_LOAD}, in which case the low
log2(@var{VS})-1 bits of @var{addr} will be considered.
@end deftypefn
@node Anchored Addresses
@section Anchored Addresses
@cindex anchored addresses
@cindex @option{-fsection-anchors}
GCC usually addresses every static object as a separate entity.
For example, if we have:
@smallexample
static int a, b, c;
int foo (void) @{ return a + b + c; @}
@end smallexample
the code for @code{foo} will usually calculate three separate symbolic
addresses: those of @code{a}, @code{b} and @code{c}. On some targets,
it would be better to calculate just one symbolic address and access
the three variables relative to it. The equivalent pseudocode would
be something like:
@smallexample
int foo (void)
@{
register int *xr = &x;
return xr[&a - &x] + xr[&b - &x] + xr[&c - &x];
@}
@end smallexample
(which isn't valid C). We refer to shared addresses like @code{x} as
``section anchors''. Their use is controlled by @option{-fsection-anchors}.
The hooks below describe the target properties that GCC needs to know
in order to make effective use of section anchors. It won't use
section anchors at all unless either @code{TARGET_MIN_ANCHOR_OFFSET}
or @code{TARGET_MAX_ANCHOR_OFFSET} is set to a nonzero value.
@deftypevar {Target Hook} HOST_WIDE_INT TARGET_MIN_ANCHOR_OFFSET
The minimum offset that should be applied to a section anchor.
On most targets, it should be the smallest offset that can be
applied to a base register while still giving a legitimate address
for every mode. The default value is 0.
@end deftypevar
@deftypevar {Target Hook} HOST_WIDE_INT TARGET_MAX_ANCHOR_OFFSET
Like @code{TARGET_MIN_ANCHOR_OFFSET}, but the maximum (inclusive)
offset that should be applied to section anchors. The default
value is 0.
@end deftypevar
@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_ANCHOR (rtx @var{x})
Write the assembly code to define section anchor @var{x}, which is a
@code{SYMBOL_REF} for which @samp{SYMBOL_REF_ANCHOR_P (@var{x})} is true.
The hook is called with the assembly output position set to the beginning
of @code{SYMBOL_REF_BLOCK (@var{x})}.
If @code{ASM_OUTPUT_DEF} is available, the hook's default definition uses
it to define the symbol as @samp{. + SYMBOL_REF_BLOCK_OFFSET (@var{x})}.
If @code{ASM_OUTPUT_DEF} is not available, the hook's default definition
is @code{NULL}, which disables the use of section anchors altogether.
@end deftypefn
@deftypefn {Target Hook} bool TARGET_USE_ANCHORS_FOR_SYMBOL_P (rtx @var{x})
Return true if GCC should attempt to use anchors to access @code{SYMBOL_REF}
@var{x}. You can assume @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})} and
@samp{!SYMBOL_REF_ANCHOR_P (@var{x})}.
The default version is correct for most targets, but you might need to
intercept this hook to handle things like target-specific attributes
or target-specific sections.
@end deftypefn
@node Condition Code
@section Condition Code Status
@cindex condition code status

View File

@ -124,9 +124,6 @@ dwarf2out_do_frame (void)
#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
DEF_VEC_P(rtx);
DEF_VEC_ALLOC_P(rtx,gc);
/* Array of RTXes referenced by the debugging information, which therefore
must be kept around forever. */
static GTY(()) VEC(rtx,gc) *used_rtx_array;

View File

@ -2467,11 +2467,7 @@ repeat:
if (RTX_FLAG (x, used))
{
rtx copy;
copy = rtx_alloc (code);
memcpy (copy, x, RTX_SIZE (code));
x = copy;
x = shallow_copy_rtx (x);
copied = 1;
}
RTX_FLAG (x, used) = 1;
@ -4978,13 +4974,11 @@ copy_insn_1 (rtx orig)
break;
}
copy = rtx_alloc (code);
/* Copy the various flags, and other information. We assume that
all fields need copying, and then clear the fields that should
/* Copy the various flags, fields, and other information. We assume
that all fields need copying, and then clear the fields that should
not be copied. That is the sensible default behavior, and forces
us to explicitly document why we are *not* copying a flag. */
memcpy (copy, orig, RTX_HDR_SIZE);
copy = shallow_copy_rtx (orig);
/* We do not copy the USED flag, which is used as a mark bit during
walks over the RTL. */
@ -5001,43 +4995,40 @@ copy_insn_1 (rtx orig)
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
copy->u.fld[i] = orig->u.fld[i];
switch (*format_ptr++)
{
case 'e':
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
break;
switch (*format_ptr++)
{
case 'e':
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
break;
case 'E':
case 'V':
if (XVEC (orig, i) == orig_asm_constraints_vector)
XVEC (copy, i) = copy_asm_constraints_vector;
else if (XVEC (orig, i) == orig_asm_operands_vector)
XVEC (copy, i) = copy_asm_operands_vector;
else if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
}
break;
case 'E':
case 'V':
if (XVEC (orig, i) == orig_asm_constraints_vector)
XVEC (copy, i) = copy_asm_constraints_vector;
else if (XVEC (orig, i) == orig_asm_operands_vector)
XVEC (copy, i) = copy_asm_operands_vector;
else if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
}
break;
case 't':
case 'w':
case 'i':
case 's':
case 'S':
case 'u':
case '0':
/* These are left unchanged. */
break;
case 't':
case 'w':
case 'i':
case 's':
case 'S':
case 'u':
case '0':
/* These are left unchanged. */
break;
default:
gcc_unreachable ();
}
}
default:
gcc_unreachable ();
}
if (code == SCRATCH)
{

View File

@ -39,6 +39,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "recog.h"
#include "langhooks.h"
#include "target.h"
#include "output.h"
static rtx break_out_memory_refs (rtx);
static void emit_stack_probe (rtx);
@ -527,6 +528,7 @@ validize_mem (rtx ref)
{
if (!MEM_P (ref))
return ref;
ref = use_anchored_address (ref);
if (! (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (ref, 0)))
&& memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
return ref;
@ -534,6 +536,60 @@ validize_mem (rtx ref)
/* Don't alter REF itself, since that is probably a stack slot. */
return replace_equiv_address (ref, XEXP (ref, 0));
}
/* If X is a memory reference to a member of an object block, try rewriting
it to use an anchor instead. Return the new memory reference on success
and the old one on failure. */
rtx
use_anchored_address (rtx x)
{
rtx base;
HOST_WIDE_INT offset;
if (!flag_section_anchors)
return x;
if (!MEM_P (x))
return x;
/* Split the address into a base and offset. */
base = XEXP (x, 0);
offset = 0;
if (GET_CODE (base) == CONST
&& GET_CODE (XEXP (base, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (base, 0), 1)) == CONST_INT)
{
offset += INTVAL (XEXP (XEXP (base, 0), 1));
base = XEXP (XEXP (base, 0), 0);
}
/* Check whether BASE is suitable for anchors. */
if (GET_CODE (base) != SYMBOL_REF
|| !SYMBOL_REF_IN_BLOCK_P (base)
|| SYMBOL_REF_ANCHOR_P (base)
|| !targetm.use_anchors_for_symbol_p (base))
return x;
/* Decide where BASE is going to be. */
place_block_symbol (base);
/* Get the anchor we need to use. */
offset += SYMBOL_REF_BLOCK_OFFSET (base);
base = get_section_anchor (SYMBOL_REF_BLOCK (base), offset,
SYMBOL_REF_TLS_MODEL (base));
/* Work out the offset from the anchor. */
offset -= SYMBOL_REF_BLOCK_OFFSET (base);
/* If we're going to run a CSE pass, force the anchor into a register.
We will then be able to reuse registers for several accesses, if the
target costs say that that's worthwhile. */
if (!cse_not_expected)
base = force_reg (GET_MODE (base), base);
return replace_equiv_address (x, plus_constant (base, offset));
}
/* Copy the value or contents of X to a new temp reg and return that reg. */

View File

@ -3081,7 +3081,7 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
be able to get a part of Y. */
if (ypart == 0 && CONSTANT_P (y))
{
y = force_const_mem (mode, y);
y = use_anchored_address (force_const_mem (mode, y));
ypart = operand_subword (y, i, 1, mode);
}
else if (ypart == 0)
@ -3194,6 +3194,8 @@ emit_move_insn (rtx x, rtx y)
of the non-legitimate constant. */
if (!y)
y = y_cst;
else
y = use_anchored_address (y);
}
}
@ -6280,6 +6282,20 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
}
/* Return a MEM that constains constant EXP. DEFER is as for
output_constant_def and MODIFIER is as for expand_expr. */
static rtx
expand_expr_constant (tree exp, int defer, enum expand_modifier modifier)
{
rtx mem;
mem = output_constant_def (exp, defer);
if (modifier != EXPAND_INITIALIZER)
mem = use_anchored_address (mem);
return mem;
}
/* A subroutine of expand_expr_addr_expr. Evaluate the address of EXP.
The TARGET, TMODE and MODIFIER arguments are as for expand_expr. */
@ -6301,14 +6317,14 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
exception here is STRING_CST. */
if (TREE_CODE (exp) == CONSTRUCTOR
|| CONSTANT_CLASS_P (exp))
return XEXP (output_constant_def (exp, 0), 0);
return XEXP (expand_expr_constant (exp, 0, modifier), 0);
/* Everything must be something allowed by is_gimple_addressable. */
switch (TREE_CODE (exp))
{
case INDIRECT_REF:
/* This case will happen via recursion for &a->b. */
return expand_expr (TREE_OPERAND (exp, 0), target, tmode, EXPAND_NORMAL);
return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
case CONST_DECL:
/* Recurse and make the output_constant_def clause above handle this. */
@ -6579,7 +6595,7 @@ static rtx
expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier, rtx *alt_rtl)
{
rtx op0, op1, temp;
rtx op0, op1, temp, decl_rtl;
tree type = TREE_TYPE (exp);
int unsignedp;
enum machine_mode mode;
@ -6701,7 +6717,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
case FUNCTION_DECL:
case RESULT_DECL:
gcc_assert (DECL_RTL (exp));
decl_rtl = DECL_RTL (exp);
gcc_assert (decl_rtl);
/* Ensure variable marked as used even if it doesn't go through
a parser. If it hasn't be used yet, write out an external
@ -6728,27 +6745,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
from its initializer, while the initializer is still being parsed.
See expand_decl. */
if (MEM_P (DECL_RTL (exp))
&& REG_P (XEXP (DECL_RTL (exp), 0)))
temp = validize_mem (DECL_RTL (exp));
if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
temp = validize_mem (decl_rtl);
/* If DECL_RTL is memory, we are in the normal case and either
the address is not valid or it is not a register and -fforce-addr
is specified, get the address into a register. */
else if (MEM_P (DECL_RTL (exp))
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_SUM
&& modifier != EXPAND_INITIALIZER
&& (! memory_address_p (DECL_MODE (exp),
XEXP (DECL_RTL (exp), 0))
|| (flag_force_addr
&& !REG_P (XEXP (DECL_RTL (exp), 0)))))
else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
{
if (alt_rtl)
*alt_rtl = DECL_RTL (exp);
temp = replace_equiv_address (DECL_RTL (exp),
copy_rtx (XEXP (DECL_RTL (exp), 0)));
*alt_rtl = decl_rtl;
decl_rtl = use_anchored_address (decl_rtl);
if (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_SUM
&& (!memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0))
|| (flag_force_addr && !REG_P (XEXP (decl_rtl, 0)))))
temp = replace_equiv_address (decl_rtl,
copy_rtx (XEXP (decl_rtl, 0)));
}
/* If we got something, return it. But first, set the alignment
@ -6765,8 +6779,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
must be a promoted value. We return a SUBREG of the wanted mode,
but mark it so that we know that it was already extended. */
if (REG_P (DECL_RTL (exp))
&& GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
if (REG_P (decl_rtl)
&& GET_MODE (decl_rtl) != DECL_MODE (exp))
{
enum machine_mode pmode;
@ -6775,15 +6789,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
(TREE_CODE (exp) == RESULT_DECL
|| TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode);
gcc_assert (GET_MODE (decl_rtl) == pmode);
temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
temp = gen_lowpart_SUBREG (mode, decl_rtl);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
return temp;
}
return DECL_RTL (exp);
return decl_rtl;
case INTEGER_CST:
temp = immed_double_const (TREE_INT_CST_LOW (exp),
@ -6852,7 +6866,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
/* ... fall through ... */
case STRING_CST:
temp = output_constant_def (exp, 1);
temp = expand_expr_constant (exp, 1, modifier);
/* temp contains a constant address.
On RISC machines where a constant address isn't valid,
@ -6953,7 +6967,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|| modifier == EXPAND_CONST_ADDRESS)
&& TREE_CONSTANT (exp)))
{
rtx constructor = output_constant_def (exp, 1);
rtx constructor = expand_expr_constant (exp, 1, modifier);
if (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER

View File

@ -647,6 +647,8 @@ extern rtx widen_memory_access (rtx, enum machine_mode, HOST_WIDE_INT);
valid address. */
extern rtx validize_mem (rtx);
extern rtx use_anchored_address (rtx);
/* Given REF, a MEM, and T, either the type of X or the expression
corresponding to REF, set the memory attributes. OBJECTP is nonzero
if we are making a new object of this type. */

View File

@ -354,6 +354,33 @@ create_field (pair_p next, type_p type, const char *name)
return field;
}
/* Like create_field, but the field is only valid when condition COND
is true. */
static pair_p
create_optional_field (pair_p next, type_p type, const char *name,
const char *cond)
{
static int id = 1;
pair_p union_fields, field;
type_p union_type;
/* Create a fake union type with a single nameless field of type TYPE.
The field has a tag of "1". This allows us to make the presence
of a field of type TYPE depend on some boolean "desc" being true. */
union_fields = create_field (NULL, type, "");
union_fields->opt = create_option (union_fields->opt, "dot", "");
union_fields->opt = create_option (union_fields->opt, "tag", "1");
union_type = new_structure (xasprintf ("%s_%d", "fake_union", id++), 1,
&lexer_line, union_fields, NULL);
/* Create the field and give it the new fake union type. Add a "desc"
tag that specifies the condition under which the field is valid. */
field = create_field (next, union_type, name);
field->opt = create_option (field->opt, "desc", cond);
return field;
}
/* We don't care how long a CONST_DOUBLE is. */
#define CONST_DOUBLE_FORMAT "ww"
/* We don't want to see codes that are only for generator files. */
@ -646,6 +673,14 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
"CONSTANT_POOL_ADDRESS_P (&%0)");
}
if (i == SYMBOL_REF)
{
/* Add the "block_sym" field if SYMBOL_REF_IN_BLOCK_P holds. */
type_p field_tp = find_structure ("block_symbol", 0);
subfields = create_optional_field (subfields, field_tp, "block_sym",
"SYMBOL_REF_IN_BLOCK_P (&%0)");
}
sname = xasprintf ("rtx_def_%s", rtx_name[i]);
substruct = new_structure (sname, 0, &lexer_line, subfields, NULL);

View File

@ -69,6 +69,14 @@ hook_bool_mode_false (enum machine_mode mode ATTRIBUTE_UNUSED)
return false;
}
/* Generic hook that takes (enum machine_mode, rtx) and returns false. */
bool
hook_bool_mode_rtx_false (enum machine_mode mode ATTRIBUTE_UNUSED,
rtx value ATTRIBUTE_UNUSED)
{
return false;
}
/* Generic hook that takes (FILE *, const char *) and does nothing. */
void
hook_void_FILEptr_constcharptr (FILE *a ATTRIBUTE_UNUSED, const char *b ATTRIBUTE_UNUSED)

View File

@ -28,6 +28,7 @@ extern bool hook_bool_void_false (void);
extern bool hook_bool_void_true (void);
extern bool hook_bool_bool_false (bool);
extern bool hook_bool_mode_false (enum machine_mode);
extern bool hook_bool_mode_rtx_false (enum machine_mode, rtx);
extern bool hook_bool_tree_false (tree);
extern bool hook_bool_tree_true (tree);
extern bool hook_bool_tree_hwi_hwi_tree_false (tree, HOST_WIDE_INT, HOST_WIDE_INT,

View File

@ -84,9 +84,6 @@ struct iv_to_split
XEXP (XEXP (single_set, loc[0]), loc[1]). */
};
DEF_VEC_P(rtx);
DEF_VEC_ALLOC_P(rtx,heap);
/* Information about accumulators to expand. */
struct var_to_expand

View File

@ -275,6 +275,8 @@ extern rtx peephole (rtx);
/* Write all the constants in the constant pool. */
extern void output_constant_pool (const char *, tree);
extern void output_object_blocks (void);
/* Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
@ -483,6 +485,8 @@ union section GTY ((desc ("(%h).common.flags & SECTION_NAMED")))
struct unnamed_section GTY ((tag ("0"))) unnamed;
};
struct object_block;
/* Special well-known sections. */
extern GTY(()) section *text_section;
extern GTY(()) section *data_section;
@ -502,6 +506,9 @@ extern section *get_unnamed_section (unsigned int, void (*) (const void *),
const void *);
extern section *get_section (const char *, unsigned int, tree);
extern section *get_named_section (tree, const char *, int);
extern void place_block_symbol (rtx);
extern rtx get_section_anchor (struct object_block *, HOST_WIDE_INT,
enum tls_model);
extern section *mergeable_constant_section (enum machine_mode,
unsigned HOST_WIDE_INT,
unsigned int);
@ -546,6 +553,8 @@ extern section *default_elf_select_rtx_section (enum machine_mode, rtx,
unsigned HOST_WIDE_INT);
extern void default_encode_section_info (tree, rtx, int);
extern const char *default_strip_name_encoding (const char *);
extern void default_asm_output_anchor (rtx);
extern bool default_use_anchors_for_symbol_p (rtx);
extern bool default_binds_local_p (tree);
extern bool default_binds_local_p_1 (tree, int);
extern void default_globalize_label (FILE *, const char *);

View File

@ -437,7 +437,7 @@ apply_macro_to_rtx (rtx original, struct mapping *macro, int value,
/* Create a shallow copy of ORIGINAL. */
bellwether_code = BELLWETHER_CODE (GET_CODE (original));
x = rtx_alloc (bellwether_code);
memcpy (x, original, RTX_SIZE (bellwether_code));
memcpy (x, original, RTX_CODE_SIZE (bellwether_code));
/* Change the mode or code itself. */
group = macro->group;

View File

@ -2607,9 +2607,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
new = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false);
if (new != XEXP (x, i) && ! copied)
{
rtx new_x = rtx_alloc (code);
memcpy (new_x, x, RTX_SIZE (code));
x = new_x;
x = shallow_copy_rtx (x);
copied = 1;
}
XEXP (x, i) = new;
@ -2626,9 +2624,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
XVEC (x, i)->elem);
if (! copied)
{
rtx new_x = rtx_alloc (code);
memcpy (new_x, x, RTX_SIZE (code));
x = new_x;
x = shallow_copy_rtx (x);
copied = 1;
}
XVEC (x, i) = new_v;

103
gcc/rtl.c
View File

@ -109,7 +109,7 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
/* Indexed by rtx code, gives the size of the rtx in bytes. */
const unsigned char rtx_size[NUM_RTX_CODE] = {
const unsigned char rtx_code_size[NUM_RTX_CODE] = {
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \
((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \
? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \
@ -170,6 +170,16 @@ rtvec_alloc (int n)
return rt;
}
/* Return the number of bytes occupied by rtx value X. */
unsigned int
rtx_size (rtx x)
{
if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_IN_BLOCK_P (x))
return RTX_HDR_SIZE + sizeof (struct block_symbol);
return RTX_CODE_SIZE (GET_CODE (x));
}
/* Allocate an rtx of code CODE. The CODE is stored in the rtx;
all the rest is initialized to zero. */
@ -178,7 +188,7 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
{
rtx rt;
rt = (rtx) ggc_alloc_zone_pass_stat (RTX_SIZE (code), &rtl_zone);
rt = (rtx) ggc_alloc_zone_pass_stat (RTX_CODE_SIZE (code), &rtl_zone);
/* We want to clear everything up to the FLD array. Normally, this
is one int, but we don't want to assume that and it isn't very
@ -189,7 +199,7 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
#ifdef GATHER_STATISTICS
rtx_alloc_counts[code]++;
rtx_alloc_sizes[code] += RTX_SIZE (code);
rtx_alloc_sizes[code] += RTX_CODE_SIZE (code);
#endif
return rt;
@ -246,13 +256,11 @@ copy_rtx (rtx orig)
break;
}
copy = rtx_alloc (code);
/* Copy the various flags, and other information. We assume that
all fields need copying, and then clear the fields that should
/* Copy the various flags, fields, and other information. We assume
that all fields need copying, and then clear the fields that should
not be copied. That is the sensible default behavior, and forces
us to explicitly document why we are *not* copying a flag. */
memcpy (copy, orig, RTX_HDR_SIZE);
copy = shallow_copy_rtx (orig);
/* We do not copy the USED flag, which is used as a mark bit during
walks over the RTL. */
@ -267,41 +275,38 @@ copy_rtx (rtx orig)
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
copy->u.fld[i] = orig->u.fld[i];
switch (*format_ptr++)
{
case 'e':
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
switch (*format_ptr++)
{
case 'e':
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
case 'E':
case 'V':
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
}
break;
case 'E':
case 'V':
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
}
break;
case 't':
case 'w':
case 'i':
case 's':
case 'S':
case 'T':
case 'u':
case 'B':
case '0':
/* These are left unchanged. */
break;
case 't':
case 'w':
case 'i':
case 's':
case 'S':
case 'T':
case 'u':
case 'B':
case '0':
/* These are left unchanged. */
break;
default:
gcc_unreachable ();
}
}
default:
gcc_unreachable ();
}
return copy;
}
@ -310,11 +315,12 @@ copy_rtx (rtx orig)
rtx
shallow_copy_rtx_stat (rtx orig MEM_STAT_DECL)
{
unsigned int size;
rtx copy;
copy = (rtx) ggc_alloc_zone_pass_stat (RTX_SIZE (GET_CODE (orig)),
&rtl_zone);
memcpy (copy, orig, RTX_SIZE (GET_CODE (orig)));
size = rtx_size (orig);
copy = (rtx) ggc_alloc_zone_pass_stat (size, &rtl_zone);
memcpy (copy, orig, size);
return copy;
}
@ -530,6 +536,17 @@ rtl_check_failed_code_mode (rtx r, enum rtx_code code, enum machine_mode mode,
func, trim_filename (file), line);
}
/* Report that line LINE of FILE tried to access the block symbol fields
of a non-block symbol. FUNC is the function that contains the line. */
void
rtl_check_failed_block_symbol (const char *file, int line, const char *func)
{
internal_error
("RTL check: attempt to treat non-block symbol as a block symbol "
"in %s, at %s:%d", func, trim_filename (file), line);
}
/* XXX Maybe print the vector? */
void
rtvec_check_failed_bounds (rtvec r, int n, const char *file, int line,

View File

@ -26,6 +26,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "machmode.h"
#include "input.h"
#include "real.h"
#include "vec.h"
#undef FFS /* Some systems predefine this symbol; don't let it interfere. */
#undef FLOAT /* Likewise. */
@ -104,7 +105,7 @@ extern const char * const rtx_format[NUM_RTX_CODE];
extern const enum rtx_class rtx_class[NUM_RTX_CODE];
#define GET_RTX_CLASS(CODE) (rtx_class[(int) (CODE)])
extern const unsigned char rtx_size[NUM_RTX_CODE];
extern const unsigned char rtx_code_size[NUM_RTX_CODE];
extern const unsigned char rtx_next[NUM_RTX_CODE];
/* The flags and bitfields of an ADDR_DIFF_VEC. BASE is the base label
@ -175,6 +176,59 @@ union rtunion_def
};
typedef union rtunion_def rtunion;
/* This structure remembers the position of a SYMBOL_REF within an
object_block structure. A SYMBOL_REF only provides this information
if SYMBOL_REF_IN_BLOCK_P is true. */
struct block_symbol GTY(()) {
/* The usual SYMBOL_REF fields. */
rtunion GTY ((skip)) fld[3];
/* The block that contains this object. */
struct object_block *block;
/* The offset of this object from the start of its block. It is negative
if the symbol has not yet been assigned an offset. */
HOST_WIDE_INT offset;
};
DEF_VEC_P(rtx);
DEF_VEC_ALLOC_P(rtx,heap);
DEF_VEC_ALLOC_P(rtx,gc);
/* Describes a group of objects that are to be placed together in such
a way that their relative positions are known. */
struct object_block GTY(())
{
/* The section in which these objects should be placed. */
section *sect;
/* The alignment of the first object, measured in bits. */
unsigned int alignment;
/* The total size of the objects, measured in bytes. */
HOST_WIDE_INT size;
/* The SYMBOL_REFs for each object. The vector is sorted in
order of increasing offset and the following conditions will
hold for each element X:
SYMBOL_REF_IN_BLOCK_P (X)
!SYMBOL_REF_ANCHOR_P (X)
SYMBOL_REF_BLOCK (X) == [address of this structure]
SYMBOL_REF_BLOCK_OFFSET (X) >= 0. */
VEC(rtx,gc) *objects;
/* All the anchor SYMBOL_REFs used to address these objects, sorted
in order of increasing offset, and then increasing TLS model.
The following conditions will hold for each element X in this vector:
SYMBOL_REF_IN_BLOCK_P (X)
SYMBOL_REF_ANCHOR_P (X)
SYMBOL_REF_BLOCK (X) == [address of this structure]
SYMBOL_REF_BLOCK_OFFSET (X) >= 0. */
VEC(rtx,gc) *anchors;
};
/* RTL expression ("rtx"). */
struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
@ -251,6 +305,7 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
union u {
rtunion fld[1];
HOST_WIDE_INT hwint[1];
struct block_symbol block_sym;
struct real_value rv;
} GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
};
@ -259,7 +314,7 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
#define RTX_HDR_SIZE offsetof (struct rtx_def, u)
/* The size in bytes of an rtx with code CODE. */
#define RTX_SIZE(CODE) rtx_size[CODE]
#define RTX_CODE_SIZE(CODE) rtx_code_size[CODE]
#define NULL_RTX (rtx) 0
@ -471,6 +526,14 @@ struct rtvec_def GTY(()) {
__LINE__, __FUNCTION__); \
&_rtx->u.rv; })
#define BLOCK_SYMBOL_CHECK(RTX) __extension__ \
({ rtx const _symbol = (RTX); \
unsigned int flags = RTL_CHECKC1 (_symbol, 1, SYMBOL_REF).rt_int; \
if ((flags & SYMBOL_FLAG_IN_BLOCK) == 0) \
rtl_check_failed_block_symbol (__FILE__, __LINE__, \
__FUNCTION__); \
&_symbol->u.block_sym; })
extern void rtl_check_failed_bounds (rtx, int, const char *, int,
const char *)
ATTRIBUTE_NORETURN;
@ -489,6 +552,8 @@ extern void rtl_check_failed_code2 (rtx, enum rtx_code, enum rtx_code,
extern void rtl_check_failed_code_mode (rtx, enum rtx_code, enum machine_mode,
bool, const char *, int, const char *)
ATTRIBUTE_NORETURN;
extern void rtl_check_failed_block_symbol (const char *, int, const char *)
ATTRIBUTE_NORETURN;
extern void rtvec_check_failed_bounds (rtvec, int, const char *, int,
const char *)
ATTRIBUTE_NORETURN;
@ -505,6 +570,7 @@ extern void rtvec_check_failed_bounds (rtvec, int, const char *, int,
#define XCMWINT(RTX, N, C, M) ((RTX)->u.hwint[N])
#define XCNMWINT(RTX, N, C, M) ((RTX)->u.hwint[N])
#define XCNMPRV(RTX, C, M) (&(RTX)->u.rv)
#define BLOCK_SYMBOL_CHECK(RTX) (&(RTX)->u.block_sym)
#endif
@ -1249,11 +1315,29 @@ do { \
#define SYMBOL_FLAG_EXTERNAL (1 << 6)
#define SYMBOL_REF_EXTERNAL_P(RTX) \
((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_EXTERNAL) != 0)
/* Set if this symbol has a block_symbol structure associated with it. */
#define SYMBOL_FLAG_IN_BLOCK (1 << 7)
#define SYMBOL_REF_IN_BLOCK_P(RTX) \
((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_IN_BLOCK) != 0)
/* Set if this symbol is a section anchor. SYMBOL_REF_ANCHOR_P implies
SYMBOL_REF_IN_BLOCK_P. */
#define SYMBOL_FLAG_ANCHOR (1 << 8)
#define SYMBOL_REF_ANCHOR_P(RTX) \
((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_ANCHOR) != 0)
/* Subsequent bits are available for the target to use. */
#define SYMBOL_FLAG_MACH_DEP_SHIFT 7
#define SYMBOL_FLAG_MACH_DEP_SHIFT 9
#define SYMBOL_FLAG_MACH_DEP (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
/* The block to which the given SYMBOL_REF belongs. Only valid if
SYMBOL_REF_IN_BLOCK_P (RTX). */
#define SYMBOL_REF_BLOCK(RTX) (BLOCK_SYMBOL_CHECK (RTX)->block)
/* The byte offset of the given SYMBOL_REF from the start of its block,
or a negative value if the symbol has not yet been assigned a position.
Only valid if SYMBOL_REF_IN_BLOCK_P (RTX). */
#define SYMBOL_REF_BLOCK_OFFSET(RTX) (BLOCK_SYMBOL_CHECK (RTX)->offset)
/* Define a macro to look for REG_INC notes,
but save time on machines where they never exist. */
@ -1384,6 +1468,7 @@ extern void dump_rtx_statistics (void);
extern rtx copy_rtx_if_shared (rtx);
/* In rtl.c */
extern unsigned int rtx_size (rtx);
extern rtx shallow_copy_rtx_stat (rtx MEM_STAT_DECL);
#define shallow_copy_rtx(a) shallow_copy_rtx_stat (a MEM_STAT_INFO)
extern int rtx_equal_p (rtx, rtx);

View File

@ -205,6 +205,14 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define TARGET_ASM_MARK_DECL_PRESERVED hook_void_constcharptr
#endif
#ifndef TARGET_ASM_OUTPUT_ANCHOR
#ifdef ASM_OUTPUT_DEF
#define TARGET_ASM_OUTPUT_ANCHOR default_asm_output_anchor
#else
#define TARGET_ASM_OUTPUT_ANCHOR NULL
#endif
#endif
#ifndef TARGET_ASM_OUTPUT_DWARF_DTPREL
#define TARGET_ASM_OUTPUT_DWARF_DTPREL NULL
#endif
@ -252,6 +260,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
TARGET_ASM_FILE_END, \
TARGET_ASM_EXTERNAL_LIBCALL, \
TARGET_ASM_MARK_DECL_PRESERVED, \
TARGET_ASM_OUTPUT_ANCHOR, \
TARGET_ASM_OUTPUT_DWARF_DTPREL}
/* Scheduler hooks. All of these default to null pointers, which
@ -373,6 +382,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define TARGET_CANNOT_COPY_INSN_P NULL
#define TARGET_COMMUTATIVE_P hook_bool_rtx_commutative_p
#define TARGET_DELEGITIMIZE_ADDRESS hook_rtx_rtx_identity
#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_rtx_false
#define TARGET_MIN_ANCHOR_OFFSET 0
#define TARGET_MAX_ANCHOR_OFFSET 0
#define TARGET_USE_ANCHORS_FOR_SYMBOL_P default_use_anchors_for_symbol_p
#define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_false
#define TARGET_COMP_TYPE_ATTRIBUTES hook_int_tree_tree_1
#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES hook_void_tree
@ -592,6 +605,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
TARGET_CANNOT_COPY_INSN_P, \
TARGET_COMMUTATIVE_P, \
TARGET_DELEGITIMIZE_ADDRESS, \
TARGET_USE_BLOCKS_FOR_CONSTANT_P, \
TARGET_MIN_ANCHOR_OFFSET, \
TARGET_MAX_ANCHOR_OFFSET, \
TARGET_USE_ANCHORS_FOR_SYMBOL_P, \
TARGET_FUNCTION_OK_FOR_SIBCALL, \
TARGET_IN_SMALL_DATA_P, \
TARGET_BINDS_LOCAL_P, \

View File

@ -198,6 +198,9 @@ struct gcc_target
linker to not dead code strip this symbol. */
void (*mark_decl_preserved) (const char *);
/* Output the definition of a section anchor. */
void (*output_anchor) (rtx);
/* Output a DTP-relative reference to a TLS symbol. */
void (*output_dwarf_dtprel) (FILE *file, int size, rtx x);
@ -421,6 +424,16 @@ struct gcc_target
/* Given an address RTX, undo the effects of LEGITIMIZE_ADDRESS. */
rtx (* delegitimize_address) (rtx);
/* True if the given constant can be put into an object_block. */
bool (* use_blocks_for_constant_p) (enum machine_mode, rtx);
/* The minimum and maximum byte offsets for anchored addresses. */
HOST_WIDE_INT min_anchor_offset;
HOST_WIDE_INT max_anchor_offset;
/* True if section anchors can be used to access the given symbol. */
bool (* use_anchors_for_symbol_p) (rtx);
/* True if it is OK to do sibling call optimization for the specified
call expression EXP. DECL will be the called function, or NULL if
this is an indirect call. */

View File

@ -1022,6 +1022,8 @@ compile_file (void)
if (flag_mudflap)
mudflap_finish_file ();
output_object_blocks ();
/* Write out any pending weak symbol declarations. */
weak_finish ();
@ -1498,6 +1500,20 @@ general_init (const char *argv0)
init_optimization_passes ();
}
/* Return true if the current target supports -fsection-anchors. */
static bool
target_supports_section_anchors_p (void)
{
if (targetm.min_anchor_offset == 0 && targetm.max_anchor_offset == 0)
return false;
if (targetm.asm_out.output_anchor == NULL)
return false;
return true;
}
/* Process the options that have been parsed. */
static void
process_options (void)
@ -1520,6 +1536,13 @@ process_options (void)
OVERRIDE_OPTIONS;
#endif
if (flag_section_anchors && !target_supports_section_anchors_p ())
{
warning (OPT_fsection_anchors,
"this target does not support %qs", "-fsection-anchors");
flag_section_anchors = 0;
}
if (flag_short_enums == 2)
flag_short_enums = targetm.default_short_enums ();
@ -1578,6 +1601,9 @@ process_options (void)
if (flag_unit_at_a_time && ! lang_hooks.callgraph.expand_function)
flag_unit_at_a_time = 0;
if (!flag_unit_at_a_time)
flag_section_anchors = 0;
if (flag_value_profile_transformations)
flag_profile_values = 1;

View File

@ -2416,7 +2416,7 @@ prepare_decl_rtl (tree *expr_p, int *ws, void *data)
expr_p = &TREE_OPERAND (*expr_p, 0))
continue;
obj = *expr_p;
if (DECL_P (obj))
if (DECL_P (obj) && !DECL_RTL_SET_P (obj))
x = produce_memory_decl_rtl (obj, regno);
break;

View File

@ -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,43 +2926,16 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
output_constant_def_contents (symbol);
}
/* We must output the constant data referred to by SYMBOL; do so. */
/* 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
output_constant_def_contents (rtx symbol)
assemble_constant_contents (tree exp, const char *label, unsigned int align)
{
tree exp = SYMBOL_REF_DECL (symbol);
const char *label = XSTR (symbol, 0);
HOST_WIDE_INT size;
/* 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));
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));
}
size = int_size_in_bytes (TREE_TYPE (exp));
if (TREE_CODE (exp) == STRING_CST)
size = MAX (TREE_STRING_LENGTH (exp), size);
size = get_constant_size (exp);
/* Do any machine/system dependent processing of the constant. */
#ifdef ASM_DECLARE_CONSTANT_NAME
@ -2724,6 +2947,36 @@ output_constant_def_contents (rtx symbol)
/* 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);
unsigned int align;
/* Make sure any other constants whose addresses appear in EXP
are assigned label numbers. */
output_addressed_constants (exp);
/* We are no longer deferring this constant. */
TREE_ASM_WRITTEN (exp) = 1;
/* 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 (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);
}
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"