operands[3] is the alignment.
operands[4] is a temp register.
operands[5] is a temp register.
- ... */
+ ...
+ operands[3+num_regs] is the last temp register.
+
+ The block move type can be one of the following:
+ BLOCK_MOVE_NORMAL Do all of the block move.
+ BLOCK_MOVE_NOT_LAST Do all but the last store.
+ BLOCK_MOVE_LAST Do just the last store. */
char *
-output_block_move (insn, operands, num_regs)
+output_block_move (insn, operands, num_regs, move_type)
rtx insn;
rtx operands[];
int num_regs;
+ enum block_move_type move_type;
{
rtx dest_reg = XEXP (operands[0], 0);
rtx src_reg = XEXP (operands[1], 0);
char *load; /* load insn without nop */
char *load_nop; /* load insn with trailing nop */
char *store; /* store insn */
+ char *final; /* if last_store used: NULL or swr */
+ char *last_store; /* last store instruction */
int offset; /* current offset */
enum machine_mode mode; /* mode to use on (MEM) */
} load_store[4];
- /* Work around a bug in GCC, where it can give us a register
+ /* Detect a bug in GCC, where it can give us a register
the same as one of the addressing registers. */
for (i = 4; i < last_operand; i++)
{
if (reg_mentioned_p (operands[i], operands[0])
|| reg_mentioned_p (operands[i], operands[1]))
{
- /* register passed as address and temp register to block move */
- /* To have a correct compiler, either this function
- has to handle the case, or something else has to make
- sure the case won't arise. */
- abort ();
+ error ("register $%d passed as address and temp register to block move",
+ REGNO (operands[i]));
for (j = i+1; j < last_operand; j++)
operands[j-1] = operands[j];
/* If we are given global or static addresses, and we would be
emitting a few instructions, try to save time by using a
temporary register for the pointer. */
- if (bytes > 2*align)
+ if (bytes > 2*align || move_type != BLOCK_MOVE_NORMAL)
{
if (CONSTANT_P (src_reg))
{
if (TARGET_STATS)
mips_count_memory_refs (operands[1], 1);
- xoperands[1] = operands[1];
- xoperands[0] = src_reg = operands[ 3 + num_regs-- ];
- output_asm_insn ("la\t%0,%1", xoperands);
+ src_reg = operands[ 3 + num_regs-- ];
+ if (move_type != BLOCK_MOVE_LAST)
+ {
+ xoperands[1] = operands[1];
+ xoperands[0] = src_reg;
+ output_asm_insn ("la\t%0,%1", xoperands);
+ }
}
if (CONSTANT_P (dest_reg))
if (TARGET_STATS)
mips_count_memory_refs (operands[0], 1);
- xoperands[1] = operands[0];
- xoperands[0] = dest_reg = operands[ 3 + num_regs-- ];
- output_asm_insn ("la\t%0,%1", xoperands);
+ dest_reg = operands[ 3 + num_regs-- ];
+ if (move_type != BLOCK_MOVE_LAST)
+ {
+ xoperands[1] = operands[0];
+ xoperands[0] = dest_reg;
+ output_asm_insn ("la\t%0,%1", xoperands);
+ }
}
}
else if (num_regs < 1)
abort ();
- if (TARGET_GAS && set_noreorder++ == 0)
+ if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && set_noreorder++ == 0)
output_asm_insn (".set\tnoreorder", operands);
while (bytes > 0)
{
load_store[num].offset = offset;
- dslots_load_total++;
- dslots_load_filled++;
if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD)
{
- load_store[num].load = "lw\t%0,%1";
- load_store[num].load_nop = "lw\t%0,%1%#";
- load_store[num].store = "sw\t%0,%1";
- load_store[num].mode = SImode;
+ load_store[num].load = "lw\t%0,%1";
+ load_store[num].load_nop = "lw\t%0,%1%#";
+ load_store[num].store = "sw\t%0,%1";
+ load_store[num].last_store = "sw\t%0,%1";
+ load_store[num].final = (char *)0;
+ load_store[num].mode = SImode;
offset += UNITS_PER_WORD;
bytes -= UNITS_PER_WORD;
}
- else if (bytes >= UNITS_PER_WORD && TARGET_GAS)
+ else if (bytes >= UNITS_PER_WORD)
{
#if BYTES_BIG_ENDIAN
- load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2";
- load_store[num].load_nop = "lwl\t%0,%1\n\tlwr\t%0,%2%#";
- load_store[num].store = "swl\t%0,%1\n\tswr\t%0,%2";
+ load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2";
+ load_store[num].load_nop = "lwl\t%0,%1\n\tlwr\t%0,%2%#";
+ load_store[num].store = "swl\t%0,%1\n\tswr\t%0,%2";
+ load_store[num].last_store = "swr\t%0,%2";
+ load_store[num].final = "swl\t%0,%1";
#else
- load_store[num].load = "lwl\t%0,%2\n\tlwr\t%0,%1";
- load_store[num].load_nop = "lwl\t%0,%2\n\tlwr\t%0,%1%#";
- load_store[num].store = "swl\t%0,%2\n\tswr\t%0,%1";
+ load_store[num].load = "lwl\t%0,%2\n\tlwr\t%0,%1";
+ load_store[num].load_nop = "lwl\t%0,%2\n\tlwr\t%0,%1%#";
+ load_store[num].store = "swl\t%0,%2\n\tswr\t%0,%1";
+ load_store[num].last_store = "swr\t%0,%1";
+ load_store[num].final = "swl\t%0,%2";
#endif
load_store[num].mode = SImode;
offset += UNITS_PER_WORD;
use_lwl_lwr = TRUE;
}
- else if (bytes >= UNITS_PER_WORD)
- {
- load_store[num].load = "ulw\t%0,%1";
- load_store[num].load_nop = "ulw\t%0,%1%#";
- load_store[num].store = "usw\t%0,%1";
- load_store[num].mode = SImode;
- offset += UNITS_PER_WORD;
- bytes -= UNITS_PER_WORD;
- }
-
else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT)
{
- load_store[num].load = "lh\t%0,%1";
- load_store[num].load_nop = "lh\t%0,%1%#";
- load_store[num].store = "sh\t%0,%1";
- load_store[num].offset = offset;
- load_store[num].mode = HImode;
+ load_store[num].load = "lh\t%0,%1";
+ load_store[num].load_nop = "lh\t%0,%1%#";
+ load_store[num].store = "sh\t%0,%1";
+ load_store[num].last_store = "sh\t%0,%1";
+ load_store[num].final = (char *)0;
+ load_store[num].offset = offset;
+ load_store[num].mode = HImode;
offset += UNITS_PER_SHORT;
bytes -= UNITS_PER_SHORT;
}
else
{
- load_store[num].load = "lb\t%0,%1";
- load_store[num].load_nop = "lb\t%0,%1%#";
- load_store[num].store = "sb\t%0,%1";
- load_store[num].mode = QImode;
+ load_store[num].load = "lb\t%0,%1";
+ load_store[num].load_nop = "lb\t%0,%1%#";
+ load_store[num].store = "sb\t%0,%1";
+ load_store[num].last_store = "sb\t%0,%1";
+ load_store[num].final = (char *)0;
+ load_store[num].mode = QImode;
offset++;
bytes--;
}
- if (TARGET_STATS)
+ if (TARGET_STATS && move_type != BLOCK_MOVE_LAST)
{
+ dslots_load_total++;
+ dslots_load_filled++;
+
if (CONSTANT_P (src_reg))
mips_count_memory_refs (src_reg, 1);
if (num == 1)
{
load_store[0].load = load_store[0].load_nop;
- dslots_load_filled--;
+ if (TARGET_STATS && move_type != BLOCK_MOVE_LAST)
+ dslots_load_filled--;
}
- for (i = 0; i < num; i++)
+ if (move_type != BLOCK_MOVE_LAST)
{
- int offset;
+ for (i = 0; i < num; i++)
+ {
+ int offset;
- if (!operands[i+4])
- abort ();
+ if (!operands[i+4])
+ abort ();
- if (GET_MODE (operands[i+4]) != load_store[i].mode)
- operands[i+4] = gen_rtx (REG, load_store[i].mode, REGNO (operands[i+4]));
+ if (GET_MODE (operands[i+4]) != load_store[i].mode)
+ operands[i+4] = gen_rtx (REG, load_store[i].mode, REGNO (operands[i+4]));
- offset = load_store[i].offset;
- xoperands[0] = operands[i+4];
- xoperands[1] = gen_rtx (MEM, load_store[i].mode,
- plus_constant (src_reg, offset));
+ offset = load_store[i].offset;
+ xoperands[0] = operands[i+4];
+ xoperands[1] = gen_rtx (MEM, load_store[i].mode,
+ plus_constant (src_reg, offset));
- if (use_lwl_lwr)
- xoperands[2] = gen_rtx (MEM, load_store[i].mode,
- plus_constant (src_reg, UNITS_PER_WORD-1+offset));
+ if (use_lwl_lwr)
+ xoperands[2] = gen_rtx (MEM, load_store[i].mode,
+ plus_constant (src_reg, UNITS_PER_WORD-1+offset));
- output_asm_insn (load_store[i].load, xoperands);
+ output_asm_insn (load_store[i].load, xoperands);
+ }
}
for (i = 0; i < num; i++)
{
+ int last_p = (i == num-1 && bytes == 0);
int offset = load_store[i].offset;
+
xoperands[0] = operands[i+4];
xoperands[1] = gen_rtx (MEM, load_store[i].mode,
plus_constant (dest_reg, offset));
xoperands[2] = gen_rtx (MEM, load_store[i].mode,
plus_constant (dest_reg, UNITS_PER_WORD-1+offset));
- output_asm_insn (load_store[i].store, xoperands);
+ if (move_type == BLOCK_MOVE_NORMAL)
+ output_asm_insn (load_store[i].store, xoperands);
+
+ else if (move_type == BLOCK_MOVE_NOT_LAST)
+ {
+ if (!last_p)
+ output_asm_insn (load_store[i].store, xoperands);
+
+ else if (load_store[i].final != (char *)0)
+ output_asm_insn (load_store[i].final, xoperands);
+ }
+
+ else if (last_p)
+ output_asm_insn (load_store[i].last_store, xoperands);
}
num = 0; /* reset load_store */
}
}
- if (TARGET_GAS && --set_noreorder == 0)
+ if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && --set_noreorder == 0)
output_asm_insn (".set\treorder", operands);
return "";