Expanders cleanups after tree-ssa merge, part 1.

2004-05-19  Steven Bosscher  <stevenb@suse.de>

	Expanders cleanups after tree-ssa merge, part 1.

	* expr.c (store_constructor): Build loop start and end by hand
	instead of via loop functions from stmt.c.
	(expand_expr_real_1): Abort if we see an EXIT_EXPR or a LOOP_EXPR.
	Remove the code to expand them.

	* stmt.c (loop_stack): Remove this and everything related.
	(struct nesting, enum nesting_desc): Update.
	(expand_fixup): Likewise.
	(expand_loop_start, expand_start_loop_continue_elsewhere,
	expand_start_null_loop, expand_loop_continue_here, expand_end_loop,
	expand_end_null_loop, expand_continue_loop, expand_exit_loop,
	expand_exit_loop_if_false, expand_exit_loop_top_cond,
	expand_exit_something): Remove.
	* tree.h: Remove prototypes.

From-SVN: r82018
This commit is contained in:
Steven Bosscher 2004-05-19 06:26:21 +00:00 committed by Steven Bosscher
parent cc52902d97
commit 6af8eb5714
4 changed files with 46 additions and 427 deletions

View File

@ -1,3 +1,20 @@
2004-05-19 Steven Bosscher <stevenb@suse.de>
* expr.c (store_constructor): Build loop start and end by hand
instead of via loop functions from stmt.c.
(expand_expr_real_1): Abort if we see an EXIT_EXPR or a LOOP_EXPR.
Remove the code to expand them.
* stmt.c (loop_stack): Remove this and everything related.
(struct nesting, enum nesting_desc): Update.
(expand_fixup): Likewise.
(expand_loop_start, expand_start_loop_continue_elsewhere,
expand_start_null_loop, expand_loop_continue_here, expand_end_loop,
expand_end_null_loop, expand_continue_loop, expand_exit_loop,
expand_exit_loop_if_false, expand_exit_loop_top_cond,
expand_exit_something): Remove.
* tree.h: Remove prototypes.
2004-05-18 Mike Stump <mrs@apple.com>
Devang Patel <dpatel@apple.com>

View File

@ -4963,8 +4963,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
rtx index_r, pos_rtx, loop_end;
struct nesting *loop;
rtx index_r, pos_rtx;
HOST_WIDE_INT lo, hi, count;
tree position;
@ -5005,9 +5004,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
}
else
{
expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
loop_end = gen_label_rtx ();
rtx loop_start = gen_label_rtx ();
rtx loop_end = gen_label_rtx ();
tree exit_cond;
expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
unsignedp = TYPE_UNSIGNED (domain);
index = build_decl (VAR_DECL, NULL_TREE, domain);
@ -5025,7 +5026,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
emit_queue ();
}
store_expr (lo_index, index_r, 0);
loop = expand_start_loop (0);
/* Build the head of the loop. */
do_pending_stack_adjust ();
emit_queue ();
emit_label (loop_start);
/* Assign value to element index. */
position
@ -5046,14 +5051,19 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
else
store_expr (value, xtarget, 0);
expand_exit_loop_if_false (loop,
build (LT_EXPR, integer_type_node,
index, hi_index));
/* Generate a conditional jump to exit the loop. */
exit_cond = build (LT_EXPR, integer_type_node,
index, hi_index);
jumpif (exit_cond, loop_end);
/* Update the loop counter, and jump to the head of
the loop. */
expand_increment (build (PREINCREMENT_EXPR,
TREE_TYPE (index),
index, integer_one_node), 0, 0);
expand_end_loop ();
emit_jump (loop_start);
/* Build the end of the loop. */
emit_label (loop_end);
}
}
@ -6804,10 +6814,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
expand_computed_goto (TREE_OPERAND (exp, 0));
return const0_rtx;
/* These are lowered during gimplification, so we should never ever
see them here. */
case LOOP_EXPR:
case EXIT_EXPR:
expand_exit_loop_if_false (NULL,
invert_truthvalue (TREE_OPERAND (exp, 0)));
return const0_rtx;
abort ();
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
@ -6823,15 +6834,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
expand_goto (LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (exp)));
return const0_rtx;
case LOOP_EXPR:
push_temp_slots ();
expand_start_loop (1);
expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
expand_end_loop ();
pop_temp_slots ();
return const0_rtx;
case BIND_EXPR:
{
tree block = BIND_EXPR_BLOCK (exp);

View File

@ -124,7 +124,7 @@ static int cost_table_initialized;
The position of an entry on `nesting_stack' is in its `depth' field.
Each type of construct has its own individual stack.
For example, loops have `loop_stack'. Each object points to the
For example, loops have `cond_stack'. Each object points to the
next object of the same type through the `next' field.
Some constructs are visible to `break' exit-statements and others
@ -142,7 +142,6 @@ struct nesting GTY(())
rtx exit_label;
enum nesting_desc {
COND_NESTING,
LOOP_NESTING,
BLOCK_NESTING,
CASE_NESTING
} desc;
@ -159,17 +158,6 @@ struct nesting GTY(())
This may be the end of the if or the next else/elseif. */
rtx next_label;
} GTY ((tag ("COND_NESTING"))) cond;
/* For loops. */
struct nesting_loop
{
/* Label at the top of the loop; place to loop back to. */
rtx start_label;
/* Label at the end of the whole construct. */
rtx end_label;
/* Label for `continue' statement to jump to;
this is in front of the stepper of the loop. */
rtx continue_label;
} GTY ((tag ("LOOP_NESTING"))) loop;
/* For variable binding contours. */
struct nesting_block
{
@ -259,8 +247,6 @@ struct nesting GTY(())
do { struct nesting *target = STACK; \
struct nesting *this; \
do { this = nesting_stack; \
if (loop_stack == this) \
loop_stack = loop_stack->next; \
if (cond_stack == this) \
cond_stack = cond_stack->next; \
if (block_stack == this) \
@ -336,9 +322,6 @@ struct stmt_status GTY(())
/* Chain of all pending conditional statements. */
struct nesting * x_cond_stack;
/* Chain of all pending loops. */
struct nesting * x_loop_stack;
/* Chain of all pending case or switch statements. */
struct nesting * x_case_stack;
@ -372,7 +355,6 @@ struct stmt_status GTY(())
#define block_stack (cfun->stmt->x_block_stack)
#define stack_block_stack (cfun->stmt->x_stack_block_stack)
#define cond_stack (cfun->stmt->x_cond_stack)
#define loop_stack (cfun->stmt->x_loop_stack)
#define case_stack (cfun->stmt->x_case_stack)
#define nesting_stack (cfun->stmt->x_nesting_stack)
#define nesting_depth (cfun->stmt->x_nesting_depth)
@ -708,14 +690,6 @@ expand_fixup (tree tree_label, rtx rtl_label, rtx last_insn)
&& (rtl_label == cond_stack->data.cond.endif_label
|| rtl_label == cond_stack->data.cond.next_label))
end_block = cond_stack;
/* If we are in a loop, recognize certain labels which
are likely targets. This reduces the number of fixups
we need to create. */
else if (loop_stack
&& (rtl_label == loop_stack->data.loop.start_label
|| rtl_label == loop_stack->data.loop.end_label
|| rtl_label == loop_stack->data.loop.continue_label))
end_block = loop_stack;
else
end_block = 0;
@ -774,9 +748,8 @@ expand_fixup (tree tree_label, rtx rtl_label, rtx last_insn)
`SUPERBLOCK') of any other BLOCK nodes which we might create
later on when we are expanding the fixup code.
Note that optimization passes (including expand_end_loop)
might move the *_BLOCK notes away, so we use a NOTE_INSN_DELETED
as a placeholder. */
Note that optimization passes might move the *_BLOCK notes away,
so we use a NOTE_INSN_DELETED as a placeholder. */
{
rtx original_before_jump
@ -2472,384 +2445,22 @@ expand_end_cond (void)
clear_last_expr ();
}
/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
loop should be exited by `exit_something'. This is a loop for which
`expand_continue' will jump to the top of the loop.
Make an entry on loop_stack to record the labels associated with
this loop. */
struct nesting *
expand_start_loop (int exit_flag)
{
struct nesting *thisloop = ALLOC_NESTING ();
/* Make an entry on loop_stack for the loop we are entering. */
thisloop->desc = LOOP_NESTING;
thisloop->next = loop_stack;
thisloop->all = nesting_stack;
thisloop->depth = ++nesting_depth;
thisloop->data.loop.start_label = gen_label_rtx ();
thisloop->data.loop.end_label = gen_label_rtx ();
thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
loop_stack = thisloop;
nesting_stack = thisloop;
do_pending_stack_adjust ();
emit_queue ();
emit_label (thisloop->data.loop.start_label);
return thisloop;
}
/* Like expand_start_loop but for a loop where the continuation point
(for expand_continue_loop) will be specified explicitly. */
struct nesting *
expand_start_loop_continue_elsewhere (int exit_flag)
{
struct nesting *thisloop = expand_start_loop (exit_flag);
loop_stack->data.loop.continue_label = gen_label_rtx ();
return thisloop;
}
/* Begin a null, aka do { } while (0) "loop". But since the contents
of said loop can still contain a break, we must frob the loop nest. */
struct nesting *
expand_start_null_loop (void)
{
struct nesting *thisloop = ALLOC_NESTING ();
/* Make an entry on loop_stack for the loop we are entering. */
thisloop->desc = LOOP_NESTING;
thisloop->next = loop_stack;
thisloop->all = nesting_stack;
thisloop->depth = ++nesting_depth;
thisloop->data.loop.start_label = emit_note (NOTE_INSN_DELETED);
thisloop->data.loop.end_label = gen_label_rtx ();
thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
thisloop->exit_label = thisloop->data.loop.end_label;
loop_stack = thisloop;
nesting_stack = thisloop;
return thisloop;
}
/* Specify the continuation point for a loop started with
expand_start_loop_continue_elsewhere.
Use this at the point in the code to which a continue statement
should jump. */
void
expand_loop_continue_here (void)
{
do_pending_stack_adjust ();
emit_label (loop_stack->data.loop.continue_label);
}
/* Finish a loop. Generate a jump back to the top and the loop-exit label.
Pop the block off of loop_stack. */
void
expand_end_loop (void)
{
rtx start_label = loop_stack->data.loop.start_label;
rtx etc_note;
int eh_regions, debug_blocks;
bool empty_test;
do_pending_stack_adjust ();
/* If the loop starts with a loop exit, roll that to the end where
it will optimize together with the jump back.
If the loop presently looks like this (in pseudo-C):
start_label:
if (test) goto end_label;
LOOP_END_TOP_COND
body;
goto start_label;
end_label:
transform it to look like:
goto start_label;
top_label:
body;
start_label:
if (test) goto end_label;
goto top_label;
end_label:
We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
the end of the entry conditional. Without this, our lexical scan
can't tell the difference between an entry conditional and a
body conditional that exits the loop. Mistaking the two means
that we can misplace the NOTE_INSN_LOOP_CONT note, which can
screw up loop unrolling.
Things will be oh so much better when loop optimization is done
off of a proper control flow graph... */
/* Scan insns from the top of the loop looking for the END_TOP_COND note. */
empty_test = true;
eh_regions = debug_blocks = 0;
for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
if (GET_CODE (etc_note) == NOTE)
{
if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND)
break;
if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG)
abort ();
/* At the same time, scan for EH region notes, as we don't want
to scrog region nesting. This shouldn't happen, but... */
if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG)
eh_regions++;
else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END)
{
if (--eh_regions < 0)
/* We've come to the end of an EH region, but never saw the
beginning of that region. That means that an EH region
begins before the top of the loop, and ends in the middle
of it. The existence of such a situation violates a basic
assumption in this code, since that would imply that even
when EH_REGIONS is zero, we might move code out of an
exception region. */
abort ();
}
/* Likewise for debug scopes. In this case we'll either (1) move
all of the notes if they are properly nested or (2) leave the
notes alone and only rotate the loop at high optimization
levels when we expect to scrog debug info. */
else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
debug_blocks++;
else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
debug_blocks--;
}
else if (INSN_P (etc_note))
empty_test = false;
if (etc_note
&& optimize
&& ! empty_test
&& eh_regions == 0
&& (debug_blocks == 0 || optimize >= 2)
&& NEXT_INSN (etc_note) != NULL_RTX
&& ! any_condjump_p (get_last_insn ()))
{
/* We found one. Move everything from START to ETC to the end
of the loop, and add a jump from the top of the loop. */
rtx top_label = gen_label_rtx ();
rtx start_move = start_label;
emit_label_before (top_label, start_move);
/* Actually move the insns. If the debug scopes are nested, we
can move everything at once. Otherwise we have to move them
one by one and squeeze out the block notes. */
if (debug_blocks == 0)
reorder_insns (start_move, etc_note, get_last_insn ());
else
{
rtx insn, next_insn;
for (insn = start_move; insn; insn = next_insn)
{
/* Figure out which insn comes after this one. We have
to do this before we move INSN. */
next_insn = (insn == etc_note ? NULL : NEXT_INSN (insn));
if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
continue;
reorder_insns (insn, insn, get_last_insn ());
}
}
/* Add the jump from the top of the loop. */
emit_jump_insn_before (gen_jump (start_label), top_label);
emit_barrier_before (top_label);
start_label = top_label;
}
if (etc_note)
delete_insn (etc_note);
emit_jump (start_label);
emit_label (loop_stack->data.loop.end_label);
POPSTACK (loop_stack);
clear_last_expr ();
}
/* Finish a null loop, aka do { } while (0). */
void
expand_end_null_loop (void)
{
do_pending_stack_adjust ();
emit_label (loop_stack->data.loop.end_label);
POPSTACK (loop_stack);
clear_last_expr ();
}
/* Generate a jump to the current loop's continue-point.
This is usually the top of the loop, but may be specified
explicitly elsewhere. If not currently inside a loop,
return 0 and do nothing; caller will print an error message. */
int
expand_continue_loop (struct nesting *whichloop)
{
/* Emit information for branch prediction. */
rtx note;
if (flag_guess_branch_prob)
{
note = emit_note (NOTE_INSN_PREDICTION);
NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
}
clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
expand_goto_internal (NULL_TREE, whichloop->data.loop.continue_label,
NULL_RTX);
return 1;
}
/* Generate a jump to exit the current loop. If not currently inside a loop,
return 0 and do nothing; caller will print an error message. */
int
expand_exit_loop (struct nesting *whichloop)
{
clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, NULL_RTX);
return 1;
}
/* Generate a conditional jump to exit the current loop if COND
evaluates to zero. If not currently inside a loop,
return 0 and do nothing; caller will print an error message. */
int
expand_exit_loop_if_false (struct nesting *whichloop, tree cond)
{
rtx label;
clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
if (integer_nonzerop (cond))
return 1;
if (integer_zerop (cond))
return expand_exit_loop (whichloop);
/* Check if we definitely won't need a fixup. */
if (whichloop == nesting_stack)
{
jumpifnot (cond, whichloop->data.loop.end_label);
return 1;
}
/* In order to handle fixups, we actually create a conditional jump
around an unconditional branch to exit the loop. If fixups are
necessary, they go before the unconditional branch. */
label = gen_label_rtx ();
jumpif (cond, label);
expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
NULL_RTX);
emit_label (label);
return 1;
}
/* Like expand_exit_loop_if_false except also emit a note marking
the end of the conditional. Should only be used immediately
after expand_loop_start. */
int
expand_exit_loop_top_cond (struct nesting *whichloop, tree cond)
{
if (! expand_exit_loop_if_false (whichloop, cond))
return 0;
emit_note (NOTE_INSN_LOOP_END_TOP_COND);
return 1;
}
/* Return nonzero if we should preserve sub-expressions as separate
pseudos. We never do so if we aren't optimizing. We always do so
if -fexpensive-optimizations.
Otherwise, we only do so if we are in the "early" part of a loop. I.e.,
the loop may still be a small one. */
if -fexpensive-optimizations. */
int
preserve_subexpressions_p (void)
{
rtx insn;
if (flag_expensive_optimizations)
return 1;
if (optimize == 0 || cfun == 0 || cfun->stmt == 0 || loop_stack == 0)
if (optimize == 0 || cfun == 0 || cfun->stmt == 0)
return 0;
insn = get_last_insn_anywhere ();
return (insn
&& (INSN_UID (insn) - INSN_UID (loop_stack->data.loop.start_label)
< n_non_fixed_regs * 3));
return 1;
}
/* Generate a jump to exit the current loop, conditional, binding contour
or case statement. Not all such constructs are visible to this function,
only those started with EXIT_FLAG nonzero. Individual languages use
the EXIT_FLAG parameter to control which kinds of constructs you can
exit this way.
If not currently inside anything that can be exited,
return 0 and do nothing; caller will print an error message. */
int
expand_exit_something (void)
{
struct nesting *n;
clear_last_expr ();
for (n = nesting_stack; n; n = n->all)
if (n->exit_label != 0)
{
expand_goto_internal (NULL_TREE, n->exit_label, NULL_RTX);
return 1;
}
return 0;
}
/* Generate RTL to return from the current function, with no value.
(That is, we do not do anything about returning any value.) */

View File

@ -3392,17 +3392,6 @@ extern void expand_start_cond (tree, int);
extern void expand_end_cond (void);
extern void expand_start_else (void);
extern void expand_start_elseif (tree);
extern struct nesting *expand_start_loop (int);
extern struct nesting *expand_start_loop_continue_elsewhere (int);
extern struct nesting *expand_start_null_loop (void);
extern void expand_loop_continue_here (void);
extern void expand_end_loop (void);
extern void expand_end_null_loop (void);
extern int expand_continue_loop (struct nesting *);
extern int expand_exit_loop (struct nesting *);
extern int expand_exit_loop_if_false (struct nesting *,tree);
extern int expand_exit_loop_top_cond (struct nesting *, tree);
extern int expand_exit_something (void);
extern void expand_stack_alloc (tree, tree);
extern rtx expand_stack_save (void);