c4x.c (c4x_modified_between_p, [...]): Delete.
* config/c4x/c4x.c (c4x_modified_between_p, c4x_mem_set_p, c4x_mem_set_p, c4x_mem_modified_between_p, c4x_insn_moveable_p, c4x_parallel_pack, c4x_parallel_find, c4x_update_info_reg, c4x_update_info_regs, c4x_copy_insn_after, c4x_copy_insns_after, c4x_merge_notes, c4x_parallel_process, c4x_combine_parallel_independent, c4x_combine_parallel_dependent, c4x_combine_parallel): Delete. From-SVN: r23878
This commit is contained in:
parent
51a6311276
commit
0fe69abaa1
@ -1,3 +1,26 @@
|
||||
Thu Nov 26 16:37:59 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* config/c4x/c4x.c (c4x_modified_between_p, c4x_mem_set_p,
|
||||
c4x_mem_set_p, c4x_mem_modified_between_p, c4x_insn_moveable_p,
|
||||
c4x_parallel_pack, c4x_parallel_find, c4x_update_info_reg,
|
||||
c4x_update_info_regs, c4x_copy_insn_after, c4x_copy_insns_after,
|
||||
c4x_merge_notes, c4x_parallel_process,
|
||||
c4x_combine_parallel_independent, c4x_combine_parallel_dependent,
|
||||
c4x_combine_parallel): Delete.
|
||||
|
||||
Thu Nov 26 15:16:05 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* config/c4x/c4x.c: (c4x_override_options): For compatibility
|
||||
with old target options clear flag_branch_on_count_reg if
|
||||
-mno-rptb specified and set flag_argument_alias is -mno-aliases
|
||||
specified.
|
||||
(c4x_output_cbranch): Handle a sequence of insns rather than a
|
||||
single insn.
|
||||
(c4x_rptb_insert): Don not emit a RPTB insn if the RC register
|
||||
has not been allocated as the loop counter.
|
||||
(c4x_address_conflict):
|
||||
|
||||
|
||||
Thu Nov 26 14:56:32 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* config/c4x/c4x.h (TARGET_DEFAULT): Add PARALEL_MPY_FLAG.
|
||||
|
@ -4107,772 +4107,6 @@ c4x_valid_type_attribute_p (type, attributes, identifier, args)
|
||||
}
|
||||
|
||||
|
||||
/* This is a modified version of modified_between_p that doesn't give
|
||||
up if a changing MEM is found. It checks all insns between START
|
||||
and END to see if any registers mentioned in X are set. */
|
||||
static int
|
||||
c4x_modified_between_p (x, start, end)
|
||||
rtx x;
|
||||
rtx start, end;
|
||||
{
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
char *fmt;
|
||||
int i, j;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CONST_INT:
|
||||
case CONST_DOUBLE:
|
||||
case CONST:
|
||||
case SYMBOL_REF:
|
||||
case LABEL_REF:
|
||||
return 0;
|
||||
|
||||
case PC:
|
||||
case CC0:
|
||||
return 1;
|
||||
|
||||
case MEM:
|
||||
break;
|
||||
|
||||
case REG:
|
||||
return reg_set_between_p (x, start, end);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fmt = GET_RTX_FORMAT (code);
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e' && c4x_modified_between_p (XEXP (x, i), start, end))
|
||||
return 1;
|
||||
|
||||
if (fmt[i] == 'E')
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
if (c4x_modified_between_p (XVECEXP (x, i, j), start, end))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if rtx X references memory that is changing. */
|
||||
static int
|
||||
c4x_mem_ref_p (x)
|
||||
rtx x;
|
||||
{
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
char *fmt;
|
||||
int i, j;
|
||||
|
||||
if (code == MEM && !RTX_UNCHANGING_P (x))
|
||||
return 1;
|
||||
|
||||
fmt = GET_RTX_FORMAT (code);
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e' && c4x_mem_ref_p (XEXP (x, i)))
|
||||
return 1;
|
||||
|
||||
if (fmt[i] == 'E')
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
if (c4x_mem_ref_p (XVECEXP (x, i, j)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if rtx X sets or clobbers memory. */
|
||||
static int
|
||||
c4x_mem_set_p (x)
|
||||
rtx x;
|
||||
{
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
char *fmt;
|
||||
int i, j;
|
||||
|
||||
if ((code == SET || code == CLOBBER)
|
||||
&& (GET_CODE (SET_DEST (x)) == MEM))
|
||||
return 1;
|
||||
|
||||
fmt = GET_RTX_FORMAT (code);
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e' && c4x_mem_set_p (XEXP (x, i)))
|
||||
return 1;
|
||||
|
||||
if (fmt[i] == 'E')
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
if (c4x_mem_set_p (XVECEXP (x, i, j)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return 1 if any insns between START and END (exclusive) sets
|
||||
or clobbers memory. */
|
||||
static int
|
||||
c4x_mem_modified_between_p (start, end)
|
||||
rtx start, end;
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
if (start == end)
|
||||
return 0;
|
||||
|
||||
for (insn = NEXT_INSN (start); insn != end; insn = NEXT_INSN (insn))
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
|
||||
&& c4x_mem_set_p (PATTERN (insn)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if INSN can be moved past all the insns between START and
|
||||
END exclusive. If TARGET_ALIASES is not set and a memory store is
|
||||
detected, then 0 is returned. */
|
||||
static int
|
||||
c4x_insn_moveable_p (insn, start, end)
|
||||
rtx insn;
|
||||
rtx start, end;
|
||||
{
|
||||
if (start == end)
|
||||
return 1;
|
||||
|
||||
/* We can't use modified_between_p since this will
|
||||
return 1 if set1 contains a MEM. */
|
||||
if (c4x_modified_between_p (insn, start, end))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* See if the insns INSN1 and INSN2 can be packed into a PARALLEL.
|
||||
Return 0 if the insns cannot be packed or the rtx of the packed
|
||||
insn (with clobbers added as necessary). If DEPEND is non zero,
|
||||
then the destination register of INSN1 must be used by INSN2. */
|
||||
static rtx
|
||||
c4x_parallel_pack (insn1, insn2, depend)
|
||||
rtx insn1;
|
||||
rtx insn2;
|
||||
int depend;
|
||||
{
|
||||
rtx set1;
|
||||
rtx set2;
|
||||
rtx pack;
|
||||
enum machine_mode mode1;
|
||||
enum machine_mode mode2;
|
||||
int num_clobbers;
|
||||
int insn_code_number;
|
||||
|
||||
/* We could generalise things to not just rely on single sets. */
|
||||
if (!(set1 = single_set (insn1))
|
||||
|| !(set2 = single_set (insn2)))
|
||||
return 0;
|
||||
|
||||
mode1 = GET_MODE (SET_DEST (set1));
|
||||
mode2 = GET_MODE (SET_DEST (set2));
|
||||
if (mode1 != mode2)
|
||||
return 0;
|
||||
|
||||
if (depend)
|
||||
{
|
||||
rtx dst1;
|
||||
|
||||
/* Require insn2 to be dependent upon the result of insn1. */
|
||||
dst1 = SET_DEST (set1);
|
||||
|
||||
if (!REG_P (dst1))
|
||||
return 0;
|
||||
|
||||
if (!reg_mentioned_p (dst1, set2))
|
||||
return 0;
|
||||
|
||||
/* The dependent register must die in insn2 since a parallel
|
||||
insn will generate a new value. */
|
||||
if (!find_regno_note (insn2, REG_DEAD, REGNO (dst1)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
pack = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2));
|
||||
num_clobbers = 0;
|
||||
if ((insn_code_number = recog (pack, pack, &num_clobbers)) < 0)
|
||||
return 0;
|
||||
|
||||
if (num_clobbers != 0)
|
||||
{
|
||||
rtx newpack;
|
||||
int i;
|
||||
|
||||
newpack = gen_rtx_PARALLEL (VOIDmode,
|
||||
gen_rtvec (GET_CODE (pack) == PARALLEL
|
||||
? XVECLEN (pack, 0) + num_clobbers
|
||||
: num_clobbers + 1));
|
||||
|
||||
if (GET_CODE (pack) == PARALLEL)
|
||||
for (i = 0; i < XVECLEN (pack, 0); i++)
|
||||
XVECEXP (newpack, 0, i) = XVECEXP (pack, 0, i);
|
||||
else
|
||||
XVECEXP (newpack, 0, 0) = pack;
|
||||
|
||||
add_clobbers (newpack, insn_code_number);
|
||||
pack = newpack;
|
||||
}
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
|
||||
static rtx
|
||||
c4x_parallel_find (insn1, loop_end, depend, insn2)
|
||||
rtx insn1;
|
||||
rtx loop_end;
|
||||
int depend;
|
||||
rtx *insn2;
|
||||
{
|
||||
rtx insn;
|
||||
rtx pack;
|
||||
|
||||
/* We could use the logical links if depend is non zero? */
|
||||
|
||||
for (insn = NEXT_INSN (insn1); insn != loop_end; insn = NEXT_INSN(insn))
|
||||
{
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
default:
|
||||
case JUMP_INSN:
|
||||
case CALL_INSN:
|
||||
case NOTE:
|
||||
break;
|
||||
|
||||
case INSN:
|
||||
if (!(pack = c4x_parallel_pack (insn1, insn, depend)))
|
||||
break;
|
||||
|
||||
/* What if insn1 or insn2 sets cc and is required by another
|
||||
insn? */
|
||||
|
||||
#if 0
|
||||
/* Check that nothing between insn1 and insn will spoil the
|
||||
show. */
|
||||
if (NEXT_INSN (insn1) != insn
|
||||
&& c4x_modified_between_p (insn, NEXT_INSN (insn1), insn))
|
||||
return 0;
|
||||
#else
|
||||
/* This will do in the interim. If the insns between
|
||||
insn1 and insn are harmless, we can move things around
|
||||
if we're careful. */
|
||||
if (next_nonnote_insn (insn1) != insn)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* Do some checks here... */
|
||||
*insn2 = insn;
|
||||
return pack;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Update the register info for reg REG found in the basic block BB,
|
||||
where SET is 1 if the register is being set. */
|
||||
static void
|
||||
c4x_update_info_reg (reg, set, bb)
|
||||
rtx reg;
|
||||
int set;
|
||||
int bb;
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (!REG_P (reg))
|
||||
fatal_insn ("Expecting register rtx", reg);
|
||||
|
||||
regno = REGNO (reg);
|
||||
|
||||
/* REGNO_FIRST_UID and REGNO_LAST_UID don't need setting. */
|
||||
|
||||
SET_REGNO_REG_SET (basic_block_live_at_start[bb], regno);
|
||||
REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
|
||||
if (set)
|
||||
REG_N_SETS (regno)++;
|
||||
else
|
||||
REG_N_REFS (regno)++;
|
||||
}
|
||||
|
||||
|
||||
/* Update the register info for all the regs in X found in the basic
|
||||
block BB. */
|
||||
static void
|
||||
c4x_update_info_regs(x, bb)
|
||||
rtx x;
|
||||
int bb;
|
||||
{
|
||||
enum rtx_code code;
|
||||
char *fmt;
|
||||
int i, j;
|
||||
|
||||
if (!x)
|
||||
return;
|
||||
|
||||
code = GET_CODE (x);
|
||||
switch (code)
|
||||
{
|
||||
case CLOBBER:
|
||||
#if 0
|
||||
if (REG_P (SET_DEST (x)))
|
||||
return;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SET:
|
||||
if (REG_P (SET_DEST (x)))
|
||||
c4x_update_info_reg (SET_DEST (x), 1, bb);
|
||||
else
|
||||
c4x_update_info_regs (SET_DEST (x), bb);
|
||||
|
||||
if (code == SET)
|
||||
c4x_update_info_regs (SET_SRC (x), bb);
|
||||
return;
|
||||
|
||||
case REG:
|
||||
c4x_update_info_reg (x, 0, bb);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fmt = GET_RTX_FORMAT (code);
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e')
|
||||
c4x_update_info_regs (XEXP (x, i), bb);
|
||||
else if (fmt[i] == 'E')
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
c4x_update_info_regs (XVECEXP (x, i, j), bb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
c4x_copy_insn_after(insn, prev, bb)
|
||||
rtx insn;
|
||||
rtx prev;
|
||||
int bb;
|
||||
{
|
||||
rtx note;
|
||||
rtx new;
|
||||
|
||||
emit_insn_after (copy_rtx (PATTERN (insn)), prev);
|
||||
|
||||
new = NEXT_INSN (prev);
|
||||
|
||||
/* Copy the REG_NOTES from insn to the new insn. */
|
||||
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
|
||||
REG_NOTES (new) = gen_rtx (GET_CODE (note),
|
||||
REG_NOTE_KIND (note),
|
||||
XEXP (note, 0),
|
||||
REG_NOTES (new));
|
||||
|
||||
/* Handle all the registers within insn and update the reg info. */
|
||||
c4x_update_info_regs (PATTERN (insn), bb);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
c4x_copy_insns_after(start, end, pprev, bb)
|
||||
rtx start;
|
||||
rtx end;
|
||||
rtx *pprev;
|
||||
int bb;
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
for (insn = start; insn != NEXT_INSN (end); insn = NEXT_INSN(insn))
|
||||
{
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
case CALL_INSN:
|
||||
/* We could allow a libcall with no side effects??? */
|
||||
fatal_insn("Repeat block loop contains a call", insn);
|
||||
break;
|
||||
|
||||
case INSN:
|
||||
c4x_copy_insn_after(insn, *pprev, bb - 1);
|
||||
*pprev = NEXT_INSN (*pprev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Merge the notes of insn2 with the notes of insn. */
|
||||
static void
|
||||
c4x_merge_notes(insn, insn2)
|
||||
rtx insn;
|
||||
rtx insn2;
|
||||
{
|
||||
rtx note;
|
||||
|
||||
for (note = REG_NOTES (insn2); note; note = XEXP (note, 1))
|
||||
{
|
||||
rtx link;
|
||||
|
||||
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
|
||||
if (REG_NOTE_KIND (note) == REG_NOTE_KIND (link)
|
||||
&& XEXP (note, 0) == XEXP (link, 0))
|
||||
remove_note (insn, note);
|
||||
}
|
||||
for (note = REG_NOTES (insn2); note; note = XEXP (note, 1))
|
||||
REG_NOTES (insn) = gen_rtx (GET_CODE (note),
|
||||
REG_NOTE_KIND (note),
|
||||
XEXP (note, 0),
|
||||
REG_NOTES (insn));
|
||||
}
|
||||
|
||||
|
||||
/* This pass must update information that subsequent passes expect to be
|
||||
correct. Namely: reg_n_refs, reg_n_sets, reg_n_deaths,
|
||||
reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
|
||||
basic_block_end. */
|
||||
|
||||
static int
|
||||
c4x_parallel_process (loop_start, loop_end)
|
||||
rtx loop_start;
|
||||
rtx loop_end;
|
||||
{
|
||||
rtx insn;
|
||||
rtx insn2;
|
||||
rtx pack;
|
||||
rtx hoist_pos;
|
||||
rtx sink_pos;
|
||||
rtx loop_count;
|
||||
rtx loop_count_set;
|
||||
rtx loop_count_reg;
|
||||
rtx jump_insn;
|
||||
rtx end_label;
|
||||
int num_packs;
|
||||
int bb;
|
||||
|
||||
jump_insn = PREV_INSN (loop_end);
|
||||
|
||||
/* The loop must have a calculable number of iterations
|
||||
since we need to reduce the loop count by one.
|
||||
|
||||
For now, only process repeat block loops, since we can tell that
|
||||
these have a calculable number of iterations.
|
||||
|
||||
The loop count must be at least 2? */
|
||||
|
||||
loop_count = PREV_INSN (loop_start);
|
||||
|
||||
if (!(loop_count_set = single_set (loop_count)))
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
/* Disable this optimisation until REG_LOOP_COUNT note
|
||||
added. */
|
||||
if (!find_reg_note (loop_count, REG_LOOP_COUNT, NULL_RTX))
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
loop_count_reg = SET_DEST (loop_count_set);
|
||||
|
||||
/* Determine places to hoist and sink insns out of the loop.
|
||||
We need to hoist insns before the label at the top of the loop.
|
||||
We'll have to update basic_block_head. */
|
||||
|
||||
/* Place in the rtx where we hoist insns after. */
|
||||
hoist_pos = loop_count;
|
||||
|
||||
/* Place in the rtx where we sink insns after. */
|
||||
sink_pos = loop_end;
|
||||
|
||||
/* There must be an easier way to work out which basic block we are
|
||||
in. */
|
||||
for (bb = 0; bb < n_basic_blocks; bb++)
|
||||
if (basic_block_head[bb] == NEXT_INSN (loop_end))
|
||||
break;
|
||||
|
||||
if (bb >= n_basic_blocks)
|
||||
fatal_insn("Cannot find basic block for insn", NEXT_INSN (loop_end));
|
||||
|
||||
/* Skip to label at top of loop. */
|
||||
for (; GET_CODE (loop_start) != CODE_LABEL;
|
||||
loop_start = NEXT_INSN(loop_start));
|
||||
|
||||
num_packs = 0;
|
||||
for (insn = loop_start; insn != loop_end; insn = NEXT_INSN(insn))
|
||||
{
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
default:
|
||||
case JUMP_INSN:
|
||||
case CALL_INSN:
|
||||
case NOTE:
|
||||
break;
|
||||
|
||||
case INSN:
|
||||
|
||||
/* Look for potential insns to combine where the second one
|
||||
is dependent upon the first. We could have another pass
|
||||
that tries combining independent insns but that is not so
|
||||
important. We could do this afterwards as a more generic
|
||||
peepholer. */
|
||||
|
||||
if ((pack = c4x_parallel_find(insn, loop_end, 1, &insn2)))
|
||||
{
|
||||
rtx set1;
|
||||
rtx set2;
|
||||
rtx note;
|
||||
rtx seq_start;
|
||||
|
||||
set1 = single_set (insn);
|
||||
set2 = single_set (insn2);
|
||||
|
||||
/* We need to hoist a copy of insn1 out of the loop and
|
||||
to sink a copy insn2 out of the loop. We can avoid
|
||||
the latter if the destination of insn2 is used
|
||||
by a following insn within the loop.
|
||||
|
||||
We cannot hoist insn1 out of the loop if any of the
|
||||
preceeding insns within the loop modifies the destination
|
||||
of insn1 or modifies any of the operands of insn1. */
|
||||
|
||||
/* If the user has flagged that there are potential aliases,
|
||||
then we can't move the insn if it references memory
|
||||
past any insns that modify memory. */
|
||||
if (TARGET_ALIASES
|
||||
&& c4x_mem_ref_p (PATTERN (insn))
|
||||
&& c4x_mem_modified_between_p (loop_start, loop_end))
|
||||
break;
|
||||
|
||||
/* None of the registers used in insn can be modified by
|
||||
any of the insns from the start of the loop until insn. */
|
||||
if (!c4x_insn_moveable_p (set1, loop_start, insn))
|
||||
break;
|
||||
|
||||
/* None of the registers used in insn can be modified by
|
||||
any of the insns after insn2 until the end of the
|
||||
loop, especially the result which needs to be saved
|
||||
for the next iteration. */
|
||||
if (!c4x_insn_moveable_p (set1, insn2, loop_end))
|
||||
break;
|
||||
|
||||
/* We need to hoist all the insns from the loop top
|
||||
to and including insn. */
|
||||
c4x_copy_insns_after (NEXT_INSN (loop_start), insn,
|
||||
&hoist_pos, bb);
|
||||
|
||||
/* We need to sink all the insns after insn to
|
||||
loop_end. */
|
||||
c4x_copy_insns_after (NEXT_INSN (insn), PREV_INSN (jump_insn),
|
||||
&sink_pos, bb + 1);
|
||||
|
||||
/* Change insn to the new parallel insn, retaining the notes
|
||||
of the old insn. */
|
||||
if (!validate_change (insn, &PATTERN (insn), pack, 0))
|
||||
fatal_insn("Cannot replace insn with parallel insn", pack);
|
||||
|
||||
/* Copy the REG_NOTES from insn2 to the new insn
|
||||
avoiding duplicates. */
|
||||
c4x_merge_notes (insn, insn2);
|
||||
|
||||
delete_insn (insn2);
|
||||
|
||||
/* The destination register of insn1 no longer dies in
|
||||
this composite insn. Don't use remove_death since that
|
||||
alters REG_N_DEATHS. The REG_DEAD note has just been
|
||||
moved. */
|
||||
note = find_regno_note (insn, REG_DEAD, REGNO (SET_DEST (set1)));
|
||||
if (note)
|
||||
remove_note (insn, note);
|
||||
|
||||
/* ??? Do we have to modify the LOG_LINKS? */
|
||||
|
||||
/* We need to decrement the loop count. We probably
|
||||
should test if the loop count is negative and branch
|
||||
to end label if so. */
|
||||
if (GET_CODE (SET_SRC (loop_count_set)) == CONST_INT)
|
||||
{
|
||||
/* The loop count must be more than 1 surely? */
|
||||
SET_SRC (loop_count_set)
|
||||
= GEN_INT (INTVAL (SET_SRC (loop_count_set)) - 1);
|
||||
}
|
||||
else if (GET_CODE (SET_SRC (loop_count_set)) == PLUS
|
||||
&& GET_CODE (XEXP (SET_SRC (loop_count_set), 1))
|
||||
== CONST_INT)
|
||||
{
|
||||
XEXP (SET_SRC (loop_count_set), 1)
|
||||
= GEN_INT (INTVAL (XEXP (SET_SRC (loop_count_set), 1))
|
||||
- 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
start_sequence ();
|
||||
expand_binop (QImode, sub_optab, loop_count_reg,
|
||||
GEN_INT (1), loop_count_reg,
|
||||
1, OPTAB_DIRECT);
|
||||
seq_start = get_insns ();
|
||||
end_sequence ();
|
||||
emit_insns_after (seq_start, loop_count);
|
||||
|
||||
/* Check this. What if we emit more than one insn?
|
||||
Can we emit more than one insn? */
|
||||
REG_NOTES (seq_start)
|
||||
= gen_rtx_EXPR_LIST (REG_UNUSED,
|
||||
loop_count_reg,
|
||||
REG_NOTES (seq_start));
|
||||
}
|
||||
|
||||
if (GET_CODE (SET_SRC (loop_count_set)) != CONST_INT)
|
||||
{
|
||||
end_label = gen_label_rtx();
|
||||
start_sequence ();
|
||||
emit_cmp_insn (loop_count_reg,
|
||||
const0_rtx, LT, NULL_RTX, word_mode, 0, 0);
|
||||
emit_jump_insn (gen_blt (end_label));
|
||||
seq_start = get_insns ();
|
||||
end_sequence ();
|
||||
emit_insns_after (seq_start, hoist_pos);
|
||||
emit_label_after (end_label, sink_pos);
|
||||
|
||||
#if 0
|
||||
/* This is a bit of a hack...but why was it necessary? */
|
||||
REG_NOTES (NEXT_INSN (seq_start))
|
||||
= gen_rtx_EXPR_LIST (REG_DEAD,
|
||||
loop_count_reg,
|
||||
REG_NOTES (NEXT_INSN (seq_start)));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (TARGET_DEVEL)
|
||||
debug_rtx(insn);
|
||||
|
||||
num_packs ++;
|
||||
|
||||
#if 1
|
||||
/* If we want to pack more than one parallel insn
|
||||
we will have to tag which insns have been
|
||||
hoisted/sunk/paired. We might need a recursive approach. */
|
||||
|
||||
return num_packs;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num_packs;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
c4x_combine_parallel_independent (insns)
|
||||
rtx insns ATTRIBUTE_UNUSED;
|
||||
{
|
||||
/* Combine independent insns like
|
||||
(set (mem (reg 0)) (reg 1))
|
||||
(set (reg 2) (mem (reg 3)))
|
||||
where (reg 1) != (reg 2) unless there is a REG_DEAD note
|
||||
on the first insn. */
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
c4x_combine_parallel_dependent (insns)
|
||||
rtx insns;
|
||||
{
|
||||
rtx insn;
|
||||
rtx loop_start;
|
||||
rtx loop_end;
|
||||
int num_jumps;
|
||||
int num_insns;
|
||||
|
||||
/* Find the innermost loop and check that it is unjumped. */
|
||||
loop_start = NULL_RTX;
|
||||
num_jumps = 0;
|
||||
for (insn = insns; insn; insn = NEXT_INSN(insn))
|
||||
{
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
case INSN:
|
||||
num_insns++;
|
||||
break;
|
||||
|
||||
case CALL_INSN:
|
||||
/* We could allow a libcall with no side effects??? */
|
||||
case JUMP_INSN:
|
||||
num_jumps++;
|
||||
break;
|
||||
|
||||
case NOTE:
|
||||
switch (NOTE_LINE_NUMBER (insn))
|
||||
{
|
||||
case NOTE_INSN_LOOP_BEG:
|
||||
loop_start = insn;
|
||||
num_jumps = 0;
|
||||
num_insns = 0;
|
||||
break;
|
||||
|
||||
case NOTE_INSN_LOOP_CONT:
|
||||
if (!loop_start)
|
||||
break;
|
||||
/* We can't handle a loop with jumps or calls.
|
||||
If there are too many insns, we are unlikely
|
||||
to be able to find a suitable case for optimisation.
|
||||
The maximum number of insns may require tweaking. */
|
||||
if (!num_jumps && num_insns < 20)
|
||||
{
|
||||
/* Skip to end of loop. */
|
||||
loop_end = NULL_RTX;
|
||||
for (; insn; insn = NEXT_INSN(insn))
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
|
||||
break;
|
||||
loop_end = insn;
|
||||
if (!loop_end)
|
||||
fatal_insn("Could not find note at end of loop",
|
||||
loop_start);
|
||||
c4x_parallel_process(loop_start, loop_end);
|
||||
}
|
||||
loop_start = NULL_RTX;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
c4x_combine_parallel (insns)
|
||||
rtx insns;
|
||||
{
|
||||
/* Only let people who know how to shoot themselves in the foot do so! */
|
||||
if (!TARGET_PARALLEL_PACK)
|
||||
return;
|
||||
|
||||
c4x_combine_parallel_dependent (insns);
|
||||
|
||||
c4x_combine_parallel_independent (insns);
|
||||
}
|
||||
|
||||
|
||||
/* !!! FIXME to emit RPTS correctly. */
|
||||
int
|
||||
c4x_rptb_rpts_p (insn, op)
|
||||
|
Loading…
Reference in New Issue
Block a user