Reg stack improvement/cleanup
Jan Hubicka
hubicka@atrey.karlin.mff.cuni.cz
Sat Oct 30 16:13:00 GMT 1999
Hi
This patch takes some fruits from the new flow implementation.
It splits out the global stuff from basic conversion - the blocks are
put together in separate pass.
This adds some flexibility. Basically I can change the basic block
interface to fit my needs, as Richard suggested about loop.
Also I can output common code for all edges to the end of basic block.
This is actually much smarter than jump, because it results in different
common code, so jump is unable to do it.
I've also added code to collect information about transparency of the
block. This can be used by future global optimizer (in long term I would
like to split out the analysys from real reg-stacking so I can first
do the analysis, then decide interfaces and then do the real conversion).
For now the the transparency info is used by emit_swap_insn.
I've already made simple global optimizer for swaps. I will send this
code later.
Note that I am not much statisfied by the way fixed_regs is handled currently,
but it may be easier to change once the replacing code is cleaned up.
Fri Oct 30 17:44:30 CEST 1999 Jan Hubicka <hubicka@freesoft.cz>
* reg-stack.c (struct block_info_def): New fields fixed_regs,
stack_out and rename.
(emit_swap_insn): New "final" parameter, update basic block info
to avoid fxch.
(change_stack): Likewise, update call of change_to_regmap.
(change_to_regmap): Likewise, update call of emit_swap_insn.
(emit_basic_block_corrections): New.
(emit_common_basic_block_corrections): New.
(convert_regs_1): Do not return integer, do not emit correction code,
initialize rename map.
(straighten_stack): Update call of emit_swap_insn.
(compare_for_stack_reg): Likewise.
(subst_stack_regs_pat): Likewise.
(move_for_stack_reg): Likewise; update rename map, propagate fixed regs,
(subst_asm_stack_regs): Update call of change_to_regmap.
(replace_reg): Set register as fixed.
(emit_pop_insn): Likewise.
(find_common_map): New function.
(remove_incomplette_cycles): New function.
(convert_regs): Call emit_common_basic_block_corrections
and emit_basic_block_corrections.
*** reg-stack.c.old1 Sat Oct 30 17:39:39 1999
--- reg-stack.c Sat Oct 30 17:40:31 1999
*************** typedef struct stack_def
*** 193,199 ****
--- 193,204 ----
typedef struct block_info_def
{
struct stack_def stack_in; /* Input stack configuration. */
+ struct stack_def stack_out; /* Output stack configuration. */
HARD_REG_SET out_reg_set; /* Stack regs live on output. */
+ HARD_REG_SET fixed_regs; /* Set for registers that must appear at
+ position given by stack_out. */
+ char rename[REG_STACK_SIZE]; /* This map is used to keep track of renames
+ done by reg-reg with REG_DEAD note. */
int done; /* True if block already converted. */
} *block_info;
*************** static int get_hard_regnum PROTO((stack
*** 243,249 ****
static void delete_insn_for_stacker PROTO((rtx));
static rtx emit_pop_insn PROTO((rtx, stack, rtx,
enum emit_where));
! static void emit_swap_insn PROTO((rtx, stack, rtx));
static void move_for_stack_reg PROTO((rtx, stack, rtx));
static int swap_rtx_condition_1 PROTO((rtx));
static int swap_rtx_condition PROTO((rtx));
--- 248,254 ----
static void delete_insn_for_stacker PROTO((rtx));
static rtx emit_pop_insn PROTO((rtx, stack, rtx,
enum emit_where));
! static void emit_swap_insn PROTO((rtx, stack, rtx, int));
static void move_for_stack_reg PROTO((rtx, stack, rtx));
static int swap_rtx_condition_1 PROTO((rtx));
static int swap_rtx_condition PROTO((rtx));
*************** static void subst_stack_regs_pat PROTO((
*** 252,265 ****
static void subst_asm_stack_regs PROTO((rtx, stack));
static void subst_stack_regs PROTO((rtx, stack));
static int change_stack PROTO((rtx, stack, stack,
! enum emit_where));
static int change_to_regmap PROTO((rtx, stack, int *,
! enum emit_where));
static int convert_regs_entry PROTO((void));
static void convert_regs_exit PROTO((void));
! static int convert_regs_1 PROTO((FILE *, basic_block));
static int convert_regs_2 PROTO((FILE *, basic_block));
static int convert_regs PROTO((FILE *));
static void print_stack PROTO((FILE *, stack));
/* Return non-zero if any stack register is mentioned somewhere within PAT. */
--- 257,272 ----
static void subst_asm_stack_regs PROTO((rtx, stack));
static void subst_stack_regs PROTO((rtx, stack));
static int change_stack PROTO((rtx, stack, stack,
! enum emit_where, int));
static int change_to_regmap PROTO((rtx, stack, int *,
! enum emit_where, int));
static int convert_regs_entry PROTO((void));
static void convert_regs_exit PROTO((void));
! static void convert_regs_1 PROTO((FILE *, basic_block));
static int convert_regs_2 PROTO((FILE *, basic_block));
static int convert_regs PROTO((FILE *));
+ static int emit_basic_block_corrections PROTO((FILE *));
+ static int emit_common_basic_block_corrections PROTO((FILE *));
static void print_stack PROTO((FILE *, stack));
/* Return non-zero if any stack register is mentioned somewhere within PAT. */
*************** straighten_stack (insn, regstack)
*** 375,381 ****
for (top = temp_stack.top = regstack->top; top >= 0; top--)
temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
! change_stack (insn, regstack, &temp_stack, EMIT_AFTER);
}
/* Pop a register from the stack */
--- 377,383 ----
for (top = temp_stack.top = regstack->top; top >= 0; top--)
temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
! change_stack (insn, regstack, &temp_stack, EMIT_AFTER, 0);
}
/* Pop a register from the stack */
--- 499,504 ----
*************** replace_reg (reg, regno)
*** 832,837 ****
--- 780,788 ----
|| ! STACK_REG_P (*reg))
abort ();
+ /* Mark register fixed. */
+ SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, true_regnum (*reg));
+
switch (GET_MODE_CLASS (GET_MODE (*reg)))
{
default: abort ();
*************** get_hard_regnum (regstack, reg)
*** 889,896 ****
}
/* Delete INSN from the RTL. Mark the insn, but don't remove it from
! the chain of insns. Doing so could confuse block_begin and block_end
! if this were the only insn in the block. */
static void
delete_insn_for_stacker (insn)
--- 840,846 ----
}
/* Delete INSN from the RTL. Mark the insn, but don't remove it from
! the chain of insns. Doing so could confuse CFG. */
static void
delete_insn_for_stacker (insn)
*************** emit_pop_insn (insn, regstack, reg, wher
*** 923,928 ****
--- 873,882 ----
if (hard_regno < FIRST_STACK_REG)
abort ();
+ /* mark popped register as fixed. */
+ if (current_block)
+ SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, true_regnum (reg));
+
pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
FP_MODE_REG (FIRST_STACK_REG, DFmode));
*************** emit_pop_insn (insn, regstack, reg, wher
*** 948,964 ****
is updated to reflect the swap. A swap insn is represented as a
PARALLEL of two patterns: each pattern moves one reg to the other.
! If REG is already at the top of the stack, no insn is emitted. */
static void
! emit_swap_insn (insn, regstack, reg)
rtx insn;
stack regstack;
rtx reg;
{
int hard_regno;
rtx swap_rtx;
! int tmp, other_reg; /* swap regno temps */
rtx i1; /* the stack-reg insn prior to INSN */
rtx i1set = NULL_RTX; /* the SET rtx within I1 */
--- 902,921 ----
is updated to reflect the swap. A swap insn is represented as a
PARALLEL of two patterns: each pattern moves one reg to the other.
! If REG is already at the top of the stack, no insn is emitted.
! If FINAL is not set, swap insn is allowed to do changes in the basic
! block interface. */
static void
! emit_swap_insn (insn, regstack, reg, final)
rtx insn;
stack regstack;
rtx reg;
+ int final;
{
int hard_regno;
rtx swap_rtx;
! int other_regno, other_reg; /* swap regno temps */
rtx i1; /* the stack-reg insn prior to INSN */
rtx i1set = NULL_RTX; /* the SET rtx within I1 */
*************** emit_swap_insn (insn, regstack, reg)
*** 971,979 ****
other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
! tmp = regstack->reg[other_reg];
! regstack->reg[other_reg] = regstack->reg[regstack->top];
! regstack->reg[regstack->top] = tmp;
/* Find the previous insn involving stack regs, but don't pass a
block boundary. */
--- 928,963 ----
other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
! other_regno = regstack->reg[regstack->top];
! regstack->reg[regstack->top] = regstack->reg[other_reg];
! regstack->reg[other_reg] = other_regno;
!
! /* Attempt to solve swap by changing input permutation. */
! if (!final
! && !TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, other_regno)
! && !TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs,
! REGNO (reg)))
! {
! block_info bi = BLOCK_INFO (current_block);
! int src = bi->rename[other_regno - FIRST_STACK_REG];
! int dest = bi->rename[REGNO (reg) - FIRST_STACK_REG];
! int i;
!
! /* If none of operands is top of stack, we may change one fxch to two.
! ??? This test can be more curefull later. */
! if (bi->stack_in.reg [bi->stack_in.top] == src
! || bi->stack_in.reg [bi->stack_in.top] == dest)
! {
! for (i = 0; i <= bi->stack_in.top; i++)
! {
! if (bi->stack_in.reg[i] == src)
! bi->stack_in.reg[i] = dest;
! else if (bi->stack_in.reg[i] == dest)
! bi->stack_in.reg[i] = src;
! }
! return;
! }
! }
/* Find the previous insn involving stack regs, but don't pass a
block boundary. */
*************** move_for_stack_reg (insn, regstack, pat)
*** 1045,1050 ****
--- 1029,1035 ----
rtx *psrc = get_true_reg (&SET_SRC (pat));
rtx *pdest = get_true_reg (&SET_DEST (pat));
rtx src, dest;
+ int ren;
rtx note;
src = *psrc; dest = *pdest;
*************** move_for_stack_reg (insn, regstack, pat)
*** 1089,1094 ****
--- 1074,1089 ----
delete_insn_for_stacker (insn);
+ /* Update rename map and propagate fixed register flag. */
+
+ ren = BLOCK_INFO (current_block)->rename[REGNO (src) - FIRST_STACK_REG];
+
+ BLOCK_INFO (current_block)->rename[REGNO (dest) - FIRST_STACK_REG]
+ = ren;
+ if (TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, ren))
+ SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs,
+ REGNO (dest));
+
return;
}
*************** move_for_stack_reg (insn, regstack, pat)
*** 1124,1130 ****
only top of stack may be saved, emit an exchange first if
needs be. */
! emit_swap_insn (insn, regstack, src);
note = find_regno_note (insn, REG_DEAD, REGNO (src));
if (note)
--- 1119,1125 ----
only top of stack may be saved, emit an exchange first if
needs be. */
! emit_swap_insn (insn, regstack, src, 0);
note = find_regno_note (insn, REG_DEAD, REGNO (src));
if (note)
*************** compare_for_stack_reg (insn, regstack, p
*** 1325,1331 ****
else
src2_note = NULL_RTX;
! emit_swap_insn (insn, regstack, *src1);
replace_reg (src1, FIRST_STACK_REG);
--- 1315,1321 ----
else
src2_note = NULL_RTX;
! emit_swap_insn (insn, regstack, *src1, 0);
replace_reg (src1, FIRST_STACK_REG);
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1489,1495 ****
if (src1 == 0)
src1 = get_true_reg (&XEXP (pat_src, 0));
! emit_swap_insn (insn, regstack, *src1);
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
--- 1479,1485 ----
if (src1 == 0)
src1 = get_true_reg (&XEXP (pat_src, 0));
! emit_swap_insn (insn, regstack, *src1, 0);
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1536,1542 ****
must be top of stack. */
if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
! emit_swap_insn (insn, regstack, *dest);
else
{
/* Both operands are REG. If neither operand is already
--- 1526,1532 ----
must be top of stack. */
if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
! emit_swap_insn (insn, regstack, *dest, 0);
else
{
/* Both operands are REG. If neither operand is already
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1552,1558 ****
if (src1_hard_regnum != FIRST_STACK_REG
&& src2_hard_regnum != FIRST_STACK_REG)
! emit_swap_insn (insn, regstack, *dest);
}
if (STACK_REG_P (*src1))
--- 1542,1548 ----
if (src1_hard_regnum != FIRST_STACK_REG
&& src2_hard_regnum != FIRST_STACK_REG)
! emit_swap_insn (insn, regstack, *dest, 0);
}
if (STACK_REG_P (*src1))
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1631,1637 ****
src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
! emit_swap_insn (insn, regstack, *src1);
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
--- 1621,1627 ----
src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
! emit_swap_insn (insn, regstack, *src1, 0);
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1687,1693 ****
have to handle it here. */
if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
&& REGNO (*dest) != regstack->reg[regstack->top])
! emit_swap_insn (insn, regstack, *dest);
src1 = get_true_reg (&XEXP (pat_src, 1));
src2 = get_true_reg (&XEXP (pat_src, 2));
--- 1677,1683 ----
have to handle it here. */
if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
&& REGNO (*dest) != regstack->reg[regstack->top])
! emit_swap_insn (insn, regstack, *dest, 0);
src1 = get_true_reg (&XEXP (pat_src, 1));
src2 = get_true_reg (&XEXP (pat_src, 2));
*************** subst_asm_stack_regs (insn, regstack)
*** 1897,1903 ****
/* Emit insns before INSN to make sure the reg-stack is in the right
order. */
! change_to_regmap (insn, regstack, regmap, EMIT_BEFORE);
/* Make the needed input register substitutions. Do death notes and
clobbers too, because these are for inputs, not outputs. */
--- 1887,1893 ----
/* Emit insns before INSN to make sure the reg-stack is in the right
order. */
! change_to_regmap (insn, regstack, regmap, EMIT_BEFORE, 0);
/* Make the needed input register substitutions. Do death notes and
clobbers too, because these are for inputs, not outputs. */
*************** find_path (registermap, s)
*** 2177,2187 ****
interface.
*/
static int
! change_to_regmap (insn, old, regmap, where)
rtx insn;
stack old;
int *regmap;
enum emit_where where;
{
int update_end = 0;
int ninsns = 0;
--- 2167,2178 ----
interface.
*/
static int
! change_to_regmap (insn, old, regmap, where, final)
rtx insn;
stack old;
int *regmap;
enum emit_where where;
+ int final;
{
int update_end = 0;
int ninsns = 0;
*************** change_to_regmap (insn, old, regmap, whe
*** 2237,2243 ****
}
if (regmap[(int) old->reg[newpos]] != -1)
! emit_swap_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode));
else
emit_pop_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), EMIT_BEFORE);
ninsns++;
--- 2228,2234 ----
}
if (regmap[(int) old->reg[newpos]] != -1)
! emit_swap_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), final);
else
emit_pop_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), EMIT_BEFORE);
ninsns++;
*************** change_to_regmap (insn, old, regmap, whe
*** 2257,2269 ****
WHERE. OLD is the original stack layout, and NEW is the desired
form. OLD is updated to reflect the code emitted, ie, it will be
the same as NEW upon return.
*/
static int
! change_stack (insn, old, new, where)
rtx insn;
stack old;
stack new;
enum emit_where where;
{
int reg;
int ninsns = 0;
--- 2248,2264 ----
WHERE. OLD is the original stack layout, and NEW is the desired
form. OLD is updated to reflect the code emitted, ie, it will be
the same as NEW upon return.
+
+ When final is nonzero, change_stack is not allowed to modify basic block
+ interface.
*/
static int
! change_stack (insn, old, new, where, final)
rtx insn;
stack old;
stack new;
enum emit_where where;
+ int final;
{
int reg;
int ninsns = 0;
*************** win1:
*** 2282,2288 ****
for (reg = 0 ; reg <= new->top ; reg++)
regmap [(int) new->reg[reg]] = reg;
! ninsns = change_to_regmap (insn, old, regmap, where);
GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win2);
abort ();
--- 2277,2283 ----
for (reg = 0 ; reg <= new->top ; reg++)
regmap [(int) new->reg[reg]] = reg;
! ninsns = change_to_regmap (insn, old, regmap, where, final);
GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win2);
abort ();
*************** convert_regs_exit ()
*** 2428,2451 ****
/* Convert stack register references in one block. */
! static int
convert_regs_1 (file, block)
FILE *file;
basic_block block;
{
! struct stack_def regstack, tmpstack;
block_info bi = BLOCK_INFO (block);
! int inserted, reg;
rtx insn, next;
edge e;
current_block = block;
!
if (file)
{
! fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
print_stack (file, &bi->stack_in);
}
/* Process all insns in this block. Keep track of NEXT so that we
don't process insns emitted while substituting in INSN. */
--- 2423,2449 ----
/* Convert stack register references in one block. */
! static void
convert_regs_1 (file, block)
FILE *file;
basic_block block;
{
! struct stack_def regstack;
block_info bi = BLOCK_INFO (block);
! int reg;
rtx insn, next;
edge e;
+ int i;
current_block = block;
!
if (file)
{
! fprintf (file, "\nBasic block %d\n Proposed input stack: ", block->index);
print_stack (file, &bi->stack_in);
}
+ for (i = 0 ; i < REG_STACK_SIZE ; i++)
+ bi->rename[i]=i+FIRST_STACK_REG;
/* Process all insns in this block. Keep track of NEXT so that we
don't process insns emitted while substituting in INSN. */
*************** convert_regs_1 (file, block)
*** 2480,2490 ****
if (file)
{
! fprintf (file, "Expected live registers [");
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
fprintf (file, " %d", reg);
! fprintf (file, " ]\nOutput stack: ");
print_stack (file, ®stack);
}
--- 2478,2490 ----
if (file)
{
! fprintf (file, " Expected live registers [");
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
fprintf (file, " %d", reg);
! fprintf (file, " ]\n Input stack: ");
! print_stack (file, &bi->stack_in);
! fprintf (file, " Output stack: ");
print_stack (file, ®stack);
}
*************** convert_regs_1 (file, block)
*** 2499,2505 ****
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
{
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
! && ! TEST_HARD_REG_BIT (regstack.reg_set, reg))
{
rtx set;
--- 2499,2505 ----
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
{
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
! && !TEST_HARD_REG_BIT (regstack.reg_set, reg))
{
rtx set;
*************** convert_regs_1 (file, block)
*** 2519,2569 ****
/* Something failed if the stack lives don't match. */
GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
abort ();
! win:
! /* Adjust the stack of this block on exit to match the stack of the
! target block, or copy stack info into the stack of the successor
of the successor hasn't been processed yet. */
! inserted = 0;
! for (e = block->succ; e ; e = e->succ_next)
{
basic_block target = e->dest;
stack target_stack = &BLOCK_INFO (target)->stack_in;
- if (file)
- fprintf (file, "Edge to block %d: ", target->index);
-
if (target_stack->top == -2)
{
/* The target block hasn't had a stack order selected.
! We need merely ensure that no pops are needed. */
! for (reg = regstack.top; reg >= 0; --reg)
! if (! TEST_HARD_REG_BIT (target_stack->reg_set,
! regstack.reg[reg]))
! break;
! if (reg == -1)
! {
! if (file)
! fprintf (file, "new block; copying stack position\n");
! /* change_stack kills values in regstack. */
! tmpstack = regstack;
! change_stack (block->end, &tmpstack,
! target_stack, EMIT_AFTER);
! continue;
! }
! if (file)
! fprintf (file, "new block; pops needed\n");
}
! else
{
! if (target_stack->top == regstack.top)
{
for (reg = target_stack->top; reg >= 0; --reg)
! if (target_stack->reg[reg] != regstack.reg[reg])
break;
if (reg == -1)
--- 2519,2691 ----
/* Something failed if the stack lives don't match. */
GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
abort ();
! win:
! /* copy stack info into the stack of the successor
of the successor hasn't been processed yet. */
!
! for (e = block->succ; e; e = e->succ_next)
{
basic_block target = e->dest;
stack target_stack = &BLOCK_INFO (target)->stack_in;
if (target_stack->top == -2)
{
+ int pops = 0;
+ struct stack_def newstack = regstack;
+
/* The target block hasn't had a stack order selected.
! We need only to pop the registers. */
! for (reg = 0; reg <= regstack.top; reg++)
! if (!TEST_HARD_REG_BIT (target_stack->reg_set,
! regstack.reg[reg]))
! {
! pop_stack (&newstack, regstack.reg[reg]);
! pops++;
! }
! if (file)
! fprintf (file, " New block %d reached; copying stack position; %i pops\n",
! target->index,
! pops);
! *target_stack = newstack;
! }
! }
! bi->stack_out = regstack;
! return;
! }
! /* Convert registers in all blocks reachable from BLOCK. */
! static int
! convert_regs_2 (file, block)
! FILE *file;
! basic_block block;
! {
! basic_block *stack, *sp;
! int inserted;
!
! stack = (basic_block *) alloca (sizeof (*stack) * n_basic_blocks);
! sp = stack;
!
! *sp++ = block;
! BLOCK_INFO (block)->done = 1;
!
! inserted = 0;
! do
! {
! edge e;
!
! block = *--sp;
! convert_regs_1 (file, block);
!
! for (e = block->succ; e ; e = e->succ_next)
! if (! BLOCK_INFO (e->dest)->done)
! {
! *sp++ = e->dest;
! BLOCK_INFO (e->dest)->done = 1;
! }
! }
! while (sp != stack);
!
! return inserted;
! }
!
! /* Set the map of permutation common for all output edges. */
! static void
! find_common_map (blockno, registermap)
! int blockno;
! int *registermap;
! {
! basic_block block = BASIC_BLOCK (blockno);
! edge e = block->succ;
! block_info bi = BLOCK_INFO (e->dest);
! int i;
!
! for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! registermap[i] = -2;
! for (i = 0; i <= bi->stack_in.top; i++)
! registermap[(int) bi->stack_in.reg[i]] = i;
! if (!e)
! return;
!
! /* Find positions common for all edges. */
! for (; e; e = e->succ_next)
! {
! bi = BLOCK_INFO (e->dest);
!
! for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! if (!TEST_HARD_REG_BIT (bi->stack_in.reg_set, i))
! registermap[i] = -2;
!
! for (i = 0; i <= bi->stack_in.top; i++)
! if (registermap[(int) bi->stack_in.reg[i]] != i)
! registermap[(int) bi->stack_in.reg[i]] = -2;
! }
! }
!
! /* Remove all incomplette cycles in the permutation. */
! static void
! remove_incomplette_cycles (registermap, s)
! int *registermap;
! stack s;
! {
! int i;
! for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! {
! int y;
! y = registermap[i];
! if (y >= 0)
! do
! y = registermap[(int) s->reg[y]];
! while (y != registermap[i] && y >= 0);
! if (y < 0)
! registermap[i] = -2;
! }
! }
!
! /* Emit code to correct different permutations of the registers
! on the starts of basic blocks. */
!
! static int
! emit_basic_block_corrections (file)
! FILE *file;
! {
! int inserted = 0;
! basic_block block;
! struct stack_def tmpstack;
! stack regstack;
! int i;
! edge e;
! int reg;
! int ninsns;
!
! current_block = NULL;
! for (i = 0; i < n_basic_blocks; ++i)
! {
! block = BASIC_BLOCK (i);
! regstack = &BLOCK_INFO (block)->stack_out;
! if (file)
! {
! fprintf (file, "\n\nBasic block %d\nOutput stack: ", block->index);
! print_stack (file, regstack);
}
! for (e = block->succ; e; e = e->succ_next)
{
! basic_block target = e->dest;
! stack target_stack = &BLOCK_INFO (target)->stack_in;
! rtx seq, after;
!
! if (file)
! fprintf (file, " Edge to block %d: ", target->index);
!
! if (target_stack->top == -2)
! abort ();
! if (target_stack->top == regstack->top)
{
for (reg = target_stack->top; reg >= 0; --reg)
! if (target_stack->reg[reg] != regstack->reg[reg])
break;
if (reg == -1)
*************** convert_regs_1 (file, block)
*** 2579,2603 ****
fprintf (file, "correcting stack to ");
print_stack (file, target_stack);
}
- }
- /* It is better to output directly to the end of the block
- instead of to the edge, because emit_swap can do minimal
- insn scheduling. We can do this when there is only one
- edge out, and it is not abnormal. */
- if (block->succ->succ_next == NULL
- && ! (e->flags & EDGE_ABNORMAL))
- {
- /* change_stack kills values in regstack. */
- tmpstack = regstack;
-
- change_stack (block->end, &tmpstack, target_stack,
- (GET_CODE (block->end) == JUMP_INSN
- ? EMIT_BEFORE : EMIT_AFTER));
- }
- else
- {
- rtx seq, after;
/* We don't support abnormal edges. Global takes
care to avoid any live register across them, so
--- 2701,2707 ----
*************** convert_regs_1 (file, block)
*** 2605,2670 ****
if (e->flags & EDGE_ABNORMAL)
abort ();
- current_block = NULL;
start_sequence ();
!
/* ??? change_stack needs some point to emit insns after.
Also needed to keep gen_sequence from returning a
pattern as opposed to a sequence, which would lose
REG_DEAD notes. */
after = emit_note (NULL, NOTE_INSN_DELETED);
! tmpstack = regstack;
! change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
seq = gen_sequence ();
end_sequence ();
insert_insn_on_edge (seq, e);
inserted = 1;
! current_block = block;
}
}
-
return inserted;
}
!
! /* Convert registers in all blocks reachable from BLOCK. */
static int
! convert_regs_2 (file, block)
FILE *file;
- basic_block block;
{
! basic_block *stack, *sp;
! int inserted;
!
! stack = (basic_block *) alloca (sizeof (*stack) * n_basic_blocks);
! sp = stack;
!
! *sp++ = block;
! BLOCK_INFO (block)->done = 1;
! inserted = 0;
! do
{
! edge e;
!
! block = *--sp;
! inserted |= convert_regs_1 (file, block);
!
! for (e = block->succ; e ; e = e->succ_next)
! if (! BLOCK_INFO (e->dest)->done)
! {
! *sp++ = e->dest;
! BLOCK_INFO (e->dest)->done = 1;
! }
}
- while (sp != stack);
-
return inserted;
}
!
/* Traverse all basic blocks in a function, converting the register
references in each insn from the "flat" register file that gcc uses,
to the stack-like registers the 387 uses. */
--- 2709,2783 ----
if (e->flags & EDGE_ABNORMAL)
abort ();
start_sequence ();
!
/* ??? change_stack needs some point to emit insns after.
Also needed to keep gen_sequence from returning a
pattern as opposed to a sequence, which would lose
REG_DEAD notes. */
after = emit_note (NULL, NOTE_INSN_DELETED);
! tmpstack = *regstack;
! ninsns = change_stack (after, &tmpstack, target_stack,
! EMIT_BEFORE, 1);
seq = gen_sequence ();
end_sequence ();
insert_insn_on_edge (seq, e);
inserted = 1;
! if (file)
! fprintf (file, " %i insns emited.\n", ninsns);
}
}
return inserted;
}
! /* Emit correction code common for all outgoing edges to the end of basic
! block. Jump optimization can't do this job for us well, because
! change_stack may choose different strategy for each edge resulting
! in no common code at all. */
static int
! emit_common_basic_block_corrections (file)
FILE *file;
{
! int registermap[LAST_STACK_REG + 1];
! int inserted = 0;
! basic_block block;
! stack regstack;
! int i;
! edge e;
! int ninsns;
! for (i = 0; i < n_basic_blocks; ++i)
{
! block = BASIC_BLOCK (i);
! current_block = block;
! regstack = &BLOCK_INFO (block)->stack_out;
!
! e = block->succ;
! if (!e)
! continue;
!
! for (; e && !(e->flags & EDGE_ABNORMAL); e = e->succ_next);
! if (e)
! continue;
!
! find_common_map (i, registermap);
! remove_incomplette_cycles (registermap, regstack);
! ninsns = change_to_regmap (block->end, regstack, registermap,
! (GET_CODE (block->end) == JUMP_INSN
! ? EMIT_BEFORE : EMIT_AFTER), 1);
! if (file)
! {
! fprintf (file, "\n%i insns emited to the basic block %i.\n New output stack:",
! ninsns, block->index);
! print_stack (file, regstack);
! }
}
return inserted;
}
!
/* Traverse all basic blocks in a function, converting the register
references in each insn from the "flat" register file that gcc uses,
to the stack-like registers the 387 uses. */
*************** convert_regs (file)
*** 2683,2692 ****
convert_regs_exit ();
BLOCK_INFO (EXIT_BLOCK_PTR)->done = 1;
- /* ??? Future: process inner loops first, and give them arbitrary
- initial stacks which emit_swap_insn can modify. This ought to
- prevent double fxch that aften appears at the head of a loop. */
-
/* Process all blocks reachable from all entry points. */
for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
inserted |= convert_regs_2 (file, e->dest);
--- 2796,2801 ----
*************** convert_regs (file)
*** 2712,2717 ****
--- 2821,2831 ----
}
}
+ if (optimize)
+ emit_common_basic_block_corrections (file);
+
+ inserted |= emit_basic_block_corrections (file);
+
if (inserted)
commit_edge_insertions ();
More information about the Gcc-patches
mailing list