From 5d257a9fb0630280c9641ba8d7483bd14abee86b Mon Sep 17 00:00:00 2001 From: Zdenek Dvorak Date: Sun, 5 Oct 2003 19:25:45 +0000 Subject: * gimple-low.c: New. * Makefile.in (gimple-low.o): Add. * cfglayout.c (insn_locators_initialize): Use new scoping info. * expr.c (expand_expr): Record scope changes. * function.c (blocks_nreverse): Export. (uninitialized_vars_warning): Use DECL_RTL_SET_P instead of DECL_RTL. (reset_block_changes, record_block_change, record_block_change, check_block_change, free_block_changes): New. * function.h (struct function): New fields dont_emit_block_notes and ib_boundaries_block. (blocks_nreverse, reset_block_changes, record_block_change, finalize_block_changes, check_block_change, free_block_changes): Declare. * sibcall.c (optimize_sibling_and_tail_recursive_call): Don't call reorder_blocks if cfun->dont_emit_block_notes. * stmt.c (expand_start_bindings_and_block, expand_end_bindings): Don't emit block notes if cfun->dont_emit_block_notes. * toplev.c (rest_of_compilation): Don't call reorder_blocks if cfun->dont_emit_block_notes. * tree-flow.h (lower_function_body): Declare. * tree-optimize.c (optimize_function_tree): Call lower_function_body. * tree.c (build1): Initialize TREE_BLOCK. * tree.h (TREE_BLOCK): New macro. (struct tree_exp): Add block field. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/tree-ssa-cfg-branch@72117 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.tree-ssa-cfg | 27 +++++++ gcc/Makefile.in | 6 +- gcc/cfglayout.c | 10 +++ gcc/expr.c | 10 ++- gcc/function.c | 59 ++++++++++++++- gcc/function.h | 14 ++++ gcc/gimple-low.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ gcc/sibcall.c | 3 +- gcc/stmt.c | 4 +- gcc/toplev.c | 26 ++++--- gcc/tree-flow.h | 2 + gcc/tree-optimize.c | 5 ++ gcc/tree.c | 1 + gcc/tree.h | 3 + 14 files changed, 333 insertions(+), 19 deletions(-) create mode 100644 gcc/gimple-low.c diff --git a/gcc/ChangeLog.tree-ssa-cfg b/gcc/ChangeLog.tree-ssa-cfg index 595926ff52c..70a227bb3a6 100644 --- a/gcc/ChangeLog.tree-ssa-cfg +++ b/gcc/ChangeLog.tree-ssa-cfg @@ -1,3 +1,30 @@ +2003-10-05 Zdenek Dvorak + + * gimple-low.c: New. + * Makefile.in (gimple-low.o): Add. + * cfglayout.c (insn_locators_initialize): Use new scoping info. + * expr.c (expand_expr): Record scope changes. + * function.c (blocks_nreverse): Export. + (uninitialized_vars_warning): Use DECL_RTL_SET_P instead of DECL_RTL. + (reset_block_changes, record_block_change, record_block_change, + check_block_change, free_block_changes): New. + * function.h (struct function): New fields dont_emit_block_notes + and ib_boundaries_block. + (blocks_nreverse, reset_block_changes, record_block_change, + finalize_block_changes, check_block_change, free_block_changes): + Declare. + * sibcall.c (optimize_sibling_and_tail_recursive_call): Don't call + reorder_blocks if cfun->dont_emit_block_notes. + * stmt.c (expand_start_bindings_and_block, expand_end_bindings): Don't + emit block notes if cfun->dont_emit_block_notes. + * toplev.c (rest_of_compilation): Don't call reorder_blocks if + cfun->dont_emit_block_notes. + * tree-flow.h (lower_function_body): Declare. + * tree-optimize.c (optimize_function_tree): Call lower_function_body. + * tree.c (build1): Initialize TREE_BLOCK. + * tree.h (TREE_BLOCK): New macro. + (struct tree_exp): Add block field. + 2003-10-03 Zdenek Dvorak * tree-ssa.c (degrees): Removed. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b4d3fa24967..ecd5f075204 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -865,7 +865,7 @@ OBJS-common = \ tree-alias-type.o gimplify.o tree-nomudflap.o tree-pretty-print.o \ tree-alias-common.o tree-ssa-ccp.o tree-browser.o @ANDER@ tree-ssa-dce.o \ tree-ssa-pre.o tree-ssa-copyprop.o tree-ssa-live.o tree-must-alias.o \ - tree-ssa-dom.o \ + tree-ssa-dom.o gimple-low.o \ alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \ cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \ @@ -1570,6 +1570,10 @@ gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ flags.h $(RTL_H) +gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ + diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ + langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ + flags.h $(RTL_H) function.h tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \ $(TM_H) coretypes.h diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 7121a3e5db4..a3199a27d34 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -310,10 +310,14 @@ insn_locators_initialize (void) switch (NOTE_LINE_NUMBER (insn)) { case NOTE_INSN_BLOCK_BEG: + if (cfun->dont_emit_block_notes) + abort (); block = NOTE_BLOCK (insn); delete_insn (insn); break; case NOTE_INSN_BLOCK_END: + if (cfun->dont_emit_block_notes) + abort (); block = BLOCK_SUPERCONTEXT (block); if (block && TREE_CODE (block) == FUNCTION_DECL) block = 0; @@ -328,11 +332,17 @@ insn_locators_initialize (void) break; } } + + if (cfun->dont_emit_block_notes) + check_block_change (insn, &block); } /* Tag the blocks with a depth number so that change_scope can find the common parent easily. */ set_block_levels (DECL_INITIAL (cfun->decl), 0); + + if (cfun->dont_emit_block_notes) + free_block_changes (); } /* For each lexical block, set BLOCK_NUMBER to the depth at which it is diff --git a/gcc/expr.c b/gcc/expr.c index 37c4d437eb9..554547ae89f 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -6762,6 +6762,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, input_line = EXPR_LINENO (exp); emit_line_note (input_location); + /* Record where the insns produced belong. */ + if (cfun->dont_emit_block_notes) + record_block_change (TREE_BLOCK (exp)); + /* This is a gross hack. Temporarily remove the locus information and re-call expand_expr. @@ -8818,7 +8822,11 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, { expand_start_else (); if (EXPR_LOCUS (exp)) - emit_line_note (*(EXPR_LOCUS (exp))); + { + emit_line_note (*(EXPR_LOCUS (exp))); + if (cfun->dont_emit_block_notes) + record_block_change (TREE_BLOCK (exp)); + } expand_elseif (TREE_OPERAND (exp, 0)); expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, 0); } diff --git a/gcc/function.c b/gcc/function.c index baec4ab3048..8d230455485 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -265,7 +265,6 @@ static tree *identify_blocks_1 (rtx, tree *, tree *, tree *); static void reorder_blocks_0 (tree); static void reorder_blocks_1 (rtx, tree, varray_type *); static void reorder_fix_fragments (tree); -static tree blocks_nreverse (tree); static int all_blocks (tree, tree *); static tree *get_block_vector (tree, int *); extern tree debug_find_var_in_block_tree (tree, tree); @@ -5598,7 +5597,7 @@ uninitialized_vars_warning (tree block) flow.c that the entire aggregate was initialized. Unions are troublesome because members may be shorter. */ && ! AGGREGATE_TYPE_P (TREE_TYPE (decl)) - && DECL_RTL (decl) != 0 + && DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG /* Global optimizations can make it difficult to determine if a particular variable has been initialized. However, a VAR_DECL @@ -5613,7 +5612,7 @@ uninitialized_vars_warning (tree block) decl, decl); if (extra_warnings && TREE_CODE (decl) == VAR_DECL - && DECL_RTL (decl) != 0 + && DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'", @@ -6177,7 +6176,7 @@ reorder_fix_fragments (tree block) /* Reverse the order of elements in the chain T of blocks, and return the new head of the chain (old last element). */ -static tree +tree blocks_nreverse (tree t) { tree prev = 0, decl, next; @@ -7939,4 +7938,56 @@ init_function_once (void) VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue"); } +/* Resets insn_block_boundaries array. */ + +void +reset_block_changes () +{ + VARRAY_TREE_INIT (cfun->ib_boundaries_block, 100, "ib_boundaries_block"); + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, NULL_TREE); +} + +/* Record the boundary for BLOCK. */ +void +record_block_change (tree block) +{ + int i, n; + tree last_block; + + if (!block) + return; + + last_block = VARRAY_TOP_TREE (cfun->ib_boundaries_block); + VARRAY_POP (cfun->ib_boundaries_block); + n = get_max_uid (); + for (i = VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block); i < n; i++) + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, last_block); + + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, block); +} + +/* Finishes record of boundaries. */ +void finalize_block_changes () +{ + record_block_change (DECL_INITIAL (current_function_decl)); +} + +/* For INSN return the BLOCK it belongs to. */ +void +check_block_change (rtx insn, tree *block) +{ + unsigned uid = INSN_UID (insn); + + if (uid >= VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block)) + return; + + *block = VARRAY_TREE (cfun->ib_boundaries_block, uid); +} + +/* Releases the ib_boundaries_block records. */ +void +free_block_changes () +{ + cfun->ib_boundaries_block = NULL; +} #include "gt-function.h" diff --git a/gcc/function.h b/gcc/function.h index 37d6e2e9a2e..5307782e6fe 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -389,6 +389,10 @@ struct function GTY(()) delay list for them is recorded here. */ rtx epilogue_delay_list; + /* Nonzero if NOTE_INSN_BLOCK_BEG / NOTE_INSN_BLOCK_END notes should not + be emitted. */ + unsigned int dont_emit_block_notes : 1; + /* How commonly executed the function is. Initialized during branch probabilities pass. */ enum function_frequency { @@ -409,6 +413,9 @@ struct function GTY(()) /* Line number of the end of the function. */ location_t function_end_locus; + /* Array mapping insn uids to blocks. */ + struct varray_head_tag *ib_boundaries_block; + /* Collected bit flags. */ /* Nonzero if function being compiled needs to be given an address @@ -601,6 +608,13 @@ extern void reorder_blocks (void); /* Set BLOCK_NUMBER for all the blocks in FN. */ extern void number_blocks (tree); +extern tree blocks_nreverse (tree); +extern void reset_block_changes (void); +extern void record_block_change (tree); +extern void finalize_block_changes (void); +extern void check_block_change (rtx, tree *); +extern void free_block_changes (void); + /* Return size needed for stack frame based on slots so far allocated. This size counts from zero. It is not rounded to STACK_BOUNDARY; the caller may have to do that. */ diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c new file mode 100644 index 00000000000..d7edd33beb2 --- /dev/null +++ b/gcc/gimple-low.c @@ -0,0 +1,182 @@ +/* Tree lowering pass. Lowers GIMPLE into unstructured form. + + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "errors.h" +#include "varray.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "tree-flow.h" +#include "timevar.h" +#include "except.h" +#include "hashtab.h" +#include "flags.h" +#include "function.h" + +struct lower_data +{ + /* Block the current statement belongs to. */ + tree block; +}; + +static void lower_stmt_body (tree *, struct lower_data *); +static void lower_stmt (tree_stmt_iterator *, struct lower_data *); +static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); +static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); +static void lower_switch_expr (tree_stmt_iterator *, struct lower_data *); + +/* Lowers the BODY. */ +void +lower_function_body (tree *body) +{ + struct lower_data data; + + if (TREE_CODE (*body) != BIND_EXPR) + abort (); + + data.block = DECL_INITIAL (current_function_decl); + BLOCK_SUBBLOCKS (data.block) = NULL_TREE; + BLOCK_CHAIN (data.block) = NULL_TREE; + + lower_stmt_body (&BIND_EXPR_BODY (*body), &data); + + if (data.block != DECL_INITIAL (current_function_decl)) + abort (); + BLOCK_SUBBLOCKS (data.block) = + blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); +} + +/* Lowers the EXPR. Unlike gimplification the statements are not relowered + when they are changed -- if this has to be done, the lowering routine must + do it explicitly. DATA is passed through the recursion. */ + +static void +lower_stmt_body (tree *expr, struct lower_data *data) +{ + tree_stmt_iterator tsi; + + for (tsi = tsi_start (expr); !tsi_end_p (tsi); tsi_next (&tsi)) + lower_stmt (&tsi, data); +} + +/* Lowers statement TSI. DATA is passed through the recursion. */ +static void +lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt = tsi_stmt (*tsi); + + if (EXPR_LOCUS (stmt)) + TREE_BLOCK (stmt) = data->block; + + switch (TREE_CODE (stmt)) + { + case BIND_EXPR: + lower_bind_expr (tsi, data); + break; + + case COMPOUND_EXPR: + abort (); + + case NOP_EXPR: + case ASM_EXPR: + case RETURN_EXPR: + case MODIFY_EXPR: + case CALL_EXPR: + case GOTO_EXPR: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + case VA_ARG_EXPR: + case RESX_EXPR: + break; + + case COND_EXPR: + lower_cond_expr (tsi, data); + break; + + case SWITCH_EXPR: + lower_switch_expr (tsi, data); + break; + + default: + print_node_brief (stderr, "", tsi_stmt (*tsi), 0); + abort (); + } +} + +/* Lowers a bind_expr TSI. DATA is passed through the recursion. */ + +static void +lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree old_block = data->block; + tree stmt = tsi_stmt (*tsi); + + if (BIND_EXPR_BLOCK (stmt)) + { + data->block = BIND_EXPR_BLOCK (stmt); + + /* Block tree may get clobbered by inlining. Normally this would be + fixed in rest_of_decl_compilation using block notes, but since we + are not going to emit them, it is up to us. */ + BLOCK_CHAIN (data->block) = BLOCK_SUBBLOCKS (old_block); + BLOCK_SUBBLOCKS (old_block) = data->block; + BLOCK_SUBBLOCKS (data->block) = NULL_TREE; + BLOCK_SUPERCONTEXT (data->block) = old_block; + } + lower_stmt_body (&BIND_EXPR_BODY (stmt), data); + + if (BIND_EXPR_BLOCK (stmt)) + { + if (data->block != BIND_EXPR_BLOCK (stmt)) + abort (); + + BLOCK_SUBBLOCKS (data->block) = + blocks_nreverse (BLOCK_SUBBLOCKS (data->block)); + data->block = old_block; + } +} + +/* Lowers a cond_expr TSI. DATA is passed through the recursion. */ + +static void +lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt = tsi_stmt (*tsi); + + lower_stmt_body (&COND_EXPR_THEN (stmt), data); + lower_stmt_body (&COND_EXPR_ELSE (stmt), data); +} + +/* Lowers a switch_expr TSI. DATA is passed through the recursion. */ + +static void +lower_switch_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + lower_stmt_body (&SWITCH_BODY (tsi_stmt (*tsi)), data); +} diff --git a/gcc/sibcall.c b/gcc/sibcall.c index ec85cb23786..bc210f9e66b 100644 --- a/gcc/sibcall.c +++ b/gcc/sibcall.c @@ -748,7 +748,8 @@ optimize_sibling_and_tail_recursive_calls (void) /* There may have been NOTE_INSN_BLOCK_{BEGIN,END} notes in the CALL_PLACEHOLDER alternatives that we didn't emit. Rebuild the lexical block tree to correspond to the notes that still exist. */ - if (replaced_call_placeholder) + if (replaced_call_placeholder + && !cfun->dont_emit_block_notes) reorder_blocks (); /* This information will be invalid after inline expansion. Kill it now. */ diff --git a/gcc/stmt.c b/gcc/stmt.c index 2e0cd523d22..403a13ad64b 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -3402,7 +3402,7 @@ expand_start_bindings_and_block (int flags, tree block) abort (); /* Create a note to mark the beginning of the block. */ - if (block_flag) + if (block_flag && !cfun->dont_emit_block_notes) { note = emit_note (NOTE_INSN_BLOCK_BEG); NOTE_BLOCK (note) = block; @@ -3822,7 +3822,7 @@ expand_end_bindings (tree vars, int mark_ends, int dont_jump_in) We do this now, after running cleanups on the variables just going out of scope, so they are in scope for their cleanups. */ - if (mark_ends) + if (mark_ends && !cfun->dont_emit_block_notes) { rtx note = emit_note (NOTE_INSN_BLOCK_END); NOTE_BLOCK (note) = NOTE_BLOCK (thisblock->data.block.first_insn); diff --git a/gcc/toplev.c b/gcc/toplev.c index 4293ac345b0..69d7026b3f4 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3139,15 +3139,20 @@ rest_of_compilation (tree decl) have been run to re-initialize it. */ cse_not_expected = ! optimize; - /* First, make sure that NOTE_BLOCK is set correctly for each - NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ - if (!cfun->x_whole_function_mode_p) - identify_blocks (); - - /* In function-at-a-time mode, we do not attempt to keep the BLOCK - tree in sensible shape. So, we just recalculate it here. */ - if (cfun->x_whole_function_mode_p) - reorder_blocks (); + if (!cfun->dont_emit_block_notes) + { + /* First, make sure that NOTE_BLOCK is set correctly for each + NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ + if (!cfun->x_whole_function_mode_p) + identify_blocks (); + + /* In function-at-a-time mode, we do not attempt to keep the BLOCK + tree in sensible shape. So, we just recalculate it here. */ + if (cfun->x_whole_function_mode_p) + reorder_blocks (); + } + else + finalize_block_changes (); init_flow (); @@ -3175,7 +3180,8 @@ rest_of_compilation (tree decl) over the instruction sequence faster, and allow the garbage collector to reclaim the memory used by the notes. */ remove_unnecessary_notes (); - reorder_blocks (); + if (!cfun->dont_emit_block_notes) + reorder_blocks (); ggc_collect (); diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 8d51c2dc88b..8f84e890e8e 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -513,6 +513,8 @@ extern void add_referenced_tmp_var (tree var); #define TDFA_USE_OPS 1 << 0 #define TDFA_USE_VOPS 1 << 1 +/* In gimple-low.c */ +void lower_function_body (tree *); /* In tree-ssa.c */ extern void init_tree_ssa (void); diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index 65954234a5a..e0a49fc4319 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -61,8 +61,13 @@ optimize_function_tree (tree fndecl) if (errorcount || sorrycount) return; + lower_function_body (&DECL_SAVED_TREE (fndecl)); fnbody = DECL_SAVED_TREE (fndecl); + /* Avoid producing notes for blocks. */ + cfun->dont_emit_block_notes = 1; + reset_block_changes (); + /* Flatten the trees. */ head.prev = head.next = NULL; last = &head; diff --git a/gcc/tree.c b/gcc/tree.c index 2fe85234030..9d735c286a1 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -2431,6 +2431,7 @@ build1 (enum tree_code code, tree type, tree node) TREE_TYPE (t) = type; /* FIXME maybe give expr a locus here? */ SET_EXPR_LOCUS (t, NULL); + TREE_BLOCK (t) = NULL; TREE_COMPLEXITY (t) = 0; TREE_OPERAND (t, 0) = node; if (node && first_rtl_op (code) != 0) diff --git a/gcc/tree.h b/gcc/tree.h index 2624fe19219..b1cab8607e8 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -426,6 +426,8 @@ extern void tree_operand_check_failed (int, enum tree_code, #endif +#define TREE_BLOCK(NODE) ((NODE)->exp.block) + #include "tree-check.h" #define TYPE_CHECK(T) TREE_CLASS_CHECK (T, 't') @@ -982,6 +984,7 @@ struct tree_exp GTY(()) struct tree_common common; location_t *locus; int complexity; + tree block; tree GTY ((special ("tree_exp"), desc ("TREE_CODE ((tree) &%0)"))) operands[1]; -- cgit v1.2.3