Commit 62551c66 by Jan Hubicka Committed by Jan Hubicka

Makefile.in (web.o): New.


	* Makefile.in (web.o): New.
	* web.c: New file.
	* rtl.h (web_main): Declare.
	* timervar.def (TV_WEB): New.
	* toplev.c (dump_file_index, dump_file_info): Add DFI_web.
	(rest_of_hanle_web): New.
	(flag_web): New static variable.
	(lang_independent_options): Add "web".
	(rest_of_compilation): Call rest_of_handle_web.
	* invoke.texi (-fweb): Document.
	* common.opt (fweb): New.
	* flags.h (flag_web): New.
	* opts.c (decode_options): Set flag_web at -O3.

	* passes.texi (web construction):  Document.
	* invoke.texi (-O3): Document that -fweb is enabled.

	* regrename.c (regrename_optimize): Deal better with situation when
	replacement failed.

	* sched-ebb.c: Include params.h and profile.h
	(schedule_ebbs):  Use tracer parameters to discover superblocks
	* Makefile.in (sched-ebb.o):  Add dependencies.

From-SVN: r72383
parent 05d362b8
2003-10-11 Jan Hubicka <jh@suse.cz>
* Makefile.in (web.o): New.
* web.c: New file.
* rtl.h (web_main): Declare.
* timervar.def (TV_WEB): New.
* toplev.c (dump_file_index, dump_file_info): Add DFI_web.
(rest_of_hanle_web): New.
(flag_web): New static variable.
(lang_independent_options): Add "web".
(rest_of_compilation): Call rest_of_handle_web.
* invoke.texi (-fweb): Document.
* common.opt (fweb): New.
* flags.h (flag_web): New.
* opts.c (decode_options): Set flag_web at -O3.
* passes.texi (web construction): Document.
* invoke.texi (-O3): Document that -fweb is enabled.
* regrename.c (regrename_optimize): Deal better with situation when
replacement failed.
* sched-ebb.c: Include params.h and profile.h
(schedule_ebbs): Use tracer parameters to discover superblocks
* Makefile.in (sched-ebb.o): Add dependencies.
2003-10-11 Roger Sayle <roger@eyesopen.com> 2003-10-11 Roger Sayle <roger@eyesopen.com>
* fold-const.c (negate_mathfn_p): New function to determine whether * fold-const.c (negate_mathfn_p): New function to determine whether
......
...@@ -847,7 +847,7 @@ OBJS-common = \ ...@@ -847,7 +847,7 @@ OBJS-common = \
sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \ sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \
stor-layout.o stringpool.o targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o \ stor-layout.o stringpool.o targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \ unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
alloc-pool.o et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) alloc-pool.o et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o
OBJS-md = $(out_object_file) OBJS-md = $(out_object_file)
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \
...@@ -1622,6 +1622,8 @@ cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ ...@@ -1622,6 +1622,8 @@ cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \ output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \
except.h $(TARGET_H) $(PARAMS_H) except.h $(TARGET_H) $(PARAMS_H)
web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h $(BASIC_BLOCK_H) function.h output.h toplev.h df.h
gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h $(GGC_H) $(RECOG_H) $(EXPR_H) \ hard-reg-set.h flags.h real.h insn-config.h $(GGC_H) $(RECOG_H) $(EXPR_H) \
$(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h $(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h
......
...@@ -715,6 +715,10 @@ fverbose-asm ...@@ -715,6 +715,10 @@ fverbose-asm
Common Common
Add extra commentary to assembler output Add extra commentary to assembler output
fweb
Common
Construct webs and split unrelated uses of single variable
fwrapv fwrapv
Common Common
Assume signed arithmetic overflow wraps around Assume signed arithmetic overflow wraps around
......
...@@ -3680,13 +3680,14 @@ also turns on the following optimization flags: ...@@ -3680,13 +3680,14 @@ also turns on the following optimization flags:
-fgcse -fgcse-lm -fgcse-sm @gol -fgcse -fgcse-lm -fgcse-sm @gol
-fdelete-null-pointer-checks @gol -fdelete-null-pointer-checks @gol
-fexpensive-optimizations @gol -fexpensive-optimizations @gol
-fregmove @gol -fregmove -@gol
-fschedule-insns -fschedule-insns2 @gol -fschedule-insns -fschedule-insns2 @gol
-fsched-interblock -fsched-spec @gol -fsched-interblock -fsched-spec @gol
-fcaller-saves @gol -fcaller-saves @gol
-fpeephole2 @gol -fpeephole2 @gol
-freorder-blocks -freorder-functions @gol -freorder-blocks -freorder-functions @gol
-fstrict-aliasing @gol -fstrict-aliasing @gol
-funit-at-a-time @gol
-falign-functions -falign-jumps @gol -falign-functions -falign-jumps @gol
-falign-loops -falign-labels} -falign-loops -falign-labels}
...@@ -3697,7 +3698,7 @@ invoking @option{-O2} on programs that use computed gotos. ...@@ -3697,7 +3698,7 @@ invoking @option{-O2} on programs that use computed gotos.
@opindex O3 @opindex O3
Optimize yet more. @option{-O3} turns on all optimizations specified by Optimize yet more. @option{-O3} turns on all optimizations specified by
@option{-O2} and also turns on the @option{-finline-functions}, @option{-O2} and also turns on the @option{-finline-functions},
@option{-funit-at-a-time} and @option{-frename-registers} options. @option{-fweb} and @option{-frename-registers} options.
@item -O0 @item -O0
@opindex O0 @opindex O0
......
...@@ -366,6 +366,18 @@ The option @option{-dG} causes a debugging dump of the RTL code after ...@@ -366,6 +366,18 @@ The option @option{-dG} causes a debugging dump of the RTL code after
this pass. This dump file's name is made by appending @samp{.bypass} this pass. This dump file's name is made by appending @samp{.bypass}
to the input file name. to the input file name.
@cindex web construction
@item
Simple optimization pass that splits independent uses of each pseudo
increasing effect of other optimizations. This can improve effect of the
other transformation, such as CSE or register allocation.
Its source files are @file{web.c}.
@opindex dZ
The option @option{-dZ} causes a debugging dump of the RTL code after
this pass. This dump file's name is made by appending @samp{.web} to
the input file name.
@item @item
@opindex frerun-cse-after-loop @opindex frerun-cse-after-loop
If @option{-frerun-cse-after-loop} was enabled, a second common If @option{-frerun-cse-after-loop} was enabled, a second common
......
...@@ -709,6 +709,8 @@ extern int flag_signaling_nans; ...@@ -709,6 +709,8 @@ extern int flag_signaling_nans;
extern int flag_unit_at_a_time; extern int flag_unit_at_a_time;
extern int flag_web;
/* A string that's used when a random name is required. NULL means /* A string that's used when a random name is required. NULL means
to make it really random. */ to make it really random. */
......
...@@ -564,6 +564,7 @@ decode_options (unsigned int argc, const char **argv) ...@@ -564,6 +564,7 @@ decode_options (unsigned int argc, const char **argv)
flag_inline_functions = 1; flag_inline_functions = 1;
flag_rename_registers = 1; flag_rename_registers = 1;
flag_unswitch_loops = 1; flag_unswitch_loops = 1;
flag_web = 1;
} }
if (optimize < 2 || optimize_size) if (optimize < 2 || optimize_size)
......
...@@ -230,7 +230,7 @@ regrename_optimize (void) ...@@ -230,7 +230,7 @@ regrename_optimize (void)
CLEAR_HARD_REG_SET (regs_seen); CLEAR_HARD_REG_SET (regs_seen);
while (all_chains) while (all_chains)
{ {
int new_reg, best_new_reg = -1; int new_reg, best_new_reg;
int n_uses; int n_uses;
struct du_chain *this = all_chains; struct du_chain *this = all_chains;
struct du_chain *tmp, *last; struct du_chain *tmp, *last;
...@@ -240,6 +240,8 @@ regrename_optimize (void) ...@@ -240,6 +240,8 @@ regrename_optimize (void)
all_chains = this->next_chain; all_chains = this->next_chain;
best_new_reg = reg;
#if 0 /* This just disables optimization opportunities. */ #if 0 /* This just disables optimization opportunities. */
/* Only rename once we've seen the reg more than once. */ /* Only rename once we've seen the reg more than once. */
if (! TEST_HARD_REG_BIT (regs_seen, reg)) if (! TEST_HARD_REG_BIT (regs_seen, reg))
...@@ -320,8 +322,7 @@ regrename_optimize (void) ...@@ -320,8 +322,7 @@ regrename_optimize (void)
break; break;
if (! tmp) if (! tmp)
{ {
if (best_new_reg == -1 if (tick[best_new_reg] > tick[new_reg])
|| tick[best_new_reg] > tick[new_reg])
best_new_reg = new_reg; best_new_reg = new_reg;
} }
} }
...@@ -334,15 +335,16 @@ regrename_optimize (void) ...@@ -334,15 +335,16 @@ regrename_optimize (void)
fprintf (rtl_dump_file, " crosses a call"); fprintf (rtl_dump_file, " crosses a call");
} }
if (best_new_reg == -1) if (best_new_reg == reg)
{ {
tick[reg] = ++this_tick;
if (rtl_dump_file) if (rtl_dump_file)
fprintf (rtl_dump_file, "; no available registers\n"); fprintf (rtl_dump_file, "; no available better choice\n");
continue; continue;
} }
do_replace (this, best_new_reg); do_replace (this, best_new_reg);
tick[best_new_reg] = this_tick++; tick[best_new_reg] = ++this_tick;
if (rtl_dump_file) if (rtl_dump_file)
fprintf (rtl_dump_file, ", renamed as %s\n", reg_names[best_new_reg]); fprintf (rtl_dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
......
...@@ -2055,6 +2055,8 @@ extern rtx remove_death (unsigned int, rtx); ...@@ -2055,6 +2055,8 @@ extern rtx remove_death (unsigned int, rtx);
extern void dump_combine_stats (FILE *); extern void dump_combine_stats (FILE *);
extern void dump_combine_total_stats (FILE *); extern void dump_combine_total_stats (FILE *);
#endif #endif
/* In web.c */
extern void web_main PARAMS ((void));
/* In sched.c. */ /* In sched.c. */
#ifdef BUFSIZ #ifdef BUFSIZ
......
...@@ -39,6 +39,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -39,6 +39,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h" #include "toplev.h"
#include "recog.h" #include "recog.h"
#include "cfglayout.h" #include "cfglayout.h"
#include "params.h"
#include "sched-int.h" #include "sched-int.h"
#include "target.h" #include "target.h"
...@@ -561,6 +562,13 @@ void ...@@ -561,6 +562,13 @@ void
schedule_ebbs (FILE *dump_file) schedule_ebbs (FILE *dump_file)
{ {
basic_block bb; basic_block bb;
int probability_cutoff;
if (profile_info && flag_branch_probabilities)
probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
else
probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;
/* Taking care of this degenerate case makes the rest of /* Taking care of this degenerate case makes the rest of
this code simpler. */ this code simpler. */
...@@ -592,7 +600,7 @@ schedule_ebbs (FILE *dump_file) ...@@ -592,7 +600,7 @@ schedule_ebbs (FILE *dump_file)
break; break;
if (! e) if (! e)
break; break;
if (e->probability < REG_BR_PROB_BASE / 2) if (e->probability <= probability_cutoff)
break; break;
bb = bb->next_bb; bb = bb->next_bb;
} }
......
...@@ -69,6 +69,7 @@ DEFTIMEVAR (TV_GCSE , "global CSE") ...@@ -69,6 +69,7 @@ DEFTIMEVAR (TV_GCSE , "global CSE")
DEFTIMEVAR (TV_LOOP , "loop analysis") DEFTIMEVAR (TV_LOOP , "loop analysis")
DEFTIMEVAR (TV_BYPASS , "bypass jumps") DEFTIMEVAR (TV_BYPASS , "bypass jumps")
DEFTIMEVAR (TV_TRACER , "tracer") DEFTIMEVAR (TV_TRACER , "tracer")
DEFTIMEVAR (TV_WEB , "web")
DEFTIMEVAR (TV_CSE2 , "CSE 2") DEFTIMEVAR (TV_CSE2 , "CSE 2")
DEFTIMEVAR (TV_BRANCH_PROB , "branch prediction") DEFTIMEVAR (TV_BRANCH_PROB , "branch prediction")
DEFTIMEVAR (TV_FLOW , "flow analysis") DEFTIMEVAR (TV_FLOW , "flow analysis")
......
...@@ -266,6 +266,7 @@ enum dump_file_index ...@@ -266,6 +266,7 @@ enum dump_file_index
DFI_bp, DFI_bp,
DFI_ce1, DFI_ce1,
DFI_tracer, DFI_tracer,
DFI_web,
DFI_loop2, DFI_loop2,
DFI_cse2, DFI_cse2,
DFI_life, DFI_life,
...@@ -295,7 +296,7 @@ enum dump_file_index ...@@ -295,7 +296,7 @@ enum dump_file_index
Remaining -d letters: Remaining -d letters:
" m q " " m q "
" JK O Q V YZ" " JK O Q V Y "
*/ */
static struct dump_file_info dump_file[DFI_MAX] = static struct dump_file_info dump_file[DFI_MAX] =
...@@ -319,6 +320,7 @@ static struct dump_file_info dump_file[DFI_MAX] = ...@@ -319,6 +320,7 @@ static struct dump_file_info dump_file[DFI_MAX] =
{ "bp", 'b', 1, 0, 0 }, { "bp", 'b', 1, 0, 0 },
{ "ce1", 'C', 1, 0, 0 }, { "ce1", 'C', 1, 0, 0 },
{ "tracer", 'T', 1, 0, 0 }, { "tracer", 'T', 1, 0, 0 },
{ "web", 'Z', 0, 0, 0 },
{ "loop2", 'L', 1, 0, 0 }, { "loop2", 'L', 1, 0, 0 },
{ "cse2", 't', 1, 0, 0 }, { "cse2", 't', 1, 0, 0 },
{ "life", 'f', 1, 0, 0 }, /* Yes, duplicate enable switch. */ { "life", 'f', 1, 0, 0 }, /* Yes, duplicate enable switch. */
...@@ -654,6 +656,10 @@ int flag_complex_divide_method = 0; ...@@ -654,6 +656,10 @@ int flag_complex_divide_method = 0;
int flag_syntax_only = 0; int flag_syntax_only = 0;
/* Nonzero means performs web construction pass. */
int flag_web;
/* Nonzero means perform loop optimizer. */ /* Nonzero means perform loop optimizer. */
int flag_loop_optimize; int flag_loop_optimize;
...@@ -1065,6 +1071,7 @@ static const lang_independent_options f_options[] = ...@@ -1065,6 +1071,7 @@ static const lang_independent_options f_options[] =
{"pcc-struct-return", &flag_pcc_struct_return, 1 }, {"pcc-struct-return", &flag_pcc_struct_return, 1 },
{"reg-struct-return", &flag_pcc_struct_return, 0 }, {"reg-struct-return", &flag_pcc_struct_return, 0 },
{"delayed-branch", &flag_delayed_branch, 1 }, {"delayed-branch", &flag_delayed_branch, 1 },
{"web", &flag_web, 1},
{"gcse", &flag_gcse, 1 }, {"gcse", &flag_gcse, 1 },
{"gcse-lm", &flag_gcse_lm, 1 }, {"gcse-lm", &flag_gcse_lm, 1 },
{"gcse-sm", &flag_gcse_sm, 1 }, {"gcse-sm", &flag_gcse_sm, 1 },
...@@ -2427,6 +2434,20 @@ rest_of_handle_if_after_combine (tree decl, rtx insns) ...@@ -2427,6 +2434,20 @@ rest_of_handle_if_after_combine (tree decl, rtx insns)
timevar_pop (TV_IFCVT); timevar_pop (TV_IFCVT);
} }
static void
rest_of_handle_web (tree decl, rtx insns)
{
open_dump_file (DFI_web, decl);
timevar_push (TV_WEB);
web_main ();
delete_trivially_dead_insns (insns, max_reg_num ());
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_WEB);
close_dump_file (DFI_web, print_rtl_with_bb, insns);
reg_scan (get_insns (), max_reg_num (), 0);
}
/* Do branch profiling and static profile estimation passes. */ /* Do branch profiling and static profile estimation passes. */
static void static void
rest_of_handle_branch_prob (tree decl, rtx insns) rest_of_handle_branch_prob (tree decl, rtx insns)
...@@ -3313,6 +3334,9 @@ rest_of_compilation (tree decl) ...@@ -3313,6 +3334,9 @@ rest_of_compilation (tree decl)
rest_of_handle_cfg (decl, insns); rest_of_handle_cfg (decl, insns);
if (flag_web)
rest_of_handle_web (decl, insns);
if (optimize > 0 if (optimize > 0
|| profile_arc_flag || flag_test_coverage || flag_branch_probabilities) || profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
rest_of_handle_branch_prob (decl, insns); rest_of_handle_branch_prob (decl, insns);
......
/* Web construction code for GNU compiler.
Contributed by Jan Hubicka
Copyright (C) 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* Simple optimization pass that splits indepdendent uses of each pseudo
increasing effectivity of other optimizations. The optimization can
serve as an example of the use of dataflow module.
We don't split registers with REG_USERVAR set unless -fmessy-debugging is
used, because debug information about such split variables is almost
useless.
TODO
- Add code to keep debugging up-to-date after splitting of user variable
pseudos. This can be done by remembering all the pseudos used for the
variable and use life analysis information before reload to determing
wich one of the possible choices is alive and in case more are live,
choose one with latest definition.
Some other optimization passes will benefit from the infrastructure
too.
- We may use profile information and ignore infrequent use for purposes
of web unifying inserting the compensation code later to implement full
induction variable expansion for loops (currently we expand only if
induction is dead afterwards, that is often the case anyway). */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "basic-block.h"
#include "output.h"
#include "df.h"
#include "function.h"
/* This entry is allocated for each reference in the insn stream. */
struct web_entry
{
/* pointer to the parent in the union/find tree. */
struct web_entry *pred;
/* Newly assigned register to the entry. Set only for roots. */
rtx reg;
};
static struct web_entry *unionfind_root PARAMS ((struct web_entry *));
static void unionfind_union PARAMS ((struct web_entry *,
struct web_entry *));
static void union_defs PARAMS ((struct df *, struct ref *,
struct web_entry *,
struct web_entry *));
static rtx entry_register PARAMS ((struct web_entry *,
struct ref *, char *, char *));
static void replace_ref PARAMS ((struct ref *, rtx));
static int mark_addressof PARAMS ((rtx *, void *));
/* Find the root of unionfind tree (the representatnt of set). */
static struct web_entry *
unionfind_root (element)
struct web_entry *element;
{
struct web_entry *element1 = element, *element2;
while (element->pred)
element = element->pred;
while (element1->pred)
{
element2 = element1->pred;
element1->pred = element;
element1 = element2;
}
return element;
}
/* Union sets. */
static void
unionfind_union (first, second)
struct web_entry *first, *second;
{
first = unionfind_root (first);
second = unionfind_root (second);
if (first == second)
return;
second->pred = first;
}
/* For each use, all possible defs reaching it must come in same register,
union them. */
static void
union_defs (df, use, def_entry, use_entry)
struct df *df;
struct ref *use;
struct web_entry *def_entry;
struct web_entry *use_entry;
{
rtx insn = DF_REF_INSN (use);
struct df_link *link = DF_REF_CHAIN (use);
struct df_link *use_link = DF_INSN_USES (df, insn);
struct df_link *def_link = DF_INSN_DEFS (df, insn);
rtx set = single_set (insn);
/* Some instructions may use match_dup for it's operands. In case the
operands are dead, we will assign them different pseudos creating
invalid instruction, so union all uses of the same operands for each
insn. */
while (use_link)
{
if (use != use_link->ref
&& DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link->ref))
unionfind_union (use_entry + DF_REF_ID (use),
use_entry + DF_REF_ID (use_link->ref));
use_link = use_link->next;
}
/* Recognize trivial noop moves and attempt to keep them noop.
While most of noop moves should be removed we still keep some at
libcall boundaries and such. */
if (set
&& SET_SRC (set) == DF_REF_REG (use)
&& SET_SRC (set) == SET_DEST (set))
{
while (def_link)
{
if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link->ref))
unionfind_union (use_entry + DF_REF_ID (use),
def_entry + DF_REF_ID (def_link->ref));
def_link = def_link->next;
}
}
while (link)
{
unionfind_union (use_entry + DF_REF_ID (use),
def_entry + DF_REF_ID (link->ref));
link = link->next;
}
/* An READ_WRITE use require the corresponding def to be in the same
register. Find it and union. */
if (use->flags & DF_REF_READ_WRITE)
{
struct df_link *link = DF_INSN_DEFS (df, DF_REF_INSN (use));
while (DF_REF_REAL_REG (link->ref) != DF_REF_REAL_REG (use))
link = link->next;
unionfind_union (use_entry + DF_REF_ID (use),
def_entry + DF_REF_ID (link->ref));
}
}
/* Find corresponding register for given entry. */
static rtx
entry_register (entry, ref, used, use_addressof)
struct web_entry *entry;
struct ref *ref;
char *used;
char *use_addressof;
{
struct web_entry *root;
rtx reg, newreg;
/* Find corresponding web and see if it has been visited. */
root = unionfind_root (entry);
if (root->reg)
return root->reg;
/* We are seeing this web first time, do the assignment. */
reg = DF_REF_REAL_REG (ref);
/* In case the original register is already assigned, generate new one. */
if (!used[REGNO (reg)])
newreg = reg, used[REGNO (reg)] = 1;
else if (REG_USERVAR_P (reg) && 0/*&& !flag_messy_debugging*/)
{
newreg = reg;
if (rtl_dump_file)
fprintf (rtl_dump_file,
"New web forced to keep reg=%i (user variable)\n",
REGNO (reg));
}
else if (use_addressof [REGNO (reg)])
{
newreg = reg;
if (rtl_dump_file)
fprintf (rtl_dump_file,
"New web forced to keep reg=%i (address taken)\n",
REGNO (reg));
}
else
{
newreg = gen_reg_rtx (GET_MODE (reg));
REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
REG_POINTER (newreg) = REG_POINTER (reg);
REG_LOOP_TEST_P (newreg) = REG_LOOP_TEST_P (reg);
RTX_UNCHANGING_P (newreg) = RTX_UNCHANGING_P (reg);
REG_ATTRS (newreg) = REG_ATTRS (reg);
if (rtl_dump_file)
fprintf (rtl_dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
REGNO (newreg));
}
root->reg = newreg;
return newreg;
}
/* Replace the reference by REG. */
static void
replace_ref (ref, reg)
struct ref *ref;
rtx reg;
{
rtx oldreg = DF_REF_REAL_REG (ref);
rtx *loc = DF_REF_REAL_LOC (ref);
if (oldreg == reg)
return;
if (rtl_dump_file)
fprintf (rtl_dump_file, "Updating insn %i (%i->%i)\n",
INSN_UID (DF_REF_INSN (ref)), REGNO (oldreg), REGNO (reg));
*loc = reg;
}
/* Mark each pseudo, whose address is taken. */
static int
mark_addressof (rtl, data)
rtx *rtl;
void *data;
{
if (!*rtl)
return 0;
if (GET_CODE (*rtl) == ADDRESSOF
&& REG_P (XEXP (*rtl, 0)))
((char *)data)[REGNO (XEXP (*rtl, 0))] = 1;
return 0;
}
/* Main entry point. */
void
web_main ()
{
struct df *df;
struct web_entry *def_entry;
struct web_entry *use_entry;
unsigned int i;
int max = max_reg_num ();
char *used;
char *use_addressof;
rtx insn;
df = df_init ();
df_analyse (df, 0, DF_UD_CHAIN | DF_EQUIV_NOTES);
def_entry =
(struct web_entry *) xcalloc (df->n_defs, sizeof (struct web_entry));
use_entry =
(struct web_entry *) xcalloc (df->n_uses, sizeof (struct web_entry));
used = (char *) xcalloc (max, sizeof (char));
use_addressof = (char *) xcalloc (max, sizeof (char));
if (rtl_dump_file)
df_dump (df, DF_UD_CHAIN | DF_DU_CHAIN, rtl_dump_file);
/* Produce the web. */
for (i = 0; i < df->n_uses; i++)
union_defs (df, df->uses[i], def_entry, use_entry);
/* We can not safely rename registers whose address is taken. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
for_each_rtx (&PATTERN (insn), mark_addressof, use_addressof);
/* Update the instruction stream, allocating new registers for split pseudos
in progress. */
for (i = 0; i < df->n_uses; i++)
replace_ref (df->uses[i], entry_register (use_entry + i, df->uses[i],
used, use_addressof));
for (i = 0; i < df->n_defs; i++)
replace_ref (df->defs[i], entry_register (def_entry + i, df->defs[i],
used, use_addressof));
/* Dataflow information is corrupt here, but it can be easy to update it
by creating new entries for new registers and update or calilng
df_insns_modify. */
free (def_entry);
free (use_entry);
free (used);
free (use_addressof);
df_finish (df);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment