xtensa.c (xtensa_expand_block_move): Expand block move to rtl completely.
* config/xtensa/xtensa.c (xtensa_expand_block_move): Expand block move to rtl completely. (struct meminsnbuf, xtensa_emit_block_move): Remove. (xtensa_find_mode_for_size): Remove. * config/xtensa/xtensa-protos.h (xtensa_emit_block_move): Remove. * config/xtensa/xtensa.md (movmemsi_internal): Remove. From-SVN: r86235
This commit is contained in:
parent
8804266301
commit
7eda7cda0a
@ -1,3 +1,12 @@
|
|||||||
|
2004-08-18 Richard Henderson <rth@redhat.com>
|
||||||
|
|
||||||
|
* config/xtensa/xtensa.c (xtensa_expand_block_move): Expand block
|
||||||
|
move to rtl completely.
|
||||||
|
(struct meminsnbuf, xtensa_emit_block_move): Remove.
|
||||||
|
(xtensa_find_mode_for_size): Remove.
|
||||||
|
* config/xtensa/xtensa-protos.h (xtensa_emit_block_move): Remove.
|
||||||
|
* config/xtensa/xtensa.md (movmemsi_internal): Remove.
|
||||||
|
|
||||||
2004-08-18 Richard Henderson <rth@redhat.com>
|
2004-08-18 Richard Henderson <rth@redhat.com>
|
||||||
|
|
||||||
* config/mcore/mcore.c (mode_from_align): Remove DImode.
|
* config/mcore/mcore.c (mode_from_align): Remove DImode.
|
||||||
|
@ -69,7 +69,6 @@ extern int xtensa_expand_block_move (rtx *);
|
|||||||
extern void xtensa_split_operand_pair (rtx *, enum machine_mode);
|
extern void xtensa_split_operand_pair (rtx *, enum machine_mode);
|
||||||
extern int xtensa_emit_move_sequence (rtx *, enum machine_mode);
|
extern int xtensa_emit_move_sequence (rtx *, enum machine_mode);
|
||||||
extern rtx xtensa_copy_incoming_a7 (rtx);
|
extern rtx xtensa_copy_incoming_a7 (rtx);
|
||||||
extern void xtensa_emit_block_move (rtx *, rtx *, int);
|
|
||||||
extern void xtensa_expand_nonlocal_goto (rtx *);
|
extern void xtensa_expand_nonlocal_goto (rtx *);
|
||||||
extern void xtensa_emit_loop_end (rtx, rtx *);
|
extern void xtensa_emit_loop_end (rtx, rtx *);
|
||||||
extern char *xtensa_emit_call (int, rtx *);
|
extern char *xtensa_emit_call (int, rtx *);
|
||||||
|
@ -200,7 +200,6 @@ static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *);
|
|||||||
static rtx gen_float_relational (enum rtx_code, rtx, rtx);
|
static rtx gen_float_relational (enum rtx_code, rtx, rtx);
|
||||||
static rtx gen_conditional_move (rtx);
|
static rtx gen_conditional_move (rtx);
|
||||||
static rtx fixup_subreg_mem (rtx);
|
static rtx fixup_subreg_mem (rtx);
|
||||||
static enum machine_mode xtensa_find_mode_for_size (unsigned);
|
|
||||||
static struct machine_function * xtensa_init_machine_status (void);
|
static struct machine_function * xtensa_init_machine_status (void);
|
||||||
static bool xtensa_return_in_msb (tree);
|
static bool xtensa_return_in_msb (tree);
|
||||||
static void printx (FILE *, signed int);
|
static void printx (FILE *, signed int);
|
||||||
@ -1439,19 +1438,35 @@ xtensa_copy_incoming_a7 (rtx opnd)
|
|||||||
int
|
int
|
||||||
xtensa_expand_block_move (rtx *operands)
|
xtensa_expand_block_move (rtx *operands)
|
||||||
{
|
{
|
||||||
rtx dest = operands[0];
|
static const enum machine_mode mode_from_align[] =
|
||||||
rtx src = operands[1];
|
{
|
||||||
int bytes = INTVAL (operands[2]);
|
VOIDmode, QImode, HImode, VOIDmode, SImode,
|
||||||
int align = XINT (operands[3], 0);
|
};
|
||||||
|
|
||||||
|
rtx dst_mem = operands[0];
|
||||||
|
rtx src_mem = operands[1];
|
||||||
|
HOST_WIDE_INT bytes, align;
|
||||||
int num_pieces, move_ratio;
|
int num_pieces, move_ratio;
|
||||||
|
rtx temp[2];
|
||||||
|
enum machine_mode mode[2];
|
||||||
|
int amount[2];
|
||||||
|
bool active[2];
|
||||||
|
int phase = 0;
|
||||||
|
int next;
|
||||||
|
int offset_ld = 0;
|
||||||
|
int offset_st = 0;
|
||||||
|
rtx x;
|
||||||
|
|
||||||
/* If this is not a fixed size move, just call memcpy. */
|
/* If this is not a fixed size move, just call memcpy. */
|
||||||
if (!optimize || (GET_CODE (operands[2]) != CONST_INT))
|
if (!optimize || (GET_CODE (operands[2]) != CONST_INT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bytes = INTVAL (operands[2]);
|
||||||
|
align = INTVAL (operands[3]);
|
||||||
|
|
||||||
/* Anything to move? */
|
/* Anything to move? */
|
||||||
if (bytes <= 0)
|
if (bytes <= 0)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
if (align > MOVE_MAX)
|
if (align > MOVE_MAX)
|
||||||
align = MOVE_MAX;
|
align = MOVE_MAX;
|
||||||
@ -1461,147 +1476,62 @@ xtensa_expand_block_move (rtx *operands)
|
|||||||
if (optimize > 2)
|
if (optimize > 2)
|
||||||
move_ratio = LARGEST_MOVE_RATIO;
|
move_ratio = LARGEST_MOVE_RATIO;
|
||||||
num_pieces = (bytes / align) + (bytes % align); /* Close enough anyway. */
|
num_pieces = (bytes / align) + (bytes % align); /* Close enough anyway. */
|
||||||
if (num_pieces >= move_ratio)
|
if (num_pieces > move_ratio)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Make sure the memory addresses are valid. */
|
x = XEXP (dst_mem, 0);
|
||||||
operands[0] = validize_mem (dest);
|
if (!REG_P (x))
|
||||||
operands[1] = validize_mem (src);
|
|
||||||
|
|
||||||
emit_insn (gen_movmemsi_internal (operands[0], operands[1],
|
|
||||||
operands[2], operands[3]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Emit a sequence of instructions to implement a block move, trying
|
|
||||||
to hide load delay slots as much as possible. Load N values into
|
|
||||||
temporary registers, store those N values, and repeat until the
|
|
||||||
complete block has been moved. N=delay_slots+1. */
|
|
||||||
|
|
||||||
struct meminsnbuf
|
|
||||||
{
|
|
||||||
char template[30];
|
|
||||||
rtx operands[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
xtensa_emit_block_move (rtx *operands, rtx *tmpregs, int delay_slots)
|
|
||||||
{
|
|
||||||
rtx dest = operands[0];
|
|
||||||
rtx src = operands[1];
|
|
||||||
int bytes = INTVAL (operands[2]);
|
|
||||||
int align = XINT (operands[3], 0);
|
|
||||||
rtx from_addr = XEXP (src, 0);
|
|
||||||
rtx to_addr = XEXP (dest, 0);
|
|
||||||
int from_struct = MEM_IN_STRUCT_P (src);
|
|
||||||
int to_struct = MEM_IN_STRUCT_P (dest);
|
|
||||||
int offset = 0;
|
|
||||||
int chunk_size, item_size;
|
|
||||||
struct meminsnbuf *ldinsns, *stinsns;
|
|
||||||
const char *ldname, *stname;
|
|
||||||
enum machine_mode mode;
|
|
||||||
|
|
||||||
if (align > MOVE_MAX)
|
|
||||||
align = MOVE_MAX;
|
|
||||||
item_size = align;
|
|
||||||
chunk_size = delay_slots + 1;
|
|
||||||
|
|
||||||
ldinsns = (struct meminsnbuf *)
|
|
||||||
alloca (chunk_size * sizeof (struct meminsnbuf));
|
|
||||||
stinsns = (struct meminsnbuf *)
|
|
||||||
alloca (chunk_size * sizeof (struct meminsnbuf));
|
|
||||||
|
|
||||||
mode = xtensa_find_mode_for_size (item_size);
|
|
||||||
item_size = GET_MODE_SIZE (mode);
|
|
||||||
ldname = xtensa_ld_opcodes[(int) mode];
|
|
||||||
stname = xtensa_st_opcodes[(int) mode];
|
|
||||||
|
|
||||||
while (bytes > 0)
|
|
||||||
{
|
{
|
||||||
int n;
|
x = force_reg (Pmode, x);
|
||||||
|
dst_mem = replace_equiv_address (dst_mem, x);
|
||||||
|
}
|
||||||
|
|
||||||
for (n = 0; n < chunk_size; n++)
|
x = XEXP (src_mem, 0);
|
||||||
|
if (!REG_P (x))
|
||||||
|
{
|
||||||
|
x = force_reg (Pmode, x);
|
||||||
|
src_mem = replace_equiv_address (src_mem, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
active[0] = active[1] = false;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
next = phase;
|
||||||
|
phase ^= 1;
|
||||||
|
|
||||||
|
if (bytes > 0)
|
||||||
{
|
{
|
||||||
rtx addr, mem;
|
int next_amount;
|
||||||
|
|
||||||
if (bytes == 0)
|
next_amount = (bytes >= 4 ? 4 : (bytes >= 2 ? 2 : 1));
|
||||||
{
|
next_amount = MIN (next_amount, align);
|
||||||
chunk_size = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes < item_size)
|
amount[next] = next_amount;
|
||||||
{
|
mode[next] = mode_from_align[next_amount];
|
||||||
/* Find a smaller item_size which we can load & store. */
|
temp[next] = gen_reg_rtx (mode[next]);
|
||||||
item_size = bytes;
|
|
||||||
mode = xtensa_find_mode_for_size (item_size);
|
|
||||||
item_size = GET_MODE_SIZE (mode);
|
|
||||||
ldname = xtensa_ld_opcodes[(int) mode];
|
|
||||||
stname = xtensa_st_opcodes[(int) mode];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Record the load instruction opcode and operands. */
|
x = adjust_address (src_mem, mode[next], offset_ld);
|
||||||
addr = plus_constant (from_addr, offset);
|
emit_insn (gen_rtx_SET (VOIDmode, temp[next], x));
|
||||||
mem = gen_rtx_MEM (mode, addr);
|
|
||||||
if (! memory_address_p (mode, addr))
|
|
||||||
abort ();
|
|
||||||
MEM_IN_STRUCT_P (mem) = from_struct;
|
|
||||||
ldinsns[n].operands[0] = tmpregs[n];
|
|
||||||
ldinsns[n].operands[1] = mem;
|
|
||||||
sprintf (ldinsns[n].template, "%s\t%%0, %%1", ldname);
|
|
||||||
|
|
||||||
/* Record the store instruction opcode and operands. */
|
offset_ld += next_amount;
|
||||||
addr = plus_constant (to_addr, offset);
|
bytes -= next_amount;
|
||||||
mem = gen_rtx_MEM (mode, addr);
|
active[next] = true;
|
||||||
if (! memory_address_p (mode, addr))
|
|
||||||
abort ();
|
|
||||||
MEM_IN_STRUCT_P (mem) = to_struct;
|
|
||||||
stinsns[n].operands[0] = tmpregs[n];
|
|
||||||
stinsns[n].operands[1] = mem;
|
|
||||||
sprintf (stinsns[n].template, "%s\t%%0, %%1", stname);
|
|
||||||
|
|
||||||
offset += item_size;
|
|
||||||
bytes -= item_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now output the loads followed by the stores. */
|
if (active[phase])
|
||||||
for (n = 0; n < chunk_size; n++)
|
{
|
||||||
output_asm_insn (ldinsns[n].template, ldinsns[n].operands);
|
active[phase] = false;
|
||||||
for (n = 0; n < chunk_size; n++)
|
|
||||||
output_asm_insn (stinsns[n].template, stinsns[n].operands);
|
x = adjust_address (dst_mem, mode[phase], offset_st);
|
||||||
|
emit_insn (gen_rtx_SET (VOIDmode, x, temp[phase]));
|
||||||
|
|
||||||
|
offset_st += amount[phase];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
while (active[next]);
|
||||||
|
|
||||||
|
return 1;
|
||||||
static enum machine_mode
|
|
||||||
xtensa_find_mode_for_size (unsigned item_size)
|
|
||||||
{
|
|
||||||
enum machine_mode mode, tmode;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
mode = VOIDmode;
|
|
||||||
|
|
||||||
/* Find mode closest to but not bigger than item_size. */
|
|
||||||
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
|
|
||||||
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
|
|
||||||
if (GET_MODE_SIZE (tmode) <= item_size)
|
|
||||||
mode = tmode;
|
|
||||||
if (mode == VOIDmode)
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
item_size = GET_MODE_SIZE (mode);
|
|
||||||
|
|
||||||
if (xtensa_ld_opcodes[(int) mode]
|
|
||||||
&& xtensa_st_opcodes[(int) mode])
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Cannot load & store this mode; try something smaller. */
|
|
||||||
item_size -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1069,25 +1069,6 @@
|
|||||||
DONE;
|
DONE;
|
||||||
})
|
})
|
||||||
|
|
||||||
(define_insn "movmemsi_internal"
|
|
||||||
[(set (match_operand:BLK 0 "memory_operand" "=U")
|
|
||||||
(match_operand:BLK 1 "memory_operand" "U"))
|
|
||||||
(use (match_operand:SI 2 "arith_operand" ""))
|
|
||||||
(use (match_operand:SI 3 "const_int_operand" ""))
|
|
||||||
(clobber (match_scratch:SI 4 "=&r"))
|
|
||||||
(clobber (match_scratch:SI 5 "=&r"))]
|
|
||||||
""
|
|
||||||
{
|
|
||||||
rtx tmpregs[2];
|
|
||||||
tmpregs[0] = operands[4];
|
|
||||||
tmpregs[1] = operands[5];
|
|
||||||
xtensa_emit_block_move (operands, tmpregs, 1);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
[(set_attr "type" "multi")
|
|
||||||
(set_attr "mode" "none")
|
|
||||||
(set_attr "length" "300")])
|
|
||||||
|
|
||||||
|
|
||||||
;; Shift instructions.
|
;; Shift instructions.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user