aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog51
-rw-r--r--gcc/Makefile.in7
-rw-r--r--gcc/builtins.c12
-rw-r--r--gcc/cfgexpand.c480
-rw-r--r--gcc/expr.c89
-rw-r--r--gcc/passes.c22
-rw-r--r--gcc/predict.def3
-rw-r--r--gcc/tree-cfg.c68
-rw-r--r--gcc/tree-flow.h5
-rw-r--r--gcc/tree-mudflap.c765
-rw-r--r--gcc/tree-optimize.c51
-rw-r--r--gcc/tree-sra.c3
12 files changed, 1066 insertions, 490 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6402c1e..2b72586 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,54 @@
+2004-06-19 Jan Hubicka <jh@suse.cz>
+ Steven Bosscher <stevenb@suse.de>
+
+ CFG transparent RTL expansion:
+ * Makefile.in (cfgexpand.o): New object file.
+ (builtins.o): Add dependency on basic-block.h
+ * builtins.c: Include basic-block.h
+ (entry_of_function): New function.
+ (expand_builtin_apply_args, expand_builtin_saveargs): Use it.
+ * cfgexpand.c: New file.
+ * expr.c (execute_expand, pass_expand): Kill.
+ * pass.c (rest_of_compilation): Do not build CFG unless called from
+ coverage code.
+ * tree-cfg.c (delete_tree_cfg): Rename to..
+ (delete_tree_cfg_annotations): ... this one; Do not remove the CFG itself.
+ * tree-flow.h (delete_tree_cfg_annotations): Declare.
+ (dleete_tree_cfg): Kill.
+ * tree-optimize.c (execute_rebuild_bind, pass_rebuild_bind): Kill.
+ (execute_del_cfg): Rename to...
+ (execute_free_datastructures): This one...
+ (pass_del_cfg): Rename to...
+ (pass_free_datastructures): ... this one; Do not kill PROP_cfg.
+ (init_tree_optimization_passes): Make cfg build and profiling to happen
+ unconditionally.
+
+2004-06-19 Steven Bosscher <stevenb@suse.de>
+
+ * tree-mudflap.c (mf_decl_cache_locals): Skip labels before
+ inserting the cache variables.
+
+ * tree-mudflap.c: Include headers to make basic_block available.
+ Move functions around such that related functions are near each
+ other. Add prototypes for all static functions. Add comments
+ briefly explaining what IR the mudflap1 and mudflap2 work on and
+ what they do.
+ (mudflap_function_decls): Rename to execute_mudflap_function_decls.
+ (mudflap_function_ops): Rename to execute_mudflap_function_ops.
+ (pass_mudflap_1, pass_mudflap_2): Update.
+ (mf_decl_cache_locals): Make it work on the CFG instead of the saved
+ function tree.
+ (mf_build_check_statement_for): Make it work on the CFG.
+ (mf_xform_derefs_1): Likewise. Cleanup code style.
+ (mf_xform_derefs): Likewise.
+
+2004-06-19 Jan Hubicka <jh@suse.cz>
+
+ * tree-cfg.c (label_to_block): Invent the label destination for
+ undefined labels.
+ (cleanup_dead_labels): Update table in the case label_to_block added
+ new label.
+
2004-06-18 Richard Henderson <rth@redhat.com>
PR c++/16036
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 0c1981f..75b3686 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -916,7 +916,7 @@ OBJS-common = \
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 passes.o \
- rtl-profile.o tree-profile.o rtlhooks.o
+ rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o
OBJS-md = $(out_object_file)
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \
@@ -1793,7 +1793,7 @@ dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_
builtins.o : builtins.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H)\
$(TREE_GIMPLE_H) $(FLAGS_H) $(TARGET_H) function.h $(REGS_H) $(EXPR_H) $(OPTABS_H) \
insn-config.h $(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \
- except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h
+ except.h $(TM_P_H) $(PREDICT_H) libfuncs.h real.h langhooks.h basic-block.h
calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) \
$(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \
libfuncs.h $(REGS_H) toplev.h output.h function.h $(TIMEVAR_H) $(TM_P_H) cgraph.h except.h
@@ -1930,6 +1930,9 @@ cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) in
function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h $(TIMEVAR_H)
cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(BASIC_BLOCK_H) $(CFGLAYOUT_H) $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h
+cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
+ $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
+ $(TREE_DUMP_H) except.h langhooks.h cfgloop.h gt-tree-cfg.h tree-pass.h $(RTL_H)
cfgrtl.o : cfgrtl.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) insn-config.h $(EXPR_H)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 2ae99ba..7ccdded 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tm_p.h"
#include "target.h"
#include "langhooks.h"
+#include "basic-block.h"
#define CALLED_AS_BUILT_IN(NODE) \
(!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
@@ -1206,6 +1207,13 @@ expand_builtin_apply_args_1 (void)
return copy_addr_to_reg (XEXP (registers, 0));
}
+/* Return RTX to emit after when we want to emit code on the entry of function. */
+static rtx
+entry_of_function (void)
+{
+ return (n_basic_blocks ? BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+}
+
/* __builtin_apply_args returns block of memory allocated on
the stack into which is stored the arg pointer, structure
value address, static chain, and all the registers that might
@@ -1239,7 +1247,7 @@ expand_builtin_apply_args (void)
chain current, so the code is placed at the start of the
function. */
push_topmost_sequence ();
- emit_insn_before (seq, NEXT_INSN (get_insns ()));
+ emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
pop_topmost_sequence ();
return temp;
}
@@ -4010,7 +4018,7 @@ expand_builtin_saveregs (void)
is inside a start_sequence, make the outer-level insn chain current, so
the code is placed at the start of the function. */
push_topmost_sequence ();
- emit_insn_after (seq, get_insns ());
+ emit_insn_after (seq, entry_of_function ());
pop_topmost_sequence ();
return val;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
new file mode 100644
index 0000000..d9be28b
--- /dev/null
+++ b/gcc/cfgexpand.c
@@ -0,0 +1,480 @@
+/* A pass for lowering trees to RTL.
+ Copyright (C) 2004 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. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "function.h"
+#include "expr.h"
+#include "langhooks.h"
+#include "tree-flow.h"
+#include "timevar.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "except.h"
+#include "flags.h"
+/* Expand basic block BB from GIMPLE trees to RTL. */
+
+static basic_block
+expand_block (basic_block bb, FILE * dump_file)
+{
+ block_stmt_iterator bsi = bsi_start (bb);
+ tree stmt = NULL;
+ rtx note, last;
+ edge e;
+
+ if (dump_file)
+ {
+ tree_register_cfg_hooks ();
+ dump_bb (bb, dump_file, 0);
+ rtl_register_cfg_hooks ();
+ }
+
+ if (!bsi_end_p (bsi))
+ stmt = bsi_stmt (bsi);
+
+ if (stmt && TREE_CODE (stmt) == LABEL_EXPR)
+ {
+ last = get_last_insn ();
+
+ expand_expr_stmt_value (stmt, 0, 0);
+
+ /* Java emits line number notes in the top of labels.
+ ??? Make this go away once line number notes are obsoleted. */
+ BB_HEAD (bb) = NEXT_INSN (last);
+ if (GET_CODE (BB_HEAD (bb)) == NOTE)
+ BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb));
+ bsi_next (&bsi);
+ note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb));
+ }
+ else
+ note = BB_HEAD (bb) = emit_note (NOTE_INSN_BASIC_BLOCK);
+
+ NOTE_BASIC_BLOCK (note) = bb;
+
+ e = bb->succ;
+ while (e)
+ {
+ edge next = e->succ_next;
+
+ /* Clear EDGE_EXECUTABLE. This flag is never used in the backend. */
+ e->flags &= ~EDGE_EXECUTABLE;
+
+ /* At the moment not all abnormal edges match the RTL representation.
+ It is safe to remove them here as find_sub_basic_blocks will
+ rediscover them. In the future we should get this fixed properly. */
+ if (e->flags & EDGE_ABNORMAL)
+ remove_edge (e);
+
+ e = next;
+ }
+
+ for (; !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+
+ last = get_last_insn ();
+
+ if (!stmt)
+ continue;
+
+ /* Expand this statement, then evaluate the resulting RTL and
+ fixup the CFG accordingly. */
+ switch (TREE_CODE (stmt))
+ {
+ case COND_EXPR:
+ {
+ basic_block new_bb, dest;
+ edge new_edge;
+ edge true_edge;
+ edge false_edge;
+ tree pred = COND_EXPR_COND (stmt);
+ tree then_exp = COND_EXPR_THEN (stmt);
+ tree else_exp = COND_EXPR_ELSE (stmt);
+ rtx last = get_last_insn ();
+
+ extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
+ if (EXPR_LOCUS (stmt))
+ {
+ emit_line_note (*(EXPR_LOCUS (stmt)));
+ if (cfun->dont_emit_block_notes)
+ record_block_change (TREE_BLOCK (stmt));
+ }
+
+ /* These flags have no purpose in RTL land. */
+ true_edge->flags &= ~EDGE_TRUE_VALUE;
+ false_edge->flags &= ~EDGE_FALSE_VALUE;
+
+ /* We can either have a pure conditional jump with one fallthru
+ edge or two-way jump that needs to be decomposed into two
+ basic blocks. */
+ if (TREE_CODE (then_exp) == GOTO_EXPR
+ && TREE_CODE (else_exp) == NOP_EXPR)
+ {
+ jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
+ break;
+ }
+ if (TREE_CODE (else_exp) == GOTO_EXPR
+ && TREE_CODE (then_exp) == NOP_EXPR)
+ {
+ jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_exp)));
+ break;
+ }
+ if (TREE_CODE (then_exp) != GOTO_EXPR
+ || TREE_CODE (else_exp) != GOTO_EXPR)
+ abort ();
+
+ jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
+ last = get_last_insn ();
+ expand_expr (else_exp, const0_rtx, VOIDmode, 0);
+
+ BB_END (bb) = last;
+ if (GET_CODE (BB_END (bb)) == BARRIER)
+ BB_END (bb) = PREV_INSN (BB_END (bb));
+ update_bb_for_insn (bb);
+
+ new_bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
+ dest = false_edge->dest;
+ redirect_edge_succ (false_edge, new_bb);
+ false_edge->flags |= EDGE_FALLTHRU;
+ new_bb->count = false_edge->count;
+ new_bb->frequency = EDGE_FREQUENCY (false_edge);
+ new_edge = make_edge (new_bb, dest, 0);
+ new_edge->probability = REG_BR_PROB_BASE;
+ new_edge->count = new_bb->count;
+ if (GET_CODE (BB_END (new_bb)) == BARRIER)
+ BB_END (new_bb) = PREV_INSN (BB_END (new_bb));
+ update_bb_for_insn (new_bb);
+
+ if (dump_file)
+ {
+ dump_bb (bb, dump_file, 0);
+ dump_bb (new_bb, dump_file, 0);
+ }
+ return new_bb;
+ }
+
+ /* Update after expansion of sibling call. */
+ case CALL_EXPR:
+ case MODIFY_EXPR:
+ case RETURN_EXPR:
+ expand_expr_stmt_value (stmt, 0, 0);
+ for (last = NEXT_INSN (last); last; last = NEXT_INSN (last))
+ {
+ if (GET_CODE (last) == CALL_INSN && SIBLING_CALL_P (last))
+ {
+ edge e;
+ int probability = 0;
+ gcov_type count = 0;
+
+ do_pending_stack_adjust ();
+ e = bb->succ;
+ while (e)
+ {
+ edge next = e->succ_next;
+
+ if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH)))
+ {
+ if (e->dest != EXIT_BLOCK_PTR)
+ {
+ e->dest->count -= e->count;
+ e->dest->frequency -= EDGE_FREQUENCY (e);
+ if (e->dest->count < 0)
+ e->dest->count = 0;
+ if (e->dest->frequency < 0)
+ e->dest->frequency = 0;
+ }
+ count += e->count;
+ probability += e->probability;
+ remove_edge (e);
+ }
+
+ e = next;
+ }
+
+ /* This is somewhat ugly: the call_expr expander often emits instructions
+ after the sibcall (to perform the function return). These confuse the
+ find_sub_basic_blocks code, so we need to get rid of these. */
+ last = NEXT_INSN (last);
+ if (GET_CODE (last) != BARRIER)
+ abort ();
+ while (NEXT_INSN (last))
+ {
+ /* For instance an sqrt builtin expander expands if with
+ sibcall in the then and label for `else`. */
+ if (GET_CODE (NEXT_INSN (last)) == CODE_LABEL)
+ break;
+ delete_insn (NEXT_INSN (last));
+ }
+ e = make_edge (bb, EXIT_BLOCK_PTR,
+ EDGE_ABNORMAL | EDGE_SIBCALL);
+ e->probability += probability;
+ e->count += count;
+ BB_END (bb) = last;
+ update_bb_for_insn (bb);
+ if (NEXT_INSN (last))
+ bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
+ else
+ return bb;
+ }
+ }
+ break;
+
+ default:
+ expand_expr_stmt_value (stmt, 0, 0);
+ break;
+ }
+ }
+
+ do_pending_stack_adjust ();
+
+ /* Find the the block tail. The last insn is the block is the insn
+ before a barrier and/or table jump insn. */
+ last = get_last_insn ();
+ if (GET_CODE (last) == BARRIER)
+ last = PREV_INSN (last);
+ if (JUMP_TABLE_DATA_P (last))
+ last = PREV_INSN (PREV_INSN (last));
+ BB_END (bb) = last;
+
+ if (dump_file)
+ dump_bb (bb, dump_file, 0);
+ update_bb_for_insn (bb);
+ return bb;
+}
+
+
+/* Create a basic block for initialization code. */
+
+static basic_block
+construct_init_block (void)
+{
+ basic_block init_block, first_block;
+ edge e;
+
+ expand_start_bindings_and_block (0, NULL_TREE);
+
+ for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
+ if (e->dest == ENTRY_BLOCK_PTR->next_bb)
+ break;
+
+ init_block = create_basic_block (NEXT_INSN (get_insns ()),
+ get_last_insn (),
+ ENTRY_BLOCK_PTR);
+ init_block->frequency = ENTRY_BLOCK_PTR->frequency;
+ init_block->count = ENTRY_BLOCK_PTR->count;
+ if (e)
+ {
+ first_block = e->dest;
+ redirect_edge_succ (e, init_block);
+ e = make_edge (init_block, first_block, EDGE_FALLTHRU);
+ }
+ else
+ e = make_edge (init_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = ENTRY_BLOCK_PTR->count;
+
+ update_bb_for_insn (init_block);
+ return init_block;
+}
+
+
+/* Create a block containing landing pads and similar stuff. */
+
+static void
+construct_exit_block (void)
+{
+ rtx head = get_last_insn ();
+ rtx end;
+ basic_block exit_block;
+ edge e, e2, next;
+
+ /* We hard-wired immediate_size_expand to zero above.
+ expand_function_end will decrement this variable. So, we set the
+ variable to one here, so that after the decrement it will remain
+ zero. */
+ immediate_size_expand = 1;
+
+ /* Make sure the locus is set to the end of the function, so that
+ epilogue line numbers and warnings are set properly. */
+ if (cfun->function_end_locus.file)
+ input_location = cfun->function_end_locus;
+
+ /* The following insns belong to the top scope. */
+ record_block_change (DECL_INITIAL (current_function_decl));
+
+ expand_end_bindings (NULL_TREE, 1, 0);
+
+ /* Generate rtl for function exit. */
+ expand_function_end ();
+
+ end = get_last_insn ();
+ if (head == end)
+ return;
+ while (NEXT_INSN (head) && GET_CODE (NEXT_INSN (head)) == NOTE)
+ head = NEXT_INSN (head);
+ exit_block = create_basic_block (NEXT_INSN (head), end, EXIT_BLOCK_PTR->prev_bb);
+ exit_block->frequency = EXIT_BLOCK_PTR->frequency;
+ exit_block->count = EXIT_BLOCK_PTR->count;
+ for (e = EXIT_BLOCK_PTR->pred; e; e = next)
+ {
+ next = e->pred_next;
+ if (!(e->flags & EDGE_ABNORMAL))
+ redirect_edge_succ (e, exit_block);
+ }
+ e = make_edge (exit_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = EXIT_BLOCK_PTR->count;
+ for (e2 = EXIT_BLOCK_PTR->pred; e2; e2 = e2->pred_next)
+ if (e2 != e)
+ {
+ e->count -= e2->count;
+ exit_block->count -= e2->count;
+ exit_block->frequency -= EDGE_FREQUENCY (e2);
+ }
+ if (e->count < 0)
+ e->count = 0;
+ if (exit_block->count < 0)
+ exit_block->count = 0;
+ if (exit_block->frequency < 0)
+ exit_block->frequency = 0;
+ update_bb_for_insn (exit_block);
+}
+
+/* Called to move the SAVE_EXPRs for parameter declarations in a
+ nested function into the nested function. DATA is really the
+ nested FUNCTION_DECL. */
+
+static tree
+set_save_expr_context (tree *tp,
+ int *walk_subtrees,
+ void *data)
+{
+ if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
+ SAVE_EXPR_CONTEXT (*tp) = (tree) data;
+ /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
+ circularity. */
+ else if (DECL_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL;
+}
+
+
+/* Translate the intermediate representation contained in the CFG
+ from GIMPLE trees to RTL.
+
+ We do conversion per basic block and preserve/update the tree CFG.
+ This implies we have to do some magic as the CFG can simultaneously
+ consist of basic blocks containing RTL and GIMPLE trees. This can
+ confuse the CFG hooks, so be curefull to not manipulate CFG during
+ the expansion. */
+
+static void
+tree_expand_cfg (void)
+{
+ basic_block bb, init_block;
+ sbitmap blocks;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n;; Function %s",
+ (*lang_hooks.decl_printable_name) (current_function_decl, 2));
+ fprintf (dump_file, " (%s)\n",
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
+ }
+
+ /* If the function has a variably modified type, there may be
+ SAVE_EXPRs in the parameter types. Their context must be set to
+ refer to this function; they cannot be expanded in the containing
+ function. */
+ if (decl_function_context (current_function_decl) == current_function_decl
+ && variably_modified_type_p (TREE_TYPE (current_function_decl)))
+ walk_tree (&TREE_TYPE (current_function_decl), set_save_expr_context,
+ current_function_decl, NULL);
+
+ /* Expand the variables recorded during gimple lowering. This must
+ occur before the call to expand_function_start to ensure that
+ all used variables are expanded before we expand anything on the
+ PENDING_SIZES list. */
+ expand_used_vars ();
+
+ /* Set up parameters and prepare for return, for the function. */
+ expand_function_start (current_function_decl, 0);
+
+ /* If this function is `main', emit a call to `__main'
+ to run global initializers, etc. */
+ if (DECL_NAME (current_function_decl)
+ && MAIN_NAME_P (DECL_NAME (current_function_decl))
+ && DECL_FILE_SCOPE_P (current_function_decl))
+ expand_main_function ();
+
+ /* Write the flowgraph to a dot file. */
+ rtl_register_cfg_hooks ();
+
+ init_block = construct_init_block ();
+
+ FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb)
+ bb = expand_block (bb, dump_file);
+
+ construct_exit_block ();
+
+ /* Convert from NOTE_INSN_EH_REGION style notes, and do other
+ sorts of eh initialization. Delay this until after the
+ initial rtl dump so that we can see the original nesting. */
+ convert_from_eh_region_ranges ();
+
+ rebuild_jump_labels (get_insns ());
+ find_exception_handler_labels ();
+
+ blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_ones (blocks);
+ find_many_sub_basic_blocks (blocks);
+ purge_all_dead_edges (0);
+ sbitmap_free (blocks);
+
+ compact_blocks ();
+#ifdef ENABLE_CHECKING
+ verify_flow_info();
+#endif
+}
+
+struct tree_opt_pass pass_expand =
+{
+ "expand", /* name */
+ NULL, /* gate */
+ tree_expand_cfg, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_EXPAND, /* tv_id */
+ /* ??? If TER is enabled, we actually receive GENERIC. */
+ PROP_gimple_leh | PROP_cfg, /* properties_required */
+ PROP_rtl, /* properties_provided */
+ PROP_gimple_leh, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+};
+
diff --git a/gcc/expr.c b/gcc/expr.c
index 651d6cd..aad7b1c 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -168,7 +168,6 @@ static void emit_single_push_insn (enum machine_mode, rtx, tree);
#endif
static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx);
static rtx const_vector_from_tree (tree);
-static void execute_expand (void);
/* Record for each mode whether we can move a register directly to or
from an object of that mode in memory. If we can't, we won't try
@@ -10213,92 +10212,4 @@ const_vector_from_tree (tree exp)
return gen_rtx_raw_CONST_VECTOR (mode, v);
}
-
-/* Called to move the SAVE_EXPRs for parameter declarations in a
- nested function into the nested function. DATA is really the
- nested FUNCTION_DECL. */
-
-static tree
-set_save_expr_context (tree *tp,
- int *walk_subtrees,
- void *data)
-{
- if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
- SAVE_EXPR_CONTEXT (*tp) = (tree) data;
- /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
- circularity. */
- else if (DECL_P (*tp))
- *walk_subtrees = 0;
-
- return NULL;
-}
-
-
-static void
-execute_expand (void)
-{
- /* If the function has a variably modified type, there may be
- SAVE_EXPRs in the parameter types. Their context must be set to
- refer to this function; they cannot be expanded in the containing
- function. */
- if (decl_function_context (current_function_decl) == current_function_decl
- && variably_modified_type_p (TREE_TYPE (current_function_decl)))
- walk_tree (&TREE_TYPE (current_function_decl), set_save_expr_context,
- current_function_decl, NULL);
-
- /* Expand the variables recorded during gimple lowering. This must
- occur before the call to expand_function_start to ensure that
- all used variables are expanded before we expand anything on the
- PENDING_SIZES list. */
- expand_used_vars ();
-
- /* Set up parameters and prepare for return, for the function. */
- expand_function_start (current_function_decl, 0);
-
- /* If this function is `main', emit a call to `__main'
- to run global initializers, etc. */
- if (DECL_NAME (current_function_decl)
- && MAIN_NAME_P (DECL_NAME (current_function_decl))
- && DECL_FILE_SCOPE_P (current_function_decl))
- expand_main_function ();
-
- /* Generate the RTL for this function. */
- expand_expr_stmt_value (DECL_SAVED_TREE (current_function_decl), 0, 0);
-
- /* We hard-wired immediate_size_expand to zero above.
- expand_function_end will decrement this variable. So, we set the
- variable to one here, so that after the decrement it will remain
- zero. */
- immediate_size_expand = 1;
-
- /* Make sure the locus is set to the end of the function, so that
- epilogue line numbers and warnings are set properly. */
- if (cfun->function_end_locus.file)
- input_location = cfun->function_end_locus;
-
- /* The following insns belong to the top scope. */
- record_block_change (DECL_INITIAL (current_function_decl));
-
- /* Generate rtl for function exit. */
- expand_function_end ();
-}
-
-struct tree_opt_pass pass_expand =
-{
- "expand", /* name */
- NULL, /* gate */
- execute_expand, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_EXPAND, /* tv_id */
- /* ??? If TER is enabled, we actually receive GENERIC. */
- PROP_gimple_leh, /* properties_required */
- PROP_rtl, /* properties_provided */
- PROP_cfg | PROP_gimple_leh, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
-};
-
-
#include "gt-expr.h"
diff --git a/gcc/passes.c b/gcc/passes.c
index d959679..a4fb35a 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1385,8 +1385,6 @@ rest_of_compilation (void)
else
finalize_block_changes ();
- init_flow ();
-
/* Dump the rtl code if we are dumping rtl. */
if (open_dump_file (DFI_rtl, current_function_decl))
close_dump_file (DFI_rtl, print_rtl, get_insns ());
@@ -1443,11 +1441,21 @@ rest_of_compilation (void)
timevar_push (TV_JUMP);
open_dump_file (DFI_sibling, current_function_decl);
- rebuild_jump_labels (get_insns ());
- find_exception_handler_labels ();
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
+ /* ??? We may get called either via tree_rest_of_compilation when the CFG
+ is already built or directly (for instance from coverage code).
+ The direct callers shall be updated. */
+ if (!basic_block_info)
+ {
+ init_flow ();
+ rebuild_jump_labels (get_insns ());
+ find_exception_handler_labels ();
+ find_basic_blocks (get_insns (), max_reg_num (), dump_file);
+ }
delete_unreachable_blocks ();
+#ifdef ENABLE_CHECKING
+ verify_flow_info();
+#endif
/* Turn NOTE_INSN_PREDICTIONs into branch predictions. */
if (flag_guess_branch_prob)
@@ -1515,10 +1523,8 @@ rest_of_compilation (void)
if (flag_guess_branch_prob)
expected_value_to_br_prob ();
- reg_scan (get_insns (), max_reg_num (), 0);
- rebuild_jump_labels (get_insns ());
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
+ reg_scan (get_insns(), max_reg_num (), 0);
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
diff --git a/gcc/predict.def b/gcc/predict.def
index 836d853..4b57163 100644
--- a/gcc/predict.def
+++ b/gcc/predict.def
@@ -116,3 +116,6 @@ DEF_PREDICTOR (PRED_NEGATIVE_RETURN, "negative return", HITRATE (96), 0)
/* Branch ending with return; is probably not taken */
DEF_PREDICTOR (PRED_NULL_RETURN, "null return", HITRATE (90), 0)
+
+/* Branches to a mudflap bounds check are extremely unlikely. */
+DEF_PREDICTOR (PRED_MUDFLAP, "mudflap check", HITRATE (99), 0)
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 1fad3da..243a654 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -619,7 +619,21 @@ make_switch_expr_edges (basic_block bb)
basic_block
label_to_block (tree dest)
{
- return VARRAY_BB (label_to_block_map, LABEL_DECL_UID (dest));
+ int uid = LABEL_DECL_UID (dest);
+
+ /* We would die hard when faced by undefined label. Emit label to
+ very first basic block. This will hopefully make even the dataflow
+ and undefined variable warnings quite right. */
+ if ((errorcount || sorrycount) && uid < 0)
+ {
+ block_stmt_iterator bsi = bsi_start (BASIC_BLOCK (0));
+ tree stmt;
+
+ stmt = build1 (LABEL_EXPR, void_type_node, dest);
+ bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+ uid = LABEL_DECL_UID (dest);
+ }
+ return VARRAY_BB (label_to_block_map, uid);
}
@@ -756,6 +770,18 @@ update_eh_label (struct eh_region *region)
}
}
+/* Given LABEL return the first label in the same basic block. */
+static tree
+main_block_label (tree label)
+{
+ basic_block bb = label_to_block (label);
+
+ /* label_to_block possibly inserted undefined label into the chain. */
+ if (!label_for_bb[bb->index])
+ label_for_bb[bb->index] = label;
+ return label_for_bb[bb->index];
+}
+
/* Cleanup redundant labels. This is a three-steo process:
1) Find the leading label for each block.
2) Redirect all references to labels to the leading labels.
@@ -815,15 +841,14 @@ cleanup_dead_labels (void)
case COND_EXPR:
{
tree true_branch, false_branch;
- basic_block true_bb, false_bb;
true_branch = COND_EXPR_THEN (stmt);
false_branch = COND_EXPR_ELSE (stmt);
- true_bb = label_to_block (GOTO_DESTINATION (true_branch));
- false_bb = label_to_block (GOTO_DESTINATION (false_branch));
- GOTO_DESTINATION (true_branch) = label_for_bb[true_bb->index];
- GOTO_DESTINATION (false_branch) = label_for_bb[false_bb->index];
+ GOTO_DESTINATION (true_branch)
+ = main_block_label (GOTO_DESTINATION (true_branch));
+ GOTO_DESTINATION (false_branch)
+ = main_block_label (GOTO_DESTINATION (false_branch));
break;
}
@@ -836,12 +861,8 @@ cleanup_dead_labels (void)
/* Replace all destination labels. */
for (i = 0; i < n; ++i)
- {
- tree label = CASE_LABEL (TREE_VEC_ELT (vec, i));
-
- CASE_LABEL (TREE_VEC_ELT (vec, i)) =
- label_for_bb[label_to_block (label)->index];
- }
+ CASE_LABEL (TREE_VEC_ELT (vec, i))
+ = main_block_label (CASE_LABEL (TREE_VEC_ELT (vec, i)));
break;
}
@@ -849,13 +870,12 @@ cleanup_dead_labels (void)
/* We have to handle GOTO_EXPRs until they're removed, and we don't
remove them until after we've created the CFG edges. */
case GOTO_EXPR:
- {
- tree label = GOTO_DESTINATION (stmt);
- if (! computed_goto_p (stmt))
- GOTO_DESTINATION (stmt) =
- label_for_bb[label_to_block (label)->index];
- break;
- }
+ if (! computed_goto_p (stmt))
+ {
+ GOTO_DESTINATION (stmt)
+ = main_block_label (GOTO_DESTINATION (stmt));
+ break;
+ }
default:
break;
@@ -2636,19 +2656,19 @@ disband_implicit_edges (void)
}
}
-
-/* Remove all the blocks and edges that make up the flowgraph. */
+/* Remove block annotations and other datastructures. */
void
-delete_tree_cfg (void)
+delete_tree_cfg_annotations (void)
{
+ basic_block bb;
if (n_basic_blocks > 0)
free_blocks_annotations ();
- free_basic_block_vars ();
- basic_block_info = NULL;
label_to_block_map = NULL;
free_rbi_pool ();
+ FOR_EACH_BB (bb)
+ bb->rbi = NULL;
}
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index d440c8b..6ddf72c 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -434,7 +434,7 @@ extern void bsi_replace (const block_stmt_iterator *, tree, bool);
/* Location to track pending stmt for edge insertion. */
#define PENDING_STMT(e) ((e)->insns.t)
-extern void delete_tree_cfg (void);
+extern void delete_tree_cfg_annotations (void);
extern void disband_implicit_edges (void);
extern bool stmt_ends_bb_p (tree);
extern bool is_ctrl_stmt (tree);
@@ -582,6 +582,9 @@ void set_value_handle (tree, tree);
void debug_value_expressions (tree);
void print_value_expressions (FILE *, tree);
+/* In tree-sra.c */
+void insert_edge_copies (tree stmt, basic_block bb);
+
#include "tree-flow-inline.h"
#endif /* _TREE_FLOW_H */
diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c
index 8a57efb..732ef5e 100644
--- a/gcc/tree-mudflap.c
+++ b/gcc/tree-mudflap.c
@@ -26,7 +26,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hard-reg-set.h"
+#include "rtl.h"
#include "tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
#include "flags.h"
#include "function.h"
#include "tree-inline.h"
@@ -43,50 +47,31 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
/* Internal function decls */
-static void mf_xform_derefs (tree);
-static void mf_xform_decls (tree, tree);
-static void mf_init_extern_trees (void);
-static void mf_decl_cache_locals (tree *);
-static void mf_decl_clear_locals (void);
+/* Helpers. */
+static tree mf_build_string (const char *string);
static tree mf_varname_tree (tree);
-static tree mx_xfn_xform_decls (tree *, int *, void *);
-
-static void mx_register_decls (tree, tree *);
-
-
-/* extern mudflap functions */
-
-static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
-
-
-/* Mark and return the given tree node to prevent further mudflap
- transforms. */
-tree
-mf_mark (tree t)
-{
- void **slot;
-
- if (marked_trees == NULL)
- marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
+static tree mf_file_function_line_tree (location_t *);
- slot = htab_find_slot (marked_trees, t, INSERT);
- *slot = t;
- return t;
-}
+/* Initialization of all the mf-runtime.h extern decls. */
+static void mf_init_extern_trees (void);
+/* Indirection-related instrumentation. */
+static void mf_decl_cache_locals (void);
+static void mf_decl_clear_locals (void);
+static void mf_xform_derefs (void);
+static void execute_mudflap_function_ops (void);
-int
-mf_marked_p (tree t)
-{
- void *entry;
+/* Addressable variables instrumentation. */
+static void mf_xform_decls (tree, tree);
+static tree mx_xfn_xform_decls (tree *, int *, void *);
+static void mx_register_decls (tree, tree *);
+static void execute_mudflap_function_decls (void);
- if (marked_trees == NULL)
- return 0;
- entry = htab_find (marked_trees, t);
- return (entry != NULL);
-}
+/* ------------------------------------------------------------------------ */
+/* Some generally helpful functions for mudflap instrumentation. */
+/* Build a reference to a literal string. */
static tree
mf_build_string (const char *string)
{
@@ -106,192 +91,6 @@ mf_build_string (const char *string)
return mf_mark (result);
}
-/* Perform the declaration-related mudflap tree transforms on the
- given function. Update its DECL_SAVED_TREE. */
-
-static void
-mudflap_function_decls (void)
-{
- if (mf_marked_p (current_function_decl))
- return;
-
- push_gimplify_context ();
-
- mf_init_extern_trees ();
- mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
- DECL_ARGUMENTS (current_function_decl));
-
- pop_gimplify_context (NULL);
-}
-
-static bool
-gate_mudflap (void)
-{
- return flag_mudflap != 0;
-}
-
-struct tree_opt_pass pass_mudflap_1 =
-{
- "mudflap1", /* name */
- gate_mudflap, /* gate */
- mudflap_function_decls, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_gimple_any, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
-};
-
-
-/* Same as above, for the indirection-related transforms. */
-
-static void
-mudflap_function_ops (void)
-{
- if (mf_marked_p (current_function_decl))
- return;
-
- push_gimplify_context ();
-
- /* In multithreaded mode, don't cache the lookup cache parameters. */
- if (! flag_mudflap_threads)
- mf_decl_cache_locals (&DECL_SAVED_TREE (current_function_decl));
-
- mf_xform_derefs (DECL_SAVED_TREE (current_function_decl));
-
- if (! flag_mudflap_threads)
- mf_decl_clear_locals ();
-
- pop_gimplify_context (NULL);
-}
-
-struct tree_opt_pass pass_mudflap_2 =
-{
- "mudflap2", /* name */
- gate_mudflap, /* gate */
- mudflap_function_ops, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_gimple_leh, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
-};
-
-/* global tree nodes */
-
-/* Global tree objects for global variables and functions exported by
- mudflap runtime library. mf_init_extern_trees must be called
- before using these. */
-
-/* uintptr_t (usually "unsigned long") */
-static GTY (()) tree mf_uintptr_type;
-
-/* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
-static GTY (()) tree mf_cache_struct_type;
-
-/* struct __mf_cache * const */
-static GTY (()) tree mf_cache_structptr_type;
-
-/* extern struct __mf_cache __mf_lookup_cache []; */
-static GTY (()) tree mf_cache_array_decl;
-
-/* extern const unsigned char __mf_lc_shift; */
-static GTY (()) tree mf_cache_shift_decl;
-
-/* extern const uintptr_t __mf_lc_mask; */
-static GTY (()) tree mf_cache_mask_decl;
-
-/* Their function-scope local shadows, used in single-threaded mode only. */
-
-/* auto const unsigned char __mf_lc_shift_l; */
-static GTY (()) tree mf_cache_shift_decl_l;
-
-/* auto const uintptr_t __mf_lc_mask_l; */
-static GTY (()) tree mf_cache_mask_decl_l;
-
-/* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
-static GTY (()) tree mf_check_fndecl;
-
-/* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
-static GTY (()) tree mf_register_fndecl;
-
-/* extern void __mf_unregister (void *ptr, size_t sz); */
-static GTY (()) tree mf_unregister_fndecl;
-
-
-/* Initialize the global tree nodes that correspond to mf-runtime.h
- declarations. */
-static void
-mf_init_extern_trees (void)
-{
- static bool done = false;
-
- if (done)
- return;
- done = true;
-
- mf_uintptr_type = TREE_TYPE (mflang_lookup_decl ("uintptr_t"));
- mf_cache_array_decl = mf_mark (mflang_lookup_decl ("__mf_lookup_cache"));
- mf_cache_struct_type = TREE_TYPE (TREE_TYPE (mf_cache_array_decl));
- mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
- mf_cache_shift_decl = mf_mark (mflang_lookup_decl ("__mf_lc_shift"));
- mf_cache_mask_decl = mf_mark (mflang_lookup_decl ("__mf_lc_mask"));
- mf_check_fndecl = mflang_lookup_decl ("__mf_check");
- mf_register_fndecl = mflang_lookup_decl ("__mf_register");
- mf_unregister_fndecl = mflang_lookup_decl ("__mf_unregister");
-}
-
-
-
-/* Create and initialize local shadow variables for the lookup cache
- globals. Put their decls in the *_l globals for use by
- mf_build_check_statement_for. */
-
-static void
-mf_decl_cache_locals (tree* body)
-{
- tree_stmt_iterator i = tsi_start (*body);
- tree t;
-
- mf_cache_shift_decl_l
- = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
- "__mf_lookup_shift_l"));
-
- mf_cache_mask_decl_l
- = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
- "__mf_lookup_mask_l"));
-
- /* Build initialization nodes for them. */
- t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
- mf_cache_shift_decl_l, mf_cache_shift_decl);
- annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
- gimplify_stmt (&t);
- tsi_link_before (&i, t, TSI_NEW_STMT);
-
- t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
- mf_cache_mask_decl_l, mf_cache_mask_decl);
- annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
- gimplify_stmt (&t);
- tsi_link_before (&i, t, TSI_NEW_STMT);
-}
-
-
-static void
-mf_decl_clear_locals (void)
-{
- /* Unset local shadows. */
- mf_cache_shift_decl_l = NULL_TREE;
- mf_cache_mask_decl_l = NULL_TREE;
-}
-
/* Create a properly typed STRING_CST node that describes the given
declaration. It will be used as an argument for __mf_register().
Try to construct a helpful string, including file/function/variable
@@ -432,35 +231,229 @@ mf_file_function_line_tree (location_t *locus)
}
+/* global tree nodes */
+
+/* Global tree objects for global variables and functions exported by
+ mudflap runtime library. mf_init_extern_trees must be called
+ before using these. */
+
+/* uintptr_t (usually "unsigned long") */
+static GTY (()) tree mf_uintptr_type;
+
+/* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
+static GTY (()) tree mf_cache_struct_type;
+
+/* struct __mf_cache * const */
+static GTY (()) tree mf_cache_structptr_type;
+
+/* extern struct __mf_cache __mf_lookup_cache []; */
+static GTY (()) tree mf_cache_array_decl;
+
+/* extern const unsigned char __mf_lc_shift; */
+static GTY (()) tree mf_cache_shift_decl;
+
+/* extern const uintptr_t __mf_lc_mask; */
+static GTY (()) tree mf_cache_mask_decl;
+
+/* Their function-scope local shadows, used in single-threaded mode only. */
+
+/* auto const unsigned char __mf_lc_shift_l; */
+static GTY (()) tree mf_cache_shift_decl_l;
+
+/* auto const uintptr_t __mf_lc_mask_l; */
+static GTY (()) tree mf_cache_mask_decl_l;
+
+/* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
+static GTY (()) tree mf_check_fndecl;
+
+/* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
+static GTY (()) tree mf_register_fndecl;
+
+/* extern void __mf_unregister (void *ptr, size_t sz); */
+static GTY (()) tree mf_unregister_fndecl;
+
+
+/* Initialize the global tree nodes that correspond to mf-runtime.h
+ declarations. */
+static void
+mf_init_extern_trees (void)
+{
+ static bool done = false;
+
+ if (done)
+ return;
+ done = true;
+
+ mf_uintptr_type = TREE_TYPE (mflang_lookup_decl ("uintptr_t"));
+ mf_cache_array_decl = mf_mark (mflang_lookup_decl ("__mf_lookup_cache"));
+ mf_cache_struct_type = TREE_TYPE (TREE_TYPE (mf_cache_array_decl));
+ mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
+ mf_cache_shift_decl = mf_mark (mflang_lookup_decl ("__mf_lc_shift"));
+ mf_cache_mask_decl = mf_mark (mflang_lookup_decl ("__mf_lc_mask"));
+ mf_check_fndecl = mflang_lookup_decl ("__mf_check");
+ mf_register_fndecl = mflang_lookup_decl ("__mf_register");
+ mf_unregister_fndecl = mflang_lookup_decl ("__mf_unregister");
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Memory reference transforms. Perform the mudflap indirection-related
+ tree transforms on the current function.
+
+ This is the second part of the mudflap instrumentation. It works on
+ low-level GIMPLE using the CFG, because we want to run this pass after
+ tree optimizations have been performed, but we have to preserve the CFG
+ for expansion from trees to RTL. */
+
+static void
+execute_mudflap_function_ops (void)
+{
+ if (mf_marked_p (current_function_decl))
+ return;
+
+ push_gimplify_context ();
+
+ /* In multithreaded mode, don't cache the lookup cache parameters. */
+ if (! flag_mudflap_threads)
+ mf_decl_cache_locals ();
+
+ mf_xform_derefs ();
+
+ if (! flag_mudflap_threads)
+ mf_decl_clear_locals ();
+
+ pop_gimplify_context (NULL);
+}
+
+/* Create and initialize local shadow variables for the lookup cache
+ globals. Put their decls in the *_l globals for use by
+ mf_build_check_statement_for. */
+
+static void
+mf_decl_cache_locals (void)
+{
+ tree t, shift_init_stmts, mask_init_stmts;
+ tree_stmt_iterator tsi;
+
+ /* Build the cache vars. */
+ mf_cache_shift_decl_l
+ = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
+ "__mf_lookup_shift_l"));
+
+ mf_cache_mask_decl_l
+ = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
+ "__mf_lookup_mask_l"));
+
+ /* Build initialization nodes for the cache vars. We just load the
+ globals into the cache variables. */
+ t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
+ mf_cache_shift_decl_l, mf_cache_shift_decl);
+ annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
+ gimplify_to_stmt_list (&t);
+ shift_init_stmts = t;
+
+ t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
+ mf_cache_mask_decl_l, mf_cache_mask_decl);
+ annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
+ gimplify_to_stmt_list (&t);
+ mask_init_stmts = t;
+
+ /* Anticipating multiple entry points, we insert the cache vars
+ initializers in each successor of the ENTRY_BLOCK_PTR. */
+ for (tsi = tsi_start (shift_init_stmts);
+ ! tsi_end_p (tsi);
+ tsi_next (&tsi))
+ insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
+
+ for (tsi = tsi_start (mask_init_stmts);
+ ! tsi_end_p (tsi);
+ tsi_next (&tsi))
+ insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
+ bsi_commit_edge_inserts (NULL);
+}
+
+
static void
-mf_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter,
+mf_decl_clear_locals (void)
+{
+ /* Unset local shadows. */
+ mf_cache_shift_decl_l = NULL_TREE;
+ mf_cache_mask_decl_l = NULL_TREE;
+}
+
+static void
+mf_build_check_statement_for (tree addr, tree size,
+ block_stmt_iterator *instr_bsi,
location_t *locus, tree dirflag)
{
+ tree_stmt_iterator head, tsi;
tree ptrtype = TREE_TYPE (addr);
- tree stmt, cond, t, u, v;
+ block_stmt_iterator bsi;
+ basic_block cond_bb, then_bb, join_bb;
+ edge e;
+ tree cond, t, u, v, l1, l2;
tree mf_value;
tree mf_base;
tree mf_elem;
+ /* We first need to split the current basic block, and start altering
+ the CFG. This allows us to insert the statements we're about to
+ construct into the right basic blocks. The label l1 is the label
+ of the block for the THEN clause of the conditional jump we're
+ about to construct, and l2 is the ELSE clause, which is just the
+ continuation of the old statement stream. */
+ l1 = create_artificial_label ();
+ l2 = create_artificial_label ();
+ cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi));
+ bsi = *instr_bsi;
+ bsi_prev (&bsi);
+ if (! bsi_end_p (bsi))
+ {
+ e = split_block (cond_bb, bsi_stmt (bsi));
+ cond_bb = e->src;
+ join_bb = e->dest;
+ }
+ else
+ {
+ join_bb = cond_bb;
+ cond_bb = create_empty_bb (join_bb->prev_bb);
+ e = make_edge (cond_bb, join_bb, 0);
+ }
+ e->flags = EDGE_FALSE_VALUE;
+ then_bb = create_empty_bb (cond_bb);
+ make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
+ make_edge (then_bb, join_bb, EDGE_FALLTHRU);
+
+ /* We expect that the conditional jump we will construct will not
+ be taken very often as it basically is an exception condition. */
+ predict_edge_def (then_bb->pred, PRED_MUDFLAP, NOT_TAKEN);
+
+ /* Update dominance info. Note that bb_join's data was
+ updated by split_block. */
+ if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+ {
+ set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
+ set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
+ }
+
/* Build our local variables. */
mf_value = create_tmp_var (ptrtype, "__mf_value");
mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
/* Build: __mf_value = <address expression>. */
- stmt = build (MODIFY_EXPR, void_type_node, mf_value, addr);
- if (locus != NULL)
- annotate_with_locus (stmt, *locus);
- gimplify_stmt (&stmt);
- tsi_link_before (iter, stmt, TSI_SAME_STMT);
+ t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
+ SET_EXPR_LOCUS (t, locus);
+ gimplify_to_stmt_list (&t);
+ head = tsi_start (t);
+ tsi = tsi_last (t);
/* Build: __mf_base = (uintptr_t)__mf_value. */
- stmt = build (MODIFY_EXPR, void_type_node, mf_base,
- build1 (NOP_EXPR, mf_uintptr_type, mf_value));
- if (locus != NULL)
- annotate_with_locus (stmt, *locus);
- gimplify_stmt (&stmt);
- tsi_link_before (iter, stmt, TSI_SAME_STMT);
+ t = build (MODIFY_EXPR, void_type_node, mf_base,
+ build1 (NOP_EXPR, mf_uintptr_type, mf_value));
+ SET_EXPR_LOCUS (t, locus);
+ gimplify_to_stmt_list (&t);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
/* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
& __mf_mask]. */
@@ -472,81 +465,120 @@ mf_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter,
TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
mf_cache_array_decl, t);
t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
- stmt = build (MODIFY_EXPR, void_type_node, mf_elem, t);
- if (locus != NULL)
- annotate_with_locus (stmt, *locus);
- gimplify_stmt (&stmt);
- tsi_link_before (iter, stmt, TSI_SAME_STMT);
+ t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
+ SET_EXPR_LOCUS (t, locus);
+ gimplify_to_stmt_list (&t);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
/* Quick validity check.
- if (__builtin_expect ((__mf_elem->low > __mf_base)
- | (__mf_elem_high < __mf_base + sizeof(T) - 1),
- 0))
- {
- __mf_check ();
- ... and only if single-threaded:
- __mf_lookup_shift_1 = f...;
- __mf_lookup_mask_l = ...;
- }
- */
- /* __mf_elem->low */
+ if (__mf_elem->low > __mf_base
+ || (__mf_elem_high < __mf_base + sizeof(T) - 1))
+ {
+ __mf_check ();
+ ... and only if single-threaded:
+ __mf_lookup_shift_1 = f...;
+ __mf_lookup_mask_l = ...;
+ }
+
+ It is expected that this body of code is rarely executed so we mark
+ the edge to the THEN clause of the conditional jump as unlikely. */
+
+ /* Construct t <-- '__mf_elem->low > __mf_base'. */
t = build (COMPONENT_REF, mf_uintptr_type,
build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
TYPE_FIELDS (mf_cache_struct_type));
+ t = build (GT_EXPR, boolean_type_node, t, mf_base);
+
+ /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
+
+ First build:
+ 1) u <-- '__mf_elem->high'
+ 2) v <-- '__mf_base + sizeof (T) - 1'.
+
+ Then build 'u <-- (u < v). */
+
- /* __mf_elem->high */
u = build (COMPONENT_REF, mf_uintptr_type,
build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)));
- /* __mf_base + sizeof (T) - 1 */
- v = size_binop (MINUS_EXPR, size, size_one_node);
- v = convert (mf_uintptr_type, v);
+ v = convert (mf_uintptr_type,
+ size_binop (MINUS_EXPR, size, size_one_node));
v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
- t = build (TRUTH_OR_EXPR, boolean_type_node,
- build (GT_EXPR, boolean_type_node, t, mf_base),
- build (LT_EXPR, boolean_type_node, u, v));
+ u = build (LT_EXPR, boolean_type_node, u, v);
+
+ /* Build the composed conditional: t <-- 't || u'. Then store the
+ result of the evaluation of 't' in a temporary variable which we
+ can use as the condition for the conditional jump. */
+ t = build (TRUTH_OR_EXPR, boolean_type_node, t, u);
+ cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond");
+ t = build (MODIFY_EXPR, boolean_type_node, cond, t);
+ gimplify_to_stmt_list (&t);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
+
+ /* Build the conditional jump. 'cond' is just a temporary so we can
+ simply build a void COND_EXPR. We do need labels in both arms though. */
+ t = build (COND_EXPR, void_type_node, cond,
+ build (GOTO_EXPR, void_type_node, tree_block_label (then_bb)),
+ build (GOTO_EXPR, void_type_node, tree_block_label (join_bb)));
+ SET_EXPR_LOCUS (t, locus);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
- /* Mark condition as UNLIKELY using __builtin_expect. */
- u = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- u = tree_cons (NULL_TREE, convert (long_integer_type_node, t), u);
- cond = build_function_call_expr (built_in_decls[BUILT_IN_EXPECT], u);
+ /* At this point, after so much hard work, we have only constructed
+ the conditional jump,
- /* Build up the body of the cache-miss handling:
- __mf_check(); refresh *_l vars. */
+ if (__mf_elem->low > __mf_base
+ || (__mf_elem_high < __mf_base + sizeof(T) - 1))
- stmt = NULL;
+ The lowered GIMPLE tree representing this code is in the statement
+ list starting at 'head'.
+
+ We can insert this now in the current basic block, ie. the one that
+ the statement we're instrumenting was originally in. */
+ bsi = bsi_last (cond_bb);
+ for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
+ bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
+
+ /* Now build up the body of the cache-miss handling:
+
+ __mf_check();
+ refresh *_l vars.
+
+ This is the body of the conditional. */
u = tree_cons (NULL_TREE, mf_file_function_line_tree (locus), NULL_TREE);
u = tree_cons (NULL_TREE, dirflag, u);
u = tree_cons (NULL_TREE, size, u);
u = tree_cons (NULL_TREE, mf_value, u);
t = build_function_call_expr (mf_check_fndecl, u);
- append_to_statement_list (t, &stmt);
+ gimplify_to_stmt_list (&t);
+ head = tsi_start (t);
+ tsi = tsi_last (t);
if (! flag_mudflap_threads)
{
t = build (MODIFY_EXPR, void_type_node,
mf_cache_shift_decl_l, mf_cache_shift_decl);
- append_to_statement_list (t, &stmt);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
t = build (MODIFY_EXPR, void_type_node,
mf_cache_mask_decl_l, mf_cache_mask_decl);
- append_to_statement_list (t, &stmt);
+ tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
}
- stmt = build (COND_EXPR, void_type_node, cond, stmt, build_empty_stmt ());
- if (locus != NULL)
- annotate_with_locus (stmt, *locus);
- gimplify_to_stmt_list (&stmt);
- lower_stmt_body (stmt, NULL);
- tsi_link_before (iter, stmt, TSI_SAME_STMT);
+ /* Insert the check code in the THEN block. */
+ bsi = bsi_start (then_bb);
+ for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
+ bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
+
+ *instr_bsi = bsi_start (join_bb);
+ bsi_next (instr_bsi);
}
static void
-mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp,
+mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
location_t *locus, tree dirflag)
{
tree type, ptr_type, addr, size, t;
@@ -574,15 +606,14 @@ mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp,
{
tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
- /* Test for index in range. Break if not. */
- if (!dom)
- break;
- if (!TYPE_MIN_VALUE (dom) || !really_constant_p (TYPE_MIN_VALUE (dom)))
- break;
- if (!TYPE_MAX_VALUE (dom) || !really_constant_p (TYPE_MAX_VALUE (dom)))
- break;
- if (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
- || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1))
+ /* Test for index in range. Break if not. */
+ if (!dom
+ || (! TYPE_MIN_VALUE (dom)
+ || ! really_constant_p (TYPE_MIN_VALUE (dom)))
+ || (! TYPE_MAX_VALUE (dom)
+ || ! really_constant_p (TYPE_MAX_VALUE (dom)))
+ || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
+ || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
break;
/* If we're looking at a non-external VAR_DECL, then the
@@ -679,45 +710,74 @@ mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp,
}
static void
-mf_xform_derefs (tree fnbody)
+mf_xform_derefs (void)
{
- tree_stmt_iterator i = tsi_start (fnbody);
+ basic_block bb, next;
+ block_stmt_iterator i;
+ int saved_last_basic_block = last_basic_block;
- for (i = tsi_start (fnbody); !tsi_end_p (i); tsi_next (&i))
+ bb = ENTRY_BLOCK_PTR ->next_bb;
+ do
{
- tree s = tsi_stmt (i);
-
- /* Only a few GIMPLE statements can reference memory. */
- switch (TREE_CODE (s))
- {
- case MODIFY_EXPR: /* This includes INIT_EXPR after gimplification. */
- mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
- integer_one_node);
- mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
- integer_zero_node);
- break;
-
- case RETURN_EXPR:
- if (TREE_OPERAND (s, 0) != NULL_TREE)
- {
- if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
- mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1), EXPR_LOCUS (s),
- integer_zero_node);
- else
- mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
- integer_zero_node);
- }
- break;
-
- default:
- ;
- }
+ next = bb->next_bb;
+ for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
+ {
+ tree s = bsi_stmt (i);
+
+ /* Only a few GIMPLE statements can reference memory. */
+ switch (TREE_CODE (s))
+ {
+ case MODIFY_EXPR:
+ mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
+ integer_one_node);
+ mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
+ integer_zero_node);
+ break;
+
+ case RETURN_EXPR:
+ if (TREE_OPERAND (s, 0) != NULL_TREE)
+ {
+ if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
+ mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1),
+ EXPR_LOCUS (s), integer_zero_node);
+ else
+ mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
+ integer_zero_node);
+ }
+ break;
+
+ default:
+ ;
+ }
+ }
+ bb = next;
}
+ while (bb && bb->index <= saved_last_basic_block);
}
/* ------------------------------------------------------------------------ */
-/* ADDR_EXPR transform */
+/* ADDR_EXPR transforms. Perform the declaration-related mudflap tree
+ transforms on the current function.
+
+ This is the first part of the mudflap instrumentation. It works on
+ high-level GIMPLE because after lowering, all variables are moved out
+ of their BIND_EXPR binding context, and we lose liveness information
+ for the declarations we wish to instrument. */
+
+static void
+execute_mudflap_function_decls (void)
+{
+ if (mf_marked_p (current_function_decl))
+ return;
+ push_gimplify_context ();
+
+ mf_init_extern_trees ();
+ mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
+ DECL_ARGUMENTS (current_function_decl));
+
+ pop_gimplify_context (NULL);
+}
/* This struct is passed between mf_xform_decls to store state needed
during the traversal searching for objects that have their
@@ -936,13 +996,41 @@ mf_xform_decls (tree fnbody, tree fnparams)
/* ------------------------------------------------------------------------ */
+/* Externally visible mudflap functions. */
+
+
+/* Mark and return the given tree node to prevent further mudflap
+ transforms. */
+static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
+
+tree
+mf_mark (tree t)
+{
+ void **slot;
+
+ if (marked_trees == NULL)
+ marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
+
+ slot = htab_find_slot (marked_trees, t, INSERT);
+ *slot = t;
+ return t;
+}
+
+int
+mf_marked_p (tree t)
+{
+ void *entry;
+ if (marked_trees == NULL)
+ return 0;
+
+ entry = htab_find (marked_trees, t);
+ return (entry != NULL);
+}
/* Remember given node as a static of some kind: global data,
function-scope static, or an anonymous constant. Its assembler
- label is given.
-*/
-
+ label is given. */
/* A list of globals whose incomplete declarations we encountered.
Instead of emitting the __mf_register call for them here, it's
@@ -1066,7 +1154,6 @@ mudflap_enqueue_constant (tree obj)
}
-
/* Emit any file-wide instrumentation. */
void
mudflap_finish_file (void)
@@ -1093,5 +1180,43 @@ mudflap_finish_file (void)
}
+static bool
+gate_mudflap (void)
+{
+ return flag_mudflap != 0;
+}
+
+struct tree_opt_pass pass_mudflap_1 =
+{
+ "mudflap1", /* name */
+ gate_mudflap, /* gate */
+ execute_mudflap_function_decls, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_gimple_any, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func /* todo_flags_finish */
+};
+
+struct tree_opt_pass pass_mudflap_2 =
+{
+ "mudflap2", /* name */
+ gate_mudflap, /* gate */
+ execute_mudflap_function_ops, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_gimple_leh, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_verify_flow | TODO_verify_stmts
+ | TODO_dump_func /* todo_flags_finish */
+};
#include "gt-tree-mudflap.h"
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
index 16ddd8f..30e1e7c 100644
--- a/gcc/tree-optimize.c
+++ b/gcc/tree-optimize.c
@@ -84,33 +84,6 @@ static struct tree_opt_pass pass_gimple =
TODO_dump_func /* todo_flags_finish */
};
-/* Pass: replace the outermost BIND_EXPR. We removed all of them while
- optimizing, but the tree->rtl expander requires it. */
-
-static void
-execute_rebuild_bind (void)
-{
- DECL_SAVED_TREE (current_function_decl)
- = build (BIND_EXPR, void_type_node, NULL_TREE,
- DECL_SAVED_TREE (current_function_decl), NULL_TREE);
-}
-
-static struct tree_opt_pass pass_rebuild_bind =
-{
- NULL, /* name */
- NULL, /* gate */
- execute_rebuild_bind, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
-};
-
/* Gate: execute, or not, all of the non-trivial optimizations. */
static bool
@@ -141,9 +114,8 @@ static struct tree_opt_pass pass_all_optimizations =
passes. */
static void
-execute_del_cfg (void)
+execute_free_datastructures (void)
{
- basic_block bb;
tree *chain;
/* ??? This isn't the right place for this. Worse, it got computed
@@ -160,27 +132,23 @@ execute_del_cfg (void)
/* Re-chain the statements from the blocks. */
chain = &DECL_SAVED_TREE (current_function_decl);
*chain = alloc_stmt_list ();
- FOR_EACH_BB (bb)
- {
- append_to_statement_list_force (bb->stmt_list, chain);
- }
- /* And get rid of the cfg. */
- delete_tree_cfg ();
+ /* And get rid of annotations we no longer need. */
+ delete_tree_cfg_annotations ();
}
-static struct tree_opt_pass pass_del_cfg =
+static struct tree_opt_pass pass_free_datastructures =
{
NULL, /* name */
NULL, /* gate */
- execute_del_cfg, /* execute */
+ execute_free_datastructures, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
- PROP_cfg, /* properties_destroyed */
+ 0, /* properties_destroyed */
0, /* todo_flags_start */
0 /* todo_flags_finish */
};
@@ -283,16 +251,16 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_mudflap_1);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_eh);
+ NEXT_PASS (pass_build_cfg);
+ NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_all_optimizations);
NEXT_PASS (pass_mudflap_2);
- NEXT_PASS (pass_rebuild_bind);
+ NEXT_PASS (pass_free_datastructures);
NEXT_PASS (pass_expand);
NEXT_PASS (pass_rest_of_compilation);
*p = NULL;
p = &pass_all_optimizations.sub;
- NEXT_PASS (pass_build_cfg);
- NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_build_pta);
NEXT_PASS (pass_build_ssa);
@@ -335,7 +303,6 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_del_ssa);
NEXT_PASS (pass_nrv);
NEXT_PASS (pass_remove_useless_vars);
- NEXT_PASS (pass_del_cfg);
*p = NULL;
#undef NEXT_PASS
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 060b7e8..b5e4735 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -56,7 +56,6 @@ enum sra_copy_mode { SCALAR_SCALAR, FIELD_SCALAR, SCALAR_FIELD };
/* Local functions. */
static inline bool can_be_scalarized_p (tree);
-static inline void insert_edge_copies (tree stmt, basic_block bb);
static tree create_scalar_copies (tree lhs, tree rhs, enum sra_copy_mode mode);
static inline void scalarize_component_ref (tree, tree *tp);
static void scalarize_structures (void);
@@ -556,7 +555,7 @@ find_candidates_for_sra (void)
has more than one edge, STMT will be replicated for each edge. Also,
abnormal edges will be ignored. */
-static inline void
+void
insert_edge_copies (tree stmt, basic_block bb)
{
edge e;