cris: Move trivially from cc0 to reg:CC model, removing most optimizations.

In the parlance of <https://gcc.gnu.org/wiki/CC0Transition>,
this is a basic "type 2" conversion, without
condition-code-related optimizations (just plain CCmode), but
with "cstore{M}4" defined.  CRIS is somewhat similar to the
m68k; most instructions affect condition-codes.  To wit, it
lacks sufficient instructions to compose an arbitrary valid
address in a register, specifically from a valid address where
involved registers have to be spilled or adjusted, without
affecting condition-codes in CRIS_CC0_REGNUM aka. dccr.

On the other hand, moving dccr to and from a stackpointer-plus-
constant-offset-address *can* be done without additional register
use, and moving to or from a general register does not affect
it.  There's no instruction to add a constant to a register or
to put a constant in a register, without affecting dccr, but
there *is* an instruction to add a register (optionally scaled)
to another without affecting dccr (i.e. "addi").  Also, moves
*to* memory from any register do not affect dccr, and likewise
between another special registers and a general register.  Maybe
some of that opens up the solution-space to a better solution
than clobbering dccr until reload_completed; to be investigated.
FAOD: I know what to do in the direction of defining and using
additional CCmodes, but prefer to do the full transition in
smaller steps.

Regarding the similarity to m68k, I didn't follow the steps of
the m68k cc0 transition, making use of the final_postscan_insn
hook as with the a NOTICE_UPDATE_CC machinery.  For one, because
it seems to be lacking in that it keeps compare-elimination
restricted to output-time, but also because it seems a bad match
considering that CRIS has delay-slots; better try to eliminate
compares earlier.  Another approach which I originally intended
to implement, that of the visium port of defining three variants
for most insns (not counting the define_subst expansions;
unaffecting-before-reload, clobbering and setting), seems
overworked and bloating the machine description.  I may be
proven wrong, but I prefer we fix gcc if some something bails on
seeing a parallel with a clobber of that specific hard-register.

Also, I chose to remove most anonymous combination-matching
patterns; matchers, splitters and peepholes instead of
converting them to add clobbers of CRIS_CC0_REGNUM.  There are
exclusions: those covered in the test-suite, if trivial enough.

Many of these patterns are used to handle the side-effect-
assignment addressing-modes as put together by combine: a
"prefix instruction" before the main instruction, where the main
instruction uses the post-incremented-register addressing-mode
and the "left-over" instruction-field in the prefixed insn to
assign a register.  An example: the hopefully descriptive
"move.d $r9,[$r0=$r1+1234]" compared to "move.d $r9,[$r1+1234]";
both formed by the prefix insn "biap.w 1234,$r1" before
respectively "move.d $r9,[$r0+]" and "move.d $r9,[$r0]".  Other
prefix variants exist.  Useful, but optional, except where
side-effect assignment was used in a special case in the
function prologue; adjusted to a less optimal combination.
Support like the function cris_side_effect_mode_ok is kept.

I intend to put back as many as I find use for, of those
anonymous patterns in a controlled manner, with self-contained
test-cases proving their usability, rather than symmetry with
other instructions and similar addressing modes, which guided
the original introduction.  I've entered pr93372 to track code
performance regressions related to this transition, with focus
on target-side causes and fixes; besides the function prologue
special-case, there were some checking presence of the bit-test
(btstq) instruction.

The now-gone "tst<mode>" patterns deserve a comment too: they
were an artefact from pre-"cbranch" era, now fully folded into
the "cmp<mode>" patterns.

I've left the now-unused "cc" insn attribute in, for the time
being; to be removed, used or transformed to be useful with
further work to fix pr93372.  It can't be used as is, because
"normal" doesn't mean "like a compare instruction" but "handled
by NOTICE_UPDATE_CC" and may in fact be reflecting e.g. reverse
operands, something that bit me during the conversion.

gcc:
	Move trivially from cc0 to reg:CC model, removing most optimizations.
	* config/cris/cris.md: Remove all side-effect patterns and their
	splitters.  Remove most peepholes.  Add clobbers of CRIS_CC0_REGNUM
	to all but post-reload control-flow and movem insns.  Remove
	constraints on all modified expanders.  Remove obsoleted cc0-related
	references.
	(attr "cc"): Remove alternative "rev".
	(mode_iterator BWDD, DI_, SI_): New.
	(mode_attr sCC_destc, cmp_op1c, cmp_op2c): New.
	("tst<mode>"): Remove; fold as "M" alternative into compare insn.
	("mstep_shift", "mstep_mul"): Remove patterns.
	("s<rcond>", "s<ocond>", "s<ncond>"): Anonymize.
	* config/cris/cris.c: Change all non-condition-code,
	non-control-flow emitted insns to add a parallel with clobber of
	CRIS_CC0_REGNUM, mostly by changing from gen_rtx_SET with
	emit_insn to use of emit_move_insn, gen_add2_insn or
	cris_emit_insn, as convenient.
	(cris_reg_overlap_mentioned_p)
	(cris_normal_notice_update_cc, cris_notice_update_cc): Remove.
	(cris_movem_load_rest_p): Don't assume all elements in a
	PARALLEL are SETs.
	(cris_store_multiple_op_p): Ditto.
	(cris_emit_insn): New function.
	* cris/cris-protos.h (cris_emit_insn): Declare.
