From: Richard Henderson Date: Fri, 21 Nov 2003 04:05:08 +0000 (-0800) Subject: ssa.c, [...]: Remove files. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c132886e7c0605edb5f66c0614c98b61840efc24;p=gcc.git ssa.c, [...]: Remove files. * ssa.c, ssa-dce.c, ssa-ccp.c: Remove files. * Makefile.in (OBJS-common, GTFILES): Don't reference them. (gtype-desc.o, toplev.o, flow.o): Remove ssa.h. (ssa.o, ssa-dce.o, ssa-ccp.o): Remove. * flow.c: Don't include ssa.h. (set_phi_alternative_reg): Remove. (calculate_global_regs_live): Don't call it. (mark_used_regs): Don't handle PHI. * gengtype.c (open_base_files): Don't reference ssa.h. * rtl.def (PHI): Remove. * timevar.def (TV_TO_SSA, TV_SSA_CCP, TV_SSA_DCE, TV_FROM_SSA): Kill. * common.opt: Remove -fssa, -fssa-ccp, -fssa-dce. * opts.c (common_handle_option): Likewise. * toplev.c (f_options): Likewise. (DFI_ssa, DFI_ssa_ccp, DFI_ssa_dce, DFI_ussa): Remove. (dump_file): Update to match. (flag_ssa, flag_ssa_ccp, flag_ssa_dce): Remove. (rest_of_handle_ssa): Remove. (rest_of_compilation): Don't call it. * toplev.h (flag_ssa, flag_ssa_dce, flag_ssa_ccp): Remove. * doc/invoke.texi: Remove -fssa, -fssa-ccp, -fssa-dce. * doc/passes.texi (SSA optimizations): Remove. * gcc.dg/20020201-2.c: Remove. * gcc.dg/20020201-4.c: Remove. * gcc.dg/20020304-1.c: Remove. From-SVN: r73789 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6f83a5af043..b6b6b090579 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2003-11-20 Richard Henderson + + * ssa.c, ssa-dce.c, ssa-ccp.c: Remove files. + * Makefile.in (OBJS-common, GTFILES): Don't reference them. + (gtype-desc.o, toplev.o, flow.o): Remove ssa.h. + (ssa.o, ssa-dce.o, ssa-ccp.o): Remove. + * flow.c: Don't include ssa.h. + (set_phi_alternative_reg): Remove. + (calculate_global_regs_live): Don't call it. + (mark_used_regs): Don't handle PHI. + * gengtype.c (open_base_files): Don't reference ssa.h. + * rtl.def (PHI): Remove. + * timevar.def (TV_TO_SSA, TV_SSA_CCP, TV_SSA_DCE, TV_FROM_SSA): Kill. + * common.opt: Remove -fssa, -fssa-ccp, -fssa-dce. + * opts.c (common_handle_option): Likewise. + * toplev.c (f_options): Likewise. + (DFI_ssa, DFI_ssa_ccp, DFI_ssa_dce, DFI_ussa): Remove. + (dump_file): Update to match. + (flag_ssa, flag_ssa_ccp, flag_ssa_dce): Remove. + (rest_of_handle_ssa): Remove. + (rest_of_compilation): Don't call it. + * toplev.h (flag_ssa, flag_ssa_dce, flag_ssa_ccp): Remove. + * doc/invoke.texi: Remove -fssa, -fssa-ccp, -fssa-dce. + * doc/passes.texi (SSA optimizations): Remove. + 2003-11-20 Bob Wilson * configure.in: Add xtensa-*-* targets to test for dwarf2 debug_line. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c073b1e23fb..a2406f49a9e 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -865,15 +865,15 @@ OBJS-common = \ insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \ integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \ loop.o optabs.o options.o opts.o params.o postreload.o predict.o \ - print-rtl.o print-tree.o value-prof.o \ + print-rtl.o print-tree.o value-prof.o \ profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \ real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \ reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \ sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.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 \ - 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) web.o + sibcall.o simplify-rtx.o sreal.o stmt.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 alloc-pool.o \ + et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ @@ -1467,7 +1467,7 @@ version.o: version.c version.h gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h \ $(HASHTAB_H) $(TREE_H) $(RTL_H) function.h insn-config.h $(EXPR_H) $(OPTABS_H) \ libfuncs.h debug.h $(GGC_H) bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h \ - ssa.h cselib.h insn-addr.h + cselib.h insn-addr.h ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ $(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h @@ -1533,7 +1533,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_ debug.h insn-config.h intl.h $(RECOG_H) Makefile toplev.h \ dwarf2out.h sdbout.h dbxout.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \ graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) value-prof.h \ - ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \ + $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \ langhooks.h insn-flags.h cfglayout.h real.h cfgloop.h \ hosthooks.h $(LANGHOOKS_DEF_H) cgraph.h $(COVERAGE_H) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ @@ -1669,14 +1669,6 @@ resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h $(SYSTEM_H) coretype lcm.o : lcm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h real.h insn-config.h $(INSN_ATTR_H) $(RECOG_H) $(EXPR_H) \ $(BASIC_BLOCK_H) $(TM_P_H) df.h function.h -ssa.o : ssa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) varray.h \ - $(EXPR_H) hard-reg-set.h flags.h function.h real.h insn-config.h $(RECOG_H) \ - $(BASIC_BLOCK_H) output.h ssa.h -ssa-dce.o : ssa-dce.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) hard-reg-set.h \ - $(BASIC_BLOCK_H) ssa.h insn-config.h $(RECOG_H) output.h -ssa-ccp.o : ssa-ccp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) hard-reg-set.h \ - $(BASIC_BLOCK_H) ssa.h insn-config.h $(RECOG_H) output.h \ - errors.h $(GGC_H) df.h function.h df.o : df.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 $(FIBHEAP_H) @@ -1702,7 +1694,7 @@ unroll.o : unroll.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-co alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ - $(RECOG_H) function.h except.h $(EXPR_H) ssa.h $(GGC_H) $(TM_P_H) + $(RECOG_H) function.h except.h $(EXPR_H) $(GGC_H) $(TM_P_H) cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h insn-config.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h @@ -2068,7 +2060,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h $(srcdir)/cpplib.h \ $(host_xm_file_list) $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) \ $(srcdir)/bitmap.h $(srcdir)/coverage.c $(srcdir)/function.h $(srcdir)/rtl.h \ $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/libfuncs.h $(srcdir)/hashtable.h \ - $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/ssa.h $(srcdir)/insn-addr.h \ + $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/cgraph.h \ $(srcdir)/c-common.h $(srcdir)/c-tree.h \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ diff --git a/gcc/common.opt b/gcc/common.opt index 2ad0e0a58f6..fdb7a849ed4 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -628,18 +628,6 @@ fsingle-precision-constant Common Convert floating point constants to single precision constants -fssa -Common -Enable static single assignment optimizations - -fssa-ccp -Common -Enable SSA conditional constant propagation - -fssa-dce -Common -Enable aggressive SSA dead code elimination - fstack-check Common Insert stack checking code into the program diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ca71dde15c4..b1b2e8c2cec 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -291,7 +291,7 @@ in the following sections. -fsched-stalled-insns=@var{n} -sched-stalled-insns-dep=@var{n} @gol -fsched2-use-superblocks @gol -fsched2-use-traces -fsignaling-nans @gol --fsingle-precision-constant -fssa -fssa-ccp -fssa-dce @gol +-fsingle-precision-constant @gol -fstrength-reduce -fstrict-aliasing -ftracer -fthread-jumps @gol -funroll-all-loops -funroll-loops -fpeel-loops @gol -funswitch-loops -fold-unroll-loops -fold-unroll-all-loops @gol @@ -4674,23 +4674,6 @@ You will not be able to use @code{gprof} on all systems if you specify this option and you may have problems with debugging if you specify both this option and @option{-g}. -@item -fssa -@opindex fssa -Perform optimizations in static single assignment form. Each function's -flow graph is translated into SSA form, optimizations are performed, and -the flow graph is translated back from SSA form. Users should not -specify this option, since it is not yet ready for production use. - -@item -fssa-ccp -@opindex fssa-ccp -Perform Sparse Conditional Constant Propagation in SSA form. Requires -@option{-fssa}. Like @option{-fssa}, this is an experimental feature. - -@item -fssa-dce -@opindex fssa-dce -Perform aggressive dead-code elimination in SSA form. Requires @option{-fssa}. -Like @option{-fssa}, this is an experimental feature. - @item -fbranch-target-load-optimize @opindex fbranch-target-load-optimize Perform branch target register load optimization before prologue / epilogue @@ -4704,9 +4687,6 @@ a separate optimization pass. Perform branch target register load optimization after prologue / epilogue threading. - - - @item --param @var{name}=@var{value} @opindex param In some places, GCC uses various constants to control the amount of diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi index ad07f60841e..6bbc61c2822 100644 --- a/gcc/doc/passes.texi +++ b/gcc/doc/passes.texi @@ -237,57 +237,6 @@ the second conditional test. The source code for this pass is in @file{jump.c}. This optimization is only performed if @option{-fthread-jumps} is enabled. -@cindex SSA optimizations -@cindex Single Static Assignment optimizations -@opindex fssa -@item -Static Single Assignment (SSA) based optimization passes. The -SSA conversion passes (to/from) are turned on by the @option{-fssa} -option (it is also done automatically if you enable an SSA optimization pass). -These passes utilize a form called Static Single Assignment. In SSA form, -each variable (pseudo register) is only set once, giving you def-use -and use-def chains for free, and enabling a lot more optimization -passes to be run in linear time. -Conversion to and from SSA form is handled by functions in -@file{ssa.c}. - -@opindex de -The option @option{-de} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.ssa} to -the input file name. -@itemize @bullet -@cindex SSA Conditional Constant Propagation -@cindex Conditional Constant Propagation, SSA based -@cindex conditional constant propagation -@opindex fssa-ccp -@item -SSA Conditional Constant Propagation. Turned on by the @option{-fssa-ccp} -option. This pass performs conditional constant propagation to simplify -instructions including conditional branches. This pass is more aggressive -than the constant propagation done by the CSE and GCSE passes, but operates -in linear time. - -@opindex dW -The option @option{-dW} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.ssaccp} to -the input file name. - -@cindex SSA DCE -@cindex DCE, SSA based -@cindex dead code elimination -@opindex fssa-dce -@item -SSA Aggressive Dead Code Elimination. Turned on by the @option{-fssa-dce} -option. This pass performs elimination of code considered unnecessary because -it has no externally visible effects on the program. It operates in -linear time. - -@opindex dX -The option @option{-dX} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.ssadce} to -the input file name. -@end itemize - @cindex common subexpression elimination @cindex constant propagation @item diff --git a/gcc/flow.c b/gcc/flow.c index 2694a0b07e0..7ad7a803ef9 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -136,7 +136,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "toplev.h" #include "recog.h" #include "expr.h" -#include "ssa.h" #include "timevar.h" #include "obstack.h" @@ -293,7 +292,6 @@ static void notice_stack_pointer_modification_1 (rtx, rtx, void *); static void notice_stack_pointer_modification (rtx); static void mark_reg (rtx, void *); static void mark_regs_live_at_end (regset); -static int set_phi_alternative_reg (rtx, int, int, void *); static void calculate_global_regs_live (sbitmap, sbitmap, int); static void propagate_block_delete_insn (rtx); static rtx propagate_block_delete_libcall (rtx, rtx); @@ -1033,20 +1031,6 @@ mark_regs_live_at_end (regset set) diddle_return_value (mark_reg, set); } -/* Callback function for for_each_successor_phi. DATA is a regset. - Sets the SRC_REGNO, the regno of the phi alternative for phi node - INSN, in the regset. */ - -static int -set_phi_alternative_reg (rtx insn ATTRIBUTE_UNUSED, - int dest_regno ATTRIBUTE_UNUSED, int src_regno, - void *data) -{ - regset live = (regset) data; - SET_REGNO_REG_SET (live, src_regno); - return 0; -} - /* Propagate global life info around the graph of basic blocks. Begin considering blocks with their corresponding bit set in BLOCKS_IN. If BLOCKS_IN is null, consider it the universal set. @@ -1208,14 +1192,6 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM); } - /* Regs used in phi nodes are not included in - global_live_at_start, since they are live only along a - particular edge. Set those regs that are live because of a - phi node alternative corresponding to this particular block. */ - if (in_ssa_form) - for_each_successor_phi (bb, &set_phi_alternative_reg, - new_live_at_end); - if (bb == ENTRY_BLOCK_PTR) { COPY_REG_SET (bb->global_live_at_end, new_live_at_end); @@ -3908,14 +3884,6 @@ mark_used_regs (struct propagate_block_info *pbi, rtx x, rtx cond, rtx insn) x = COND_EXEC_CODE (x); goto retry; - case PHI: - /* We _do_not_ want to scan operands of phi nodes. Operands of - a phi function are evaluated only when control reaches this - block along a particular edge. Therefore, regs that appear - as arguments to phi should not be added to the global live at - start. */ - return; - default: break; } diff --git a/gcc/gengtype.c b/gcc/gengtype.c index c663a8a3add..e5579a46837 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1087,7 +1087,7 @@ open_base_files (void) "config.h", "system.h", "coretypes.h", "tm.h", "varray.h", "hashtab.h", "splay-tree.h", "bitmap.h", "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h", "hard-reg-set.h", - "basic-block.h", "cselib.h", "insn-addr.h", "ssa.h", "optabs.h", + "basic-block.h", "cselib.h", "insn-addr.h", "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", NULL }; diff --git a/gcc/opts.c b/gcc/opts.c index 694cac74a7d..cbfbd64607f 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1299,18 +1299,6 @@ common_handle_option (size_t scode, const char *arg, flag_single_precision_constant = value; break; - case OPT_fssa: - flag_ssa = value; - break; - - case OPT_fssa_ccp: - flag_ssa_ccp = value; - break; - - case OPT_fssa_dce: - flag_ssa_dce = value; - break; - case OPT_fstack_check: flag_stack_check = value; break; diff --git a/gcc/rtl.def b/gcc/rtl.def index a7de17beea5..6371cf0fcbe 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -1208,20 +1208,6 @@ DEF_RTL_EXPR(SS_TRUNCATE, "ss_truncate", "e", '1') /* Unsigned saturating truncate. */ DEF_RTL_EXPR(US_TRUNCATE, "us_truncate", "e", '1') -/* The SSA phi operator. - - The argument is a vector of 2N rtxes. Element 2N+1 is a CONST_INT - containing the block number of the predecessor through which control - has passed when the register at element 2N is used. - - Note that PHI may only appear at the beginning of a basic block. - - ??? There may be multiple PHI insns, but they are all evaluated - in parallel. This probably ought to be changed to use a real - PARALLEL, as that would be less confusing and more in the spirit - of canonical RTL. It is, however, easier to manipulate this way. */ -DEF_RTL_EXPR(PHI, "phi", "E", 'x') - /* Local variables: diff --git a/gcc/ssa-ccp.c b/gcc/ssa-ccp.c deleted file mode 100644 index 7ff305a9d3d..00000000000 --- a/gcc/ssa-ccp.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* Conditional constant propagation pass for the GNU compiler. - Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Original framework by Daniel Berlin - Fleshed out and major cleanups by Jeff Law - -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. */ - -/* Conditional constant propagation. - - References: - - Constant propagation with conditional branches, - Wegman and Zadeck, ACM TOPLAS 13(2):181-210. - - Building an Optimizing Compiler, - Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. - - Advanced Compiler Design and Implementation, - Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 - - The overall structure is as follows: - - 1. Run a simple SSA based DCE pass to remove any dead code. - 2. Run CCP to compute what registers are known constants - and what edges are not executable. Remove unexecutable - edges from the CFG and simplify PHI nodes. - 3. Replace registers with constants where possible. - 4. Remove unreachable blocks computed in step #2. - 5. Another simple SSA DCE pass to remove dead code exposed - by CCP. - - When we exit, we are still in SSA form. - - - Potential further enhancements: - - 1. Handle SUBREGs, STRICT_LOW_PART, etc in destinations more - gracefully. - - 2. Handle insns with multiple outputs more gracefully. - - 3. Handle CONST_DOUBLE and symbolic constants. - - 4. Fold expressions after performing constant substitutions. */ - - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" - -#include "rtl.h" -#include "hard-reg-set.h" -#include "basic-block.h" -#include "ssa.h" -#include "insn-config.h" -#include "recog.h" -#include "output.h" -#include "errors.h" -#include "ggc.h" -#include "df.h" -#include "function.h" - -/* Possible lattice values. */ - -typedef enum -{ - UNDEFINED, - CONSTANT, - VARYING -} latticevalue; - -/* Main structure for CCP. - - Contains the lattice value and, if it's a constant, the constant - value. */ -typedef struct -{ - latticevalue lattice_val; - rtx const_value; -} value; - -/* Array of values indexed by register number. */ -static value *values; - -/* A bitmap to keep track of executable blocks in the CFG. */ -static sbitmap executable_blocks; - -/* A bitmap for all executable edges in the CFG. */ -static sbitmap executable_edges; - -/* Array of edges on the work list. */ -static edge *edge_info; - -/* We need an edge list to be able to get indexes easily. */ -static struct edge_list *edges; - -/* For building/following use-def and def-use chains. */ -static struct df *df_analyzer; - -/* Current edge we are operating on, from the worklist */ -static edge flow_edges; - -/* Bitmap of SSA edges which will need reexamination as their definition - has changed. */ -static sbitmap ssa_edges; - -/* Simple macros to simplify code */ -#define SSA_NAME(x) REGNO (SET_DEST (x)) -#define EIE(x,y) EDGE_INDEX (edges, x, y) - -static void visit_phi_node (rtx, basic_block); -static void visit_expression (rtx, basic_block); -static void defs_to_undefined (rtx); -static void defs_to_varying (rtx); -static void examine_flow_edges (void); -static int mark_references (rtx *, void *); -static void follow_def_use_chains (void); -static void optimize_unexecutable_edges (struct edge_list *, sbitmap); -static void ssa_ccp_substitute_constants (void); -static void ssa_ccp_df_delete_unreachable_insns (void); -static void ssa_fast_dce (struct df *); - -/* Loop through the PHI_NODE's parameters for BLOCK and compare their - lattice values to determine PHI_NODE's lattice value. */ -static void -visit_phi_node (rtx phi_node, basic_block block) -{ - unsigned int i; - rtx phi_node_expr = NULL; - unsigned int phi_node_name = SSA_NAME (PATTERN (phi_node)); - latticevalue phi_node_lattice_val = UNDEFINED; - rtx pat = PATTERN (phi_node); - rtvec phi_vec = XVEC (SET_SRC (pat), 0); - unsigned int num_elem = GET_NUM_ELEM (phi_vec); - - for (i = 0; i < num_elem; i += 2) - { - if (TEST_BIT (executable_edges, - EIE (BASIC_BLOCK (INTVAL (RTVEC_ELT (phi_vec, i + 1))), - block))) - { - unsigned int current_parm - = REGNO (RTVEC_ELT (phi_vec, i)); - - latticevalue current_parm_lattice_val - = values[current_parm].lattice_val; - - /* If any node is VARYING, then new value of PHI_NODE - is VARYING. */ - if (current_parm_lattice_val == VARYING) - { - phi_node_lattice_val = VARYING; - phi_node_expr = NULL; - break; - } - - /* If we have more than one distinct constant, then the new - value of PHI_NODE is VARYING. */ - if (current_parm_lattice_val == CONSTANT - && phi_node_lattice_val == CONSTANT - && values[current_parm].const_value != phi_node_expr) - { - phi_node_lattice_val = VARYING; - phi_node_expr = NULL; - break; - } - - /* If the current value of PHI_NODE is UNDEFINED and one - node in PHI_NODE is CONSTANT, then the new value of the - PHI is that CONSTANT. Note this can turn into VARYING - if we find another distinct constant later. */ - if (phi_node_lattice_val == UNDEFINED - && phi_node_expr == NULL - && current_parm_lattice_val == CONSTANT) - { - phi_node_expr = values[current_parm].const_value; - phi_node_lattice_val = CONSTANT; - continue; - } - } - } - - /* If the value of PHI_NODE changed, then we will need to - re-execute uses of the output of PHI_NODE. */ - if (phi_node_lattice_val != values[phi_node_name].lattice_val) - { - values[phi_node_name].lattice_val = phi_node_lattice_val; - values[phi_node_name].const_value = phi_node_expr; - SET_BIT (ssa_edges, phi_node_name); - } -} - -/* Sets all defs in an insn to UNDEFINED. */ -static void -defs_to_undefined (rtx insn) -{ - struct df_link *currdef; - for (currdef = DF_INSN_DEFS (df_analyzer, insn); currdef; - currdef = currdef->next) - { - if (values[DF_REF_REGNO (currdef->ref)].lattice_val != UNDEFINED) - SET_BIT (ssa_edges, DF_REF_REGNO (currdef->ref)); - values[DF_REF_REGNO (currdef->ref)].lattice_val = UNDEFINED; - } -} - -/* Sets all defs in an insn to VARYING. */ -static void -defs_to_varying (rtx insn) -{ - struct df_link *currdef; - for (currdef = DF_INSN_DEFS (df_analyzer, insn); currdef; - currdef = currdef->next) - { - if (values[DF_REF_REGNO (currdef->ref)].lattice_val != VARYING) - SET_BIT (ssa_edges, DF_REF_REGNO (currdef->ref)); - values[DF_REF_REGNO (currdef->ref)].lattice_val = VARYING; - } -} - -/* Go through the expression, call the appropriate evaluation routines - to attempt cprop */ -static void -visit_expression (rtx insn, basic_block block) -{ - rtx src, dest, set; - - - /* Ugh. CALL_INSNs may end a basic block and have multiple edges - leading out from them. - - Mark all the outgoing edges as executable, then fall into the - normal processing below. */ - if (GET_CODE (insn) == CALL_INSN && block->end == insn) - { - edge curredge; - - for (curredge = block->succ; curredge; - curredge = curredge->succ_next) - { - int index = EIE (curredge->src, curredge->dest); - - if (TEST_BIT (executable_edges, index)) - continue; - - SET_BIT (executable_edges, index); - edge_info[index] = flow_edges; - flow_edges = curredge; - } - } - - set = single_set (insn); - if (! set) - { - defs_to_varying (insn); - return; - } - - src = SET_SRC (set); - dest = SET_DEST (set); - - /* We may want to refine this some day. */ - if (GET_CODE (dest) != REG && dest != pc_rtx) - { - defs_to_varying (insn); - return; - } - - /* Hard registers are not put in SSA form and thus we must consider - them varying. All the more reason to avoid hard registers in - RTL until as late as possible in the compilation. */ - if (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER) - { - defs_to_varying (insn); - return; - } - - /* If this is assigning DEST to a constant, record that fact. */ - if (GET_CODE (src) == CONST_INT && GET_CODE (insn) == INSN) - { - unsigned int resultreg = REGNO (dest); - - values[resultreg].lattice_val = CONSTANT; - values[resultreg].const_value = SET_SRC (PATTERN (insn)); - SET_BIT (ssa_edges, resultreg); - } - - /* If this is a copy operation, then we can copy the lattice values. */ - else if (GET_CODE (src) == REG && GET_CODE (dest) == REG) - { - unsigned int old_value = REGNO (src); - latticevalue old_lattice_value = values[old_value].lattice_val; - unsigned int new_value = REGNO (dest); - - /* Unless the lattice value is going to change, don't bother - adding the "new value" into the worklist. */ - if (values[new_value].lattice_val != old_lattice_value - || values[new_value].const_value != values[old_value].const_value) - SET_BIT (ssa_edges, new_value); - - /* Copy the old lattice node info into the new value lattice node. */ - values[new_value].lattice_val = old_lattice_value; - values[new_value].const_value = values[old_value].const_value; - } - - /* Handle jumps. */ - else if (GET_CODE (insn) == JUMP_INSN) - { - rtx x = pc_set (insn); - if (GET_CODE (src) != IF_THEN_ELSE) - { - edge curredge; - - /* This is a computed jump, table jump, or an unconditional - jump. For all these cases we want to mark all successor - blocks as executable if they have not already been - marked. - - One day we may try do better with switch tables and - other computed jumps. */ - for (curredge = block->succ; curredge; - curredge = curredge->succ_next) - { - int index = EIE (curredge->src, curredge->dest); - - if (TEST_BIT (executable_edges, index)) - continue; - - SET_BIT (executable_edges, index); - edge_info[index] = flow_edges; - flow_edges = curredge; - } - } - else - { - edge curredge; - enum rtx_code comparison_code; - rtx comparison_src0; - rtx comparison_src1; - - comparison_code = GET_CODE (XEXP (src, 0)); - comparison_src0 = XEXP (XEXP (src, 0), 0); - comparison_src1 = XEXP (XEXP (src, 0), 1); - - /* If either operand is undefined, then there is nothing to - do right now. If/when operands are later defined we will - revaluate the condition and take the appropriate action. */ - if ((GET_CODE (comparison_src0) == REG - && values[REGNO (comparison_src0)].lattice_val == UNDEFINED) - || (GET_CODE (comparison_src1) == REG - && values[REGNO (comparison_src1)].lattice_val == UNDEFINED)) - return; - - /* If either operand is varying, then we must consider all - paths as executable. */ - if ((GET_CODE (comparison_src0) == REG - && values[REGNO (comparison_src0)].lattice_val == VARYING) - || (GET_CODE (comparison_src1) == REG - && values[REGNO (comparison_src1)].lattice_val == VARYING)) - { - for (curredge = block->succ; curredge; - curredge = curredge->succ_next) - { - int index = EIE (curredge->src, curredge->dest); - - if (TEST_BIT (executable_edges, index)) - continue; - - SET_BIT (executable_edges, index); - edge_info[index] = flow_edges; - flow_edges = curredge; - } - return; - } - - /* Try to simplify the comparison. */ - if (GET_CODE (comparison_src0) == REG - && values[REGNO (comparison_src0)].lattice_val == CONSTANT) - comparison_src0 = values[REGNO (comparison_src0)].const_value; - - if (GET_CODE (comparison_src1) == REG - && values[REGNO (comparison_src1)].lattice_val == CONSTANT) - comparison_src1 = values[REGNO (comparison_src1)].const_value; - - x = simplify_ternary_operation (IF_THEN_ELSE, - VOIDmode, - GET_MODE (XEXP (src, 0)), - gen_rtx (comparison_code, - GET_MODE (XEXP (src, 0)), - comparison_src0, - comparison_src1), - XEXP (src, 1), - XEXP (src, 2)); - - /* Walk through all the outgoing edges from this block and see - which (if any) we should mark as executable. */ - for (curredge = block->succ; curredge; - curredge = curredge->succ_next) - { - int index = EIE (curredge->src, curredge->dest); - - if (TEST_BIT (executable_edges, index)) - continue; - - /* If we were unable to simplify the expression at this - point, it's highly unlikely we'll be able to simplify - it later. So consider all edges as executable if the - expression did not simplify. - - If the expression simplified to (pc), then we know we - will take the fall-thru edge, so mark it. Similarly, - if the expression simplified to (label_ref ...), then - we know the branch will be taken and we mark that - edge as taken. */ - if (!x - || (x == pc_rtx - && (curredge->flags & EDGE_FALLTHRU)) - || (GET_CODE (x) == LABEL_REF - && ! (curredge->flags & EDGE_FALLTHRU))) - { - SET_BIT (executable_edges, index); - edge_info[index] = flow_edges; - flow_edges = curredge; - } - } - } - } - else if (!PHI_NODE_P (insn)) - { - rtx simplified = NULL; - - /* We've got some kind of INSN. If it's simple, try to evaluate - it and record the results. - - We already know this insn is a single_set and that it sets - a pseudo register. So we just need to extract the source - arguments, simplify them to constants if possible, then - simplify the expression as a whole if possible. */ - switch (GET_RTX_CLASS (GET_CODE (src))) - { - case '<': - { - rtx src0 = XEXP (src, 0); - rtx src1 = XEXP (src, 1); - enum machine_mode mode; - - /* If either is undefined, then the result is undefined. */ - if ((GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == UNDEFINED) - || (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == UNDEFINED)) - { - defs_to_undefined (insn); - break; - } - - /* Determine the mode for the operation before we simplify - our arguments to constants. */ - mode = GET_MODE (src0); - if (mode == VOIDmode) - mode = GET_MODE (src1); - - /* Simplify source operands to whatever known values they - may have. */ - if (GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == CONSTANT) - src0 = values[REGNO (src0)].const_value; - - if (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == CONSTANT) - src1 = values[REGNO (src1)].const_value; - - /* See if the simplifier can determine if this operation - computes a constant value. */ - simplified = simplify_relational_operation (GET_CODE (src), - mode, src0, src1); - break; - - } - - case '1': - { - rtx src0 = XEXP (src, 0); - enum machine_mode mode0 = GET_MODE (src0); - - /* If the operand is undefined, then the result is undefined. */ - if (GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == UNDEFINED) - { - defs_to_undefined (insn); - break; - } - - /* Simplify source operands to whatever known values they - may have. */ - if (GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == CONSTANT) - src0 = values[REGNO (src0)].const_value; - - /* See if the simplifier can determine if this operation - computes a constant value. */ - simplified = simplify_unary_operation (GET_CODE (src), - GET_MODE (src), - src0, - mode0); - break; - } - - case '2': - case 'c': - { - rtx src0 = XEXP (src, 0); - rtx src1 = XEXP (src, 1); - - /* If either is undefined, then the result is undefined. */ - if ((GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == UNDEFINED) - || (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == UNDEFINED)) - { - defs_to_undefined (insn); - break; - } - - /* Simplify source operands to whatever known values they - may have. */ - if (GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == CONSTANT) - src0 = values[REGNO (src0)].const_value; - - if (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == CONSTANT) - src1 = values[REGNO (src1)].const_value; - - /* See if the simplifier can determine if this operation - computes a constant value. */ - simplified = simplify_binary_operation (GET_CODE (src), - GET_MODE (src), - src0, src1); - break; - } - - case '3': - case 'b': - { - rtx src0 = XEXP (src, 0); - rtx src1 = XEXP (src, 1); - rtx src2 = XEXP (src, 2); - - /* If either is undefined, then the result is undefined. */ - if ((GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == UNDEFINED) - || (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == UNDEFINED) - || (GET_CODE (src2) == REG - && values[REGNO (src2)].lattice_val == UNDEFINED)) - { - defs_to_undefined (insn); - break; - } - - /* Simplify source operands to whatever known values they - may have. */ - if (GET_CODE (src0) == REG - && values[REGNO (src0)].lattice_val == CONSTANT) - src0 = values[REGNO (src0)].const_value; - - if (GET_CODE (src1) == REG - && values[REGNO (src1)].lattice_val == CONSTANT) - src1 = values[REGNO (src1)].const_value; - - if (GET_CODE (src2) == REG - && values[REGNO (src2)].lattice_val == CONSTANT) - src2 = values[REGNO (src2)].const_value; - - /* See if the simplifier can determine if this operation - computes a constant value. */ - simplified = simplify_ternary_operation (GET_CODE (src), - GET_MODE (src), - GET_MODE (src), - src0, src1, src2); - break; - } - - default: - defs_to_varying (insn); - } - - if (simplified && GET_CODE (simplified) == CONST_INT) - { - if (values[REGNO (dest)].lattice_val != CONSTANT - || values[REGNO (dest)].const_value != simplified) - SET_BIT (ssa_edges, REGNO (dest)); - - values[REGNO (dest)].lattice_val = CONSTANT; - values[REGNO (dest)].const_value = simplified; - } - else - defs_to_varying (insn); - } -} - -/* Iterate over the FLOW_EDGES work list. Simulate the target block - for each edge. */ -static void -examine_flow_edges (void) -{ - while (flow_edges != NULL) - { - basic_block succ_block; - rtx curr_phi_node; - - /* Pull the next block to simulate off the worklist. */ - succ_block = flow_edges->dest; - flow_edges = edge_info[EIE (flow_edges->src, flow_edges->dest)]; - - /* There is nothing to do for the exit block. */ - if (succ_block == EXIT_BLOCK_PTR) - continue; - - /* Always simulate PHI nodes, even if we have simulated this block - before. Note that all PHI nodes are consecutive within a block. */ - for (curr_phi_node = first_insn_after_basic_block_note (succ_block); - PHI_NODE_P (curr_phi_node); - curr_phi_node = NEXT_INSN (curr_phi_node)) - visit_phi_node (curr_phi_node, succ_block); - - /* If this is the first time we've simulated this block, then we - must simulate each of its insns. */ - if (!TEST_BIT (executable_blocks, succ_block->index)) - { - rtx currinsn; - edge succ_edge = succ_block->succ; - - /* Note that we have simulated this block. */ - SET_BIT (executable_blocks, succ_block->index); - - /* Simulate each insn within the block. */ - currinsn = succ_block->head; - while (currinsn != succ_block->end) - { - if (INSN_P (currinsn)) - visit_expression (currinsn, succ_block); - - currinsn = NEXT_INSN (currinsn); - } - - /* Don't forget the last insn in the block. */ - if (INSN_P (currinsn)) - visit_expression (currinsn, succ_block); - - /* If we haven't looked at the next block, and it has a - single successor, add it onto the worklist. This is because - if we only have one successor, we know it gets executed, - so we don't have to wait for cprop to tell us. */ - if (succ_edge != NULL - && succ_edge->succ_next == NULL - && !TEST_BIT (executable_edges, - EIE (succ_edge->src, succ_edge->dest))) - { - SET_BIT (executable_edges, - EIE (succ_edge->src, succ_edge->dest)); - edge_info[EIE (succ_edge->src, succ_edge->dest)] = flow_edges; - flow_edges = succ_edge; - } - } - } -} - -/* Follow the def-use chains for each definition on the worklist and - simulate the uses of the definition. */ - -static void -follow_def_use_chains (void) -{ - /* Iterate over all the entries on the SSA_EDGES worklist. */ - while (sbitmap_first_set_bit (ssa_edges) >= 0) - { - int member; - struct df_link *curruse; - - /* Pick an entry off the worklist (it does not matter which - entry we pick). */ - member = sbitmap_first_set_bit (ssa_edges); - RESET_BIT (ssa_edges, member); - - /* Iterate through all the uses of this entry. */ - for (curruse = df_analyzer->regs[member].uses; curruse; - curruse = curruse->next) - { - rtx useinsn; - - useinsn = DF_REF_INSN (curruse->ref); - if (PHI_NODE_P (useinsn)) - { - if (TEST_BIT (executable_blocks, BLOCK_NUM (useinsn))) - visit_phi_node (useinsn, BLOCK_FOR_INSN (useinsn)); - } - else - { - if (TEST_BIT (executable_blocks, BLOCK_NUM (useinsn))) - visit_expression (useinsn, BLOCK_FOR_INSN (useinsn)); - } - } - } -} - -/* Examine each edge to see if we were able to prove any were - not executable. - - If an edge is not executable, then we can remove its alternative - in PHI nodes as the destination of the edge, we can simplify the - conditional branch at the source of the edge, and we can remove - the edge from the CFG. Note we do not delete unreachable blocks - yet as the DF analyzer can not deal with that yet. */ -static void -optimize_unexecutable_edges (struct edge_list *edges, - sbitmap executable_edges) -{ - int i; - basic_block bb; - - for (i = 0; i < NUM_EDGES (edges); i++) - { - if (!TEST_BIT (executable_edges, i)) - { - edge edge = INDEX_EDGE (edges, i); - - if (edge->flags & EDGE_ABNORMAL) - continue; - - /* We found an edge that is not executable. First simplify - the PHI nodes in the target block. */ - if (edge->dest != EXIT_BLOCK_PTR) - { - rtx insn = first_insn_after_basic_block_note (edge->dest); - - while (PHI_NODE_P (insn)) - { - remove_phi_alternative (PATTERN (insn), edge->src); - if (rtl_dump_file) - fprintf (rtl_dump_file, - "Removing alternative for bb %d of phi %d\n", - edge->src->index, SSA_NAME (PATTERN (insn))); - insn = NEXT_INSN (insn); - } - } - if (rtl_dump_file) - fprintf (rtl_dump_file, - "Removing unexecutable edge from %d to %d\n", - edge->src->index, edge->dest->index); - /* Since the edge was not executable, remove it from the CFG. */ - remove_edge (edge); - } - } - - /* We have removed all the unexecutable edges from the CFG. Fix up - the conditional jumps at the end of any affected block. - - We have three cases to deal with: - - a. Both outgoing edges are not executable. This happens if the - source block is not reachable. We will deal with this by - deleting all the insns in the block later. - - b. The fall-thru edge is not executable. In this case we - change the conditional jump into an unconditional jump and - add a BARRIER after the unconditional jump. Note that since - we are working on generic RTL we can change the jump in-place - instead of dealing with the headache of reemitting the jump. - - c. The branch taken edge is not executable. In this case - we turn the jump into (set (pc) (pc)) which is a nop-jump - and we will remove the unrecognizable insn later. - - In cases B & C we are removing uses of registers, so make sure - to note those changes for the DF analyzer. */ - - FOR_EACH_BB (bb) - { - rtx insn = bb->end; - edge edge = bb->succ; - - /* If we have no predecessors, then this block is unreachable and - will be cleaned up when we remove unreachable blocks. */ - if (bb->pred == NULL || GET_CODE (insn) != JUMP_INSN) - continue; - - /* If this block ends in a conditional jump, but only has one - successor, then the jump needs adjustment. */ - if (condjump_p (insn) && ! simplejump_p (insn) - && bb->succ && bb->succ->succ_next == NULL) - { - /* If the fallthru edge is the executable edge, then turn - this jump into a nop jump, otherwise make it an unconditional - jump to its target. */ - if (edge->flags & EDGE_FALLTHRU) - { - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - } - else - { - SET_SRC (PATTERN (insn)) = gen_rtx_LABEL_REF (Pmode, - JUMP_LABEL (insn)); - emit_barrier_after (insn); - INSN_CODE (insn) = -1; - } - - /* Inform the DF analyzer that this insn changed. */ - df_insn_modify (df_analyzer, BLOCK_FOR_INSN (insn), insn); - } - } -} - -/* Perform substitution of known values for pseudo registers. - - ??? Note we do not do simplifications or constant folding here, it - is unlikely that any significant simplifications can be done here - anyway. Consider that if the simplification would result in an - expression that produces a constant value that the value would - have been discovered and recorded already. - - We perform two transformations. First, we initialize pseudos to their - known constant values at their definition point. Second, we try to - replace uses with the known constant value. */ - -static void -ssa_ccp_substitute_constants (void) -{ - unsigned int i; - - for (i = FIRST_PSEUDO_REGISTER; i < VARRAY_SIZE (ssa_definition); i++) - { - if (values[i].lattice_val == CONSTANT) - { - rtx def = VARRAY_RTX (ssa_definition, i); - rtx set = single_set (def); - struct df_link *curruse; - - if (! set) - continue; - - /* Do not try to simplify PHI nodes down to a constant load. - That will be done later as we translate out of SSA. Also, - doing that here could violate the rule that all PHI nodes - are consecutive at the start of the basic block. - - Don't do anything to nodes that were already sets to - constants. */ - if (! PHI_NODE_P (def) - && ! ((GET_CODE (def) == INSN - && GET_CODE (SET_SRC (set)) == CONST_INT))) - { - if (rtl_dump_file) - fprintf (rtl_dump_file, - "Register %d is now set to a constant\n", - SSA_NAME (PATTERN (def))); - SET_SRC (set) = values[i].const_value; - INSN_CODE (def) = -1; - df_insn_modify (df_analyzer, BLOCK_FOR_INSN (def), def); - } - - /* Iterate through all the uses of this entry and try replacements - there too. Note it is not particularly profitable to try - and fold/simplify expressions here as most of the common - cases were handled above. */ - for (curruse = df_analyzer->regs[i].uses; - curruse; - curruse = curruse->next) - { - rtx useinsn; - - useinsn = DF_REF_INSN (curruse->ref); - - if (!INSN_DELETED_P (useinsn) - && ! (GET_CODE (useinsn) == NOTE - && NOTE_LINE_NUMBER (useinsn) == NOTE_INSN_DELETED) - && (GET_CODE (useinsn) == INSN - || GET_CODE (useinsn) == JUMP_INSN)) - { - - if (validate_replace_src (regno_reg_rtx [i], - values[i].const_value, - useinsn)) - { - if (rtl_dump_file) - fprintf (rtl_dump_file, - "Register %d in insn %d replaced with constant\n", - i, INSN_UID (useinsn)); - INSN_CODE (useinsn) = -1; - df_insn_modify (df_analyzer, - BLOCK_FOR_INSN (useinsn), - useinsn); - } - - } - } - } - } -} - -/* Now find all unreachable basic blocks. All the insns in those - blocks are unreachable, so delete them and mark any necessary - updates for the DF analyzer. */ - -static void -ssa_ccp_df_delete_unreachable_insns (void) -{ - basic_block b; - - /* Use the CFG to find all the reachable blocks. */ - find_unreachable_blocks (); - - /* Now we know what blocks are not reachable. Mark all the insns - in those blocks as deleted for the DF analyzer. We'll let the - normal flow code actually remove the unreachable blocks. */ - FOR_EACH_BB_REVERSE (b) - { - if (!(b->flags & BB_REACHABLE)) - { - rtx start = b->head; - rtx end = b->end; - rtx tmp; - - /* Include any jump table following the basic block. */ - end = b->end; - if (tablejump_p (end, NULL, &tmp)) - end = tmp; - - while (1) - { - rtx next = NEXT_INSN (start); - - if (GET_CODE (start) == INSN - || GET_CODE (start) == CALL_INSN - || GET_CODE (start) == JUMP_INSN) - df_insn_delete (df_analyzer, BLOCK_FOR_INSN (start), start); - - if (start == end) - break; - start = next; - } - } - } -} - - -/* Main entry point for SSA Conditional Constant Propagation. - - Long term it should accept as input the specific flow graph to - operate on so that it can be called for sub-graphs. */ - -void -ssa_const_prop (void) -{ - unsigned int i; - edge curredge; - - /* We need alias analysis (for what?) */ - init_alias_analysis (); - - df_analyzer = df_init (); - df_analyse (df_analyzer, 0, - DF_RD_CHAIN | DF_RU_CHAIN | DF_REG_INFO | DF_HARD_REGS); - - /* Perform a quick and dirty dead code elimination pass. This is not - as aggressive as it could be, but it's good enough to clean up a - lot of unwanted junk and it is fast. */ - ssa_fast_dce (df_analyzer); - - /* Build an edge list from the CFG. */ - edges = create_edge_list (); - - /* Initialize the values array with everything as undefined. */ - values = xmalloc (VARRAY_SIZE (ssa_definition) * sizeof (value)); - for (i = 0; i < VARRAY_SIZE (ssa_definition); i++) - { - if (i < FIRST_PSEUDO_REGISTER) - values[i].lattice_val = VARYING; - else - values[i].lattice_val = UNDEFINED; - values[i].const_value = NULL; - } - - ssa_edges = sbitmap_alloc (VARRAY_SIZE (ssa_definition)); - sbitmap_zero (ssa_edges); - - executable_blocks = sbitmap_alloc (last_basic_block); - sbitmap_zero (executable_blocks); - - executable_edges = sbitmap_alloc (NUM_EDGES (edges)); - sbitmap_zero (executable_edges); - - edge_info = xmalloc (NUM_EDGES (edges) * sizeof (edge)); - flow_edges = ENTRY_BLOCK_PTR->succ; - - /* Add the successors of the entry block to the edge worklist. That - is enough of a seed to get SSA-CCP started. */ - for (curredge = ENTRY_BLOCK_PTR->succ; curredge; - curredge = curredge->succ_next) - { - int index = EIE (curredge->src, curredge->dest); - SET_BIT (executable_edges, index); - edge_info[index] = curredge->succ_next; - } - - /* Iterate until until the worklists are empty. */ - do - { - examine_flow_edges (); - follow_def_use_chains (); - } - while (flow_edges != NULL); - - /* Now perform substitutions based on the known constant values. */ - ssa_ccp_substitute_constants (); - - /* Remove unexecutable edges from the CFG and make appropriate - adjustments to PHI nodes. */ - optimize_unexecutable_edges (edges, executable_edges); - - /* Now remove all unreachable insns and update the DF information. - as appropriate. */ - ssa_ccp_df_delete_unreachable_insns (); - -#if 0 - /* The DF analyzer expects the number of blocks to remain constant, - so we can't remove unreachable blocks. - - Code the DF analyzer calls expects there to be no unreachable - blocks in the CFG. So we can't leave unreachable blocks in the - CFG. - - So, there is no way to do an incremental update of the DF data - at this point. */ - df_analyse (df_analyzer, 0, - DF_RD_CHAIN | DF_RU_CHAIN | DF_REG_INFO | DF_HARD_REGS); -#endif - - /* Clean up any dead code exposed by SSA-CCP, do this after updating - the dataflow information! */ - ssa_fast_dce (df_analyzer); - - free (values); - values = NULL; - - free (edge_info); - edge_info = NULL; - - sbitmap_free (executable_blocks); - executable_blocks = NULL; - - sbitmap_free (ssa_edges); - ssa_edges = NULL; - - free_edge_list (edges); - edges = NULL; - - sbitmap_free (executable_edges); - executable_edges = NULL; - - df_finish (df_analyzer); - end_alias_analysis (); -} - -static int -mark_references (rtx *current_rtx, void *data) -{ - rtx x = *current_rtx; - sbitmap worklist = (sbitmap) data; - - if (x == NULL_RTX) - return 0; - - if (GET_CODE (x) == SET) - { - rtx dest = SET_DEST (x); - - if (GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == SIGN_EXTRACT - || GET_CODE (dest) == ZERO_EXTRACT) - { - rtx reg; - - reg = dest; - - while (GET_CODE (reg) == STRICT_LOW_PART - || GET_CODE (reg) == SUBREG - || GET_CODE (reg) == SIGN_EXTRACT - || GET_CODE (reg) == ZERO_EXTRACT) - reg = XEXP (reg, 0); - - if (GET_CODE (reg) == REG) - SET_BIT (worklist, REGNO (reg)); - } - - if (GET_CODE (dest) == REG) - { - for_each_rtx (&SET_SRC (x), mark_references, data); - return -1; - } - - return 0; - } - else if (GET_CODE (x) == REG) - { - SET_BIT (worklist, REGNO (x)); - return -1; - } - else if (GET_CODE (x) == CLOBBER) - return -1; - else - return 0; -} - -static void -ssa_fast_dce (struct df *df) -{ - sbitmap worklist = sbitmap_alloc (VARRAY_SIZE (ssa_definition)); - sbitmap_ones (worklist); - - /* Iterate on the worklist until there's no definitions left to - examine. */ - while (sbitmap_first_set_bit (worklist) >= 0) - { - struct df_link *curruse; - int reg, found_use; - - /* Remove an item from the worklist. */ - reg = sbitmap_first_set_bit (worklist); - RESET_BIT (worklist, reg); - - /* We never consider deleting assignments to hard regs or things - which do not have SSA definitions, or things we have already - deleted, or things with unusual side effects. */ - if (reg < FIRST_PSEUDO_REGISTER - || ! VARRAY_RTX (ssa_definition, reg) - || INSN_DELETED_P (VARRAY_RTX (ssa_definition, reg)) - || (GET_CODE (VARRAY_RTX (ssa_definition, reg)) == NOTE - && (NOTE_LINE_NUMBER (VARRAY_RTX (ssa_definition, reg)) - == NOTE_INSN_DELETED)) - || side_effects_p (PATTERN (VARRAY_RTX (ssa_definition, reg)))) - continue; - - /* Iterate over the uses of this register. If we can not find - any uses that have not been deleted, then the definition of - this register is dead. */ - found_use = 0; - for (curruse = df->regs[reg].uses; curruse; curruse = curruse->next) - { - if (curruse->ref - && DF_REF_INSN (curruse->ref) - && ! INSN_DELETED_P (DF_REF_INSN (curruse->ref)) - && ! (GET_CODE (DF_REF_INSN (curruse->ref)) == NOTE - && (NOTE_LINE_NUMBER (DF_REF_INSN (curruse->ref)) - == NOTE_INSN_DELETED)) - && DF_REF_INSN (curruse->ref) != VARRAY_RTX (ssa_definition, reg)) - { - found_use = 1; - break; - } - } - - /* If we did not find a use of this register, then the definition - of this register is dead. */ - - if (! found_use) - { - rtx def = VARRAY_RTX (ssa_definition, reg); - - /* Add all registers referenced by INSN to the work - list. */ - for_each_rtx (&PATTERN (def), mark_references, worklist); - - /* Inform the analyzer that this insn is going to be - deleted. */ - df_insn_delete (df, BLOCK_FOR_INSN (def), def); - - VARRAY_RTX (ssa_definition, reg) = NULL; - } - } - - sbitmap_free (worklist); - - /* Update the use-def chains in the df_analyzer as needed. */ - df_analyse (df_analyzer, 0, - DF_RD_CHAIN | DF_RU_CHAIN | DF_REG_INFO | DF_HARD_REGS); -} diff --git a/gcc/ssa-dce.c b/gcc/ssa-dce.c deleted file mode 100644 index c308c7793b6..00000000000 --- a/gcc/ssa-dce.c +++ /dev/null @@ -1,713 +0,0 @@ -/* Dead-code elimination pass for the GNU compiler. - Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Written by Jeffrey D. Oldham . - -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. */ - -/* Dead-code elimination is the removal of instructions which have no - impact on the program's output. "Dead instructions" have no impact - on the program's output, while "necessary instructions" may have - impact on the output. - - The algorithm consists of three phases: - 1) marking as necessary all instructions known to be necessary, - e.g., writing a value to memory, - 2) propagating necessary instructions, e.g., the instructions - giving values to operands in necessary instructions, and - 3) removing dead instructions (except replacing dead conditionals - with unconditional jumps). - - Side Effects: - The last step can require adding labels, deleting insns, and - modifying basic block structures. Some conditional jumps may be - converted to unconditional jumps so the control-flow graph may be - out-of-date. - - Edges from some infinite loops to the exit block can be added to - the control-flow graph, but will be removed after this pass is - complete. - - It Does Not Perform: - We decided to not simultaneously perform jump optimization and dead - loop removal during dead-code elimination. Thus, all jump - instructions originally present remain after dead-code elimination - but 1) unnecessary conditional jump instructions are changed to - unconditional jump instructions and 2) all unconditional jump - instructions remain. - - Assumptions: - 1) SSA has been performed. - 2) The basic block and control-flow graph structures are accurate. - 3) The flow graph permits constructing an edge_list. - 4) note rtxes should be saved. - - Unfinished: - When replacing unnecessary conditional jumps with unconditional - jumps, the control-flow graph is not updated. It should be. - - References: - Building an Optimizing Compiler - Robert Morgan - Butterworth-Heinemann, 1998 - Section 8.9 -*/ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" - -#include "rtl.h" -#include "hard-reg-set.h" -#include "basic-block.h" -#include "ssa.h" -#include "insn-config.h" -#include "recog.h" -#include "output.h" - - -/* A map from blocks to the edges on which they are control dependent. */ -typedef struct { - /* A dynamically allocated array. The Nth element corresponds to - the block with index N + 2. The Ith bit in the bitmap is set if - that block is dependent on the Ith edge. */ - bitmap *data; - /* The number of elements in the array. */ - int length; -} control_dependent_block_to_edge_map_s, *control_dependent_block_to_edge_map; - -/* Local function prototypes. */ -static control_dependent_block_to_edge_map control_dependent_block_to_edge_map_create - (size_t num_basic_blocks); -static void set_control_dependent_block_to_edge_map_bit - (control_dependent_block_to_edge_map c, basic_block bb, int edge_index); -static void control_dependent_block_to_edge_map_free - (control_dependent_block_to_edge_map c); -static void find_all_control_dependences - (struct edge_list *el, dominance_info pdom, - control_dependent_block_to_edge_map cdbte); -static void find_control_dependence - (struct edge_list *el, int edge_index, dominance_info pdom, - control_dependent_block_to_edge_map cdbte); -static basic_block find_pdom (dominance_info pdom, basic_block block); -static int inherently_necessary_register_1 (rtx *current_rtx, void *data); -static int inherently_necessary_register (rtx current_rtx); -static int find_inherently_necessary (rtx current_rtx); -static int propagate_necessity_through_operand (rtx *current_rtx, void *data); -static void note_inherently_necessary_set (rtx, rtx, void *); - -/* Unnecessary insns are indicated using insns' in_struct bit. */ - -/* Indicate INSN is dead-code; returns nothing. */ -#define KILL_INSN(INSN) INSN_DEAD_CODE_P(INSN) = 1 -/* Indicate INSN is necessary, i.e., not dead-code; returns nothing. */ -#define RESURRECT_INSN(INSN) INSN_DEAD_CODE_P(INSN) = 0 -/* Return nonzero if INSN is unnecessary. */ -#define UNNECESSARY_P(INSN) INSN_DEAD_CODE_P(INSN) -static void mark_all_insn_unnecessary (void); -/* Execute CODE with free variable INSN for all unnecessary insns in - an unspecified order, producing no output. */ -#define EXECUTE_IF_UNNECESSARY(INSN, CODE) \ -{ \ - rtx INSN; \ - \ - for (INSN = get_insns (); INSN != NULL_RTX; INSN = NEXT_INSN (INSN)) \ - if (INSN_P (insn) && INSN_DEAD_CODE_P (INSN)) \ - { \ - CODE; \ - } \ -} - -/* Find the label beginning block BB. */ -static rtx find_block_label (basic_block bb); -/* Remove INSN, updating its basic block structure. */ -static void delete_insn_bb (rtx insn); - -/* Recording which blocks are control dependent on which edges. We - expect each block to be control dependent on very few edges so we - use a bitmap for each block recording its edges. An array holds - the bitmap. Its position 0 entry holds the bitmap for block - INVALID_BLOCK+1 so that all blocks, including the entry and exit - blocks can participate in the data structure. */ - -/* Create a control_dependent_block_to_edge_map, given the number - NUM_BASIC_BLOCKS of non-entry, non-exit basic blocks, e.g., - n_basic_blocks. This memory must be released using - control_dependent_block_to_edge_map_free (). */ - -static control_dependent_block_to_edge_map -control_dependent_block_to_edge_map_create (size_t num_basic_blocks) -{ - int i; - control_dependent_block_to_edge_map c - = xmalloc (sizeof (control_dependent_block_to_edge_map_s)); - c->length = num_basic_blocks - (INVALID_BLOCK+1); - c->data = xmalloc ((size_t) c->length*sizeof (bitmap)); - for (i = 0; i < c->length; ++i) - c->data[i] = BITMAP_XMALLOC (); - - return c; -} - -/* Indicate block BB is control dependent on an edge with index - EDGE_INDEX in the mapping C of blocks to edges on which they are - control-dependent. */ - -static void -set_control_dependent_block_to_edge_map_bit (control_dependent_block_to_edge_map c, - basic_block bb, int edge_index) -{ - if (bb->index - (INVALID_BLOCK+1) >= c->length) - abort (); - - bitmap_set_bit (c->data[bb->index - (INVALID_BLOCK+1)], - edge_index); -} - -/* Execute CODE for each edge (given number EDGE_NUMBER within the - CODE) for which the block containing INSN is control dependent, - returning no output. CDBTE is the mapping of blocks to edges on - which they are control-dependent. */ - -#define EXECUTE_IF_CONTROL_DEPENDENT(CDBTE, INSN, EDGE_NUMBER, CODE) \ - EXECUTE_IF_SET_IN_BITMAP \ - (CDBTE->data[BLOCK_NUM (INSN) - (INVALID_BLOCK+1)], 0, \ - EDGE_NUMBER, CODE) - -/* Destroy a control_dependent_block_to_edge_map C. */ - -static void -control_dependent_block_to_edge_map_free (control_dependent_block_to_edge_map c) -{ - int i; - for (i = 0; i < c->length; ++i) - BITMAP_XFREE (c->data[i]); - free (c); -} - -/* Record all blocks' control dependences on all edges in the edge - list EL, ala Morgan, Section 3.6. The mapping PDOM of blocks to - their postdominators are used, and results are stored in CDBTE, - which should be empty. */ - -static void -find_all_control_dependences (struct edge_list *el, dominance_info pdom, - control_dependent_block_to_edge_map cdbte) -{ - int i; - - for (i = 0; i < NUM_EDGES (el); ++i) - find_control_dependence (el, i, pdom, cdbte); -} - -/* Determine all blocks' control dependences on the given edge with - edge_list EL index EDGE_INDEX, ala Morgan, Section 3.6. The - mapping PDOM of blocks to their postdominators are used, and - results are stored in CDBTE, which is assumed to be initialized - with zeros in each (block b', edge) position. */ - -static void -find_control_dependence (struct edge_list *el, int edge_index, - dominance_info pdom, - control_dependent_block_to_edge_map cdbte) -{ - basic_block current_block; - basic_block ending_block; - - if (INDEX_EDGE_PRED_BB (el, edge_index) == EXIT_BLOCK_PTR) - abort (); - ending_block = - (INDEX_EDGE_PRED_BB (el, edge_index) == ENTRY_BLOCK_PTR) - ? ENTRY_BLOCK_PTR->next_bb - : find_pdom (pdom, INDEX_EDGE_PRED_BB (el, edge_index)); - - for (current_block = INDEX_EDGE_SUCC_BB (el, edge_index); - current_block != ending_block && current_block != EXIT_BLOCK_PTR; - current_block = find_pdom (pdom, current_block)) - { - set_control_dependent_block_to_edge_map_bit (cdbte, - current_block, - edge_index); - } -} - -/* Find the immediate postdominator PDOM of the specified basic block - BLOCK. This function is necessary because some blocks have - negative numbers. */ - -static basic_block -find_pdom (dominance_info pdom, basic_block block) -{ - if (!block) - abort (); - if (block->index == INVALID_BLOCK) - abort (); - - if (block == ENTRY_BLOCK_PTR) - return ENTRY_BLOCK_PTR->next_bb; - else if (block == EXIT_BLOCK_PTR) - return EXIT_BLOCK_PTR; - else - { - basic_block bb = get_immediate_dominator (pdom, block); - if (!bb) - return EXIT_BLOCK_PTR; - return bb; - } -} - -/* Determine if the given CURRENT_RTX uses a hard register not - converted to SSA. Returns nonzero only if it uses such a hard - register. DATA is not used. - - The program counter (PC) is not considered inherently necessary - since code should be position-independent and thus not depend on - particular PC values. */ - -static int -inherently_necessary_register_1 (rtx *current_rtx, - void *data ATTRIBUTE_UNUSED) -{ - rtx x = *current_rtx; - - if (x == NULL_RTX) - return 0; - switch (GET_CODE (x)) - { - case CLOBBER: - /* Do not traverse the rest of the clobber. */ - return -1; - break; - case PC: - return 0; - break; - case REG: - if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)) || x == pc_rtx) - return 0; - else - return !0; - break; - default: - return 0; - break; - } -} - -/* Return nonzero if the insn CURRENT_RTX is inherently necessary. */ - -static int -inherently_necessary_register (rtx current_rtx) -{ - return for_each_rtx (¤t_rtx, - &inherently_necessary_register_1, NULL); -} - - -/* Called via note_stores for each store in an insn. Note whether - or not a particular store is inherently necessary. Store a - nonzero value in inherently_necessary_p if such a store is found. */ - -static void -note_inherently_necessary_set (rtx dest, rtx set ATTRIBUTE_UNUSED, void *data) -{ - int *inherently_necessary_set_p = (int *) data; - - while (GET_CODE (dest) == SUBREG - || GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == ZERO_EXTRACT - || GET_CODE (dest) == SIGN_EXTRACT) - dest = XEXP (dest, 0); - - if (GET_CODE (dest) == MEM - || GET_CODE (dest) == UNSPEC - || GET_CODE (dest) == UNSPEC_VOLATILE) - *inherently_necessary_set_p = 1; -} - -/* Mark X as inherently necessary if appropriate. For example, - function calls and storing values into memory are inherently - necessary. This function is to be used with for_each_rtx (). - Return nonzero iff inherently necessary. */ - -static int -find_inherently_necessary (rtx x) -{ - if (x == NULL_RTX) - return 0; - else if (inherently_necessary_register (x)) - return !0; - else - switch (GET_CODE (x)) - { - case CALL_INSN: - case BARRIER: - case PREFETCH: - return !0; - case CODE_LABEL: - case NOTE: - return 0; - case JUMP_INSN: - return JUMP_TABLE_DATA_P (x) || computed_jump_p (x) != 0; - case INSN: - { - int inherently_necessary_set = 0; - note_stores (PATTERN (x), - note_inherently_necessary_set, - &inherently_necessary_set); - - /* If we found an inherently necessary set or an asm - instruction, then we consider this insn inherently - necessary. */ - return (inherently_necessary_set - || GET_CODE (PATTERN (x)) == ASM_INPUT - || asm_noperands (PATTERN (x)) >= 0); - } - default: - /* Found an impossible insn type. */ - abort (); - break; - } -} - -/* Propagate necessity through REG and SUBREG operands of CURRENT_RTX. - This function is called with for_each_rtx () on necessary - instructions. The DATA must be a varray of unprocessed - instructions. */ - -static int -propagate_necessity_through_operand (rtx *current_rtx, void *data) -{ - rtx x = *current_rtx; - varray_type *unprocessed_instructions = (varray_type *) data; - - if (x == NULL_RTX) - return 0; - switch ( GET_CODE (x)) - { - case REG: - if (CONVERT_REGISTER_TO_SSA_P (REGNO (x))) - { - rtx insn = VARRAY_RTX (ssa_definition, REGNO (x)); - if (insn != NULL_RTX && UNNECESSARY_P (insn)) - { - RESURRECT_INSN (insn); - VARRAY_PUSH_RTX (*unprocessed_instructions, insn); - } - } - return 0; - - default: - return 0; - } -} - -/* Indicate all insns initially assumed to be unnecessary. */ - -static void -mark_all_insn_unnecessary (void) -{ - rtx insn; - for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn)) { - if (INSN_P (insn)) - KILL_INSN (insn); - } - -} - -/* Find the label beginning block BB, adding one if necessary. */ - -static rtx -find_block_label (basic_block bb) -{ - rtx insn = bb->head; - if (LABEL_P (insn)) - return insn; - else - { - rtx new_label = emit_label_before (gen_label_rtx (), insn); - if (insn == bb->head) - bb->head = new_label; - return new_label; - } -} - -/* Remove INSN, updating its basic block structure. */ - -static void -delete_insn_bb (rtx insn) -{ - if (!insn) - abort (); - - /* Do not actually delete anything that is not an INSN. - - We can get here because we only consider INSNs as - potentially necessary. We leave it to later passes - to remove unnecessary notes, unused labels, etc. */ - if (! INSN_P (insn)) - return; - - delete_insn (insn); -} - -/* Perform the dead-code elimination. */ - -void -ssa_eliminate_dead_code (void) -{ - rtx insn; - basic_block bb; - /* Necessary instructions with operands to explore. */ - varray_type unprocessed_instructions; - /* Map element (b,e) is nonzero if the block is control dependent on - edge. "cdbte" abbreviates control dependent block to edge. */ - control_dependent_block_to_edge_map cdbte; - /* Element I is the immediate postdominator of block I. */ - dominance_info pdom; - struct edge_list *el; - - /* Initialize the data structures. */ - mark_all_insn_unnecessary (); - VARRAY_RTX_INIT (unprocessed_instructions, 64, - "unprocessed instructions"); - cdbte = control_dependent_block_to_edge_map_create (last_basic_block); - - /* Prepare for use of BLOCK_NUM (). */ - connect_infinite_loops_to_exit (); - - /* Compute control dependence. */ - pdom = calculate_dominance_info (CDI_POST_DOMINATORS); - el = create_edge_list (); - find_all_control_dependences (el, pdom, cdbte); - - /* Find inherently necessary instructions. */ - for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn)) - if (find_inherently_necessary (insn) && INSN_P (insn)) - { - RESURRECT_INSN (insn); - VARRAY_PUSH_RTX (unprocessed_instructions, insn); - } - - /* Propagate necessity using the operands of necessary instructions. */ - while (VARRAY_ACTIVE_SIZE (unprocessed_instructions) > 0) - { - rtx current_instruction; - int edge_number; - - current_instruction = VARRAY_TOP_RTX (unprocessed_instructions); - VARRAY_POP (unprocessed_instructions); - - /* Make corresponding control dependent edges necessary. */ - /* Assume the only JUMP_INSN is the block's last insn. It appears - that the last instruction of the program need not be a - JUMP_INSN. */ - - if (INSN_P (current_instruction) - && !JUMP_TABLE_DATA_P (current_instruction)) - { - /* Notes and labels contain no interesting operands. */ - EXECUTE_IF_CONTROL_DEPENDENT - (cdbte, current_instruction, edge_number, - { - rtx jump_insn = (INDEX_EDGE_PRED_BB (el, edge_number))->end; - if (GET_CODE (jump_insn) == JUMP_INSN - && UNNECESSARY_P (jump_insn)) - { - RESURRECT_INSN (jump_insn); - VARRAY_PUSH_RTX (unprocessed_instructions, jump_insn); - } - }); - - /* Propagate through the operands. */ - for_each_rtx (¤t_instruction, - &propagate_necessity_through_operand, - &unprocessed_instructions); - - /* PHI nodes are somewhat special in that each PHI alternative - has data and control dependencies. The data dependencies - are handled via propagate_necessity_through_operand. We - handle the control dependency here. - - We consider the control dependent edges leading to the - predecessor block associated with each PHI alternative - as necessary. */ - if (PHI_NODE_P (current_instruction)) - { - rtvec phi_vec = XVEC (SET_SRC (PATTERN (current_instruction)), 0); - int num_elem = GET_NUM_ELEM (phi_vec); - int v; - - for (v = num_elem - 2; v >= 0; v -= 2) - { - basic_block bb; - - bb = BASIC_BLOCK (INTVAL (RTVEC_ELT (phi_vec, v + 1))); - EXECUTE_IF_CONTROL_DEPENDENT - (cdbte, bb->end, edge_number, - { - rtx jump_insn; - - jump_insn = (INDEX_EDGE_PRED_BB (el, edge_number))->end; - if (((GET_CODE (jump_insn) == JUMP_INSN)) - && UNNECESSARY_P (jump_insn)) - { - RESURRECT_INSN (jump_insn); - VARRAY_PUSH_RTX (unprocessed_instructions, jump_insn); - } - }); - - } - } - } - } - - /* Remove the unnecessary instructions. */ - EXECUTE_IF_UNNECESSARY (insn, - { - if (any_condjump_p (insn)) - { - basic_block bb = BLOCK_FOR_INSN (insn); - basic_block pdom_bb = find_pdom (pdom, bb); - rtx lbl; - edge e; - - /* Egad. The immediate post dominator is the exit block. We - would like to optimize this conditional jump to jump directly - to the exit block. That can be difficult as we may not have - a suitable CODE_LABEL that allows us to fall unmolested into - the exit block. - - So, we just delete the conditional branch by turning it into - a deleted note. That is safe, but just not as optimal as - it could be. */ - if (pdom_bb == EXIT_BLOCK_PTR) - { - /* Since we're going to just delete the branch, we need - look at all the edges and remove all those which are not - a fallthru edge. */ - e = bb->succ; - while (e) - { - edge temp = e; - - e = e->succ_next; - if ((temp->flags & EDGE_FALLTHRU) == 0) - { - /* We've found a non-fallthru edge, find any PHI nodes - at the target and clean them up. */ - if (temp->dest != EXIT_BLOCK_PTR) - { - rtx insn - = first_insn_after_basic_block_note (temp->dest); - - while (PHI_NODE_P (insn)) - { - remove_phi_alternative (PATTERN (insn), temp->src); - insn = NEXT_INSN (insn); - } - } - - remove_edge (temp); - } - } - - /* Now "delete" the conditional jump. */ - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - continue; - } - - /* We've found a conditional branch that is unnecessary. - - First, remove all outgoing edges from this block, updating - PHI nodes as appropriate. */ - e = bb->succ; - while (e) - { - edge temp = e; - - e = e->succ_next; - - if (temp->flags & EDGE_ABNORMAL) - continue; - - /* We found an edge that is not executable. First simplify - the PHI nodes in the target block. */ - if (temp->dest != EXIT_BLOCK_PTR) - { - rtx insn = first_insn_after_basic_block_note (temp->dest); - - while (PHI_NODE_P (insn)) - { - remove_phi_alternative (PATTERN (insn), temp->src); - insn = NEXT_INSN (insn); - } - } - - remove_edge (temp); - } - - /* Create an edge from this block to the post dominator. - What about the PHI nodes at the target? */ - make_edge (bb, pdom_bb, 0); - - /* Third, transform this insn into an unconditional - jump to the label for the immediate postdominator. */ - lbl = find_block_label (pdom_bb); - SET_SRC (PATTERN (insn)) = gen_rtx_LABEL_REF (VOIDmode, lbl); - INSN_CODE (insn) = -1; - JUMP_LABEL (insn) = lbl; - LABEL_NUSES (lbl)++; - - /* A barrier must follow any unconditional jump. Barriers - are not in basic blocks so this must occur after - deleting the conditional jump. */ - emit_barrier_after (insn); - } - else if (!JUMP_P (insn)) - delete_insn_bb (insn); - }); - - /* Remove fake edges from the CFG. */ - remove_fake_edges (); - - /* Find any blocks with no successors and ensure they are followed - by a BARRIER. delete_insn has the nasty habit of deleting barriers - when deleting insns. */ - FOR_EACH_BB (bb) - { - if (bb->succ == NULL) - { - rtx next = NEXT_INSN (bb->end); - - if (!next || GET_CODE (next) != BARRIER) - emit_barrier_after (bb->end); - } - } - /* Release allocated memory. */ - for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn)) { - if (INSN_P (insn)) - RESURRECT_INSN (insn); - } - - if (VARRAY_ACTIVE_SIZE (unprocessed_instructions) != 0) - abort (); - control_dependent_block_to_edge_map_free (cdbte); - free (pdom); - free_edge_list (el); -} diff --git a/gcc/ssa.c b/gcc/ssa.c deleted file mode 100644 index c12cdbe7afb..00000000000 --- a/gcc/ssa.c +++ /dev/null @@ -1,2214 +0,0 @@ -/* Static Single Assignment conversion routines for the GNU compiler. - Copyright (C) 2000, 2001, 2002, 2003 - 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. */ - -/* References: - - Building an Optimizing Compiler - Robert Morgan - Butterworth-Heinemann, 1998 - - Static Single Assignment Construction - Preston Briggs, Tim Harvey, Taylor Simpson - Technical Report, Rice University, 1995 - ftp://ftp.cs.rice.edu/public/preston/optimizer/SSA.ps.gz. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" - -#include "rtl.h" -#include "expr.h" -#include "varray.h" -#include "partition.h" -#include "sbitmap.h" -#include "hashtab.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "flags.h" -#include "function.h" -#include "real.h" -#include "insn-config.h" -#include "recog.h" -#include "basic-block.h" -#include "output.h" -#include "ssa.h" - -/* TODO: - - Handle subregs better, maybe. For now, if a reg that's set in a - subreg expression is duplicated going into SSA form, an extra copy - is inserted first that copies the entire reg into the duplicate, so - that the other bits are preserved. This isn't strictly SSA, since - at least part of the reg is assigned in more than one place (though - they are adjacent). - - ??? What to do about strict_low_part. Probably I'll have to split - them out of their current instructions first thing. - - Actually the best solution may be to have a kind of "mid-level rtl" - in which the RTL encodes exactly what we want, without exposing a - lot of niggling processor details. At some later point we lower - the representation, calling back into optabs to finish any necessary - expansion. */ - -/* All pseudo-registers and select hard registers are converted to SSA - form. When converting out of SSA, these select hard registers are - guaranteed to be mapped to their original register number. Each - machine's .h file should define CONVERT_HARD_REGISTER_TO_SSA_P - indicating which hard registers should be converted. - - When converting out of SSA, temporaries for all registers are - partitioned. The partition is checked to ensure that all uses of - the same hard register in the same machine mode are in the same - class. */ - -/* If conservative_reg_partition is nonzero, use a conservative - register partitioning algorithm (which leaves more regs after - emerging from SSA) instead of the coalescing one. This is being - left in for a limited time only, as a debugging tool until the - coalescing algorithm is validated. */ - -static int conservative_reg_partition; - -/* This flag is set when the CFG is in SSA form. */ -int in_ssa_form = 0; - -/* Element I is the single instruction that sets register I. */ -varray_type ssa_definition; - -/* Element I-PSEUDO is the normal register that originated the ssa - register in question. */ -varray_type ssa_rename_from; - -/* Element I is the normal register that originated the ssa - register in question. - - A hash table stores the (register, rtl) pairs. These are each - xmalloc'ed and deleted when the hash table is destroyed. */ -htab_t ssa_rename_from_ht; - -/* The running target ssa register for a given pseudo register. - (Pseudo registers appear in only one mode.) */ -static rtx *ssa_rename_to_pseudo; -/* Similar, but for hard registers. A hard register can appear in - many modes, so we store an equivalent pseudo for each of the - modes. */ -static rtx ssa_rename_to_hard[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES]; - -/* ssa_rename_from maps pseudo registers to the original corresponding - RTL. It is implemented as using a hash table. */ - -typedef struct { - unsigned int reg; - rtx original; -} ssa_rename_from_pair; - -struct ssa_rename_from_hash_table_data { - sbitmap canonical_elements; - partition reg_partition; -}; - -static rtx gen_sequence (void); -static void ssa_rename_from_initialize (void); -static rtx ssa_rename_from_lookup (int reg); -static unsigned int original_register (unsigned int regno); -static void ssa_rename_from_insert (unsigned int reg, rtx r); -static void ssa_rename_from_free (void); -typedef int (*srf_trav) (int regno, rtx r, sbitmap canonical_elements, - partition reg_partition); -static void ssa_rename_from_traverse (htab_trav callback_function, - sbitmap canonical_elements, partition reg_partition); -/*static Avoid warning message. */ void ssa_rename_from_print (void); -static int ssa_rename_from_print_1 (void **slot, void *data); -static hashval_t ssa_rename_from_hash_function (const void * srfp); -static int ssa_rename_from_equal (const void *srfp1, const void *srfp2); -static void ssa_rename_from_delete (void *srfp); - -static rtx ssa_rename_to_lookup (rtx reg); -static void ssa_rename_to_insert (rtx reg, rtx r); - -/* The number of registers that were live on entry to the SSA routines. */ -static unsigned int ssa_max_reg_num; - -/* Local function prototypes. */ - -struct rename_context; - -static inline rtx * phi_alternative (rtx, int); -static void compute_dominance_frontiers_1 (sbitmap *frontiers, - dominance_info idom, int bb, - sbitmap done); -static void find_evaluations_1 (rtx dest, rtx set, void *data); -static void find_evaluations (sbitmap *evals, int nregs); -static void compute_iterated_dominance_frontiers (sbitmap *idfs, - sbitmap *frontiers, - sbitmap *evals, int nregs); -static void insert_phi_node (int regno, int b); -static void insert_phi_nodes (sbitmap *idfs, sbitmap *evals, int nregs); -static void create_delayed_rename (struct rename_context *, rtx *); -static void apply_delayed_renames (struct rename_context *); -static int rename_insn_1 (rtx *ptr, void *data); -static void rename_block (int b, dominance_info dom); -static void rename_registers (int nregs, dominance_info idom); - -static inline int ephi_add_node (rtx reg, rtx *nodes, int *n_nodes); -static int * ephi_forward (int t, sbitmap visited, sbitmap *succ, int *tstack); -static void ephi_backward (int t, sbitmap visited, sbitmap *pred, rtx *nodes); -static void ephi_create (int t, sbitmap visited, sbitmap *pred, - sbitmap *succ, rtx *nodes); -static void eliminate_phi (edge e, partition reg_partition); -static int make_regs_equivalent_over_bad_edges (int bb, - partition reg_partition); - -/* These are used only in the conservative register partitioning - algorithms. */ -static int make_equivalent_phi_alternatives_equivalent - (int bb, partition reg_partition); -static partition compute_conservative_reg_partition (void); -static int record_canonical_element_1 (void **srfp, void *data); -static int check_hard_regs_in_partition (partition reg_partition); - -/* These are used in the register coalescing algorithm. */ -static int coalesce_if_unconflicting (partition p, conflict_graph conflicts, - int reg1, int reg2); -static int coalesce_regs_in_copies (basic_block bb, partition p, - conflict_graph conflicts); -static int coalesce_reg_in_phi (rtx, int dest_regno, int src_regno, - void *data); -static int coalesce_regs_in_successor_phi_nodes (basic_block bb, - partition p, - conflict_graph conflicts); -static partition compute_coalesced_reg_partition (void); -static int mark_reg_in_phi (rtx *ptr, void *data); -static void mark_phi_and_copy_regs (regset phi_set); - -static int rename_equivalent_regs_in_insn (rtx *ptr, void *data); -static void rename_equivalent_regs (partition reg_partition); - -/* Deal with hard registers. */ -static int conflicting_hard_regs_p (int reg1, int reg2); - -/* ssa_rename_to maps registers and machine modes to SSA pseudo registers. */ - -/* Find the register associated with REG in the indicated mode. */ - -static rtx -ssa_rename_to_lookup (rtx reg) -{ - if (!HARD_REGISTER_P (reg)) - return ssa_rename_to_pseudo[REGNO (reg) - FIRST_PSEUDO_REGISTER]; - else - return ssa_rename_to_hard[REGNO (reg)][GET_MODE (reg)]; -} - -/* Store a new value mapping REG to R in ssa_rename_to. */ - -static void -ssa_rename_to_insert (rtx reg, rtx r) -{ - if (!HARD_REGISTER_P (reg)) - ssa_rename_to_pseudo[REGNO (reg) - FIRST_PSEUDO_REGISTER] = r; - else - ssa_rename_to_hard[REGNO (reg)][GET_MODE (reg)] = r; -} - -/* Prepare ssa_rename_from for use. */ - -static void -ssa_rename_from_initialize (void) -{ - /* We use an arbitrary initial hash table size of 64. */ - ssa_rename_from_ht = htab_create (64, - &ssa_rename_from_hash_function, - &ssa_rename_from_equal, - &ssa_rename_from_delete); -} - -/* Find the REG entry in ssa_rename_from. Return NULL_RTX if no entry is - found. */ - -static rtx -ssa_rename_from_lookup (int reg) -{ - ssa_rename_from_pair srfp; - ssa_rename_from_pair *answer; - srfp.reg = reg; - srfp.original = NULL_RTX; - answer = htab_find_with_hash (ssa_rename_from_ht, (void *) &srfp, reg); - return (answer == 0 ? NULL_RTX : answer->original); -} - -/* Find the number of the original register specified by REGNO. If - the register is a pseudo, return the original register's number. - Otherwise, return this register number REGNO. */ - -static unsigned int -original_register (unsigned int regno) -{ - rtx original_rtx = ssa_rename_from_lookup (regno); - return original_rtx != NULL_RTX ? REGNO (original_rtx) : regno; -} - -/* Add mapping from R to REG to ssa_rename_from even if already present. */ - -static void -ssa_rename_from_insert (unsigned int reg, rtx r) -{ - void **slot; - ssa_rename_from_pair *srfp = xmalloc (sizeof (ssa_rename_from_pair)); - srfp->reg = reg; - srfp->original = r; - slot = htab_find_slot_with_hash (ssa_rename_from_ht, (const void *) srfp, - reg, INSERT); - if (*slot != 0) - free ((void *) *slot); - *slot = srfp; -} - -/* Apply the CALLBACK_FUNCTION to each element in ssa_rename_from. - CANONICAL_ELEMENTS and REG_PARTITION pass data needed by the only - current use of this function. */ - -static void -ssa_rename_from_traverse (htab_trav callback_function, - sbitmap canonical_elements, partition reg_partition) -{ - struct ssa_rename_from_hash_table_data srfhd; - srfhd.canonical_elements = canonical_elements; - srfhd.reg_partition = reg_partition; - htab_traverse (ssa_rename_from_ht, callback_function, (void *) &srfhd); -} - -/* Destroy ssa_rename_from. */ - -static void -ssa_rename_from_free (void) -{ - htab_delete (ssa_rename_from_ht); -} - -/* Print the contents of ssa_rename_from. */ - -/* static Avoid erroneous error message. */ -void -ssa_rename_from_print (void) -{ - printf ("ssa_rename_from's hash table contents:\n"); - htab_traverse (ssa_rename_from_ht, &ssa_rename_from_print_1, NULL); -} - -/* Print the contents of the hash table entry SLOT, passing the unused - attribute DATA. Used as a callback function with htab_traverse (). */ - -static int -ssa_rename_from_print_1 (void **slot, void *data ATTRIBUTE_UNUSED) -{ - ssa_rename_from_pair * p = *slot; - printf ("ssa_rename_from maps pseudo %i to original %i.\n", - p->reg, REGNO (p->original)); - return 1; -} - -/* Given a hash entry SRFP, yield a hash value. */ - -static hashval_t -ssa_rename_from_hash_function (const void *srfp) -{ - return ((const ssa_rename_from_pair *) srfp)->reg; -} - -/* Test whether two hash table entries SRFP1 and SRFP2 are equal. */ - -static int -ssa_rename_from_equal (const void *srfp1, const void *srfp2) -{ - return ssa_rename_from_hash_function (srfp1) == - ssa_rename_from_hash_function (srfp2); -} - -/* Delete the hash table entry SRFP. */ - -static void -ssa_rename_from_delete (void *srfp) -{ - free (srfp); -} - -/* Given the SET of a PHI node, return the address of the alternative - for predecessor block C. */ - -static inline rtx * -phi_alternative (rtx set, int c) -{ - rtvec phi_vec = XVEC (SET_SRC (set), 0); - int v; - - for (v = GET_NUM_ELEM (phi_vec) - 2; v >= 0; v -= 2) - if (INTVAL (RTVEC_ELT (phi_vec, v + 1)) == c) - return &RTVEC_ELT (phi_vec, v); - - return NULL; -} - -/* Given the SET of a phi node, remove the alternative for predecessor - block C. Return nonzero on success, or zero if no alternative is - found for C. */ - -int -remove_phi_alternative (rtx set, basic_block block) -{ - rtvec phi_vec = XVEC (SET_SRC (set), 0); - int num_elem = GET_NUM_ELEM (phi_vec); - int v, c; - - c = block->index; - for (v = num_elem - 2; v >= 0; v -= 2) - if (INTVAL (RTVEC_ELT (phi_vec, v + 1)) == c) - { - if (v < num_elem - 2) - { - RTVEC_ELT (phi_vec, v) = RTVEC_ELT (phi_vec, num_elem - 2); - RTVEC_ELT (phi_vec, v + 1) = RTVEC_ELT (phi_vec, num_elem - 1); - } - PUT_NUM_ELEM (phi_vec, num_elem - 2); - return 1; - } - - return 0; -} - -/* For all registers, find all blocks in which they are set. - - This is the transform of what would be local kill information that - we ought to be getting from flow. */ - -static sbitmap *fe_evals; -static int fe_current_bb; - -static void -find_evaluations_1 (rtx dest, rtx set ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - if (GET_CODE (dest) == REG - && CONVERT_REGISTER_TO_SSA_P (REGNO (dest))) - SET_BIT (fe_evals[REGNO (dest)], fe_current_bb); -} - -static void -find_evaluations (sbitmap *evals, int nregs) -{ - basic_block bb; - - sbitmap_vector_zero (evals, nregs); - fe_evals = evals; - - FOR_EACH_BB_REVERSE (bb) - { - rtx p, last; - - fe_current_bb = bb->index; - p = bb->head; - last = bb->end; - while (1) - { - if (INSN_P (p)) - note_stores (PATTERN (p), find_evaluations_1, NULL); - - if (p == last) - break; - p = NEXT_INSN (p); - } - } -} - -/* Computing the Dominance Frontier: - - As described in Morgan, section 3.5, this may be done simply by - walking the dominator tree bottom-up, computing the frontier for - the children before the parent. When considering a block B, - there are two cases: - - (1) A flow graph edge leaving B that does not lead to a child - of B in the dominator tree must be a block that is either equal - to B or not dominated by B. Such blocks belong in the frontier - of B. - - (2) Consider a block X in the frontier of one of the children C - of B. If X is not equal to B and is not dominated by B, it - is in the frontier of B. -*/ - -static void -compute_dominance_frontiers_1 (sbitmap *frontiers, dominance_info idom, - int bb, sbitmap done) -{ - basic_block b = BASIC_BLOCK (bb); - edge e; - basic_block c; - - SET_BIT (done, bb); - sbitmap_zero (frontiers[bb]); - - /* Do the frontier of the children first. Not all children in the - dominator tree (blocks dominated by this one) are children in the - CFG, so check all blocks. */ - FOR_EACH_BB (c) - if (get_immediate_dominator (idom, c)->index == bb - && ! TEST_BIT (done, c->index)) - compute_dominance_frontiers_1 (frontiers, idom, c->index, done); - - /* Find blocks conforming to rule (1) above. */ - for (e = b->succ; e; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR) - continue; - if (get_immediate_dominator (idom, e->dest)->index != bb) - SET_BIT (frontiers[bb], e->dest->index); - } - - /* Find blocks conforming to rule (2). */ - FOR_EACH_BB (c) - if (get_immediate_dominator (idom, c)->index == bb) - { - int x; - EXECUTE_IF_SET_IN_SBITMAP (frontiers[c->index], 0, x, - { - if (get_immediate_dominator (idom, BASIC_BLOCK (x))->index != bb) - SET_BIT (frontiers[bb], x); - }); - } -} - -void -compute_dominance_frontiers (sbitmap *frontiers, dominance_info idom) -{ - sbitmap done = sbitmap_alloc (last_basic_block); - sbitmap_zero (done); - - compute_dominance_frontiers_1 (frontiers, idom, 0, done); - - sbitmap_free (done); -} - -/* Computing the Iterated Dominance Frontier: - - This is the set of merge points for a given register. - - This is not particularly intuitive. See section 7.1 of Morgan, in - particular figures 7.3 and 7.4 and the immediately surrounding text. -*/ - -static void -compute_iterated_dominance_frontiers (sbitmap *idfs, sbitmap *frontiers, - sbitmap *evals, int nregs) -{ - sbitmap worklist; - int reg, passes = 0; - - worklist = sbitmap_alloc (last_basic_block); - - for (reg = 0; reg < nregs; ++reg) - { - sbitmap idf = idfs[reg]; - int b, changed; - - /* Start the iterative process by considering those blocks that - evaluate REG. We'll add their dominance frontiers to the - IDF, and then consider the blocks we just added. */ - sbitmap_copy (worklist, evals[reg]); - - /* Morgan's algorithm is incorrect here. Blocks that evaluate - REG aren't necessarily in REG's IDF. Start with an empty IDF. */ - sbitmap_zero (idf); - - /* Iterate until the worklist is empty. */ - do - { - changed = 0; - passes++; - EXECUTE_IF_SET_IN_SBITMAP (worklist, 0, b, - { - RESET_BIT (worklist, b); - /* For each block on the worklist, add to the IDF all - blocks on its dominance frontier that aren't already - on the IDF. Every block that's added is also added - to the worklist. */ - sbitmap_union_of_diff (worklist, worklist, frontiers[b], idf); - sbitmap_a_or_b (idf, idf, frontiers[b]); - changed = 1; - }); - } - while (changed); - } - - sbitmap_free (worklist); - - if (rtl_dump_file) - { - fprintf (rtl_dump_file, - "Iterated dominance frontier: %d passes on %d regs.\n", - passes, nregs); - } -} - -/* Insert the phi nodes. */ - -static void -insert_phi_node (int regno, int bb) -{ - basic_block b = BASIC_BLOCK (bb); - edge e; - int npred, i; - rtvec vec; - rtx phi, reg; - rtx insn; - int end_p; - - /* Find out how many predecessors there are. */ - for (e = b->pred, npred = 0; e; e = e->pred_next) - if (e->src != ENTRY_BLOCK_PTR) - npred++; - - /* If this block has no "interesting" preds, then there is nothing to - do. Consider a block that only has the entry block as a pred. */ - if (npred == 0) - return; - - /* This is the register to which the phi function will be assigned. */ - reg = regno_reg_rtx[regno]; - - /* Construct the arguments to the PHI node. The use of pc_rtx is just - a placeholder; we'll insert the proper value in rename_registers. */ - vec = rtvec_alloc (npred * 2); - for (e = b->pred, i = 0; e ; e = e->pred_next, i += 2) - if (e->src != ENTRY_BLOCK_PTR) - { - RTVEC_ELT (vec, i + 0) = pc_rtx; - RTVEC_ELT (vec, i + 1) = GEN_INT (e->src->index); - } - - phi = gen_rtx_PHI (VOIDmode, vec); - phi = gen_rtx_SET (VOIDmode, reg, phi); - - insn = first_insn_after_basic_block_note (b); - end_p = PREV_INSN (insn) == b->end; - emit_insn_before (phi, insn); - if (end_p) - b->end = PREV_INSN (insn); -} - -static void -insert_phi_nodes (sbitmap *idfs, sbitmap *evals ATTRIBUTE_UNUSED, int nregs) -{ - int reg; - - for (reg = 0; reg < nregs; ++reg) - if (CONVERT_REGISTER_TO_SSA_P (reg)) - { - int b; - EXECUTE_IF_SET_IN_SBITMAP (idfs[reg], 0, b, - { - if (REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start, reg)) - insert_phi_node (reg, b); - }); - } -} - -/* Rename the registers to conform to SSA. - - This is essentially the algorithm presented in Figure 7.8 of Morgan, - with a few changes to reduce pattern search time in favor of a bit - more memory usage. */ - -/* One of these is created for each set. It will live in a list local - to its basic block for the duration of that block's processing. */ -struct rename_set_data -{ - struct rename_set_data *next; - /* This is the SET_DEST of the (first) SET that sets the REG. */ - rtx *reg_loc; - /* This is what used to be at *REG_LOC. */ - rtx old_reg; - /* This is the REG that will replace OLD_REG. It's set only - when the rename data is moved onto the DONE_RENAMES queue. */ - rtx new_reg; - /* This is what to restore ssa_rename_to_lookup (old_reg) to. It is - usually the previous contents of ssa_rename_to_lookup (old_reg). */ - rtx prev_reg; - /* This is the insn that contains all the SETs of the REG. */ - rtx set_insn; -}; - -/* This struct is used to pass information to callback functions while - renaming registers. */ -struct rename_context -{ - struct rename_set_data *new_renames; - struct rename_set_data *done_renames; - rtx current_insn; -}; - -/* Queue the rename of *REG_LOC. */ -static void -create_delayed_rename (struct rename_context *c, rtx *reg_loc) -{ - struct rename_set_data *r; - r = xmalloc (sizeof(*r)); - - if (GET_CODE (*reg_loc) != REG - || !CONVERT_REGISTER_TO_SSA_P (REGNO (*reg_loc))) - abort (); - - r->reg_loc = reg_loc; - r->old_reg = *reg_loc; - r->prev_reg = ssa_rename_to_lookup(r->old_reg); - r->set_insn = c->current_insn; - r->next = c->new_renames; - c->new_renames = r; -} - -/* This is part of a rather ugly hack to allow the pre-ssa regno to be - reused. If, during processing, a register has not yet been touched, - ssa_rename_to[regno][machno] will be NULL. Now, in the course of pushing - and popping values from ssa_rename_to, when we would ordinarily - pop NULL back in, we pop RENAME_NO_RTX. We treat this exactly the - same as NULL, except that it signals that the original regno has - already been reused. */ -#define RENAME_NO_RTX pc_rtx - -/* Move all the entries from NEW_RENAMES onto DONE_RENAMES by - applying all the renames on NEW_RENAMES. */ - -static void -apply_delayed_renames (struct rename_context *c) -{ - struct rename_set_data *r; - struct rename_set_data *last_r = NULL; - - for (r = c->new_renames; r != NULL; r = r->next) - { - int new_regno; - - /* Failure here means that someone has a PARALLEL that sets - a register twice (bad!). */ - if (ssa_rename_to_lookup (r->old_reg) != r->prev_reg) - abort (); - /* Failure here means we have changed REG_LOC before applying - the rename. */ - /* For the first set we come across, reuse the original regno. */ - if (r->prev_reg == NULL_RTX && !HARD_REGISTER_P (r->old_reg)) - { - r->new_reg = r->old_reg; - /* We want to restore RENAME_NO_RTX rather than NULL_RTX. */ - r->prev_reg = RENAME_NO_RTX; - } - else - r->new_reg = gen_reg_rtx (GET_MODE (r->old_reg)); - new_regno = REGNO (r->new_reg); - ssa_rename_to_insert (r->old_reg, r->new_reg); - - if (new_regno >= (int) ssa_definition->num_elements) - { - int new_limit = new_regno * 5 / 4; - VARRAY_GROW (ssa_definition, new_limit); - } - - VARRAY_RTX (ssa_definition, new_regno) = r->set_insn; - ssa_rename_from_insert (new_regno, r->old_reg); - last_r = r; - } - if (last_r != NULL) - { - last_r->next = c->done_renames; - c->done_renames = c->new_renames; - c->new_renames = NULL; - } -} - -/* Part one of the first step of rename_block, called through for_each_rtx. - Mark pseudos that are set for later update. Transform uses of pseudos. */ - -static int -rename_insn_1 (rtx *ptr, void *data) -{ - rtx x = *ptr; - struct rename_context *context = data; - - if (x == NULL_RTX) - return 0; - - switch (GET_CODE (x)) - { - case SET: - { - rtx *destp = &SET_DEST (x); - rtx dest = SET_DEST (x); - - /* An assignment to a paradoxical SUBREG does not read from - the destination operand, and thus does not need to be - wrapped into a SEQUENCE when translating into SSA form. - We merely strip off the SUBREG and proceed normally for - this case. */ - if (GET_CODE (dest) == SUBREG - && (GET_MODE_SIZE (GET_MODE (dest)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))) - && GET_CODE (SUBREG_REG (dest)) == REG - && CONVERT_REGISTER_TO_SSA_P (REGNO (SUBREG_REG (dest)))) - { - destp = &XEXP (dest, 0); - dest = XEXP (dest, 0); - } - - /* Some SETs also use the REG specified in their LHS. - These can be detected by the presence of - STRICT_LOW_PART, SUBREG, SIGN_EXTRACT, and ZERO_EXTRACT - in the LHS. Handle these by changing - (set (subreg (reg foo)) ...) - into - (sequence [(set (reg foo_1) (reg foo)) - (set (subreg (reg foo_1)) ...)]) - - FIXME: Much of the time this is too much. For some constructs - we know that the output register is strictly an output - (paradoxical SUBREGs and some libcalls for example). - - For those cases we are better off not making the false - dependency. */ - if (GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == SIGN_EXTRACT - || GET_CODE (dest) == ZERO_EXTRACT) - { - rtx i, reg; - reg = dest; - - while (GET_CODE (reg) == STRICT_LOW_PART - || GET_CODE (reg) == SUBREG - || GET_CODE (reg) == SIGN_EXTRACT - || GET_CODE (reg) == ZERO_EXTRACT) - reg = XEXP (reg, 0); - - if (GET_CODE (reg) == REG - && CONVERT_REGISTER_TO_SSA_P (REGNO (reg))) - { - /* Generate (set reg reg), and do renaming on it so - that it becomes (set reg_1 reg_0), and we will - replace reg with reg_1 in the SUBREG. */ - - struct rename_set_data *saved_new_renames; - saved_new_renames = context->new_renames; - context->new_renames = NULL; - i = emit_insn (gen_rtx_SET (VOIDmode, reg, reg)); - for_each_rtx (&i, rename_insn_1, data); - apply_delayed_renames (context); - context->new_renames = saved_new_renames; - } - } - else if (GET_CODE (dest) == REG - && CONVERT_REGISTER_TO_SSA_P (REGNO (dest))) - { - /* We found a genuine set of an interesting register. Tag - it so that we can create a new name for it after we finish - processing this insn. */ - - create_delayed_rename (context, destp); - - /* Since we do not wish to (directly) traverse the - SET_DEST, recurse through for_each_rtx for the SET_SRC - and return. */ - if (GET_CODE (x) == SET) - for_each_rtx (&SET_SRC (x), rename_insn_1, data); - return -1; - } - - /* Otherwise, this was not an interesting destination. Continue - on, marking uses as normal. */ - return 0; - } - - case REG: - if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)) - && REGNO (x) < ssa_max_reg_num) - { - rtx new_reg = ssa_rename_to_lookup (x); - - if (new_reg != RENAME_NO_RTX && new_reg != NULL_RTX) - { - if (GET_MODE (x) != GET_MODE (new_reg)) - abort (); - *ptr = new_reg; - } - else - { - /* Undefined value used, rename it to a new pseudo register so - that it cannot conflict with an existing register. */ - *ptr = gen_reg_rtx (GET_MODE (x)); - } - } - return -1; - - case CLOBBER: - /* There is considerable debate on how CLOBBERs ought to be - handled in SSA. For now, we're keeping the CLOBBERs, which - means that we don't really have SSA form. There are a couple - of proposals for how to fix this problem, but neither is - implemented yet. */ - { - rtx dest = XCEXP (x, 0, CLOBBER); - if (REG_P (dest)) - { - if (CONVERT_REGISTER_TO_SSA_P (REGNO (dest)) - && REGNO (dest) < ssa_max_reg_num) - { - rtx new_reg = ssa_rename_to_lookup (dest); - if (new_reg != NULL_RTX && new_reg != RENAME_NO_RTX) - XCEXP (x, 0, CLOBBER) = new_reg; - } - /* Stop traversing. */ - return -1; - } - else - /* Continue traversing. */ - return 0; - } - - case PHI: - /* Never muck with the phi. We do that elsewhere, special-like. */ - return -1; - - default: - /* Anything else, continue traversing. */ - return 0; - } -} - -static rtx -gen_sequence (void) -{ - rtx first_insn = get_insns (); - rtx result; - rtx tem; - int i; - int len; - - /* Count the insns in the chain. */ - len = 0; - for (tem = first_insn; tem; tem = NEXT_INSN (tem)) - len++; - - result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len)); - - for (i = 0, tem = first_insn; tem; tem = NEXT_INSN (tem), i++) - XVECEXP (result, 0, i) = tem; - - return result; -} - -static void -rename_block (int bb, dominance_info idom) -{ - basic_block b = BASIC_BLOCK (bb); - edge e; - rtx insn, next, last; - struct rename_set_data *set_data = NULL; - basic_block c; - - /* Step One: Walk the basic block, adding new names for sets and - replacing uses. */ - - next = b->head; - last = b->end; - do - { - insn = next; - if (INSN_P (insn)) - { - struct rename_context context; - context.done_renames = set_data; - context.new_renames = NULL; - context.current_insn = insn; - - start_sequence (); - for_each_rtx (&PATTERN (insn), rename_insn_1, &context); - for_each_rtx (®_NOTES (insn), rename_insn_1, &context); - - /* Sometimes, we end up with a sequence of insns that - SSA needs to treat as a single insn. Wrap these in a - SEQUENCE. (Any notes now get attached to the SEQUENCE, - not to the old version inner insn.) */ - if (get_insns () != NULL_RTX) - { - rtx seq; - int i; - - emit (PATTERN (insn)); - seq = gen_sequence (); - /* We really want a SEQUENCE of SETs, not a SEQUENCE - of INSNs. */ - for (i = 0; i < XVECLEN (seq, 0); i++) - XVECEXP (seq, 0, i) = PATTERN (XVECEXP (seq, 0, i)); - PATTERN (insn) = seq; - } - end_sequence (); - - apply_delayed_renames (&context); - set_data = context.done_renames; - } - - next = NEXT_INSN (insn); - } - while (insn != last); - - /* Step Two: Update the phi nodes of this block's successors. */ - - for (e = b->succ; e; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR) - continue; - - insn = first_insn_after_basic_block_note (e->dest); - - while (PHI_NODE_P (insn)) - { - rtx phi = PATTERN (insn); - rtx reg; - - /* Find out which of our outgoing registers this node is - intended to replace. Note that if this is not the first PHI - node to have been created for this register, we have to - jump through rename links to figure out which register - we're talking about. This can easily be recognized by - noting that the regno is new to this pass. */ - reg = SET_DEST (phi); - if (REGNO (reg) >= ssa_max_reg_num) - reg = ssa_rename_from_lookup (REGNO (reg)); - if (reg == NULL_RTX) - abort (); - reg = ssa_rename_to_lookup (reg); - - /* It is possible for the variable to be uninitialized on - edges in. Reduce the arity of the PHI so that we don't - consider those edges. */ - if (reg == NULL || reg == RENAME_NO_RTX) - { - if (! remove_phi_alternative (phi, b)) - abort (); - } - else - { - /* When we created the PHI nodes, we did not know what mode - the register should be. Now that we've found an original, - we can fill that in. */ - if (GET_MODE (SET_DEST (phi)) == VOIDmode) - PUT_MODE (SET_DEST (phi), GET_MODE (reg)); - else if (GET_MODE (SET_DEST (phi)) != GET_MODE (reg)) - abort (); - - *phi_alternative (phi, bb) = reg; - } - - insn = NEXT_INSN (insn); - } - } - - /* Step Three: Do the same to the children of this block in - dominator order. */ - - FOR_EACH_BB (c) - if (get_immediate_dominator (idom, c)->index == bb) - rename_block (c->index, idom); - - /* Step Four: Update the sets to refer to their new register, - and restore ssa_rename_to to its previous state. */ - - while (set_data) - { - struct rename_set_data *next; - rtx old_reg = *set_data->reg_loc; - - if (*set_data->reg_loc != set_data->old_reg) - abort (); - *set_data->reg_loc = set_data->new_reg; - - ssa_rename_to_insert (old_reg, set_data->prev_reg); - - next = set_data->next; - free (set_data); - set_data = next; - } -} - -static void -rename_registers (int nregs, dominance_info idom) -{ - VARRAY_RTX_INIT (ssa_definition, nregs * 3, "ssa_definition"); - ssa_rename_from_initialize (); - - ssa_rename_to_pseudo = alloca (nregs * sizeof(rtx)); - memset (ssa_rename_to_pseudo, 0, nregs * sizeof(rtx)); - memset (ssa_rename_to_hard, 0, - FIRST_PSEUDO_REGISTER * NUM_MACHINE_MODES * sizeof (rtx)); - - rename_block (0, idom); - - /* ??? Update basic_block_live_at_start, and other flow info - as needed. */ - - ssa_rename_to_pseudo = NULL; -} - -/* The main entry point for moving to SSA. */ - -void -convert_to_ssa (void) -{ - /* Element I is the set of blocks that set register I. */ - sbitmap *evals; - - /* Dominator bitmaps. */ - sbitmap *dfs; - sbitmap *idfs; - - /* Element I is the immediate dominator of block I. */ - dominance_info idom; - - int nregs; - - basic_block bb; - - /* Don't do it twice. */ - if (in_ssa_form) - abort (); - - /* Need global_live_at_{start,end} up to date. Do not remove any - dead code. We'll let the SSA optimizers do that. */ - life_analysis (get_insns (), NULL, 0); - - idom = calculate_dominance_info (CDI_DOMINATORS); - - if (rtl_dump_file) - { - fputs (";; Immediate Dominators:\n", rtl_dump_file); - FOR_EACH_BB (bb) - fprintf (rtl_dump_file, ";\t%3d = %3d\n", bb->index, - get_immediate_dominator (idom, bb)->index); - fflush (rtl_dump_file); - } - - /* Compute dominance frontiers. */ - - dfs = sbitmap_vector_alloc (last_basic_block, last_basic_block); - compute_dominance_frontiers (dfs, idom); - - if (rtl_dump_file) - { - dump_sbitmap_vector (rtl_dump_file, ";; Dominance Frontiers:", - "; Basic Block", dfs, last_basic_block); - fflush (rtl_dump_file); - } - - /* Compute register evaluations. */ - - ssa_max_reg_num = max_reg_num (); - nregs = ssa_max_reg_num; - evals = sbitmap_vector_alloc (nregs, last_basic_block); - find_evaluations (evals, nregs); - - /* Compute the iterated dominance frontier for each register. */ - - idfs = sbitmap_vector_alloc (nregs, last_basic_block); - compute_iterated_dominance_frontiers (idfs, dfs, evals, nregs); - - if (rtl_dump_file) - { - dump_sbitmap_vector (rtl_dump_file, ";; Iterated Dominance Frontiers:", - "; Register", idfs, nregs); - fflush (rtl_dump_file); - } - - /* Insert the phi nodes. */ - - insert_phi_nodes (idfs, evals, nregs); - - /* Rename the registers to satisfy SSA. */ - - rename_registers (nregs, idom); - - /* All done! Clean up and go home. */ - - sbitmap_vector_free (dfs); - sbitmap_vector_free (evals); - sbitmap_vector_free (idfs); - in_ssa_form = 1; - - reg_scan (get_insns (), max_reg_num (), 1); - free_dominance_info (idom); -} - -/* REG is the representative temporary of its partition. Add it to the - set of nodes to be processed, if it hasn't been already. Return the - index of this register in the node set. */ - -static inline int -ephi_add_node (rtx reg, rtx *nodes, int *n_nodes) -{ - int i; - for (i = *n_nodes - 1; i >= 0; --i) - if (REGNO (reg) == REGNO (nodes[i])) - return i; - - nodes[i = (*n_nodes)++] = reg; - return i; -} - -/* Part one of the topological sort. This is a forward (downward) search - through the graph collecting a stack of nodes to process. Assuming no - cycles, the nodes at top of the stack when we are finished will have - no other dependencies. */ - -static int * -ephi_forward (int t, sbitmap visited, sbitmap *succ, int *tstack) -{ - int s; - - SET_BIT (visited, t); - - EXECUTE_IF_SET_IN_SBITMAP (succ[t], 0, s, - { - if (! TEST_BIT (visited, s)) - tstack = ephi_forward (s, visited, succ, tstack); - }); - - *tstack++ = t; - return tstack; -} - -/* Part two of the topological sort. The is a backward search through - a cycle in the graph, copying the data forward as we go. */ - -static void -ephi_backward (int t, sbitmap visited, sbitmap *pred, rtx *nodes) -{ - int p; - - SET_BIT (visited, t); - - EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p, - { - if (! TEST_BIT (visited, p)) - { - ephi_backward (p, visited, pred, nodes); - emit_move_insn (nodes[p], nodes[t]); - } - }); -} - -/* Part two of the topological sort. Create the copy for a register - and any cycle of which it is a member. */ - -static void -ephi_create (int t, sbitmap visited, sbitmap *pred, sbitmap *succ, rtx *nodes) -{ - rtx reg_u = NULL_RTX; - int unvisited_predecessors = 0; - int p; - - /* Iterate through the predecessor list looking for unvisited nodes. - If there are any, we have a cycle, and must deal with that. At - the same time, look for a visited predecessor. If there is one, - we won't need to create a temporary. */ - - EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p, - { - if (! TEST_BIT (visited, p)) - unvisited_predecessors = 1; - else if (!reg_u) - reg_u = nodes[p]; - }); - - if (unvisited_predecessors) - { - /* We found a cycle. Copy out one element of the ring (if necessary), - then traverse the ring copying as we go. */ - - if (!reg_u) - { - reg_u = gen_reg_rtx (GET_MODE (nodes[t])); - emit_move_insn (reg_u, nodes[t]); - } - - EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p, - { - if (! TEST_BIT (visited, p)) - { - ephi_backward (p, visited, pred, nodes); - emit_move_insn (nodes[p], reg_u); - } - }); - } - else - { - /* No cycle. Just copy the value from a successor. */ - - int s; - EXECUTE_IF_SET_IN_SBITMAP (succ[t], 0, s, - { - SET_BIT (visited, t); - emit_move_insn (nodes[t], nodes[s]); - return; - }); - } -} - -/* Convert the edge to normal form. */ - -static void -eliminate_phi (edge e, partition reg_partition) -{ - int n_nodes; - sbitmap *pred, *succ; - sbitmap visited; - rtx *nodes; - int *stack, *tstack; - rtx insn; - int i; - - /* Collect an upper bound on the number of registers needing processing. */ - - insn = first_insn_after_basic_block_note (e->dest); - - n_nodes = 0; - while (PHI_NODE_P (insn)) - { - insn = next_nonnote_insn (insn); - n_nodes += 2; - } - - if (n_nodes == 0) - return; - - /* Build the auxiliary graph R(B). - - The nodes of the graph are the members of the register partition - present in Phi(B). There is an edge from FIND(T0)->FIND(T1) for - each T0 = PHI(...,T1,...), where T1 is for the edge from block C. */ - - nodes = alloca (n_nodes * sizeof(rtx)); - pred = sbitmap_vector_alloc (n_nodes, n_nodes); - succ = sbitmap_vector_alloc (n_nodes, n_nodes); - sbitmap_vector_zero (pred, n_nodes); - sbitmap_vector_zero (succ, n_nodes); - - insn = first_insn_after_basic_block_note (e->dest); - - n_nodes = 0; - for (; PHI_NODE_P (insn); insn = next_nonnote_insn (insn)) - { - rtx* preg = phi_alternative (PATTERN (insn), e->src->index); - rtx tgt = SET_DEST (PATTERN (insn)); - rtx reg; - - /* There may be no phi alternative corresponding to this edge. - This indicates that the phi variable is undefined along this - edge. */ - if (preg == NULL) - continue; - reg = *preg; - - if (GET_CODE (reg) != REG || GET_CODE (tgt) != REG) - abort (); - - reg = regno_reg_rtx[partition_find (reg_partition, REGNO (reg))]; - tgt = regno_reg_rtx[partition_find (reg_partition, REGNO (tgt))]; - /* If the two registers are already in the same partition, - nothing will need to be done. */ - if (reg != tgt) - { - int ireg, itgt; - - ireg = ephi_add_node (reg, nodes, &n_nodes); - itgt = ephi_add_node (tgt, nodes, &n_nodes); - - SET_BIT (pred[ireg], itgt); - SET_BIT (succ[itgt], ireg); - } - } - - if (n_nodes == 0) - goto out; - - /* Begin a topological sort of the graph. */ - - visited = sbitmap_alloc (n_nodes); - sbitmap_zero (visited); - - tstack = stack = alloca (n_nodes * sizeof (int)); - - for (i = 0; i < n_nodes; ++i) - if (! TEST_BIT (visited, i)) - tstack = ephi_forward (i, visited, succ, tstack); - - sbitmap_zero (visited); - - /* As we find a solution to the tsort, collect the implementation - insns in a sequence. */ - start_sequence (); - - while (tstack != stack) - { - i = *--tstack; - if (! TEST_BIT (visited, i)) - ephi_create (i, visited, pred, succ, nodes); - } - - insn = get_insns (); - end_sequence (); - insert_insn_on_edge (insn, e); - if (rtl_dump_file) - fprintf (rtl_dump_file, "Emitting copy on edge (%d,%d)\n", - e->src->index, e->dest->index); - - sbitmap_free (visited); -out: - sbitmap_vector_free (pred); - sbitmap_vector_free (succ); -} - -/* For basic block B, consider all phi insns which provide an - alternative corresponding to an incoming abnormal critical edge. - Place the phi alternative corresponding to that abnormal critical - edge in the same register class as the destination of the set. - - From Morgan, p. 178: - - For each abnormal critical edge (C, B), - if T0 = phi (T1, ..., Ti, ..., Tm) is a phi node in B, - and C is the ith predecessor of B, - then T0 and Ti must be equivalent. - - Return nonzero iff any such cases were found for which the two - regs were not already in the same class. */ - -static int -make_regs_equivalent_over_bad_edges (int bb, partition reg_partition) -{ - int changed = 0; - basic_block b = BASIC_BLOCK (bb); - rtx phi; - - /* Advance to the first phi node. */ - phi = first_insn_after_basic_block_note (b); - - /* Scan all the phi nodes. */ - for (; - PHI_NODE_P (phi); - phi = next_nonnote_insn (phi)) - { - edge e; - int tgt_regno; - rtx set = PATTERN (phi); - rtx tgt = SET_DEST (set); - - /* The set target is expected to be an SSA register. */ - if (GET_CODE (tgt) != REG - || !CONVERT_REGISTER_TO_SSA_P (REGNO (tgt))) - abort (); - tgt_regno = REGNO (tgt); - - /* Scan incoming abnormal critical edges. */ - for (e = b->pred; e; e = e->pred_next) - if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e)) - { - rtx *alt = phi_alternative (set, e->src->index); - int alt_regno; - - /* If there is no alternative corresponding to this edge, - the value is undefined along the edge, so just go on. */ - if (alt == 0) - continue; - - /* The phi alternative is expected to be an SSA register. */ - if (GET_CODE (*alt) != REG - || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt))) - abort (); - alt_regno = REGNO (*alt); - - /* If the set destination and the phi alternative aren't - already in the same class... */ - if (partition_find (reg_partition, tgt_regno) - != partition_find (reg_partition, alt_regno)) - { - /* ... make them such. */ - if (conflicting_hard_regs_p (tgt_regno, alt_regno)) - /* It is illegal to unify a hard register with a - different register. */ - abort (); - - partition_union (reg_partition, - tgt_regno, alt_regno); - ++changed; - } - } - } - - return changed; -} - -/* Consider phi insns in basic block BB pairwise. If the set target - of both insns are equivalent pseudos, make the corresponding phi - alternatives in each phi corresponding equivalent. - - Return nonzero if any new register classes were unioned. */ - -static int -make_equivalent_phi_alternatives_equivalent (int bb, partition reg_partition) -{ - int changed = 0; - basic_block b = BASIC_BLOCK (bb); - rtx phi; - - /* Advance to the first phi node. */ - phi = first_insn_after_basic_block_note (b); - - /* Scan all the phi nodes. */ - for (; - PHI_NODE_P (phi); - phi = next_nonnote_insn (phi)) - { - rtx set = PATTERN (phi); - /* The regno of the destination of the set. */ - int tgt_regno = REGNO (SET_DEST (PATTERN (phi))); - - rtx phi2 = next_nonnote_insn (phi); - - /* Scan all phi nodes following this one. */ - for (; - PHI_NODE_P (phi2); - phi2 = next_nonnote_insn (phi2)) - { - rtx set2 = PATTERN (phi2); - /* The regno of the destination of the set. */ - int tgt2_regno = REGNO (SET_DEST (set2)); - - /* Are the set destinations equivalent regs? */ - if (partition_find (reg_partition, tgt_regno) == - partition_find (reg_partition, tgt2_regno)) - { - edge e; - /* Scan over edges. */ - for (e = b->pred; e; e = e->pred_next) - { - int pred_block = e->src->index; - /* Identify the phi alternatives from both phi - nodes corresponding to this edge. */ - rtx *alt = phi_alternative (set, pred_block); - rtx *alt2 = phi_alternative (set2, pred_block); - - /* If one of the phi nodes doesn't have a - corresponding alternative, just skip it. */ - if (alt == 0 || alt2 == 0) - continue; - - /* Both alternatives should be SSA registers. */ - if (GET_CODE (*alt) != REG - || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt))) - abort (); - if (GET_CODE (*alt2) != REG - || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt2))) - abort (); - - /* If the alternatives aren't already in the same - class ... */ - if (partition_find (reg_partition, REGNO (*alt)) - != partition_find (reg_partition, REGNO (*alt2))) - { - /* ... make them so. */ - if (conflicting_hard_regs_p (REGNO (*alt), REGNO (*alt2))) - /* It is illegal to unify a hard register with - a different register. */ - abort (); - - partition_union (reg_partition, - REGNO (*alt), REGNO (*alt2)); - ++changed; - } - } - } - } - } - - return changed; -} - -/* Compute a conservative partition of outstanding pseudo registers. - See Morgan 7.3.1. */ - -static partition -compute_conservative_reg_partition (void) -{ - basic_block bb; - int changed = 0; - - /* We don't actually work with hard registers, but it's easier to - carry them around anyway rather than constantly doing register - number arithmetic. */ - partition p = - partition_new (ssa_definition->num_elements); - - /* The first priority is to make sure registers that might have to - be copied on abnormal critical edges are placed in the same - partition. This saves us from having to split abnormal critical - edges. */ - FOR_EACH_BB_REVERSE (bb) - changed += make_regs_equivalent_over_bad_edges (bb->index, p); - - /* Now we have to insure that corresponding arguments of phi nodes - assigning to corresponding regs are equivalent. Iterate until - nothing changes. */ - while (changed > 0) - { - changed = 0; - FOR_EACH_BB_REVERSE (bb) - changed += make_equivalent_phi_alternatives_equivalent (bb->index, p); - } - - return p; -} - -/* The following functions compute a register partition that attempts - to eliminate as many reg copies and phi node copies as possible by - coalescing registers. This is the strategy: - - 1. As in the conservative case, the top priority is to coalesce - registers that otherwise would cause copies to be placed on - abnormal critical edges (which isn't possible). - - 2. Figure out which regs are involved (in the LHS or RHS) of - copies and phi nodes. Compute conflicts among these regs. - - 3. Walk around the instruction stream, placing two regs in the - same class of the partition if one appears on the LHS and the - other on the RHS of a copy or phi node and the two regs don't - conflict. The conflict information of course needs to be - updated. - - 4. If anything has changed, there may be new opportunities to - coalesce regs, so go back to 2. -*/ - -/* If REG1 and REG2 don't conflict in CONFLICTS, place them in the - same class of partition P, if they aren't already. Update - CONFLICTS appropriately. - - Returns one if REG1 and REG2 were placed in the same class but were - not previously; zero otherwise. - - See Morgan figure 11.15. */ - -static int -coalesce_if_unconflicting (partition p, conflict_graph conflicts, - int reg1, int reg2) -{ - int reg; - - /* Work only on SSA registers. */ - if (!CONVERT_REGISTER_TO_SSA_P (reg1) || !CONVERT_REGISTER_TO_SSA_P (reg2)) - return 0; - - /* Find the canonical regs for the classes containing REG1 and - REG2. */ - reg1 = partition_find (p, reg1); - reg2 = partition_find (p, reg2); - - /* If they're already in the same class, there's nothing to do. */ - if (reg1 == reg2) - return 0; - - /* If the regs conflict, our hands are tied. */ - if (conflicting_hard_regs_p (reg1, reg2) || - conflict_graph_conflict_p (conflicts, reg1, reg2)) - return 0; - - /* We're good to go. Put the regs in the same partition. */ - partition_union (p, reg1, reg2); - - /* Find the new canonical reg for the merged class. */ - reg = partition_find (p, reg1); - - /* Merge conflicts from the two previous classes. */ - conflict_graph_merge_regs (conflicts, reg, reg1); - conflict_graph_merge_regs (conflicts, reg, reg2); - - return 1; -} - -/* For each register copy insn in basic block BB, place the LHS and - RHS regs in the same class in partition P if they do not conflict - according to CONFLICTS. - - Returns the number of changes that were made to P. - - See Morgan figure 11.14. */ - -static int -coalesce_regs_in_copies (basic_block bb, partition p, conflict_graph conflicts) -{ - int changed = 0; - rtx insn; - rtx end = bb->end; - - /* Scan the instruction stream of the block. */ - for (insn = bb->head; insn != end; insn = NEXT_INSN (insn)) - { - rtx pattern; - rtx src; - rtx dest; - - /* If this isn't a set insn, go to the next insn. */ - if (GET_CODE (insn) != INSN) - continue; - pattern = PATTERN (insn); - if (GET_CODE (pattern) != SET) - continue; - - src = SET_SRC (pattern); - dest = SET_DEST (pattern); - - /* We're only looking for copies. */ - if (GET_CODE (src) != REG || GET_CODE (dest) != REG) - continue; - - /* Coalesce only if the reg modes are the same. As long as - each reg's rtx is unique, it can have only one mode, so two - pseudos of different modes can't be coalesced into one. - - FIXME: We can probably get around this by inserting SUBREGs - where appropriate, but for now we don't bother. */ - if (GET_MODE (src) != GET_MODE (dest)) - continue; - - /* Found a copy; see if we can use the same reg for both the - source and destination (and thus eliminate the copy, - ultimately). */ - changed += coalesce_if_unconflicting (p, conflicts, - REGNO (src), REGNO (dest)); - } - - return changed; -} - -struct phi_coalesce_context -{ - partition p; - conflict_graph conflicts; - int changed; -}; - -/* Callback function for for_each_successor_phi. If the set - destination and the phi alternative regs do not conflict, place - them in the same partition class. DATA is a pointer to a - phi_coalesce_context struct. */ - -static int -coalesce_reg_in_phi (rtx insn ATTRIBUTE_UNUSED, int dest_regno, - int src_regno, void *data) -{ - struct phi_coalesce_context *context = - (struct phi_coalesce_context *) data; - - /* Attempt to use the same reg, if they don't conflict. */ - context->changed - += coalesce_if_unconflicting (context->p, context->conflicts, - dest_regno, src_regno); - return 0; -} - -/* For each alternative in a phi function corresponding to basic block - BB (in phi nodes in successor block to BB), place the reg in the - phi alternative and the reg to which the phi value is set into the - same class in partition P, if allowed by CONFLICTS. - - Return the number of changes that were made to P. - - See Morgan figure 11.14. */ - -static int -coalesce_regs_in_successor_phi_nodes (basic_block bb, partition p, - conflict_graph conflicts) -{ - struct phi_coalesce_context context; - context.p = p; - context.conflicts = conflicts; - context.changed = 0; - - for_each_successor_phi (bb, &coalesce_reg_in_phi, &context); - - return context.changed; -} - -/* Compute and return a partition of pseudos. Where possible, - non-conflicting pseudos are placed in the same class. - - The caller is responsible for deallocating the returned partition. */ - -static partition -compute_coalesced_reg_partition (void) -{ - basic_block bb; - int changed = 0; - regset_head phi_set_head; - regset phi_set = &phi_set_head; - - partition p = - partition_new (ssa_definition->num_elements); - - /* The first priority is to make sure registers that might have to - be copied on abnormal critical edges are placed in the same - partition. This saves us from having to split abnormal critical - edges (which can't be done). */ - FOR_EACH_BB_REVERSE (bb) - make_regs_equivalent_over_bad_edges (bb->index, p); - - INIT_REG_SET (phi_set); - - do - { - conflict_graph conflicts; - - changed = 0; - - /* Build the set of registers involved in phi nodes, either as - arguments to the phi function or as the target of a set. */ - CLEAR_REG_SET (phi_set); - mark_phi_and_copy_regs (phi_set); - - /* Compute conflicts. */ - conflicts = conflict_graph_compute (phi_set, p); - - /* FIXME: Better would be to process most frequently executed - blocks first, so that most frequently executed copies would - be more likely to be removed by register coalescing. But any - order will generate correct, if non-optimal, results. */ - FOR_EACH_BB_REVERSE (bb) - { - changed += coalesce_regs_in_copies (bb, p, conflicts); - changed += - coalesce_regs_in_successor_phi_nodes (bb, p, conflicts); - } - - conflict_graph_delete (conflicts); - } - while (changed > 0); - - FREE_REG_SET (phi_set); - - return p; -} - -/* Mark the regs in a phi node. PTR is a phi expression or one of its - components (a REG or a CONST_INT). DATA is a reg set in which to - set all regs. Called from for_each_rtx. */ - -static int -mark_reg_in_phi (rtx *ptr, void *data) -{ - rtx expr = *ptr; - regset set = (regset) data; - - switch (GET_CODE (expr)) - { - case REG: - SET_REGNO_REG_SET (set, REGNO (expr)); - /* Fall through. */ - case CONST_INT: - case PHI: - return 0; - default: - abort (); - } -} - -/* Mark in PHI_SET all pseudos that are used in a phi node -- either - set from a phi expression, or used as an argument in one. Also - mark regs that are the source or target of a reg copy. Uses - ssa_definition. */ - -static void -mark_phi_and_copy_regs (regset phi_set) -{ - unsigned int reg; - - /* Scan the definitions of all regs. */ - for (reg = 0; reg < VARRAY_SIZE (ssa_definition); ++reg) - if (CONVERT_REGISTER_TO_SSA_P (reg)) - { - rtx insn = VARRAY_RTX (ssa_definition, reg); - rtx pattern; - rtx src; - - if (insn == NULL - || (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)) - continue; - pattern = PATTERN (insn); - /* Sometimes we get PARALLEL insns. These aren't phi nodes or - copies. */ - if (GET_CODE (pattern) != SET) - continue; - src = SET_SRC (pattern); - - if (GET_CODE (src) == REG) - { - /* It's a reg copy. */ - SET_REGNO_REG_SET (phi_set, reg); - SET_REGNO_REG_SET (phi_set, REGNO (src)); - } - else if (GET_CODE (src) == PHI) - { - /* It's a phi node. Mark the reg being set. */ - SET_REGNO_REG_SET (phi_set, reg); - /* Mark the regs used in the phi function. */ - for_each_rtx (&src, mark_reg_in_phi, phi_set); - } - /* ... else nothing to do. */ - } -} - -/* Rename regs in insn PTR that are equivalent. DATA is the register - partition which specifies equivalences. */ - -static int -rename_equivalent_regs_in_insn (rtx *ptr, void* data) -{ - rtx x = *ptr; - partition reg_partition = (partition) data; - - if (x == NULL_RTX) - return 0; - - switch (GET_CODE (x)) - { - case REG: - if (CONVERT_REGISTER_TO_SSA_P (REGNO (x))) - { - unsigned int regno = REGNO (x); - unsigned int new_regno = partition_find (reg_partition, regno); - rtx canonical_element_rtx = ssa_rename_from_lookup (new_regno); - - if (canonical_element_rtx != NULL_RTX && - HARD_REGISTER_P (canonical_element_rtx)) - { - if (REGNO (canonical_element_rtx) != regno) - *ptr = canonical_element_rtx; - } - else if (regno != new_regno) - { - rtx new_reg = regno_reg_rtx[new_regno]; - if (GET_MODE (x) != GET_MODE (new_reg)) - abort (); - *ptr = new_reg; - } - } - return -1; - - case PHI: - /* No need to rename the phi nodes. We'll check equivalence - when inserting copies. */ - return -1; - - default: - /* Anything else, continue traversing. */ - return 0; - } -} - -/* Record the register's canonical element stored in SRFP in the - canonical_elements sbitmap packaged in DATA. This function is used - as a callback function for traversing ssa_rename_from. */ - -static int -record_canonical_element_1 (void **srfp, void *data) -{ - unsigned int reg = ((ssa_rename_from_pair *) *srfp)->reg; - sbitmap canonical_elements = - ((struct ssa_rename_from_hash_table_data *) data)->canonical_elements; - partition reg_partition = - ((struct ssa_rename_from_hash_table_data *) data)->reg_partition; - - SET_BIT (canonical_elements, partition_find (reg_partition, reg)); - return 1; -} - -/* For each class in the REG_PARTITION corresponding to a particular - hard register and machine mode, check that there are no other - classes with the same hard register and machine mode. Returns - nonzero if this is the case, i.e., the partition is acceptable. */ - -static int -check_hard_regs_in_partition (partition reg_partition) -{ - /* CANONICAL_ELEMENTS has a nonzero bit if a class with the given register - number and machine mode has already been seen. This is a - problem with the partition. */ - sbitmap canonical_elements; - int element_index; - int already_seen[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES]; - int reg; - int mach_mode; - - /* Collect a list of canonical elements. */ - canonical_elements = sbitmap_alloc (max_reg_num ()); - sbitmap_zero (canonical_elements); - ssa_rename_from_traverse (&record_canonical_element_1, - canonical_elements, reg_partition); - - /* We have not seen any hard register uses. */ - for (reg = 0; reg < FIRST_PSEUDO_REGISTER; ++reg) - for (mach_mode = 0; mach_mode < NUM_MACHINE_MODES; ++mach_mode) - already_seen[reg][mach_mode] = 0; - - /* Check for classes with the same hard register and machine mode. */ - EXECUTE_IF_SET_IN_SBITMAP (canonical_elements, 0, element_index, - { - rtx hard_reg_rtx = ssa_rename_from_lookup (element_index); - if (hard_reg_rtx != NULL_RTX && - HARD_REGISTER_P (hard_reg_rtx) && - already_seen[REGNO (hard_reg_rtx)][GET_MODE (hard_reg_rtx)] != 0) - /* Two distinct partition classes should be mapped to the same - hard register. */ - return 0; - }); - - sbitmap_free (canonical_elements); - - return 1; -} - -/* Rename regs that are equivalent in REG_PARTITION. Also collapse - any SEQUENCE insns. */ - -static void -rename_equivalent_regs (partition reg_partition) -{ - basic_block b; - - FOR_EACH_BB_REVERSE (b) - { - rtx next = b->head; - rtx last = b->end; - rtx insn; - - do - { - insn = next; - if (INSN_P (insn)) - { - for_each_rtx (&PATTERN (insn), - rename_equivalent_regs_in_insn, - reg_partition); - for_each_rtx (®_NOTES (insn), - rename_equivalent_regs_in_insn, - reg_partition); - - if (GET_CODE (PATTERN (insn)) == SEQUENCE) - { - rtx s = PATTERN (insn); - int slen = XVECLEN (s, 0); - int i; - - if (slen <= 1) - abort (); - - PATTERN (insn) = XVECEXP (s, 0, slen-1); - for (i = 0; i < slen - 1; i++) - emit_insn_before (XVECEXP (s, 0, i), insn); - } - } - - next = NEXT_INSN (insn); - } - while (insn != last); - } -} - -/* The main entry point for moving from SSA. */ - -void -convert_from_ssa (void) -{ - basic_block b, bb; - partition reg_partition; - rtx insns = get_insns (); - - /* Need global_live_at_{start,end} up to date. There should not be - any significant dead code at this point, except perhaps dead - stores. So do not take the time to perform dead code elimination. - - Register coalescing needs death notes, so generate them. */ - life_analysis (insns, NULL, PROP_DEATH_NOTES); - - /* Figure out which regs in copies and phi nodes don't conflict and - therefore can be coalesced. */ - if (conservative_reg_partition) - reg_partition = compute_conservative_reg_partition (); - else - reg_partition = compute_coalesced_reg_partition (); - - if (!check_hard_regs_in_partition (reg_partition)) - /* Two separate partitions should correspond to the same hard - register but do not. */ - abort (); - - rename_equivalent_regs (reg_partition); - - /* Eliminate the PHI nodes. */ - FOR_EACH_BB_REVERSE (b) - { - edge e; - - for (e = b->pred; e; e = e->pred_next) - if (e->src != ENTRY_BLOCK_PTR) - eliminate_phi (e, reg_partition); - } - - partition_delete (reg_partition); - - /* Actually delete the PHI nodes. */ - FOR_EACH_BB_REVERSE (bb) - { - rtx insn = bb->head; - - while (1) - { - /* If this is a PHI node delete it. */ - if (PHI_NODE_P (insn)) - { - if (insn == bb->end) - bb->end = PREV_INSN (insn); - insn = delete_insn (insn); - } - /* Since all the phi nodes come at the beginning of the - block, if we find an ordinary insn, we can stop looking - for more phi nodes. */ - else if (INSN_P (insn)) - break; - /* If we've reached the end of the block, stop. */ - else if (insn == bb->end) - break; - else - insn = NEXT_INSN (insn); - } - } - - /* Commit all the copy nodes needed to convert out of SSA form. */ - commit_edge_insertions (); - - in_ssa_form = 0; - - count_or_remove_death_notes (NULL, 1); - - /* Deallocate the data structures. */ - ssa_definition = 0; - ssa_rename_from_free (); -} - -/* Scan phi nodes in successors to BB. For each such phi node that - has a phi alternative value corresponding to BB, invoke FN. FN - is passed the entire phi node insn, the regno of the set - destination, the regno of the phi argument corresponding to BB, - and DATA. - - If FN ever returns nonzero, stops immediately and returns this - value. Otherwise, returns zero. */ - -int -for_each_successor_phi (basic_block bb, successor_phi_fn fn, void *data) -{ - edge e; - - if (bb == EXIT_BLOCK_PTR) - return 0; - - /* Scan outgoing edges. */ - for (e = bb->succ; e != NULL; e = e->succ_next) - { - rtx insn; - - basic_block successor = e->dest; - if (successor == ENTRY_BLOCK_PTR - || successor == EXIT_BLOCK_PTR) - continue; - - /* Advance to the first non-label insn of the successor block. */ - insn = first_insn_after_basic_block_note (successor); - - if (insn == NULL) - continue; - - /* Scan phi nodes in the successor. */ - for ( ; PHI_NODE_P (insn); insn = NEXT_INSN (insn)) - { - int result; - rtx phi_set = PATTERN (insn); - rtx *alternative = phi_alternative (phi_set, bb->index); - rtx phi_src; - - /* This phi function may not have an alternative - corresponding to the incoming edge, indicating the - assigned variable is not defined along the edge. */ - if (alternative == NULL) - continue; - phi_src = *alternative; - - /* Invoke the callback. */ - result = (*fn) (insn, REGNO (SET_DEST (phi_set)), - REGNO (phi_src), data); - - /* Terminate if requested. */ - if (result != 0) - return result; - } - } - - return 0; -} - -/* Assuming the ssa_rename_from mapping has been established, yields - nonzero if 1) only one SSA register of REG1 and REG2 comes from a - hard register or 2) both SSA registers REG1 and REG2 come from - different hard registers. */ - -static int -conflicting_hard_regs_p (int reg1, int reg2) -{ - int orig_reg1 = original_register (reg1); - int orig_reg2 = original_register (reg2); - if (HARD_REGISTER_NUM_P (orig_reg1) && HARD_REGISTER_NUM_P (orig_reg2) - && orig_reg1 != orig_reg2) - return 1; - if (HARD_REGISTER_NUM_P (orig_reg1) && !HARD_REGISTER_NUM_P (orig_reg2)) - return 1; - if (!HARD_REGISTER_NUM_P (orig_reg1) && HARD_REGISTER_NUM_P (orig_reg2)) - return 1; - - return 0; -} diff --git a/gcc/ssa.h b/gcc/ssa.h deleted file mode 100644 index ab3cdf1a789..00000000000 --- a/gcc/ssa.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Static Single Assignment (SSA) definitions for GCC - Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. - Written by Jeffrey D. Oldham . - -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. */ - - -/* Main SSA routines. */ -extern void convert_to_ssa (void); -extern void convert_from_ssa (void); -typedef int (*successor_phi_fn) (rtx, int, int, void *); -extern int for_each_successor_phi (basic_block bb, successor_phi_fn, - void *); -void compute_dominance_frontiers (sbitmap *frontiers, dominance_info idom); -extern int remove_phi_alternative (rtx, basic_block); - - -/* Optimizations. */ -/* In ssa-dce.c */ -extern void ssa_eliminate_dead_code (void); - -/* In ssa-ccp.c */ -extern void ssa_const_prop (void); - - -/* SSA definitions and uses. */ -/* This flag is set when the CFG is in SSA form. */ -extern int in_ssa_form; - -/* Element I is the single instruction that sets register I. */ -extern GTY(()) varray_type ssa_definition; - -/* Element I is an INSN_LIST of instructions that use register I. */ -extern varray_type ssa_uses; - - -/* Specify which hard registers should be converted. */ - -/* All pseudo-registers (having register number >= - FIRST_PSEUDO_REGISTER) and hard registers satisfying - CONVERT_HARD_REGISTER_TO_SSA_P are converted to SSA form. */ - -/* Given a hard register number REG_NO, return nonzero if and only if - the register should be converted to SSA. */ - -#ifndef CONVERT_HARD_REGISTER_TO_SSA_P -#define CONVERT_HARD_REGISTER_TO_SSA_P(REG_NO) (0) /* default of no hard registers */ -#endif /* CONVERT_HARD_REGISTER_TO_SSA_P */ - -/* Given a register number REG_NO, return nonzero if and only if the - register should be converted to SSA. */ - -#define CONVERT_REGISTER_TO_SSA_P(REG_NO) \ - ((!HARD_REGISTER_NUM_P (REG_NO)) || \ - (CONVERT_HARD_REGISTER_TO_SSA_P (REG_NO))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fdfcc6ebdcb..d14e5ae1b98 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2003-11-20 Richard Henderson + + * gcc.dg/20020201-2.c: Remove. + * gcc.dg/20020201-4.c: Remove. + * gcc.dg/20020304-1.c: Remove. + 2003-11-19 Nathanael Nerode * gcc.dg/cpp/trad/xwin1.c: New test case. diff --git a/gcc/testsuite/gcc.dg/20020201-2.c b/gcc/testsuite/gcc.dg/20020201-2.c deleted file mode 100644 index 2a13c8d83ca..00000000000 --- a/gcc/testsuite/gcc.dg/20020201-2.c +++ /dev/null @@ -1,30 +0,0 @@ -/* This testcase caused ICE because gcc was not able to add instructions - on edge from ENTRY block successor to itself. */ -/* { dg-do compile } */ -/* { dg-options "-O3 -fssa" } */ - -struct A { int a1; int a2; }; -struct B { long int b[32]; }; - -extern int bar (struct B *, struct A *); - -int -foo (struct B x) -{ - struct A a, b; - struct B c; - int d; - - while (1) - { - a.a1 = 0; - a.a2 = 0; - b = a; - c = x; - d = bar (&c, &b); - if (d >= 0) - return d; - } - - return 0; -} diff --git a/gcc/testsuite/gcc.dg/20020201-4.c b/gcc/testsuite/gcc.dg/20020201-4.c deleted file mode 100644 index 3c83fe76047..00000000000 --- a/gcc/testsuite/gcc.dg/20020201-4.c +++ /dev/null @@ -1,16 +0,0 @@ -/* This testcase failed because recog_for_combine used to pass a different - pattern than contained in insn to recog. */ -/* { dg-do compile } */ -/* { dg-options "-O2 -fssa -fssa-ccp" } */ -/* { dg-options "-O2 -march=i686 -fssa -fssa-ccp" { target i?86-*-* } } */ - -extern int bar (char *); - -int -foo (void) -{ - char b[512]; - - bar (b); - return __builtin_strlen (b); -} diff --git a/gcc/testsuite/gcc.dg/20020304-1.c b/gcc/testsuite/gcc.dg/20020304-1.c deleted file mode 100644 index f6d6b4e49a7..00000000000 --- a/gcc/testsuite/gcc.dg/20020304-1.c +++ /dev/null @@ -1,37 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O -fssa -fssa-ccp" } */ - -double a[10][35], b[10][8]; -int c, c, d, e, f, g, h; - -int foo () -{ - int i, j, k, l; - - if (c > 10) - c = 10; - - for (j = 0; j < c; j++) - { - k = 0; - for (l = 0; l < h; l++) - { - if (d != 5) - return -1; - k = l * g; - a[j][k] = (double) e; k++; - a[j][k] = (double) f; k++; - } - for (i = 0;i < 35; i++) - { - if (a[j][i] >= 0.9) - a[j][i] = 0.9; - if (a[j][i] <= 0.1) - a[j][i] = 0.1; - } - k = 0; - b[j][k] = (double) e; k++; - b[j][k] = (double) f; k++; - } - return 0; -} diff --git a/gcc/timevar.def b/gcc/timevar.def index 74fda87e837..6fab782c052 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -92,10 +92,6 @@ DEFTIMEVAR (TV_DBR_SCHED , "delay branch sched") DEFTIMEVAR (TV_REORDER_BLOCKS , "reorder blocks") DEFTIMEVAR (TV_SHORTEN_BRANCH , "shorten branches") DEFTIMEVAR (TV_REG_STACK , "reg stack") -DEFTIMEVAR (TV_TO_SSA , "convert to SSA") -DEFTIMEVAR (TV_SSA_CCP , "SSA CCP") -DEFTIMEVAR (TV_SSA_DCE , "SSA aggressive DCE") -DEFTIMEVAR (TV_FROM_SSA , "convert from SSA") DEFTIMEVAR (TV_FINAL , "final") DEFTIMEVAR (TV_SYMOUT , "symout") diff --git a/gcc/toplev.c b/gcc/toplev.c index cacbb244ae4..bd1f37dd41f 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -63,7 +63,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "regs.h" #include "timevar.h" #include "diagnostic.h" -#include "ssa.h" #include "params.h" #include "reload.h" #include "dwarf2asm.h" @@ -125,7 +124,6 @@ static void print_switch_values (FILE *, int, int, const char *, /* Rest of compilation helper functions. */ static bool rest_of_handle_inlining (tree); -static rtx rest_of_handle_ssa (tree, rtx); static void rest_of_handle_cse (tree, rtx); static void rest_of_handle_cse2 (tree, rtx); static void rest_of_handle_gcse (tree, rtx); @@ -254,10 +252,6 @@ enum dump_file_index DFI_sibling, DFI_eh, DFI_jump, - DFI_ssa, - DFI_ssa_ccp, - DFI_ssa_dce, - DFI_ussa, DFI_null, DFI_cse, DFI_addressof, @@ -298,8 +292,8 @@ enum dump_file_index Remaining -d letters: - " m q " - " JK O Q Y " + " e m q " + " JK O Q WXY " */ static struct dump_file_info dump_file[DFI_MAX] = @@ -309,10 +303,6 @@ static struct dump_file_info dump_file[DFI_MAX] = { "sibling", 'i', 0, 0, 0 }, { "eh", 'h', 0, 0, 0 }, { "jump", 'j', 0, 0, 0 }, - { "ssa", 'e', 1, 0, 0 }, - { "ssaccp", 'W', 1, 0, 0 }, - { "ssadce", 'X', 1, 0, 0 }, - { "ussa", 'e', 1, 0, 0 }, /* Yes, duplicate enable switch. */ { "null", 'u', 0, 0, 0 }, { "cse", 's', 0, 0, 0 }, { "addressof", 'F', 0, 0, 0 }, @@ -904,15 +894,6 @@ int flag_gnu_linker = 1; /* Nonzero means put zero initialized data in the bss section. */ int flag_zero_initialized_in_bss = 1; -/* Enable SSA. */ -int flag_ssa = 0; - -/* Enable ssa conditional constant propagation. */ -int flag_ssa_ccp = 0; - -/* Enable ssa aggressive dead code elimination. */ -int flag_ssa_dce = 0; - /* Tag all structures with __attribute__(packed). */ int flag_pack_struct = 0; @@ -1149,9 +1130,6 @@ static const lang_independent_options f_options[] = {"dump-unnumbered", &flag_dump_unnumbered, 1 }, {"instrument-functions", &flag_instrument_function_entry_exit, 1 }, {"zero-initialized-in-bss", &flag_zero_initialized_in_bss, 1 }, - {"ssa", &flag_ssa, 1 }, - {"ssa-ccp", &flag_ssa_ccp, 1 }, - {"ssa-dce", &flag_ssa_dce, 1 }, {"leading-underscore", &flag_leading_underscore, 1 }, {"ident", &flag_no_ident, 0 }, { "peephole2", &flag_peephole2, 1 }, @@ -2750,71 +2728,6 @@ rest_of_handle_inlining (tree decl) return (bool) DECL_EXTERNAL (decl); } -/* Rest of compilation helper to convert the rtl to SSA form. */ -static rtx -rest_of_handle_ssa (tree decl, rtx insns) -{ - timevar_push (TV_TO_SSA); - open_dump_file (DFI_ssa, decl); - - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - convert_to_ssa (); - - close_dump_file (DFI_ssa, print_rtl_with_bb, insns); - timevar_pop (TV_TO_SSA); - - /* Perform sparse conditional constant propagation, if requested. */ - if (flag_ssa_ccp) - { - timevar_push (TV_SSA_CCP); - open_dump_file (DFI_ssa_ccp, decl); - - ssa_const_prop (); - - close_dump_file (DFI_ssa_ccp, print_rtl_with_bb, get_insns ()); - timevar_pop (TV_SSA_CCP); - } - - /* It would be useful to cleanup the CFG at this point, but block - merging and possibly other transformations might leave a PHI - node in the middle of a basic block, which is a strict no-no. */ - - /* The SSA implementation uses basic block numbers in its phi - nodes. Thus, changing the control-flow graph or the basic - blocks, e.g., calling find_basic_blocks () or cleanup_cfg (), - may cause problems. */ - - if (flag_ssa_dce) - { - /* Remove dead code. */ - - timevar_push (TV_SSA_DCE); - open_dump_file (DFI_ssa_dce, decl); - - insns = get_insns (); - ssa_eliminate_dead_code (); - - close_dump_file (DFI_ssa_dce, print_rtl_with_bb, insns); - timevar_pop (TV_SSA_DCE); - } - - /* Convert from SSA form. */ - - timevar_push (TV_FROM_SSA); - open_dump_file (DFI_ussa, decl); - - convert_from_ssa (); - /* New registers have been created. Rescan their usage. */ - reg_scan (insns, max_reg_num (), 1); - - close_dump_file (DFI_ussa, print_rtl_with_bb, insns); - timevar_pop (TV_FROM_SSA); - - ggc_collect (); - - return insns; -} - /* Try to identify useless null pointer tests and delete them. */ static void rest_of_handle_null_pointer (tree decl, rtx insns) @@ -3325,12 +3238,6 @@ rest_of_compilation (tree decl) if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl)) goto exit_rest_of_compilation; - /* Long term, this should probably move before the jump optimizer too, - but I didn't want to disturb the rtl_dump_and_exit and related - stuff at this time. */ - if (optimize > 0 && flag_ssa) - insns = rest_of_handle_ssa (decl, insns); - timevar_push (TV_JUMP); if (optimize) diff --git a/gcc/toplev.h b/gcc/toplev.h index 5a8b5813f09..31611c3a220 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -118,9 +118,6 @@ extern int flag_unroll_loops; extern int flag_unroll_all_loops; extern int flag_unswitch_loops; extern int flag_cprop_registers; -extern int flag_ssa; -extern int flag_ssa_ccp; -extern int flag_ssa_dce; extern int time_report; extern int flag_new_regalloc;