From 912f2dacdf24c5dde0a5a879c70fbd8ba6f45fa3 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Fri, 27 Jan 2006 22:23:32 +0000 Subject: [PATCH] re PR rtl-optimization/24762 ([killloop-branch] code motion of non-invariant expressions with hard registers.) 2006-01-27 Daniel Berlin Kenneth Zadeck PR rtl-optimization/24762 * doc/tm.texi: Added TARGET_EXTRA_LIVE_ON_ENTRY. * targhooks.c (hook_void_bitmap): New hook prototype. * targhoohs.h (hook_void_bitmap): Ditto. * bitmap.h (bitmap_head_def): Moved to coretypes.h. * coretypes.h (bitmap_head_def): Moved from bitmap.h. * target.h (live_on_entry): New function pointer. * df-scan.c (df_all_hard_regs): Removed. (df_scan_dump, df_hard_reg_init): Removed df_all_hard_regs. (df_scan_free_internal): Added df->entry_block_defs. (df_scan_alloc): Ditto. (df_scan_dump): Ditto. (df_uses_record): Plumbed flag field properly thru calls. Record EH_RETURN_DATA_REGNO in eh blocks unconditionally. This part fixes PR24762. (df_bb_refs_record): Added code to make the frame and arg pointers live in EH blocks. (df_refs_record): Added call to df_record_entry_block_defs. (df_record_entry_block_defs): New function. * df-core.c: Added comments to describe new artifical defs. * df.h (DF_REF_DIES_AFTER_THIS_USE): New flag in enum df_ref_flags. (entry_block_defs): New field in struct df. (df_all_hard_regs): Deleted. * target-def.h: Added TARGET_EXTRA_LIVE_ON_ENTRY. * df-problems.c (df_ru_bb_local_compute_process_def): Added code to handle artifical defs in the entry to a function. (df_ru_bb_local_compute): Ditto. (df_rd_bb_local_compute_process_def): Ditto. (df_rd_bb_local_compute): Ditto. (df_lr_bb_local_compute): Ditto. (df_ur_bb_local_compute): Ditto. (df_urec_bb_local_compute): Ditto. (df_chain_create_bb): Ditto. (df_ur_local_finalize): Removed entry. (df_urec_init): Ditto. (df_urec_local_finalize): Ditto. (df_ri_bb_compute): Added detection of last use of pseudos. * Makefile.in (df-scan.o): Updated dependencies. * config/mips/mips-protos.h (mips_set_live_on_entry): Added. * config/mips/mips.c (mips_set_live_on_entry): Added. * config/mips/mips.c (TARGET_EXTRA_LIVE_ON_ENTRY): Added value for target hook. * dce.c (marked_insn_p): Added code to handle artifical defs. Co-Authored-By: Kenneth Zadeck From-SVN: r110312 --- gcc/ChangeLog | 47 ++++++++ gcc/Makefile.in | 6 +- gcc/bitmap.h | 2 - gcc/config/mips/mips-protos.h | 1 + gcc/config/mips/mips.c | 19 +++ gcc/coretypes.h | 2 + gcc/df-core.c | 29 +++-- gcc/df-problems.c | 273 ++++++++++++++++++++++-------------------- gcc/df-scan.c | 209 +++++++++++++++++++++++++------- gcc/df.h | 15 ++- gcc/doc/tm.texi | 9 ++ gcc/target-def.h | 5 + gcc/target.h | 5 + gcc/targhooks.c | 5 + gcc/targhooks.h | 1 + 15 files changed, 440 insertions(+), 188 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7990d2f..867b674 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,50 @@ +2006-01-27 Daniel Berlin + Kenneth Zadeck + + PR rtl-optimization/24762 + * doc/tm.texi: Added TARGET_EXTRA_LIVE_ON_ENTRY. + * targhooks.c (hook_void_bitmap): New hook prototype. + * targhoohs.h (hook_void_bitmap): Ditto. + * bitmap.h (bitmap_head_def): Moved to coretypes.h. + * coretypes.h (bitmap_head_def): Moved from bitmap.h. + * target.h (live_on_entry): New function pointer. + * df-scan.c (df_all_hard_regs): Removed. + (df_scan_dump, df_hard_reg_init): Removed df_all_hard_regs. + (df_scan_free_internal): Added df->entry_block_defs. + (df_scan_alloc): Ditto. + (df_scan_dump): Ditto. + (df_uses_record): Plumbed flag field properly thru calls. + Record EH_RETURN_DATA_REGNO in eh blocks unconditionally. + This part fixes PR24762. + (df_bb_refs_record): Added code to make the frame and arg + pointers live in EH blocks. + (df_refs_record): Added call to df_record_entry_block_defs. + (df_record_entry_block_defs): New function. + * df-core.c: Added comments to describe new artifical defs. + * df.h (DF_REF_DIES_AFTER_THIS_USE): New flag in enum df_ref_flags. + (entry_block_defs): New field in struct df. + (df_all_hard_regs): Deleted. + * target-def.h: Added TARGET_EXTRA_LIVE_ON_ENTRY. + * df-problems.c (df_ru_bb_local_compute_process_def): + Added code to handle artifical defs in the entry to a function. + (df_ru_bb_local_compute): Ditto. + (df_rd_bb_local_compute_process_def): Ditto. + (df_rd_bb_local_compute): Ditto. + (df_lr_bb_local_compute): Ditto. + (df_ur_bb_local_compute): Ditto. + (df_urec_bb_local_compute): Ditto. + (df_chain_create_bb): Ditto. + (df_ur_local_finalize): Removed entry. + (df_urec_init): Ditto. + (df_urec_local_finalize): Ditto. + (df_ri_bb_compute): Added detection of last use of pseudos. + * Makefile.in (df-scan.o): Updated dependencies. + * config/mips/mips-protos.h (mips_set_live_on_entry): Added. + * config/mips/mips.c (mips_set_live_on_entry): Added. + * config/mips/mips.c (TARGET_EXTRA_LIVE_ON_ENTRY): Added value + for target hook. + * dce.c (marked_insn_p): Added code to handle artifical defs. + 2006-01-27 H.J. Lu * config/i386/emmintrin.h (_mm_cvtsd_f64): Add missing Intel diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 257fc6a..e28677c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2337,9 +2337,9 @@ df-problems.o : df-problems.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \ $(FLAGS_H) output.h df-scan.o : df-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h hard-reg-set.h \ - $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) $(FLAGS_H) \ - output.h + insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \ + hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \ + $(FLAGS_H) $(TARGET_H) $(TARGET_DEF_H) $(TREE_H) output.h tree-pass.h var-tracking.o : var-tracking.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \ $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \ diff --git a/gcc/bitmap.h b/gcc/bitmap.h index fb56e4e..216616d 100644 --- a/gcc/bitmap.h +++ b/gcc/bitmap.h @@ -77,8 +77,6 @@ typedef struct bitmap_head_def GTY(()) { } bitmap_head; -typedef struct bitmap_head_def *bitmap; - /* Global data */ extern bitmap_element bitmap_zero_bits; /* Zero bitmap element */ extern bitmap_obstack bitmap_default_obstack; /* Default bitmap obstack */ diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 9481b08..59dbc64 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -119,6 +119,7 @@ extern bool mips_legitimate_address_p (enum machine_mode, rtx, int); extern rtx mips_unspec_address (rtx, enum mips_symbol_type); extern bool mips_legitimize_address (rtx *, enum machine_mode); extern bool mips_legitimize_move (enum machine_mode, rtx, rtx); +extern void mips_set_live_on_entry (void *); extern int m16_uimm3_b (rtx, enum machine_mode); extern int m16_simm4_1 (rtx, enum machine_mode); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 5a655f6..fea14a7 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -56,6 +56,7 @@ Boston, MA 02110-1301, USA. */ #include "cfglayout.h" #include "sched-int.h" #include "tree-gimple.h" +#include "bitmap.h" /* True if X is an unspec wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ @@ -407,6 +408,7 @@ static rtx mips_expand_builtin_compare (enum mips_builtin_type, rtx, tree); static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx); static void mips_encode_section_info (tree, rtx, int); +static void mips_extra_live_on_entry (bitmap); /* Structure to be filled in by compute_frame_size with register save masks, and offsets for the current function. */ @@ -1160,6 +1162,12 @@ static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] = #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE mips_attribute_table +#undef TARGET_EXTRA_LIVE_ON_ENTRY +/* With -mabicalls (which is the default on GNU/Linux), + PIC_FUNCTION_ADDR_REGNUM is live on function entry and is to + initialize $28, which is PIC_OFFSET_TABLE_REGNUM. */ +#define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry + struct gcc_target targetm = TARGET_INITIALIZER; /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ @@ -10764,5 +10772,16 @@ mips_encode_section_info (tree decl, rtx rtl, int first) SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL; } } + +/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. TARGET_ABICALLS makes + PIC_FUNCTION_ADDR_REGNUM live on entry to a function. */ + +static void +mips_extra_live_on_entry (bitmap regs) +{ + if (!TARGET_ABICALLS) + bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM); +} + #include "gt-mips.h" diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 7942459..6173bd8 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -37,6 +37,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #ifndef USED_FOR_TARGET +struct bitmap_head_def; +typedef struct bitmap_head_def *bitmap; struct rtx_def; typedef struct rtx_def *rtx; struct rtvec_def; diff --git a/gcc/df-core.c b/gcc/df-core.c index a0ed23c..416406b 100644 --- a/gcc/df-core.c +++ b/gcc/df-core.c @@ -205,18 +205,23 @@ There are 4 ways to obtain access to refs: defs and uses are only there if DF_HARD_REGS was specified when the df instance was created. - Artificial defs and uses occur at the beginning blocks that are the - destination of eh edges. The defs come from the registers - specified in EH_RETURN_DATA_REGNO and the uses come from the - registers specified in ED_USES. Logically these defs and uses - should really occur along the eh edge, but there is no convienent - way to do this. Artificial edges that occur at the beginning of - the block have the DF_REF_AT_TOP flag set. - - Artificial uses also occur at the end of all blocks. These arise - from the hard registers that are always live, such as the stack - register and are put there to keep the code from forgetting about - them. + Artificial defs and uses occur both at the beginning and ends of blocks. + + For blocks that area at the destination of eh edges, the + artificial uses and defs occur at the beginning. The defs relate + to the registers specified in EH_RETURN_DATA_REGNO and the uses + relate to the registers specified in ED_USES. Logically these + defs and uses should really occur along the eh edge, but there is + no convenient way to do this. Artificial edges that occur at the + beginning of the block have the DF_REF_AT_TOP flag set. + + Artificial uses occur at the end of all blocks. These arise from + the hard registers that are always live, such as the stack + register and are put there to keep the code from forgetting about + them. + + Artifical defs occur at the end of the entry block. These arise + from registers that are live at entry to the function. 2) All of the uses and defs associated with each pseudo or hard register are linked in a bidirectional chain. These are called diff --git a/gcc/df-problems.c b/gcc/df-problems.c index fdba180..2d3fc10 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -298,7 +298,7 @@ struct df_ru_problem_data unsigned int use_sites_size; /* Size of use_sites. */ /* The set of defs to regs invalidated by call. */ bitmap sparse_invalidated_by_call; - /* The set of defs to regs invalidate by call for ru. */ + /* The set of defs to regs invalidated by call for ru. */ bitmap dense_invalidated_by_call; }; @@ -429,37 +429,41 @@ df_ru_alloc (struct dataflow *dflow, bitmap blocks_to_rescan) static void df_ru_bb_local_compute_process_def (struct dataflow *dflow, struct df_ru_bb_info *bb_info, - struct df_ref *def) + struct df_ref *def, + enum df_ref_flags top_flag) { struct df *df = dflow->df; while (def) { - unsigned int regno = DF_REF_REGNO (def); - unsigned int begin = DF_REG_USE_GET (df, regno)->begin; - unsigned int n_uses = DF_REG_USE_GET (df, regno)->n_refs; - if (!bitmap_bit_p (seen_in_block, regno)) + if (top_flag == (DF_REF_FLAGS (def) & DF_REF_AT_TOP)) { - /* The first def for regno, causes the kill info to be - generated and the gen information to cleared. */ - if (!bitmap_bit_p (seen_in_insn, regno)) + unsigned int regno = DF_REF_REGNO (def); + unsigned int begin = DF_REG_USE_GET (df, regno)->begin; + unsigned int n_uses = DF_REG_USE_GET (df, regno)->n_refs; + if (!bitmap_bit_p (seen_in_block, regno)) { - if (n_uses > DF_SPARSE_THRESHOLD) - { - bitmap_set_bit (bb_info->sparse_kill, regno); - bitmap_clear_range (bb_info->gen, begin, n_uses); - } - else + /* The first def for regno, causes the kill info to be + generated and the gen information to cleared. */ + if (!bitmap_bit_p (seen_in_insn, regno)) { - struct df_ru_problem_data *problem_data = - (struct df_ru_problem_data *) dflow->problem_data; - bitmap uses = - df_ref_bitmap (problem_data->use_sites, regno, - begin, n_uses); - bitmap_ior_into (bb_info->kill, uses); - bitmap_and_compl_into (bb_info->gen, uses); + if (n_uses > DF_SPARSE_THRESHOLD) + { + bitmap_set_bit (bb_info->sparse_kill, regno); + bitmap_clear_range (bb_info->gen, begin, n_uses); + } + else + { + struct df_ru_problem_data * problem_data = + (struct df_ru_problem_data *)dflow->problem_data; + bitmap uses = + df_ref_bitmap (problem_data->use_sites, regno, + begin, n_uses); + bitmap_ior_into (bb_info->kill, uses); + bitmap_and_compl_into (bb_info->gen, uses); + } } + bitmap_set_bit (seen_in_insn, regno); } - bitmap_set_bit (seen_in_insn, regno); } def = def->next_ref; } @@ -508,11 +512,9 @@ df_ru_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) df_get_artificial_uses (df, bb_index), DF_REF_AT_TOP); #endif - - /* Process the artificial defs first since these are at the top of - the block. */ df_ru_bb_local_compute_process_def (dflow, bb_info, - df_get_artificial_defs (df, bb_index)); + df_get_artificial_defs (df, bb_index), + DF_REF_AT_TOP); FOR_BB_INSNS (bb, insn) { @@ -521,7 +523,7 @@ df_ru_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) continue; df_ru_bb_local_compute_process_def (dflow, bb_info, - DF_INSN_UID_GET (df, uid)->defs); + DF_INSN_UID_GET (df, uid)->defs, 0); /* The use processing must happen after the defs processing even though the uses logically happen first since the defs clear @@ -537,6 +539,9 @@ df_ru_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) /* Process the hardware registers that are always live. */ df_ru_bb_local_compute_process_use (bb_info, df_get_artificial_uses (df, bb_index), 0); + + df_ru_bb_local_compute_process_def (dflow, bb_info, + df_get_artificial_defs (df, bb_index), 0); } @@ -948,45 +953,49 @@ df_rd_alloc (struct dataflow *dflow, bitmap blocks_to_rescan) static void df_rd_bb_local_compute_process_def (struct dataflow *dflow, struct df_rd_bb_info *bb_info, - struct df_ref *def) + struct df_ref *def, + enum df_ref_flags top_flag) { struct df *df = dflow->df; while (def) { - unsigned int regno = DF_REF_REGNO (def); - unsigned int begin = DF_REG_DEF_GET (df, regno)->begin; - unsigned int n_defs = DF_REG_DEF_GET (df, regno)->n_refs; - - /* Only the last def(s) for a regno in the block has any - effect. */ - if (!bitmap_bit_p (seen_in_block, regno)) + if (top_flag == (DF_REF_FLAGS (def) & DF_REF_AT_TOP)) { - /* The first def for regno in insn gets to knock out the - defs from other instructions. */ - if (!bitmap_bit_p (seen_in_insn, regno)) + unsigned int regno = DF_REF_REGNO (def); + unsigned int begin = DF_REG_DEF_GET (df, regno)->begin; + unsigned int n_defs = DF_REG_DEF_GET (df, regno)->n_refs; + + /* Only the last def(s) for a regno in the block has any + effect. */ + if (!bitmap_bit_p (seen_in_block, regno)) { - if (n_defs > DF_SPARSE_THRESHOLD) - { - bitmap_set_bit (bb_info->sparse_kill, regno); - bitmap_clear_range (bb_info->gen, begin, n_defs); - } - else + /* The first def for regno in insn gets to knock out the + defs from other instructions. */ + if (!bitmap_bit_p (seen_in_insn, regno)) { - struct df_rd_problem_data *problem_data = - (struct df_rd_problem_data *) dflow->problem_data; - bitmap defs = - df_ref_bitmap (problem_data->def_sites, regno, - begin, n_defs); - bitmap_ior_into (bb_info->kill, defs); - bitmap_and_compl_into (bb_info->gen, defs); + if (n_defs > DF_SPARSE_THRESHOLD) + { + bitmap_set_bit (bb_info->sparse_kill, regno); + bitmap_clear_range(bb_info->gen, begin, n_defs); + } + else + { + struct df_rd_problem_data * problem_data = + (struct df_rd_problem_data *)dflow->problem_data; + bitmap defs = + df_ref_bitmap (problem_data->def_sites, regno, + begin, n_defs); + bitmap_ior_into (bb_info->kill, defs); + bitmap_and_compl_into (bb_info->gen, defs); + } } + + bitmap_set_bit (seen_in_insn, regno); + /* All defs for regno in the instruction may be put into + the gen set. */ + if (! (DF_REF_FLAGS (def) & DF_REF_CLOBBER)) + bitmap_set_bit (bb_info->gen, DF_REF_ID (def)); } - - bitmap_set_bit (seen_in_insn, regno); - /* All defs for regno in the instruction may be put into - the gen set. */ - if (! (DF_REF_FLAGS (def) & DF_REF_CLOBBER)) - bitmap_set_bit (bb_info->gen, DF_REF_ID (def)); } def = def->next_ref; } @@ -1005,6 +1014,9 @@ df_rd_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) bitmap_clear (seen_in_block); bitmap_clear (seen_in_insn); + df_rd_bb_local_compute_process_def (dflow, bb_info, + df_get_artificial_defs (df, bb_index), 0); + FOR_BB_INSNS_REVERSE (bb, insn) { unsigned int uid = INSN_UID (insn); @@ -1013,7 +1025,7 @@ df_rd_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) continue; df_rd_bb_local_compute_process_def (dflow, bb_info, - DF_INSN_UID_GET (df, uid)->defs); + DF_INSN_UID_GET (df, uid)->defs, 0); /* This complex dance with the two bitmaps is required because instructions can assign twice to the same pseudo. This @@ -1025,10 +1037,12 @@ df_rd_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) bitmap_clear (seen_in_insn); } - /* Process the artificial defs last since we are going backwards - thur the block and these are logically at the start. */ + /* Process the artificial defs at the top of the block last since we + are going backwards through the block and these are logically at + the start. */ df_rd_bb_local_compute_process_def (dflow, bb_info, - df_get_artificial_defs (df, bb_index)); + df_get_artificial_defs (df, bb_index), + DF_REF_AT_TOP); } @@ -1395,6 +1409,15 @@ df_lr_bb_local_compute (struct dataflow *dflow, struct df_ref *def; struct df_ref *use; + /* Process the registers set in an exception handler. */ + for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) + if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0) + { + unsigned int dregno = DF_REF_REGNO (def); + bitmap_set_bit (bb_info->def, dregno); + bitmap_clear_bit (bb_info->use, dregno); + } + /* Process the hardware registers that are always live. */ for (use = df_get_artificial_uses (df, bb_index); use; use = use->next_ref) /* Add use to set of uses in this BB. */ @@ -1455,12 +1478,13 @@ df_lr_bb_local_compute (struct dataflow *dflow, /* Process the registers set in an exception handler. */ for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) - { - unsigned int dregno = DF_REF_REGNO (def); - bitmap_set_bit (bb_info->def, dregno); - bitmap_clear_bit (bb_info->use, dregno); - } - + if (DF_REF_FLAGS (def) & DF_REF_AT_TOP) + { + unsigned int dregno = DF_REF_REGNO (def); + bitmap_set_bit (bb_info->def, dregno); + bitmap_clear_bit (bb_info->use, dregno); + } + #ifdef EH_USES /* Process the uses that are live into an exception handler. */ for (use = df_get_artificial_uses (df, bb_index); use; use = use->next_ref) @@ -1783,6 +1807,17 @@ df_ur_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) bitmap_clear (seen_in_block); bitmap_clear (seen_in_insn); + for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) + if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0) + { + unsigned int regno = DF_REF_REGNO (def); + if (!bitmap_bit_p (seen_in_block, regno)) + { + bitmap_set_bit (seen_in_block, regno); + bitmap_set_bit (bb_info->gen, regno); + } + } + FOR_BB_INSNS_REVERSE (bb, insn) { unsigned int uid = INSN_UID (insn); @@ -1808,14 +1843,15 @@ df_ur_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) } for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) - { - unsigned int regno = DF_REF_REGNO (def); - if (!bitmap_bit_p (seen_in_block, regno)) - { - bitmap_set_bit (seen_in_block, regno); - bitmap_set_bit (bb_info->gen, regno); - } - } + if (DF_REF_FLAGS (def) & DF_REF_AT_TOP) + { + unsigned int regno = DF_REF_REGNO (def); + if (!bitmap_bit_p (seen_in_block, regno)) + { + bitmap_set_bit (seen_in_block, regno); + bitmap_set_bit (bb_info->gen, regno); + } + } } @@ -1875,9 +1911,6 @@ df_ur_local_finalize (struct dataflow *dflow, bitmap all_blocks) struct df_ur_bb_info *bb_info = df_ur_get_bb_info (dflow, bb_index); struct df_lr_bb_info *bb_lr_info = df_lr_get_bb_info (lr_dflow, bb_index); - bitmap_ior_into (bb_info->in, df_all_hard_regs); - bitmap_ior_into (bb_info->out, df_all_hard_regs); - /* No register may reach a location where it is not used. Thus we trim the rr result to the places where it is used. */ bitmap_and_into (bb_info->in, bb_lr_info->in); @@ -2336,11 +2369,12 @@ df_urec_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) struct df_ref *def; for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) - { - unsigned int regno = DF_REF_REGNO (def); - bitmap_set_bit (bb_info->gen, regno); - } - + if (DF_REF_FLAGS (def) & DF_REF_AT_TOP) + { + unsigned int regno = DF_REF_REGNO (def); + bitmap_set_bit (bb_info->gen, regno); + } + FOR_BB_INSNS (bb, insn) { if (INSN_P (insn)) @@ -2357,6 +2391,14 @@ df_urec_bb_local_compute (struct dataflow *dflow, unsigned int bb_index) } } } + + for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) + if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0) + { + unsigned int regno = DF_REF_REGNO (def); + bitmap_set_bit (bb_info->gen, regno); + } + } @@ -2424,32 +2466,8 @@ df_urec_init (struct dataflow *dflow, bitmap all_blocks) { struct df_urec_bb_info *bb_info = df_urec_get_bb_info (dflow, bb_index); - /* FIXME: This is a hack, it has been copied over from - make_accurate_live_analysis by Vlad. Most likely it is necessary - because the generation of gen and kill information for hardware - registers in ur is a subset of what is really necessary and what - is done for the lr problem. */ - - /* Inside the register allocator, partial availability is only - allowed for the psuedo registers. To implement this, the rr is - initially iored with a mask ones for the hard registers and zeros - for the pseudos before being iterated. This means that each - hardware register will be live unless explicitly killed by some - statement. Eventually most of these bit will die because the - results of rr are anded with the results of lr before being used. - Outside of register allocation, a more conservative strategy of - completely ignoring the unintialized registers is imployed in the - finalizer function. */ - if (df_state & DF_SCAN_GLOBAL) - { - bitmap_ior (bb_info->out, bb_info->gen, df_all_hard_regs); - bitmap_copy (bb_info->in, df_all_hard_regs); - } - else - { - bitmap_copy (bb_info->out, bb_info->gen); - bitmap_clear (bb_info->in); - } + bitmap_copy (bb_info->out, bb_info->gen); + bitmap_clear (bb_info->in); } } @@ -2489,12 +2507,6 @@ df_urec_local_finalize (struct dataflow *dflow, bitmap all_blocks) #endif } - if (!(df_state & DF_SCAN_GLOBAL)) - { - bitmap_ior_into (bb_info->in, df_all_hard_regs); - bitmap_ior_into (bb_info->out, df_all_hard_regs); - } - /* No register may reach a location where it is not used. Thus we trim the rr result to the places where it is used. */ bitmap_and_into (bb_info->in, bb_lr_info->in); @@ -2830,7 +2842,7 @@ df_chain_create_bb_process_use (struct dataflow *dflow, while (use) { - /* Do not want to go thur this for an uninitialized var. */ + /* Do not want to go through this for an uninitialized var. */ unsigned int uregno = DF_REF_REGNO (use); int count = DF_REG_DEF_GET (df, uregno)->n_refs; if (count) @@ -2891,14 +2903,15 @@ df_chain_create_bb (struct dataflow *dflow, #endif for (def = df_get_artificial_defs (df, bb_index); def; def = def->next_ref) - { - unsigned int dregno = DF_REF_REGNO (def); - bitmap_clear_range (cpy, - DF_REG_DEF_GET (df, dregno)->begin, - DF_REG_DEF_GET (df, dregno)->n_refs); - if (! (DF_REF_FLAGS (def) & DF_REF_CLOBBER)) - bitmap_set_bit (cpy, DF_REF_ID (def)); - } + if (DF_REF_FLAGS (def) & DF_REF_AT_TOP) + { + unsigned int dregno = DF_REF_REGNO (def); + bitmap_clear_range (cpy, + DF_REG_DEF_GET (df, dregno)->begin, + DF_REG_DEF_GET (df, dregno)->n_refs); + if (! (DF_REF_FLAGS (def) & DF_REF_CLOBBER)) + bitmap_set_bit (cpy, DF_REF_ID (def)); + } /* Process the regular instructions next. */ FOR_BB_INSNS (bb, insn) @@ -3136,8 +3149,14 @@ df_ri_bb_compute (struct dataflow *dflow, unsigned int bb_index, bitmap live) { unsigned int uregno = DF_REF_REGNO (use); - /* This register is now live. */ - bitmap_set_bit (live, uregno); + if (!bitmap_bit_p (live, uregno)) + { + use->flags |= DF_REF_DIES_AFTER_THIS_USE; + /* This register is now live. */ + bitmap_set_bit (live, uregno); + } + else + use->flags &= ~DF_REF_DIES_AFTER_THIS_USE; } /* Increment lifetimes of all live registers. */ diff --git a/gcc/df-scan.c b/gcc/df-scan.c index bba89e7..affc6df 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -46,6 +46,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "sbitmap.h" #include "bitmap.h" #include "timevar.h" +#include "tree.h" +#include "target.h" +#include "target-def.h" #include "df.h" #ifndef HAVE_epilogue @@ -82,8 +85,6 @@ bitmap df_invalidated_by_call = NULL; /* Initialize ur_in and ur_out as if all hard registers were partially available. */ -bitmap df_all_hard_regs = NULL; - static void df_ref_record (struct dataflow *, rtx, rtx *, basic_block, rtx, enum df_ref_type, enum df_ref_flags, bool record_live); @@ -99,6 +100,7 @@ static void df_refs_record (struct dataflow *, bitmap); static struct df_ref *df_ref_create_structure (struct dataflow *, rtx, rtx *, basic_block, rtx, enum df_ref_type, enum df_ref_flags); +static void df_record_entry_block_defs (struct dataflow *); static void df_record_exit_block_uses (struct dataflow *); static void df_grow_reg_info (struct dataflow *, struct df_ref_info *); static void df_grow_ref_info (struct df_ref_info *, unsigned int); @@ -148,6 +150,7 @@ df_scan_free_internal (struct dataflow *dflow) dflow->block_info_size = 0; BITMAP_FREE (df->hardware_regs_used); + BITMAP_FREE (df->entry_block_defs); BITMAP_FREE (df->exit_block_uses); free_alloc_pool (dflow->block_pool); @@ -252,6 +255,7 @@ df_scan_alloc (struct dataflow *dflow, bitmap blocks_to_rescan) } df->hardware_regs_used = BITMAP_ALLOC (NULL); + df->entry_block_defs = BITMAP_ALLOC (NULL); df->exit_block_uses = BITMAP_ALLOC (NULL); } @@ -284,12 +288,12 @@ df_scan_dump (struct dataflow *dflow ATTRIBUTE_UNUSED, FILE *file ATTRIBUTE_UNUS struct df *df = dflow->df; int i; - fprintf (file, " all hard regs \t"); - dump_bitmap (file, df_all_hard_regs); fprintf (file, " invalidated by call \t"); dump_bitmap (file, df_invalidated_by_call); fprintf (file, " hardware regs used \t"); dump_bitmap (file, df->hardware_regs_used); + fprintf (file, " entry block uses \t"); + dump_bitmap (file, df->entry_block_defs); fprintf (file, " exit block uses \t"); dump_bitmap (file, df->exit_block_uses); fprintf (file, " regs ever live \t"); @@ -1247,7 +1251,7 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, { rtx dst = SET_DEST (x); gcc_assert (!(flags & DF_REF_IN_NOTE)); - df_uses_record (dflow, &SET_SRC (x), DF_REF_REG_USE, bb, insn, 0); + df_uses_record (dflow, &SET_SRC (x), DF_REF_REG_USE, bb, insn, flags); switch (GET_CODE (dst)) { @@ -1256,7 +1260,7 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, { df_uses_record (dflow, &SUBREG_REG (dst), DF_REF_REG_USE, bb, - insn, DF_REF_READ_WRITE); + insn, flags | DF_REF_READ_WRITE); break; } /* Fall through. */ @@ -1269,7 +1273,7 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, case MEM: df_uses_record (dflow, &XEXP (dst, 0), DF_REF_REG_MEM_STORE, - bb, insn, 0); + bb, insn, flags); break; case STRICT_LOW_PART: { @@ -1290,9 +1294,9 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, DF_REF_REG_USE, bb, insn, DF_REF_READ_WRITE); df_uses_record (dflow, &XEXP (dst, 1), - DF_REF_REG_USE, bb, insn, 0); + DF_REF_REG_USE, bb, insn, flags); df_uses_record (dflow, &XEXP (dst, 2), - DF_REF_REG_USE, bb, insn, 0); + DF_REF_REG_USE, bb, insn, flags); dst = XEXP (dst, 0); break; default: @@ -1342,7 +1346,7 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++) df_uses_record (dflow, &ASM_OPERANDS_INPUT (x, j), - DF_REF_REG_USE, bb, insn, 0); + DF_REF_REG_USE, bb, insn, flags); return; } break; @@ -1355,8 +1359,9 @@ df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type, case PRE_MODIFY: case POST_MODIFY: /* Catch the def of the register being modified. */ + flags |= DF_REF_READ_WRITE; df_ref_record (dflow, XEXP (x, 0), &XEXP (x, 0), bb, insn, - DF_REF_REG_DEF, DF_REF_READ_WRITE, true); + DF_REF_REG_DEF, flags, true); /* ... Fall through to handle uses ... */ @@ -1562,41 +1567,65 @@ df_bb_refs_record (struct dataflow *dflow, basic_block bb) { unsigned int i; /* Mark the registers that will contain data for the handler. */ - if (current_function_calls_eh_return) - for (i = 0; ; ++i) - { - unsigned regno = EH_RETURN_DATA_REGNO (i); - if (regno == INVALID_REGNUM) - break; - df_ref_record (dflow, regno_reg_rtx[i], ®no_reg_rtx[i], bb, NULL, - DF_REF_REG_DEF, DF_REF_ARTIFICIAL | DF_REF_AT_TOP, false); - } + for (i = 0; ; ++i) + { + unsigned regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + df_ref_record (dflow, regno_reg_rtx[i], ®no_reg_rtx[i], bb, NULL, + DF_REF_REG_DEF, DF_REF_ARTIFICIAL | DF_REF_AT_TOP, + false); + } } #endif -#ifdef EH_USES - /* This code is putting in a artificial ref for the use at the TOP - of the block that receives the exception. It is too cumbersome - to actually put the ref on the edge. We could either model this - at the top of the receiver block or the bottom of the sender - block. - - The bottom of the sender block is problematic because not all - out-edges of the a block are eh-edges. However, it is true that - all edges into a block are either eh-edges or none of them are - eh-edges. Thus, we can model this at the top of the eh-receiver - for all of the edges at once. */ + if ((df->flags & DF_HARD_REGS) && df_has_eh_preds (bb)) { +#ifdef EH_USES unsigned int i; + /* This code is putting in a artificial ref for the use at the + TOP of the block that receives the exception. It is too + cumbersome to actually put the ref on the edge. We could + either model this at the top of the receiver block or the + bottom of the sender block. + + The bottom of the sender block is problematic because not all + out-edges of the a block are eh-edges. However, it is true + that all edges into a block are either eh-edges or none of + them are eh-edges. Thus, we can model this at the top of the + eh-receiver for all of the edges at once. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (EH_USES (i)) df_uses_record (dflow, ®no_reg_rtx[i], - DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL, - DF_REF_ARTIFICIAL | DF_REF_AT_TOP); - } + DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL, + DF_REF_ARTIFICIAL | DF_REF_AT_TOP); +#endif + + /* The following code (down thru the arg_pointer seting APPEARS + to be necessary because there is nothing that actually + describes what the exception handling code may actually need + to keep alive. */ + if (reload_completed) + { + if (frame_pointer_needed) + { + df_uses_record (dflow, ®no_reg_rtx[FRAME_POINTER_REGNUM], + DF_REF_REG_USE, bb, NULL, DF_REF_ARTIFICIAL); +#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + df_uses_record (dflow, ®no_reg_rtx[HARD_FRAME_POINTER_REGNUM], + DF_REF_REG_USE, bb, NULL, DF_REF_ARTIFICIAL); +#endif + } +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + if (fixed_regs[ARG_POINTER_REGNUM]) + df_uses_record (dflow, ®no_reg_rtx[ARG_POINTER_REGNUM], + DF_REF_REG_USE, bb, NULL, + DF_REF_ARTIFICIAL); #endif + } + } if ((df->flags & DF_HARD_REGS) && bb->index >= NUM_FIXED_BLOCKS) @@ -1652,6 +1681,9 @@ df_refs_record (struct dataflow *dflow, bitmap blocks) if (bitmap_bit_p (blocks, EXIT_BLOCK)) df_record_exit_block_uses (dflow); + + if (bitmap_bit_p (blocks, ENTRY_BLOCK)) + df_record_entry_block_defs (dflow); } @@ -1679,6 +1711,108 @@ df_mark_reg (rtx reg, void *vset) } } + +/* Record the (conservative) set of hard registers that are defined on + entry to the function. */ + +static void +df_record_entry_block_defs (struct dataflow * dflow) +{ + unsigned int i; + bitmap_iterator bi; + rtx r; + struct df * df = dflow->df; + + bitmap_clear (df->entry_block_defs); + + if (! (df->flags & DF_HARD_REGS)) + return; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (FUNCTION_ARG_REGNO_P (i)) +#ifdef INCOMING_REGNO + bitmap_set_bit (df->entry_block_defs, INCOMING_REGNO (i)); +#else + bitmap_set_bit (df->entry_block_defs, i); +#endif + } + + /* Once the prologue has been generated, all of these registers + should just show up in the first regular block. */ + if (HAVE_prologue && epilogue_completed) + { + /* Defs for the callee saved registers are inserted so that the + pushes have some defining location. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if ((call_used_regs[i] == 0) && (regs_ever_live[i])) + bitmap_set_bit (df->entry_block_defs, i); + } + else + { + if (REG_P (INCOMING_RETURN_ADDR_RTX)) + bitmap_set_bit (df->entry_block_defs, REGNO (INCOMING_RETURN_ADDR_RTX)); + + /* If STATIC_CHAIN_INCOMING_REGNUM == STATIC_CHAIN_REGNUM + only STATIC_CHAIN_REGNUM is defined. If they are different, + we only care about the STATIC_CHAIN_INCOMING_REGNUM. */ +#ifdef STATIC_CHAIN_INCOMING_REGNUM + bitmap_set_bit (df->entry_block_defs, STATIC_CHAIN_INCOMING_REGNUM); +#else +#ifdef STATIC_CHAIN_REGNUM + bitmap_set_bit (df->entry_block_defs, STATIC_CHAIN_REGNUM); +#endif +#endif + + r = TARGET_STRUCT_VALUE_RTX (current_function_decl, true); + if (r && REG_P (r)) + bitmap_set_bit (df->entry_block_defs, REGNO (r)); + } + + /* These registers are live everywhere. */ + if (!reload_completed) + { + /* Any reference to any pseudo before reload is a potential + reference of the frame pointer. */ + bitmap_set_bit (df->entry_block_defs, FRAME_POINTER_REGNUM); + +#ifdef EH_USES + /* The ia-64, the only machine that uses this, does not define these + until after reload. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (EH_USES (i)) + { + bitmap_set_bit (df->entry_block_defs, i); + } +#endif + +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + /* Pseudos with argument area equivalences may require + reloading via the argument pointer. */ + if (fixed_regs[ARG_POINTER_REGNUM]) + bitmap_set_bit (df->entry_block_defs, ARG_POINTER_REGNUM); +#endif + +#ifdef PIC_OFFSET_TABLE_REGNUM + /* Any constant, or pseudo with constant equivalences, may + require reloading from memory using the pic register. */ + if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM + && fixed_regs[PIC_OFFSET_TABLE_REGNUM]) + bitmap_set_bit (df->entry_block_defs, PIC_OFFSET_TABLE_REGNUM); +#endif + } + + (*targetm.live_on_entry) (df->entry_block_defs); + + EXECUTE_IF_SET_IN_BITMAP (df->entry_block_defs, 0, i, bi) + { + df_ref_record (dflow, regno_reg_rtx[i], ®no_reg_rtx[i], + ENTRY_BLOCK_PTR, NULL, + DF_REF_REG_DEF, DF_REF_ARTIFICIAL , false); + } +} + + /* Record the set of hard registers that are used in the exit block. */ static void @@ -1827,10 +1961,5 @@ df_hard_reg_init (void) if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) bitmap_set_bit (df_invalidated_by_call, i); - df_all_hard_regs = BITMAP_ALLOC (&persistent_obstack); - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - bitmap_set_bit (df_all_hard_regs, i); - initialized = true; } diff --git a/gcc/df.h b/gcc/df.h index f2e7bef..8c5108e3 100644 --- a/gcc/df.h +++ b/gcc/df.h @@ -211,7 +211,12 @@ enum df_ref_flags DF_REF_IN_NOTE = 16, /* This flag is set if this ref is really a clobber, and not a def. */ - DF_REF_CLOBBER = 32 + DF_REF_CLOBBER = 32, + + /* True if ref is dead (i.e. the next ref is a def or clobber or + the end of the function.) This is only valid the RI problem + has been set in this df instance. */ + DF_REF_DIES_AFTER_THIS_USE = 64 }; @@ -223,7 +228,10 @@ struct df_ref rtx reg; /* The register referenced. */ unsigned int regno; /* The register number referenced. */ basic_block bb; /* Basic block containing the instruction. */ - rtx insn; /* Insn containing ref. NB: THIS MAY BE NULL. */ + + /* Insn containing ref. This will be null if this is an artificial + reference. */ + rtx insn; rtx *loc; /* The location of the reg. */ struct df_link *chain; /* Head of def-use, use-def. */ unsigned int id; /* Location in table. */ @@ -316,6 +324,7 @@ struct df struct df_insn_info **insns; /* Insn table, indexed by insn UID. */ unsigned int insns_size; /* Size of insn table. */ bitmap hardware_regs_used; /* The set of hardware registers used. */ + bitmap entry_block_defs; /* The set of hardware registers live on entry to the function. */ bitmap exit_block_uses; /* The set of hardware registers used in exit block. */ }; @@ -422,8 +431,6 @@ extern bitmap df_invalidated_by_call; /* Initialize ur_in and ur_out as if all hard registers were partially available. */ -extern bitmap df_all_hard_regs; - /* The way that registers are processed, especially hard registers, changes as the compilation proceeds. These states are passed to df_set_state to control this processing. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 7bd8522..d60fc13 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4481,6 +4481,15 @@ as the @code{sibcall} md pattern can not fail, or fall over to a may vary greatly between different architectures. @end deftypefn +@deftypefn {Target Hook} void TARGET_EXTRA_LIVE_ON_ENTRY (bitmap *@var{regs}) +Add any hard registers to @var{regs} that are live on entry to the +function. This hook only needs to be defined to provide registers that +cannot be found by examination of FUNCTION_ARG_REGNO_P, the callee saved +registers, STATIC_CHAIN_INCOMING_REGNUM, STATIC_CHAIN_REGNUM, +TARGET_STRUCT_VALUE_RTX, FRAME_POINTER_REGNUM, EH_USES, +FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM, and the PIC_OFFSET_TABLE_REGNUM. +@end deftypefn + @node Stack Smashing Protection @subsection Stack smashing protection @cindex stack smashing protection diff --git a/gcc/target-def.h b/gcc/target-def.h index 642e970..7599101 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -185,6 +185,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_ASM_FILE_END hook_void_void #endif +#ifndef TARGET_EXTRA_LIVE_ON_ENTRY +#define TARGET_EXTRA_LIVE_ON_ENTRY hook_void_bitmap +#endif + #ifndef TARGET_ASM_FILE_START_APP_OFF #define TARGET_ASM_FILE_START_APP_OFF false #endif @@ -625,6 +629,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. TARGET_INVALID_BINARY_OP, \ TARGET_SECONDARY_RELOAD, \ TARGET_CXX, \ + TARGET_EXTRA_LIVE_ON_ENTRY, \ TARGET_UNWIND_TABLES_DEFAULT, \ TARGET_HAVE_NAMED_SECTIONS, \ TARGET_HAVE_CTORS_DTORS, \ diff --git a/gcc/target.h b/gcc/target.h index b32be83..36f2463 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -703,6 +703,11 @@ struct gcc_target target modifications). */ void (*adjust_class_at_definition) (tree type); } cxx; + + /* For targets that need to mark extra registers as live on entry to + the function, they should define this target hook and set their + bits in the bitmap passed in. */ + void (*live_on_entry) (bitmap); /* True if unwinding tables should be generated by default. */ bool unwind_tables_default; diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 786b152..f6289c8 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -337,6 +337,11 @@ hook_int_CUMULATIVE_ARGS_mode_tree_bool_0 ( return 0; } +void +hook_void_bitmap (bitmap regs ATTRIBUTE_UNUSED) +{ +} + const char * hook_invalid_arg_for_unprototyped_fn ( tree typelist ATTRIBUTE_UNUSED, diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 4439648..05d1add 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -74,3 +74,4 @@ extern rtx default_internal_arg_pointer (void); extern enum reg_class default_secondary_reload (bool, rtx, enum reg_class, enum machine_mode, secondary_reload_info *); +extern void hook_void_bitmap (bitmap); -- 2.7.4