This commit is contained in:
Hans-Peter Nilsson 2020-01-22 05:54:15 +01:00
parent d0780379c1
commit fb062a8b7b
7 changed files with 613 additions and 2571 deletions

View File

@ -9,6 +9,31 @@
* config/cris/t-elfmulti: Remove crisv32 multilib.
* config/cris: Remove shared-library and CRIS v32 support.
Move trivially from cc0 to reg:CC model, removing most optimizations.
* config/cris/cris.md: Remove all side-effect patterns and their
splitters. Remove most peepholes. Add clobbers of CRIS_CC0_REGNUM
to all but post-reload control-flow and movem insns. Remove
constraints on all modified expanders. Remove obsoleted cc0-related
references.
(attr "cc"): Remove alternative "rev".
(mode_iterator BWDD, DI_, SI_): New.
(mode_attr sCC_destc, cmp_op1c, cmp_op2c): New.
("tst<mode>"): Remove; fold as "M" alternative into compare insn.
("mstep_shift", "mstep_mul"): Remove patterns.
("s<rcond>", "s<ocond>", "s<ncond>"): Anonymize.
* config/cris/cris.c: Change all non-condition-code,
non-control-flow emitted insns to add a parallel with clobber of
CRIS_CC0_REGNUM, mostly by changing from gen_rtx_SET with
emit_insn to use of emit_move_insn, gen_add2_insn or
cris_emit_insn, as convenient.
(cris_reg_overlap_mentioned_p)
(cris_normal_notice_update_cc, cris_notice_update_cc): Remove.
(cris_movem_load_rest_p): Don't assume all elements in a
PARALLEL are SETs.
(cris_store_multiple_op_p): Ditto.
(cris_emit_insn): New function.
* cris/cris-protos.h (cris_emit_insn): Declare.
2020-05-08 Vladimir Makarov <vmakarov@redhat.com>
* ira-color.c (update_costs_from_allocno): Remove

View File

@ -36,11 +36,12 @@ extern void cris_reduce_compare (rtx *, rtx *, rtx *);
extern bool cris_biap_index_p (const_rtx, bool);
extern bool cris_legitimate_address_p (machine_mode, rtx, bool);
extern bool cris_store_multiple_op_p (rtx);
extern bool cris_movem_load_rest_p (rtx, int);
extern bool cris_movem_load_rest_p (rtx);
extern void cris_asm_output_symbol_ref (FILE *, rtx);
extern void cris_asm_output_case_end (FILE *, int, rtx_insn *);
extern rtx cris_gen_movem_load (rtx, rtx, int);
extern rtx cris_gen_movem_load (rtx, rtx);
extern rtx cris_emit_movem_store (rtx, rtx, int, bool);
extern rtx_insn *cris_emit_insn (rtx x);
extern void cris_order_for_addsi3 (rtx *, int);
extern void cris_emit_trap_for_misalignment (rtx);
#endif /* RTX_CODE */

View File

