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.

	* 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.

	* 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.

From-SVN: r83385
This commit is contained in:
Jan Hubicka 2004-06-19 15:33:06 +00:00
parent ff98621c68
commit 242229bbdc
12 changed files with 1064 additions and 488 deletions

View file

@ -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

View file

@ -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)

View file

@ -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;

480
gcc/cfgexpand.c Normal file
View file

@ -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 */
};

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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 */

View file

@ -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 mf_file_function_line_tree (location_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);
/* 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);
/* 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);
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);
}
/* ------------------------------------------------------------------------ */
/* 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_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter,
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_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);
/* 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);
/* 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 up the body of the cache-miss handling:
__mf_check(); refresh *_l vars. */
/* 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);
stmt = NULL;
/* At this point, after so much hard work, we have only constructed
the conditional jump,
if (__mf_elem->low > __mf_base
|| (__mf_elem_high < __mf_base + sizeof(T) - 1))
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);
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: /* 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;
/* 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;
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:
;
}
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"

View file

@ -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

View file

@ -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;