* Makefile.in (INTREGRATE_H): Rename to INTEGRATE_H.
* function.c (insert_block_after_note): Remove.
(retrofit_block): Likewise.
(identify_blocks): Fix indentation.
(reorder_blocks): Don't NULL out NOTE_SOURCE_FILE for a
NOTE_INSN_BLOCK_BEG or NOTE_INSN_BLOCK_END.
* function.h (insert_block_after_note): Remove prototype.
(retrofit_block): Likewise.
* integrate.c (expand_inline_function): Don't call
find_loop_tree_blocks. Use expand_start_bindings_and_block, not
just expand_start_bindings. Use the block_map to remap old
NOTE_BLOCKs to new ones.
(integrate_decl_tree): Keep track of remapped blocks.
* integrate.h (struct inline_remap): Add block_map.
* stmt.c (expand_fixup): Don't try to retrofit_blocks. Just set
NOTE_BLOCK on the notes.
(expand_start_bindings): Rename to ...
(expand_start_bindings_and_block): Add parameter. Set NOTE_BLOCK.
(expand_end_bindings): Set NOTE_BLOCK.
* toplev.c (rest_of_compilation): In function-at-a-time-mode,
reconstruct the BLOCK tree.
* tree.h (expand_start_bindings): Macroize. Call ...
(expand_start_bindings_and_block): New function.
* optimize.c (struct inline_data): Remove scope_stmt.
(remap_block): Don't use insert_block_after_note. Don't update
scope_stmt.
(expand_call_inline): Don't update scope_stmt.
(optimize_function): Don't initialize scope_stmt.
* semantics.c (expand_stmt): Set NOTE_BLOCK for newly emitted
NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END notes.
From-SVN: r30982
+1999-12-16 Mark Mitchell <mark@codesourcery.com>
+
+ * Makefile.in (INTREGRATE_H): Rename to INTEGRATE_H.
+ * function.c (insert_block_after_note): Remove.
+ (retrofit_block): Likewise.
+ (identify_blocks): Fix indentation.
+ (reorder_blocks): Don't NULL out NOTE_SOURCE_FILE for a
+ NOTE_INSN_BLOCK_BEG or NOTE_INSN_BLOCK_END.
+ * function.h (insert_block_after_note): Remove prototype.
+ (retrofit_block): Likewise.
+ * integrate.c (expand_inline_function): Don't call
+ find_loop_tree_blocks. Use expand_start_bindings_and_block, not
+ just expand_start_bindings. Use the block_map to remap old
+ NOTE_BLOCKs to new ones.
+ (integrate_decl_tree): Keep track of remapped blocks.
+ * integrate.h (struct inline_remap): Add block_map.
+ * stmt.c (expand_fixup): Don't try to retrofit_blocks. Just set
+ NOTE_BLOCK on the notes.
+ (expand_start_bindings): Rename to ...
+ (expand_start_bindings_and_block): Add parameter. Set NOTE_BLOCK.
+ (expand_end_bindings): Set NOTE_BLOCK.
+ * toplev.c (rest_of_compilation): In function-at-a-time-mode,
+ reconstruct the BLOCK tree.
+ * tree.h (expand_start_bindings): Macroize. Call ...
+ (expand_start_bindings_and_block): New function.
+
1999-12-16 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.c (print_operand): Cast fprintf arguments
RECOG_H = recog.h
EXPR_H = expr.h insn-codes.h
REGS_H = regs.h varray.h $(MACHMODE_H)
-INTREGRATE_H = integrate.h varray.h
+INTEGRATE_H = integrate.h varray.h
LOOP_H = loop.h varray.h
#\f
# Language makefile fragments.
+1999-12-16 Mark Mitchell <mark@codesourcery.com>
+
+ * optimize.c (struct inline_data): Remove scope_stmt.
+ (remap_block): Don't use insert_block_after_note. Don't update
+ scope_stmt.
+ (expand_call_inline): Don't update scope_stmt.
+ (optimize_function): Don't initialize scope_stmt.
+ * semantics.c (expand_stmt): Set NOTE_BLOCK for newly emitted
+ NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END notes.
+
1999-12-15 Mark Mitchell <mark@codesourcery.com>
* class.c (handle_using_decl): Get TYPE_FIELDS and TYPE_METHODS
inlining the body of `h', the stack will contain, `h', followed
by `g', followed by `f'. */
varray_type fns;
- /* The last SCOPE_STMT we have encountered. */
- tree scope_stmt;
/* The label to jump to when a return statement is encountered. */
tree ret_label;
/* The map from local declarations in the inlined function to
tree old_block;
tree new_block;
tree old_var;
+ tree fn;
/* Make the new block. */
old_block = SCOPE_STMT_BLOCK (scope_stmt);
}
/* We put the BLOCK_VARS in reverse order; fix that now. */
BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
- /* Graft the new block into the tree. */
- insert_block_after_note (new_block,
- SCOPE_STMT_BLOCK (id->scope_stmt),
- SCOPE_BEGIN_P (id->scope_stmt));
- /* Remember that this is now the last scope statement with
- an associated block. */
- id->scope_stmt = scope_stmt;
+ /* Attach this new block after the DECL_INITIAL block for the
+ function into which this block is being inlined. In
+ rest_of_compilation we will straighten out the BLOCK tree. */
+ fn = VARRAY_TREE (id->fns, 0);
+ BLOCK_CHAIN (new_block) = BLOCK_CHAIN (DECL_INITIAL (fn));
+ BLOCK_CHAIN (DECL_INITIAL (fn)) = new_block;
/* Remember the remapped block. */
splay_tree_insert (id->decl_map,
(splay_tree_key) old_block,
(splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));
my_friendly_assert (n != NULL, 19991203);
SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
-
- /* Remember that this is now the last scope statement with an
- associated block. */
- id->scope_stmt = scope_stmt;
}
}
id = (inline_data *) data;
t = *tp;
- /* Keep track of the last SCOPE_STMT we've seen. */
- if (TREE_CODE (t) == SCOPE_STMT)
- {
- if (SCOPE_STMT_BLOCK (t) && !id->in_target_cleanup_p)
- id->scope_stmt = t;
- return NULL_TREE;
- }
-
/* Recurse, but letting recursive invocations know that we are
inside the body of a TARGET_EXPR. */
if (TREE_CODE (*tp) == TARGET_EXPR)
remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
TREE_CHAIN (scope_stmt) = STMT_EXPR_STMT (expr);
STMT_EXPR_STMT (expr) = scope_stmt;
- id->scope_stmt = scope_stmt;
/* Tell the debugging backends that this block represents the
- outermost scope of the inlined function. FIXME what to do for
- inlines in cleanups? */
+ outermost scope of the inlined function. */
if (SCOPE_STMT_BLOCK (scope_stmt))
BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
prev_fn = s->function_decl;
}
- /* Initialize id->scope_stmt with a fake SCOPE_STMT for the outermost
- block of the function (i.e. the BLOCK with __FUNCTION__ et al). */
- id.scope_stmt = build_min_nt (SCOPE_STMT,
- BLOCK_SUBBLOCKS (DECL_INITIAL (fn)));
- SCOPE_BEGIN_P (id.scope_stmt) = 1;
-
/* Replace all calls to inline functions with the bodies of those
functions. */
expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
if (!SCOPE_NO_CLEANUPS_P (t))
{
if (SCOPE_BEGIN_P (t))
- expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
+ expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
+ SCOPE_STMT_BLOCK (t));
else if (SCOPE_END_P (t))
expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t),
SCOPE_PARTIAL_P (t));
}
else if (!SCOPE_NULLIFIED_P (t))
- emit_note (NULL,
- (SCOPE_BEGIN_P (t)
- ? NOTE_INSN_BLOCK_BEG
- : NOTE_INSN_BLOCK_END));
+ {
+ rtx note = emit_note (NULL,
+ (SCOPE_BEGIN_P (t)
+ ? NOTE_INSN_BLOCK_BEG
+ : NOTE_INSN_BLOCK_END));
+ NOTE_BLOCK (note) = SCOPE_STMT_BLOCK (t);
+ }
+
break;
case RETURN_INIT:
return tramp;
}
\f
-/* Insert the BLOCK in the block-tree, knowing that the previous
- block-note is for OLD_BLOCK. BEGIN_P is non-zero if the previous
- block-note was the for the beginning of a BLOCK. */
-
-void
-insert_block_after_note (block, old_block, begin_p)
- tree block;
- tree old_block;
- int begin_p;
-{
- if (begin_p)
- {
- /* If there was no previous block, something's gone terribly
- wrong. We used to try to use DECL_INITIAL for the current
- function, but that will never be correct, and completely
- hoses the block structure. */
- if (!old_block)
- abort ();
-
- BLOCK_SUPERCONTEXT (block) = old_block;
- BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (old_block);
- BLOCK_SUBBLOCKS (old_block) = block;
- }
- else
- {
- BLOCK_SUPERCONTEXT (block) = BLOCK_SUPERCONTEXT (old_block);
- BLOCK_CHAIN (block) = BLOCK_CHAIN (old_block);
- BLOCK_CHAIN (old_block) = block;
- }
-}
-
-/* Insert the BLOCK in the block-tree before LAST_INSN. */
-
-void
-retrofit_block (block, last_insn)
- tree block;
- rtx last_insn;
-{
- rtx insn;
-
- /* Now insert the new BLOCK at the right place in the block trees
- for the function which called the inline function. We just look
- backwards for a NOTE_INSN_BLOCK_{BEG,END}. If we find the
- beginning of a block, then this new block becomes the first
- subblock of that block. If we find the end of a block, then this
- new block follows that block in the list of blocks. */
- for (insn = last_insn; insn; insn = PREV_INSN (insn))
- if (GET_CODE (insn) == NOTE
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- break;
-
- if (insn == NULL_RTX)
- abort ();
-
- insert_block_after_note (block,
- NOTE_BLOCK (insn),
- NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG);
-}
-
/* The functions identify_blocks and reorder_blocks provide a way to
reorder the tree of BLOCK nodes, for optimizers that reshuffle or
duplicate portions of the RTL code. Call identify_blocks before
{
tree b;
- /* If there are more block notes than BLOCKs, something
- is badly wrong. */
+ /* If there are more block notes than BLOCKs, something
+ is badly wrong. */
if (current_block_number == n_blocks)
abort ();
BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
BLOCK_SUBBLOCKS (current_block) = block;
current_block = block;
- NOTE_SOURCE_FILE (insn) = 0;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
{
BLOCK_SUBBLOCKS (current_block)
= blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
current_block = BLOCK_SUPERCONTEXT (current_block);
- NOTE_SOURCE_FILE (insn) = 0;
}
}
Also store in each NOTE for the beginning or end of a block
the index of that block in the vector. */
extern void identify_blocks PROTO((tree, rtx));
-/* Insert the BLOCK in the block-tree, knowing that the previous
- block-note is for OLD_BLOCK. BEGIN_P is non-zero if the previous
- block-note was the for the beginning of a BLOCK. */
-extern void insert_block_after_note PROTO((tree, tree, int));
-/* Insert a new BLOCK at an appropriate place in the block tree. */
-extern void retrofit_block PROTO((tree, rtx));
/* Return size needed for stack frame based on slots so far allocated.
This size counts from zero. It is not rounded to STACK_BOUNDARY;
void set_decl_abstract_flags PROTO((tree, int));
static rtx expand_inline_function_eh_labelmap PROTO((rtx));
static void mark_stores PROTO((rtx, rtx, void *));
+static int compare_blocks PROTO((const PTR, const PTR));
+static int find_block PROTO((const PTR, const PTR));
/* The maximum number of instructions accepted for inlining a
function. Increasing values mean more agressive inlining.
return get_label_from_map (eif_eh_map, index);
}
+/* Compare two BLOCKs for qsort. The key we sort on is the
+ BLOCK_ABSTRACT_ORIGIN of the blocks. */
+
+static int
+compare_blocks (v1, v2)
+ const PTR v1;
+ const PTR v2;
+{
+ tree b1 = *((tree *) v1);
+ tree b2 = *((tree *) v2);
+
+ return ((char *) BLOCK_ABSTRACT_ORIGIN (b1)
+ - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+}
+
+/* Compare two BLOCKs for bsearch. The first pointer corresponds to
+ an original block; the second to a remapped equivalent. */
+
+static int
+find_block (v1, v2)
+ const PTR v1;
+ const PTR v2;
+{
+ tree b1 = (tree) v1;
+ tree b2 = *((tree *) v2);
+
+ return ((char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+}
+
/* Integrate the procedure defined by FNDECL. Note that this function
may wind up calling itself. Since the static variables are not
reentrant, we do not assign them until after the possibility
map = (struct inline_remap *) xmalloc (sizeof (struct inline_remap));
map->fndecl = fndecl;
+ VARRAY_TREE_INIT (map->block_map, 10, "block_map");
map->reg_map = (rtx *) xcalloc (max_regno, sizeof (rtx));
/* We used to use alloca here, but the size of what it would try to
RTX_INTEGRATED_P (note) = 1;
}
- /* Figure out where the blocks are if we're going to have to insert
- new BLOCKs into the existing block tree. */
- if (current_function->x_whole_function_mode_p)
- find_loop_tree_blocks ();
-
/* Process each argument. For each, set up things so that the function's
reference to the argument will refer to the argument being passed.
We only replace REG with REG here. Any simplifications are done
else
abort ();
- /* Make a fresh binding contour that we can easily remove. Do this after
- expanding our arguments so cleanups are properly scoped. */
- expand_start_bindings (0);
-
/* Initialize label_map. get_label_from_map will actually make
the labels. */
bzero ((char *) &map->label_map [min_labelno],
(max_labelno - min_labelno) * sizeof (rtx));
+ /* Make copies of the decls of the symbols in the inline function, so that
+ the copies of the variables get declared in the current function. Set
+ up things so that lookup_static_chain knows that to interpret registers
+ in SAVE_EXPRs for TYPE_SIZEs as local. */
+ inline_function_decl = fndecl;
+ integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector);
+ block = integrate_decl_tree (inl_f->original_decl_initial, map);
+ BLOCK_ABSTRACT_ORIGIN (block) = DECL_ORIGIN (fndecl);
+ inline_function_decl = 0;
+
+ /* Make a fresh binding contour that we can easily remove. Do this after
+ expanding our arguments so cleanups are properly scoped. */
+ expand_start_bindings_and_block (0, block);
+
+ /* Sort the block-map so that it will be easy to find remapped
+ blocks later. */
+ qsort (&VARRAY_TREE (map->block_map, 0),
+ map->block_map->elements_used,
+ sizeof (tree),
+ compare_blocks);
+
/* Perform postincrements before actually calling the function. */
emit_queue ();
region. */
NOTE_EH_HANDLER (copy) = CODE_LABEL_NUMBER (label);
}
+ else if (copy
+ && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END)
+ && NOTE_BLOCK (insn))
+ {
+ tree *mapped_block_p;
+
+ mapped_block_p
+ = (tree *) bsearch (NOTE_BLOCK (insn),
+ &VARRAY_TREE (map->block_map, 0),
+ map->block_map->elements_used,
+ sizeof (tree),
+ find_block);
+
+ if (!mapped_block_p)
+ abort ();
+ else
+ NOTE_BLOCK (copy) = *mapped_block_p;
+ }
}
else
copy = 0;
if (inl_f->calls_alloca)
emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
- /* Make copies of the decls of the symbols in the inline function, so that
- the copies of the variables get declared in the current function. Set
- up things so that lookup_static_chain knows that to interpret registers
- in SAVE_EXPRs for TYPE_SIZEs as local. */
-
- inline_function_decl = fndecl;
- integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector);
- block = integrate_decl_tree (inl_f->original_decl_initial, map);
- BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
- ? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
- inline_function_decl = 0;
-
- if (current_function->x_whole_function_mode_p)
- /* Insert the block into the already existing block-tree. */
- retrofit_block (block, map->insns_at_start);
- else
+ if (!current_function->x_whole_function_mode_p)
/* In statement-at-a-time mode, we just tell the front-end to add
this block to the list of blocks at this binding level. We
can't do it the way it's done for function-at-a-time mode the
superblocks have not been created yet. */
insert_block (block);
+ else
+ {
+ BLOCK_CHAIN (block)
+ = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
+ BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
+ }
/* End the scope containing the copied formal parameter variables
and copied LABEL_DECLs. We pass NULL_TREE for the variables list
free (real_label_map);
VARRAY_FREE (map->const_equiv_varray);
free (map->reg_map);
+ VARRAY_FREE (map->block_map);
free (map->insn_map);
free (map);
free (arg_vals);
tree *next;
new_block = make_node (BLOCK);
+ VARRAY_PUSH_TREE (map->block_map, new_block);
next = &BLOCK_VARS (new_block);
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
union tree_node *fndecl;
/* Place to put insns needed at start of function. */
rtx insns_at_start;
+ /* Mapping from old BLOCKs to new BLOCKs. */
+ varray_type block_map;
/* Mapping from old registers to new registers.
It is allocated and deallocated in `expand_inline_function' */
rtx *reg_map;
register rtx original_before_jump
= last_insn ? last_insn : get_last_insn ();
rtx start;
+ rtx end;
tree block;
block = make_node (BLOCK);
TREE_USED (block) = 1;
- if (current_function->x_whole_function_mode_p)
+ if (!current_function->x_whole_function_mode_p)
+ insert_block (block);
+ else
{
- find_loop_tree_blocks ();
- retrofit_block (block, original_before_jump);
+ BLOCK_CHAIN (block)
+ = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
+ BLOCK_CHAIN (DECL_INITIAL (current_function_decl))
+ = block;
}
- else
- insert_block (block);
start_sequence ();
start = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ if (current_function->x_whole_function_mode_p)
+ NOTE_BLOCK (start) = block;
fixup->before_jump = emit_note (NULL_PTR, NOTE_INSN_DELETED);
- emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+ end = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+ if (current_function->x_whole_function_mode_p)
+ NOTE_BLOCK (end) = block;
fixup->context = block;
end_sequence ();
emit_insns_after (start, original_before_jump);
will not create corresponding BLOCK nodes. (There should be
a one-to-one correspondence between NOTE_INSN_BLOCK_BEG notes
and BLOCKs.) If this flag is set, MARK_ENDS should be zero
- when expand_end_bindings is called. */
+ when expand_end_bindings is called.
+
+ If we are creating a NOTE_INSN_BLOCK_BEG note, a BLOCK may
+ optionally be supplied. If so, it becomes the NOTE_BLOCK for the
+ note. */
void
-expand_start_bindings (flags)
+expand_start_bindings_and_block (flags, block)
int flags;
+ tree block;
{
struct nesting *thisblock = ALLOC_NESTING ();
rtx note;
int exit_flag = ((flags & 1) != 0);
int block_flag = ((flags & 2) == 0);
+
+ /* If a BLOCK is supplied, then the caller should be requesting a
+ NOTE_INSN_BLOCK_BEG note. */
+ if (!block_flag && block)
+ abort ();
- note = emit_note (NULL_PTR,
- block_flag ? NOTE_INSN_BLOCK_BEG : NOTE_INSN_DELETED);
-
+ /* Create a note to mark the beginning of the block. */
+ if (block_flag)
+ {
+ note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ NOTE_BLOCK (note) = block;
+ }
+ else
+ note = emit_note (NULL_PTR, NOTE_INSN_DELETED);
+
/* Make an entry on block_stack for the block we are entering. */
thisblock->next = block_stack;
just going out of scope, so they are in scope for their cleanups. */
if (mark_ends)
- emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+ {
+ rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+ NOTE_BLOCK (note) = NOTE_BLOCK (thisblock->data.block.first_insn);
+ }
else
/* Get rid of the beginning-mark if we don't make an end-mark. */
NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
collector to reclaim the memory used by the notes. */
remove_unncessary_notes ();
+ /* 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 (current_function->x_whole_function_mode_p)
+ {
+ find_loop_tree_blocks ();
+ unroll_block_trees ();
+ }
+
/* If we are reconsidering an inline function
at the end of compilation, skip the stuff for making it inline. */
extern void expand_null_return PROTO((void));
extern void expand_return PROTO((tree));
extern int optimize_tail_recursion PROTO((tree, struct rtx_def *));
-extern void expand_start_bindings PROTO((int));
+extern void expand_start_bindings_and_block PROTO((int, tree));
+#define expand_start_bindings(flags) \
+ expand_start_bindings_and_block(flags, NULL_TREE)
extern void expand_end_bindings PROTO((tree, int, int));
extern void warn_about_unused_variables PROTO((tree));
extern void start_cleanup_deferral PROTO((void));