@ -90,9 +90,6 @@ static char cris_output_insn_is_bound = 0;
goes in code or in a static initializer. */
static int in_code = 0;
/* Fix for reg_overlap_mentioned_p. */
static int cris_reg_overlap_mentioned_p (rtx, rtx);
static machine_mode cris_promote_function_mode (const_tree, machine_mode,
int *, const_tree, int);
@ -290,9 +287,9 @@ struct gcc_target targetm = TARGET_INITIALIZER;
/* Helper for cris_load_multiple_op and cris_ret_movem_op. */
bool
cris_movem_load_rest_p (rtx op, int offs)
cris_movem_load_rest_p (rtx op)
{
unsigned int reg_count = XVECLEN (op, 0) - offs;
unsigned int reg_count = XVECLEN (op, 0);
rtx src_addr;
int i;
rtx elt;
@ -303,35 +300,36 @@ cris_movem_load_rest_p (rtx op, int offs)
/* Perform a quick check so we don't blow up below. FIXME: Adjust for
other than (MEM reg). */
if (reg_count <= 1
|| GET_CODE (XVECEXP (op, 0, offs)) != SET
|| !REG_P (SET_DEST (XVECEXP (op, 0, offs)))
|| !MEM_P (SET_SRC (XVECEXP (op, 0, offs))))
|| GET_CODE (XVECEXP (op, 0, 0)) != SET
|| !REG_P (SET_DEST (XVECEXP (op, 0, 0)))
|| !MEM_P (SET_SRC (XVECEXP (op, 0, 0))))
return false;
/* Check a possible post-inc indicator. */
if (GET_CODE (SET_SRC (XVECEXP (op, 0, offs + 1))) == PLUS)
if (GET_CODE (XVECEXP (op, 0, 1)) == SET
&& GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS)
{
rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, offs + 1)), 0);
rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, offs + 1)), 1);
rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 0);
rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1);
reg_count--;
if (reg_count == 1
|| !REG_P (reg)
|| !REG_P (SET_DEST (XVECEXP (op, 0, offs + 1)))
|| REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, offs + 1)))
|| !REG_P (SET_DEST (XVECEXP (op, 0, 1)))
|| REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, 1)))
|| !CONST_INT_P (inc)
|| INTVAL (inc) != (HOST_WIDE_INT) reg_count * 4)
return false;
i = offs + 2;
i = 2;
}
else
i = offs + 1;
i = 1;
regno_dir = -1;
regno = reg_count - 1;
elt = XVECEXP (op, 0, offs);
elt = XVECEXP (op, 0, 0);
src_addr = XEXP (SET_SRC (elt), 0);
if (GET_CODE (elt) != SET
@ -399,15 +397,15 @@ cris_store_multiple_op_p (rtx op)
dest_addr = XEXP (dest, 0);
/* Check a possible post-inc indicator. */
if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS)
if (GET_CODE (XVECEXP (op, 0, 1)) == SET
&& GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS)
{
rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 0);
rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1);
reg_count--;
if (reg_count == 1
|| !REG_P (reg)
if (!REG_P (reg)
|| !REG_P (SET_DEST (XVECEXP (op, 0, 1)))
|| REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, 1)))
|| !CONST_INT_P (inc)
@ -1501,302 +1499,6 @@ cris_memory_move_cost (machine_mode mode,
return 6;
}
/* Worker for cris_notice_update_cc; handles the "normal" cases.
FIXME: this code is historical; its functionality should be
refactored to look at insn attributes and moved to
cris_notice_update_cc. Except, we better lose cc0 entirely. */
static void
cris_normal_notice_update_cc (rtx exp, rtx insn)
{
/* "Normal" means, for:
(set (cc0) (...)):
CC is (...).
(set (reg) (...)):
CC is (reg) and (...) - unless (...) is 0 or reg is a special
register, then CC does not change.
CC_NO_OVERFLOW unless (...) is reg or mem.
(set (mem) (...)):
CC does not change.
(set (pc) (...)):
CC does not change.
(parallel
(set (reg1) (mem (bdap/biap)))
(set (reg2) (bdap/biap))):
CC is (reg1) and (mem (reg2))
(parallel
(set (mem (bdap/biap)) (reg1)) [or 0]
(set (reg2) (bdap/biap))):
CC does not change.
(where reg and mem includes strict_low_parts variants thereof)
For all others, assume CC is clobbered.
Note that we do not have to care about setting CC_NO_OVERFLOW,
since the overflow flag is set to 0 (i.e. right) for
instructions where it does not have any sane sense, but where
other flags have meanings. (This includes shifts; the carry is
not set by them).
Note that there are other parallel constructs we could match,
but we don't do that yet. */
if (GET_CODE (exp) == SET)
{
/* FIXME: Check when this happens. It looks like we should
actually do a CC_STATUS_INIT here to be safe. */
if (SET_DEST (exp) == pc_rtx)
return;
/* Record CC0 changes, so we do not have to output multiple
test insns. */
if (SET_DEST (exp) == cc0_rtx)
{
CC_STATUS_INIT;
if (GET_CODE (SET_SRC (exp)) == COMPARE
&& XEXP (SET_SRC (exp), 1) == const0_rtx)
cc_status.value1 = XEXP (SET_SRC (exp), 0);
else
cc_status.value1 = SET_SRC (exp);
/* Handle flags for the special btstq on one bit. */
if (GET_CODE (cc_status.value1) == ZERO_EXTRACT
&& XEXP (cc_status.value1, 1) == const1_rtx)
{
if (CONST_INT_P (XEXP (cc_status.value1, 0)))
/* Using cmpq. */
cc_status.flags = CC_INVERTED;
else
/* A one-bit btstq. */
cc_status.flags = CC_Z_IN_NOT_N;
}
else if (GET_CODE (SET_SRC (exp)) == COMPARE)
{
if (!REG_P (XEXP (SET_SRC (exp), 0))
&& XEXP (SET_SRC (exp), 1) != const0_rtx)
/* For some reason gcc will not canonicalize compare
operations, reversing the sign by itself if
operands are in wrong order. */
/* (But NOT inverted; eq is still eq.) */
cc_status.flags = CC_REVERSED;
/* This seems to be overlooked by gcc. FIXME: Check again.
FIXME: Is it really safe? */
cc_status.value2
= gen_rtx_MINUS (GET_MODE (SET_SRC (exp)),
XEXP (SET_SRC (exp), 0),
XEXP (SET_SRC (exp), 1));
}
return;
}
else if (REG_P (SET_DEST (exp))
|| (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
&& REG_P (XEXP (SET_DEST (exp), 0))))
{
/* A register is set; normally CC is set to show that no
test insn is needed. Catch the exceptions. */
/* If not to cc0, then no "set"s in non-natural mode give
ok cc0... */
if (GET_MODE_SIZE (GET_MODE (SET_DEST (exp))) > UNITS_PER_WORD
|| GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_FLOAT)
{
/* ... except add:s and sub:s in DImode. */
if (GET_MODE (SET_DEST (exp)) == DImode
&& (GET_CODE (SET_SRC (exp)) == PLUS
|| GET_CODE (SET_SRC (exp)) == MINUS))
{
CC_STATUS_INIT;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
if (cris_reg_overlap_mentioned_p (cc_status.value1,
cc_status.value2))
cc_status.value2 = 0;
/* Add and sub may set V, which gets us
unoptimizable results in "gt" and "le" condition
codes. */
cc_status.flags |= CC_NO_OVERFLOW;
return;
}
}
else if (SET_SRC (exp) == const0_rtx
|| (REG_P (SET_SRC (exp))
&& (REGNO (SET_SRC (exp))
> CRIS_LAST_GENERAL_REGISTER)))
{
/* There's no CC0 change for this case. Just check
for overlap. */
if (cc_status.value1
&& modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2
&& modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
return;
}
else
{
CC_STATUS_INIT;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
if (cris_reg_overlap_mentioned_p (cc_status.value1,
cc_status.value2))
cc_status.value2 = 0;
/* Some operations may set V, which gets us
unoptimizable results in "gt" and "le" condition
codes. */
if (GET_CODE (SET_SRC (exp)) == PLUS
|| GET_CODE (SET_SRC (exp)) == MINUS
|| GET_CODE (SET_SRC (exp)) == NEG)
cc_status.flags |= CC_NO_OVERFLOW;
return;
}
}
else if (MEM_P (SET_DEST (exp))
|| (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
&& MEM_P (XEXP (SET_DEST (exp), 0))))
{
/* When SET to MEM, then CC is not changed (except for
overlap). */
if (cc_status.value1
&& modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2
&& modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
return;
}
}
else if (GET_CODE (exp) == PARALLEL)
{
if (GET_CODE (XVECEXP (exp, 0, 0)) == SET
&& GET_CODE (XVECEXP (exp, 0, 1)) == SET
&& REG_P (XEXP (XVECEXP (exp, 0, 1), 0)))
{
if (REG_P (XEXP (XVECEXP (exp, 0, 0), 0))
&& MEM_P (XEXP (XVECEXP (exp, 0, 0), 1)))
{
CC_STATUS_INIT;
/* For "move.S [rx=ry+o],rz", say CC reflects
value1=rz and value2=[rx] */
cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
cc_status.value2
= replace_equiv_address (XEXP (XVECEXP (exp, 0, 0), 1),
XEXP (XVECEXP (exp, 0, 1), 0));
/* Huh? A side-effect cannot change the destination
register. */
if (cris_reg_overlap_mentioned_p (cc_status.value1,
cc_status.value2))
internal_error ("internal error: sideeffect-insn affecting main effect");
return;
}
else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1))
|| XEXP (XVECEXP (exp, 0, 0), 1) == const0_rtx)
&& MEM_P (XEXP (XVECEXP (exp, 0, 0), 0)))
{
/* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]",
say flags are not changed, except for overlap. */
if (cc_status.value1
&& modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2
&& modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
return;
}
}
}
/* If we got here, the case wasn't covered by the code above. */
CC_STATUS_INIT;
}
/* This function looks into the pattern to see how this insn affects
condition codes.
Used when to eliminate test insns before a condition-code user,
such as a "scc" insn or a conditional branch. This includes
checking if the entities that cc was updated by, are changed by the
operation.
Currently a jumble of the old peek-inside-the-insn and the newer
check-cc-attribute methods. */
void
cris_notice_update_cc (rtx exp, rtx_insn *insn)
{
enum attr_cc attrval = get_attr_cc (insn);
/* Check if user specified "-mcc-init" as a bug-workaround. Remember
to still set CC_REVERSED as below, since that's required by some
compare insn alternatives. (FIXME: GCC should do this virtual
operand swap by itself.) A test-case that may otherwise fail is
gcc.c-torture/execute/20000217-1.c -O0 and -O1. */
if (TARGET_CCINIT)
{
CC_STATUS_INIT;
if (attrval == CC_REV)
cc_status.flags = CC_REVERSED;
return;
}
/* Slowly, we're converting to using attributes to control the setting
of condition-code status. */
switch (attrval)
{
case CC_NONE:
/* Even if it is "none", a setting may clobber a previous
cc-value, so check. */
if (GET_CODE (exp) == SET)
{
if (cc_status.value1
&& modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2
&& modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
}
return;
case CC_CLOBBER:
CC_STATUS_INIT;
return;
case CC_REV:
case CC_NORMAL:
cris_normal_notice_update_cc (exp, insn);
return;
default:
internal_error ("unknown cc_attr value");
}
CC_STATUS_INIT;
}
/* Return != 0 if the return sequence for the current function is short,
like "ret" or "jump [sp+]". Prior to reloading, we can't tell if
registers must be saved, so return 0 then. */
@ -2208,23 +1910,6 @@ cris_side_effect_mode_ok (enum rtx_code code, rtx *ops,
internal_error ("internal error: cris_side_effect_mode_ok with bad operands");
}
/* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16)
does not handle the case where the IN operand is strict_low_part; it
does handle it for X. Test-case in Axis-20010516. This function takes
care of that for THIS port. FIXME: strict_low_part is going away
anyway. */
static int
cris_reg_overlap_mentioned_p (rtx x, rtx in)
{
/* The function reg_overlap_mentioned now handles when X is
strict_low_part, but not when IN is a STRICT_LOW_PART. */
if (GET_CODE (in) == STRICT_LOW_PART)
in = XEXP (in, 0);
return reg_overlap_mentioned_p (x, in);
}
/* Queue an .ident string in the queue of top-level asm statements.
If the front-end is done, we must be being called from toplev.c.
In that case, do nothing. */
@ -2480,22 +2165,20 @@ cris_split_movdx (rtx *operands)
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
operand 1, we must copy in the opposite order. */
emit_insn (gen_rtx_SET (operand_subword (dest, reverse, TRUE, mode),
operand_subword (src, reverse, TRUE, mode)));
emit_move_insn (operand_subword (dest, reverse, TRUE, mode),
operand_subword (src, reverse, TRUE, mode));
emit_insn (gen_rtx_SET (operand_subword (dest, !reverse, TRUE, mode),
operand_subword (src, !reverse, TRUE, mode)));
emit_move_insn (operand_subword (dest, !reverse, TRUE, mode),
operand_subword (src, !reverse, TRUE, mode));
}
/* Constant-to-reg copy. */
else if (CONST_INT_P (src) || GET_CODE (src) == CONST_DOUBLE)
{
rtx words[2];
split_double (src, &words[0], &words[1]);
emit_insn (gen_rtx_SET (operand_subword (dest, 0, TRUE, mode),
words[0]));
emit_move_insn (operand_subword (dest, 0, TRUE, mode), words[0]);
emit_insn (gen_rtx_SET (operand_subword (dest, 1, TRUE, mode),
words[1]));
emit_move_insn (operand_subword (dest, 1, TRUE, mode), words[1]);
}
/* Mem-to-reg copy. */
else if (MEM_P (src))
@ -2522,18 +2205,15 @@ cris_split_movdx (rtx *operands)
addresses ourselves, we must add a post-inc note
manually. */
mem = change_address (src, SImode, addr);
insn
= gen_rtx_SET (operand_subword (dest, 0, TRUE, mode), mem);
insn = emit_insn (insn);
insn = emit_move_insn (operand_subword (dest, 0, TRUE, mode),
mem);
if (GET_CODE (XEXP (mem, 0)) == POST_INC)
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_INC, XEXP (XEXP (mem, 0), 0),
REG_NOTES (insn));
mem = copy_rtx (mem);
insn
= gen_rtx_SET (operand_subword (dest, 1, TRUE, mode), mem);
insn = emit_insn (insn);
insn = emit_move_insn (operand_subword (dest, 1, TRUE, mode), mem);
if (GET_CODE (XEXP (mem, 0)) == POST_INC)
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_INC, XEXP (XEXP (mem, 0), 0),
@ -2548,19 +2228,17 @@ cris_split_movdx (rtx *operands)
if (side_effects_p (addr))
fatal_insn ("unexpected side-effects in address", addr);
emit_insn (gen_rtx_SET
(operand_subword (dest, reverse, TRUE, mode),
change_address
(src, SImode,
plus_constant (Pmode, addr,
reverse * UNITS_PER_WORD))));
emit_insn (gen_rtx_SET
(operand_subword (dest, ! reverse, TRUE, mode),
change_address
(src, SImode,
plus_constant (Pmode, addr,
(! reverse) *
UNITS_PER_WORD))));
emit_move_insn (operand_subword (dest, reverse, TRUE, mode),
change_address
(src, SImode,
plus_constant (Pmode, addr,
reverse * UNITS_PER_WORD)));
emit_move_insn (operand_subword (dest, ! reverse, TRUE, mode),
change_address
(src, SImode,
plus_constant (Pmode, addr,
(! reverse) *
UNITS_PER_WORD)));
}
}
else
@ -2582,17 +2260,14 @@ cris_split_movdx (rtx *operands)
/* Whenever we emit insns with post-incremented addresses
ourselves, we must add a post-inc note manually. */
mem = change_address (dest, SImode, addr);
insn
= gen_rtx_SET (mem, operand_subword (src, 0, TRUE, mode));
insn = emit_insn (insn);
insn = emit_move_insn (mem, operand_subword (src, 0, TRUE, mode));
if (GET_CODE (XEXP (mem, 0)) == POST_INC)
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_INC, XEXP (XEXP (mem, 0), 0),
REG_NOTES (insn));
mem = copy_rtx (mem);
insn = gen_rtx_SET (mem, operand_subword (src, 1, TRUE, mode));
insn = emit_insn (insn);
insn = emit_move_insn (mem, operand_subword (src, 1, TRUE, mode));
if (GET_CODE (XEXP (mem, 0)) == POST_INC)
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_INC, XEXP (XEXP (mem, 0), 0),
@ -2606,15 +2281,13 @@ cris_split_movdx (rtx *operands)
if (side_effects_p (addr))
fatal_insn ("unexpected side-effects in address", addr);
emit_insn (gen_rtx_SET
(change_address (dest, SImode, addr),
operand_subword (src, 0, TRUE, mode)));
emit_move_insn (change_address (dest, SImode, addr),
operand_subword (src, 0, TRUE, mode));
emit_insn (gen_rtx_SET
(change_address (dest, SImode,
plus_constant (Pmode, addr,
UNITS_PER_WORD)),
operand_subword (src, 1, TRUE, mode)));
emit_move_insn (change_address (dest, SImode,
plus_constant (Pmode, addr,
UNITS_PER_WORD)),
operand_subword (src, 1, TRUE, mode));
}
}
@ -2727,10 +2400,7 @@ cris_expand_prologue (void)
stdarg_regs > 0;
regno--, pretend -= 4, stdarg_regs--)
{
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode,
stack_pointer_rtx,
-4)));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx, GEN_INT (-4)));
/* FIXME: When dwarf2 frame output and unless asynchronous
exceptions, make dwarf2 bundle together all stack
adjustments like it does for registers between stack
@ -2755,9 +2425,8 @@ cris_expand_prologue (void)
/* Save SRP if not a leaf function. */
if (return_address_on_stack)
{
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
-4 - pretend)));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-4 - pretend)));
pretend = 0;
RTX_FRAME_RELATED_P (insn) = 1;
@ -2771,9 +2440,8 @@ cris_expand_prologue (void)
/* Set up the frame pointer, if needed. */
if (frame_pointer_needed)
{
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
-4 - pretend)));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-4 - pretend)));
pretend = 0;
RTX_FRAME_RELATED_P (insn) = 1;
@ -2820,7 +2488,10 @@ cris_expand_prologue (void)
side-effects insns are allowed. */
if ((last_movem_reg + 1) * 4 + size >= 64
&& (last_movem_reg + 1) * 4 + size <= 128
&& (cris_cpu_version >= CRIS_CPU_SVINTO || n_saved == 1)
&& cris_cpu_version >= CRIS_CPU_SVINTO
/* Don't use side-effect assignment for a single
move. */
&& n_saved > 1
&& TARGET_SIDE_EFFECT_PREFIXES)
{
mem
@ -2836,10 +2507,9 @@ cris_expand_prologue (void)
else
{
insn
= gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
-(n_saved * 4 + size)));
insn = emit_insn (insn);
= emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-(n_saved * 4
+ size))));
RTX_FRAME_RELATED_P (insn) = 1;
mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
@ -2853,10 +2523,8 @@ cris_expand_prologue (void)
size = 0;
}
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode,
stack_pointer_rtx,
-4 - size)));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-4 - size)));
RTX_FRAME_RELATED_P (insn) = 1;
mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
@ -2880,7 +2548,9 @@ cris_expand_prologue (void)
do it if side-effects insns are allowed. */
if ((last_movem_reg + 1) * 4 + size >= 64
&& (last_movem_reg + 1) * 4 + size <= 128
&& (cris_cpu_version >= CRIS_CPU_SVINTO || n_saved == 1)
&& cris_cpu_version >= CRIS_CPU_SVINTO
/* Don't use side-effect assignment for a single move. */
&& n_saved > 1
&& TARGET_SIDE_EFFECT_PREFIXES)
{
mem
@ -2893,11 +2563,8 @@ cris_expand_prologue (void)
}
else
{
insn
= gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
-(n_saved * 4 + size)));
insn = emit_insn (insn);
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-(n_saved * 4 + size))));
RTX_FRAME_RELATED_P (insn) = 1;
mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
@ -2909,20 +2576,16 @@ cris_expand_prologue (void)
/* We have to put outgoing argument space after regs. */
if (cfoa_size)
{
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode,
stack_pointer_rtx,
-cfoa_size)));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-cfoa_size)));
RTX_FRAME_RELATED_P (insn) = 1;
framesize += cfoa_size;
}
}
else if ((size + cfoa_size) > 0)
{
insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode,
stack_pointer_rtx,
-(cfoa_size + size))));
insn = emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (-(cfoa_size + size))));
RTX_FRAME_RELATED_P (insn) = 1;
framesize += size + cfoa_size;
}
@ -2988,9 +2651,8 @@ cris_expand_epilogue (void)
{
/* There is an area for outgoing parameters located before
the saved registers. We have to adjust for that. */
emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
argspace_offset)));
emit_insn (gen_add2_insn (stack_pointer_rtx,
GEN_INT (argspace_offset)));
/* Make sure we only do this once. */
argspace_offset = 0;
}
@ -3013,9 +2675,7 @@ cris_expand_epilogue (void)
if (argspace_offset)
{
emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
argspace_offset)));
emit_insn (gen_add2_insn (stack_pointer_rtx, GEN_INT (argspace_offset)));
argspace_offset = 0;
}
@ -3023,8 +2683,7 @@ cris_expand_epilogue (void)
gen_rtx_POST_INC (SImode, stack_pointer_rtx));
set_mem_alias_set (mem, get_frame_alias_set ());
insn
= emit_insn (cris_gen_movem_load (mem,
GEN_INT (last_movem_reg + 1), 0));
= emit_insn (cris_gen_movem_load (mem, GEN_INT (last_movem_reg + 1)));
/* Whenever we emit insns with post-incremented addresses
ourselves, we must add a post-inc note manually. */
if (side_effects_p (PATTERN (insn)))
@ -3071,8 +2730,7 @@ cris_expand_epilogue (void)
yet. */
size += argspace_offset;
emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx, size)));
emit_insn (gen_add2_insn (stack_pointer_rtx, GEN_INT (size)));
}
/* If this function has no pushed register parameters
@ -3097,9 +2755,8 @@ cris_expand_epilogue (void)
= alloc_EXPR_LIST (REG_INC, stack_pointer_rtx, REG_NOTES (insn));
if (crtl->calls_eh_return)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
emit_insn (gen_add2_insn (stack_pointer_rtx,
gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
cris_expand_return (false);
}
else
@ -3131,23 +2788,20 @@ cris_expand_epilogue (void)
= alloc_EXPR_LIST (REG_INC, stack_pointer_rtx, REG_NOTES (insn));
}
emit_insn (gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
pretend)));
emit_insn (gen_add2_insn (stack_pointer_rtx, GEN_INT (pretend)));
}
/* Perform the "physical" unwinding that the EH machinery calculated. */
if (crtl->calls_eh_return)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
emit_insn (gen_add2_insn (stack_pointer_rtx,
gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
cris_expand_return (false);
}
/* Worker function for generating movem from mem for load_multiple. */
rtx
cris_gen_movem_load (rtx src, rtx nregs_rtx, int nprefix)
cris_gen_movem_load (rtx src, rtx nregs_rtx)
{
int nregs = INTVAL (nregs_rtx);
rtvec vec;
@ -3166,24 +2820,23 @@ cris_gen_movem_load (rtx src, rtx nregs_rtx, int nprefix)
if (nregs == 1)
return gen_movsi (gen_rtx_REG (SImode, 0), src);
vec = rtvec_alloc (nprefix + nregs
+ (GET_CODE (XEXP (src, 0)) == POST_INC));
vec = rtvec_alloc (nregs + (GET_CODE (XEXP (src, 0)) == POST_INC));
if (GET_CODE (XEXP (src, 0)) == POST_INC)
{
RTVEC_ELT (vec, nprefix + 1)
RTVEC_ELT (vec, 1)
= gen_rtx_SET (srcreg, plus_constant (Pmode, srcreg, nregs * 4));
eltno++;
}
src = replace_equiv_address (src, srcreg);
RTVEC_ELT (vec, nprefix)
RTVEC_ELT (vec, 0)
= gen_rtx_SET (gen_rtx_REG (SImode, regno), src);
regno += regno_inc;
for (i = 1; i < nregs; i++, eltno++)
{
RTVEC_ELT (vec, nprefix + eltno)
RTVEC_ELT (vec, eltno)
= gen_rtx_SET (gen_rtx_REG (SImode, regno),
adjust_address_nv (src, SImode, i * 4));
regno += regno_inc;
@ -3192,6 +2845,22 @@ cris_gen_movem_load (rtx src, rtx nregs_rtx, int nprefix)
return gen_rtx_PARALLEL (VOIDmode, vec);
}
/* Convenience function for CRIS-local use of emit_insn, wrapping the
argument in a parallel with a clobber of CRIS_CC0_REGNUM before
passing on to emit_insn. */
rtx_insn *
cris_emit_insn (rtx x)
{
rtvec vec = rtvec_alloc (2);
RTVEC_ELT (vec, 0) = x;
RTVEC_ELT (vec, 1)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CRIS_CC0_REGNUM));
return emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
}
/* Worker function for generating movem to mem. If FRAME_RELATED, notes
are added that the dwarf2 machinery understands. */
@ -3219,11 +2888,9 @@ cris_emit_movem_store (rtx dest, rtx nregs_rtx, int increment,
/* Don't use movem for just one insn. The insns are equivalent. */
if (nregs == 1)
{
rtx mov = gen_rtx_SET (dest, gen_rtx_REG (SImode, 0));
if (increment == 0)
{
insn = emit_insn (mov);
insn = emit_move_insn (dest, gen_rtx_REG (SImode, 0));
if (frame_related)
RTX_FRAME_RELATED_P (insn) = 1;
return insn;
@ -3231,11 +2898,15 @@ cris_emit_movem_store (rtx dest, rtx nregs_rtx, int increment,
/* If there was a request for a side-effect, create the ordinary
parallel. */
vec = rtvec_alloc (2);
vec = rtvec_alloc (3);
rtx mov = gen_rtx_SET (dest, gen_rtx_REG (SImode, 0));
RTVEC_ELT (vec, 0) = mov;
RTVEC_ELT (vec, 1) = gen_rtx_SET (destreg, plus_constant (Pmode, destreg,
increment));
RTVEC_ELT (vec, 2)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CRIS_CC0_REGNUM));
if (frame_related)
{
RTX_FRAME_RELATED_P (mov) = 1;

View File

@ -698,11 +698,8 @@ struct cum_args {int regs;};
/* Node: Condition Code */
#define NOTICE_UPDATE_CC(EXP, INSN) cris_notice_update_cc (EXP, INSN)
/* FIXME: Maybe define CANONICALIZE_COMPARISON later, when playing with
optimizations. It is needed; currently we do this with instruction
patterns and NOTICE_UPDATE_CC. */
/* FIXME: Maybe define TARGET_CANONICALIZE_COMPARISON later, when
playing with optimizations. Definitely define SELECT_CC_MODE. */
/* Node: Costs */

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@
(define_predicate "cris_load_multiple_op"
(and (match_code "parallel")
(match_test "cris_movem_load_rest_p (op, 0)")))
(match_test "cris_movem_load_rest_p (op)")))
(define_predicate "cris_store_multiple_op"
(and (match_code "parallel")

View File

@ -123,7 +123,8 @@
(match_operand:BWD 2 "<atomic_op_op_pred>" "<atomic_op_op_cnstr>")))
(set (match_operand:BWD 0 "register_operand" "=&r")
(match_dup 1))
(clobber (match_scratch:SI 3 "=&r"))]
(clobber (match_scratch:SI 3 "=&r"))
(clobber (reg:CC CRIS_CC0_REGNUM))]
"<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS"
{
/* Can't be too sure; better ICE if this happens. */
@ -226,7 +227,8 @@
[(match_dup 2)
(match_dup 3)
(match_operand:BWD 4 "register_operand" "r")]
CRIS_UNSPEC_ATOMIC_SWAP_MEM))]
CRIS_UNSPEC_ATOMIC_SWAP_MEM))
(clobber (reg:CC CRIS_CC0_REGNUM))]
"<MODE>mode == QImode || !TARGET_ATOMICS_MAY_CALL_LIBFUNCS"
{
if (cris_cpu_version == 10)