pdp11-protos.h (output_move_double, [...]): Delete.

* config/pdp11/pdp11-protos.h (output_move_double,
output_move_quad): Delete.
(output_move_multiple, pdp11_expand_operands): New functions.
(pdp11_action, pdp11_partorder): New enums.
* config/pdp11/pdp11.md (movdi, movsi, movdf, movsf): Use
output_move_multiple.
(adddi3, subdi3, negdi2): New patterns.
(addsi3, subsi3, negsi2): Use pdp11_expand_operands.
(abshi2): Delete.
(neghi2, negqi2): Use PDPint iterator.
* config/pdp11/pdp11.c (find_addr_reg, output_move_double,
output_move_quad): Delete. 
(pdp11_expand_operands, output_move_multiple): New functions.

From-SVN: r167676
This commit is contained in:
Paul Koning 2010-12-09 20:31:08 -05:00 committed by Paul Koning
parent a23980bdb6
commit 30442c59aa
4 changed files with 378 additions and 541 deletions

View File

@ -1,3 +1,19 @@
2010-12-09 Paul Koning <ni1d@arrl.net>
* config/pdp11/pdp11-protos.h (output_move_double,
output_move_quad): Delete.
(output_move_multiple, pdp11_expand_operands): New functions.
(pdp11_action, pdp11_partorder): New enums.
* config/pdp11/pdp11.md (movdi, movsi, movdf, movsf): Use
output_move_multiple.
(adddi3, subdi3, negdi2): New patterns.
(addsi3, subsi3, negsi2): Use pdp11_expand_operands.
(abshi2): Delete.
(neghi2, negqi2): Use PDPint iterator.
* config/pdp11/pdp11.c (find_addr_reg, output_move_double,
output_move_quad): Delete.
(pdp11_expand_operands, output_move_multiple): New functions.
2010-12-09 Joseph Myers <joseph@codesourcery.com>
* config/vax/linux.h (WCHAR_TYPE, WCHAR_TYPE_SIZE): Define.

View File

@ -26,8 +26,7 @@ extern int simple_memory_operand (rtx, enum machine_mode);
extern int legitimate_const_double_p (rtx);
extern void notice_update_cc_on_set (rtx, rtx);
extern void output_addr_const_pdp11 (FILE *, rtx);
extern const char *output_move_double (rtx *);
extern const char *output_move_quad (rtx *);
extern const char *output_move_multiple (rtx *);
extern const char *output_block_move (rtx *);
extern const char *output_jump (enum rtx_code, int, int);
extern void print_operand_address (FILE *, rtx);
@ -35,6 +34,10 @@ extern bool pdp11_cannot_change_mode_class (enum machine_mode,
enum machine_mode, enum reg_class);
extern bool pdp11_secondary_memory_needed (reg_class_t, reg_class_t,
enum machine_mode);
typedef enum { no_action, dec_before, inc_after } pdp11_action;
typedef enum { little, either, big } pdp11_partorder;
extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
pdp11_action *, pdp11_partorder);
extern int pdp11_initial_elimination_offset (int, int);
extern enum reg_class pdp11_regno_reg_class (int);

View File

@ -140,7 +140,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
static bool pdp11_handle_option (size_t, const char *, int);
static void pdp11_option_init_struct (struct gcc_options *);
static rtx find_addr_reg (rtx);
static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int);
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
@ -236,7 +235,6 @@ static const struct default_options pdp11_option_optimization_table[] =
#undef TARGET_ASM_FUNCTION_SECTION
#define TARGET_ASM_FUNCTION_SECTION pdp11_function_section
/* Implement TARGET_HANDLE_OPTION. */
@ -483,407 +481,215 @@ singlemove_string (rtx *operands)
}
/* Output assembler code to perform a doubleword move insn
with operands OPERANDS. */
const char *
output_move_double (rtx *operands)
/* Expand multi-word operands (SImode or DImode) into the 2 or 4
corresponding HImode operands. The number of operands is given
as the third argument, and the required order of the parts as
the fourth argument. */
bool
pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
pdp11_action *action, pdp11_partorder order)
{
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx addreg0 = 0, addreg1 = 0;
/* First classify both operands. */
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1])
#if 0
|| GET_CODE (operands[1]) == CONST_DOUBLE
#endif
)
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
/* Check for the cases that the operand constraints are not
supposed to allow to happen. Abort if we get one,
because generating code for these cases is painful. */
gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
/* If one operand is decrementing and one is incrementing
decrement the former register explicitly
and change that operand into ordinary indexing. */
if (optype0 == PUSHOP && optype1 == POPOP)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $4,%0", operands);
operands[0] = gen_rtx_MEM (SImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("sub $4,%1", operands);
operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
}
/* If an operand is an unoffsettable memory ref, find a register
we can increment temporarily to make it refer to the second word. */
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
/* Ok, we can do one word at a time.
Normally we do the low-numbered word first,
but if either operand is autodecrementing then we
do the high-numbered word first.
In either case, set up in LATEHALF the operands to use
for the high-numbered word and in some cases alter the
operands in OPERANDS to be suitable for the low-numbered word. */
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], HImode, 2);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], HImode, 2);
else if (optype1 == CNSTOP)
{
if (CONSTANT_P (operands[1]))
{
/* now the mess begins, high word is in lower word???
that's what ashc makes me think, but I don't remember :-( */
latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
}
else
/* immediate 32-bit values not allowed */
gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE);
}
else
latehalf[1] = operands[1];
/* If insn is effectively movd N(sp),-(sp) then we will do the
high word first. We should use the adjusted operand 1 (which is N+4(sp))
for the low word as well, to compensate for the first decrement of sp. */
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
operands[1] = latehalf[1];
/* If one or both operands autodecrementing,
do the two words, high-numbered first. */
/* Likewise, the first move would clobber the source of the second one,
do them in the other order. This happens only for registers;
such overlap can't happen in memory unless the user explicitly
sets it up, and that is an undefined circumstance. */
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1])))
{
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
output_asm_insn ("add $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $2,%0", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $2,%0", &addreg1);
/* Do low-numbered word. */
return singlemove_string (operands);
}
/* Normal case: do the two words, low-numbered first. */
output_asm_insn (singlemove_string (operands), operands);
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
output_asm_insn ("add $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $2,%0", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $2,%0", &addreg1);
return "";
}
/* Output assembler code to perform a quadword move insn
with operands OPERANDS. */
const char *
output_move_quad (rtx *operands)
{
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx addreg0 = 0, addreg1 = 0;
output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
int words, op, w, i, sh;
pdp11_partorder useorder;
bool sameoff = false;
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype;
REAL_VALUE_TYPE r;
long sval[2];
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1])
|| GET_CODE (operands[1]) == CONST_DOUBLE)
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
/* Check for the cases that the operand constraints are not
supposed to allow to happen. Abort if we get one,
because generating code for these cases is painful. */
gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16;
if (optype0 == REGOP || optype1 == REGOP)
{
/* check for use of clrd????
if you ever allow ac4 and ac5 (now we require secondary load)
you must check whether
you want to load into them or store from them -
then dump ac0 into $help$ movce ac4/5 to ac0, do the
store from ac0, and restore ac0 - if you can find
an unused ac[0-3], use that and you save a store and a load!*/
if (FPU_REG_P(REGNO(operands[0])))
{
if (GET_CODE(operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
if (REAL_VALUES_EQUAL (r, dconst0))
return "{clrd|clrf} %0";
}
return "{ldd|movf} %1, %0";
}
if (FPU_REG_P(REGNO(operands[1])))
return "{std|movf} %1, %0";
}
/* If one operand is decrementing and one is incrementing
decrement the former register explicitly
and change that operand into ordinary indexing. */
if (optype0 == PUSHOP && optype1 == POPOP)
/* If either piece order is accepted and one is pre-decrement
while the other is post-increment, set order to be high order
word first. That will force the pre-decrement to be turned
into a pointer adjust, then offset addressing.
Otherwise, if either operand uses pre-decrement, that means
the order is low order first.
Otherwise, if both operands are registers and destination is
higher than source and they overlap, do low order word (highest
register number) first. */
useorder = either;
if (opcount == 2)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $8,%0", operands);
operands[0] = gen_rtx_MEM (DImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("sub $8,%1", operands);
operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
if (!REG_P (operands[0]) && !REG_P (operands[1]) &&
!(CONSTANT_P (operands[1]) ||
GET_CODE (operands[1]) == CONST_DOUBLE) &&
((GET_CODE (XEXP (operands[0], 0)) == POST_INC &&
GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ||
(GET_CODE (XEXP (operands[0], 0)) == PRE_DEC &&
GET_CODE (XEXP (operands[1], 0)) == POST_INC)))
useorder = big;
else if ((!REG_P (operands[0]) &&
GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ||
(!REG_P (operands[1]) &&
!(CONSTANT_P (operands[1]) ||
GET_CODE (operands[1]) == CONST_DOUBLE) &&
GET_CODE (XEXP (operands[1], 0)) == PRE_DEC))
useorder = little;
else if (REG_P (operands[0]) && REG_P (operands[1]) &&
REGNO (operands[0]) > REGNO (operands[1]) &&
REGNO (operands[0]) < REGNO (operands[1]) + words)
useorder = little;
/* Check for source == offset from register and dest == push of
the same register. In that case, we have to use the same
offset (the one for the low order word) for all words, because
the push increases the offset to each source word.
In theory there are other cases like this, for example dest == pop,
but those don't occur in real life so ignore those. */
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
sameoff = true;
}
/* If an operand is an unoffsettable memory ref, find a register
we can increment temporarily to make it refer to the second word. */
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
/* Ok, we can do one word at a time.
Normally we do the low-numbered word first,
but if either operand is autodecrementing then we
do the high-numbered word first.
In either case, set up in LATEHALF the operands to use
for the high-numbered word and in some cases alter the
operands in OPERANDS to be suitable for the low-numbered word. */
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], SImode, 4);
/* If the caller didn't specify order, use the one we computed,
or high word first if we don't care either. If the caller did
specify, verify we don't have a problem with that order.
(If it matters to the caller, constraints need to be used to
ensure this case doesn't occur). */
if (order == either)
order = (useorder == either) ? big : useorder;
else
latehalf[0] = operands[0];
gcc_assert (useorder == either || useorder == order);
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], SImode, 4);
else if (optype1 == CNSTOP)
for (op = 0; op < opcount; op++)
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long dval[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
latehalf[1] = GEN_INT (dval[1]);
operands[1] = GEN_INT (dval[0]);
}
else if (GET_CODE(operands[1]) == CONST_INT)
{
latehalf[1] = const0_rtx;
}
/* First classify the operand. */
if (REG_P (operands[op]))
optype = REGOP;
else if (CONSTANT_P (operands[op])
|| GET_CODE (operands[op]) == CONST_DOUBLE)
optype = CNSTOP;
else if (GET_CODE (XEXP (operands[op], 0)) == POST_INC)
optype = POPOP;
else if (GET_CODE (XEXP (operands[op], 0)) == PRE_DEC)
optype = PUSHOP;
else if (!reload_in_progress || offsettable_memref_p (operands[op]))
optype = OFFSOP;
else if (GET_CODE (operands[op]) == MEM)
optype = MEMOP;
else
gcc_unreachable ();
optype = RNDOP;
/* Check for the cases that the operand constraints are not
supposed to allow to happen. Return failure for such cases. */
if (optype == RNDOP)
return false;
if (action != NULL)
action[op] = no_action;
/* If the operand uses pre-decrement addressing but we
want to get the parts high order first,
decrement the former register explicitly
and change the operand into ordinary indexing. */
if (optype == PUSHOP && order == big)
{
gcc_assert (action != NULL);
action[op] = dec_before;
operands[op] = gen_rtx_MEM (GET_MODE (operands[op]),
XEXP (XEXP (operands[op], 0), 0));
optype = OFFSOP;
}
/* If the operand uses post-increment mode but we want
to get the parts low order first, change the operand
into ordinary indexing and remember to increment
the register explicitly when we're done. */
else if (optype == POPOP && order == little)
{
gcc_assert (action != NULL);
action[op] = inc_after;
operands[op] = gen_rtx_MEM (GET_MODE (operands[op]),
XEXP (XEXP (operands[op], 0), 0));
optype = OFFSOP;
}
if (GET_CODE (operands[op]) == CONST_DOUBLE)
{
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[op]);
REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
}
for (i = 0; i < words; i++)
{
if (order == big)
w = i;
else if (sameoff)
w = words - 1;
else
w = words - 1 - i;
/* Set the output operand to be word "w" of the input. */
if (optype == REGOP)
exops[i][op] = gen_rtx_REG (HImode, REGNO (operands[op]) + w);
else if (optype == OFFSOP)
exops[i][op] = adjust_address (operands[op], HImode, w * 2);
else if (optype == CNSTOP)
{
if (GET_CODE (operands[op]) == CONST_DOUBLE)
{
sh = 16 - (w & 1) * 16;
exops[i][op] = gen_rtx_CONST_INT (HImode, (sval[w / 2] >> sh) & 0xffff);
}
else
{
sh = ((words - 1 - w) * 16);
exops[i][op] = gen_rtx_CONST_INT (HImode, trunc_int_for_mode (INTVAL(operands[op]) >> sh, HImode));
}
}
else
exops[i][op] = operands[op];
}
}
else
latehalf[1] = operands[1];
/* If insn is effectively movd N(sp),-(sp) then we will do the
high word first. We should use the adjusted operand 1 (which is N+4(sp))
for the low word as well, to compensate for the first decrement of sp. */
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
operands[1] = latehalf[1];
/* If one or both operands autodecrementing,
do the two words, high-numbered first. */
/* Likewise, the first move would clobber the source of the second one,
do them in the other order. This happens only for registers;
such overlap can't happen in memory unless the user explicitly
sets it up, and that is an undefined circumstance. */
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1])))
{
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
output_asm_insn ("add $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $4,%0", &addreg1);
/* Do that word. */
output_asm_insn(output_move_double(latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $4,%0", &addreg1);
/* Do low-numbered word. */
return output_move_double (operands);
}
/* Normal case: do the two words, low-numbered first. */
output_asm_insn (output_move_double (operands), operands);
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
output_asm_insn ("add $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $4,%0", &addreg1);
/* Do that word. */
output_asm_insn (output_move_double (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $4,%0", &addreg1);
return "";
return true;
}
/* Return a REG that occurs in ADDR with coefficient 1.
ADDR can be effectively incremented by incrementing REG. */
/* Output assembler code to perform a multiple-word move insn
with operands OPERANDS. This moves 2 or 4 words depending
on the machine mode of the operands. */
static rtx
find_addr_reg (rtx addr)
const char *
output_move_multiple (rtx *operands)
{
while (GET_CODE (addr) == PLUS)
rtx exops[4][2];
pdp11_action action[2];
int i, words;
words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16;
pdp11_expand_operands (operands, exops, 2, action, either);
/* Check for explicit decrement before. */
if (action[0] == dec_before)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
addr = XEXP (addr, 0);
if (GET_CODE (XEXP (addr, 1)) == REG)
addr = XEXP (addr, 1);
if (CONSTANT_P (XEXP (addr, 0)))
addr = XEXP (addr, 1);
if (CONSTANT_P (XEXP (addr, 1)))
addr = XEXP (addr, 0);
operands[0] = XEXP (operands[0], 0);
output_asm_insn ("sub $4,%0", operands);
}
if (GET_CODE (addr) == REG)
return addr;
return 0;
if (action[1] == dec_before)
{
operands[1] = XEXP (operands[1], 0);
output_asm_insn ("sub $4,%1", operands);
}
/* Do the words. */
for (i = 0; i < words; i++)
output_asm_insn (singlemove_string (exops[i]), exops[i]);
/* Check for increment after. */
if (action[0] == inc_after)
{
operands[0] = XEXP (operands[0], 0);
output_asm_insn ("add $4,%0", operands);
}
if (action[1] == inc_after)
{
operands[1] = XEXP (operands[1], 0);
output_asm_insn ("add $4,%1", operands);
}
return "";
}
/* Output an ascii string. */
@ -1806,6 +1612,7 @@ pdp11_legitimate_address_p (enum machine_mode mode,
return false;
}
}
/* Return the class number of the smallest class containing
reg number REGNO. */
enum reg_class

View File

@ -260,21 +260,21 @@
;; Move instructions
(define_insn "movdi"
[(set (match_operand:DI 0 "nonimmediate_operand" "=g,rm,o")
(match_operand:DI 1 "general_operand" "m,r,a"))]
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
(match_operand:DI 1 "general_operand" "rN,g"))]
""
"* return output_move_quad (operands);"
"* return output_move_multiple (operands);"
;; what's the mose expensive code - say twice movsi = 16
[(set_attr "length" "32,32,32")])
[(set_attr "length" "16,32")])
(define_insn "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,rm,m")
(match_operand:SI 1 "general_operand" "rN,IJ,K,m,r"))]
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
(match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))]
""
"* return output_move_double (operands);"
"* return output_move_multiple (operands);"
;; what's the most expensive code ? - I think 8!
;; we could split it up and make several sub-cases...
[(set_attr "length" "4,6,8,16,16")])
[(set_attr "length" "4,6,8,16")])
(define_insn "mov<mode>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
@ -298,7 +298,7 @@
else if (which_alternative == 1 || which_alternative == 3)
return \"std %1, %0\";
else
return output_move_quad (operands); "
return output_move_multiple (operands); "
;; just a guess..
[(set_attr "length" "2,2,10,10,32")])
@ -311,7 +311,7 @@
else if (which_alternative == 1 || which_alternative == 3)
return \"{stcdf|movfo} %1, %0\";
else
return output_move_double (operands); "
return output_move_multiple (operands); "
;; just a guess..
[(set_attr "length" "2,2,10,10,16")])
@ -614,55 +614,79 @@
"{addd|addf} %2, %0"
[(set_attr "length" "2,4,10")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o,r,r,r,o,o,o")
(plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0,0,0,0,0,0,0")
(match_operand:SI 2 "general_operand" "r,o,r,o,I,J,K,I,J,K")))]
(define_insn "adddi3"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))]
""
"*
{ /* Here we trust that operands don't overlap
or is lateoperands the low word?? - looks like it! */
rtx lateoperands[3];
{
rtx inops[2];
rtx exops[4][2];
lateoperands[0] = operands[0];
if (REG_P (operands[0]))
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
else
operands[0] = adjust_address (operands[0], HImode, 2);
inops[0] = operands[0];
inops[1] = operands[2];
pdp11_expand_operands (inops, exops, 2, NULL, either);
if (! CONSTANT_P(operands[2]))
if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
output_asm_insn (\"add %1, %0\", exops[0]);
if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
{
lateoperands[2] = operands[2];
if (REG_P (operands[2]))
operands[2] = gen_rtx_REG (HImode, REGNO (operands[2]) + 1);
else
operands[2] = adjust_address (operands[2], HImode, 2);
output_asm_insn (\"add %2, %0\", operands);
output_asm_insn (\"adc %0\", lateoperands);
output_asm_insn (\"add %2, %0\", lateoperands);
return \"\";
output_asm_insn (\"add %1, %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
}
lateoperands[2] = GEN_INT ((INTVAL (operands[2]) >> 16) & 0xffff);
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
if (INTVAL(operands[2]))
{
output_asm_insn (\"add %2, %0\", operands);
output_asm_insn (\"adc %0\", lateoperands);
if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
{
output_asm_insn (\"add %1, %0\", exops[2]);
output_asm_insn (\"adc %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
}
if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
{
output_asm_insn (\"add %1, %0\", exops[3]);
output_asm_insn (\"adc %0\", exops[2]);
output_asm_insn (\"adc %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
}
if (INTVAL(lateoperands[2]))
output_asm_insn (\"add %2, %0\", lateoperands);
return \"\";
}"
[(set_attr "length" "6,10,12,16,6,2,10,10,6,16")])
[(set_attr "length" "20,28,40,48")])
;; Note that the register operand is not marked earlyclobber.
;; The reason is that SI values go in register pairs, so they
;; can't partially overlap. They can be either disjoint, or
;; source and destination can be equal. The latter case is
;; handled properly because of the ordering of the individual
;; instructions used. Specifically, carry from the low to the
;; high word is added at the end, so the adding of the high parts
;; will always used the original high part and not a high part
;; modified by carry (which would amount to double carry).
(define_insn "addsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
(plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))]
""
"*
{
rtx inops[2];
rtx exops[2][2];
inops[0] = operands[0];
inops[1] = operands[2];
pdp11_expand_operands (inops, exops, 2, NULL, either);
if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
output_asm_insn (\"add %1, %0\", exops[0]);
if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
{
output_asm_insn (\"add %1, %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
}
return \"\";
}"
[(set_attr "length" "6,10,12,16")])
(define_insn "addhi3"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
@ -697,38 +721,69 @@
"{subd|subf} %2, %0"
[(set_attr "length" "2,4")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
(match_operand:SI 2 "general_operand" "r,o,r,o")))]
(define_insn "subdi3"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))]
""
"*
{ /* Here we trust that operands don't overlap
or is lateoperands the low word?? - looks like it! */
rtx lateoperands[3];
{
rtx inops[2];
rtx exops[4][2];
lateoperands[0] = operands[0];
if (REG_P (operands[0]))
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
else
operands[0] = adjust_address (operands[0], HImode, 2);
inops[0] = operands[0];
inops[1] = operands[2];
pdp11_expand_operands (inops, exops, 2, NULL, either);
lateoperands[2] = operands[2];
if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
output_asm_insn (\"sub %1, %0\", exops[0]);
if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
{
output_asm_insn (\"sub %1, %0\", exops[1]);
output_asm_insn (\"sbc %0\", exops[0]);
}
if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
{
output_asm_insn (\"sub %1, %0\", exops[2]);
output_asm_insn (\"sbc %0\", exops[1]);
output_asm_insn (\"sbc %0\", exops[0]);
}
if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
{
output_asm_insn (\"sub %1, %0\", exops[3]);
output_asm_insn (\"sbc %0\", exops[2]);
output_asm_insn (\"sbc %0\", exops[1]);
output_asm_insn (\"sbc %0\", exops[0]);
}
return \"\";
}"
[(set_attr "length" "20,28,40,48")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))]
""
"*
{
rtx inops[2];
rtx exops[2][2];
inops[0] = operands[0];
inops[1] = operands[2];
pdp11_expand_operands (inops, exops, 2, NULL, either);
if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
output_asm_insn (\"sub %1, %0\", exops[0]);
if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
{
output_asm_insn (\"sub %1, %0\", exops[1]);
output_asm_insn (\"sbc %0\", exops[0]);
}
if (REG_P (operands[2]))
operands[2] = gen_rtx_REG (HImode, REGNO (operands[2]) + 1);
else
operands[2] = adjust_address (operands[2], HImode, 2);
output_asm_insn (\"sub %2, %0\", operands);
output_asm_insn (\"sbc %0\", lateoperands);
output_asm_insn (\"sub %2, %0\", lateoperands);
return \"\";
}"
;; offsettable memory addresses always are expensive!!!
[(set_attr "length" "6,10,12,16")])
(define_insn "subhi3"
@ -1070,60 +1125,6 @@
"{absd|absf} %0"
[(set_attr "length" "2,4")])
(define_insn "abshi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,o")
(abs:HI (match_operand:HI 1 "general_operand" "0,0")))]
""
"*
{
static int count = 0;
char buf[200];
output_asm_insn(\"tst %0\", operands);
sprintf(buf, \"bge abshi%d\", count);
output_asm_insn(buf, NULL);
output_asm_insn(\"neg %0\", operands);
sprintf(buf, \"\\nabshi%d:\", count++);
output_asm_insn(buf, NULL);
return \"\";
}"
[(set_attr "length" "6,10")])
;; define expand abshi - is much better !!! - but
;; will it be optimized into an abshi2 ?
;; it will leave better code, because the tsthi might be
;; optimized away!!
; -- just a thought - don't have time to check
;
;(define_expand "abshi2"
; [(match_operand:HI 0 "nonimmediate_operand" "")
; (match_operand:HI 1 "general_operand" "")]
; ""
; "
;{
; rtx label = gen_label_rtx ();
;
; /* do I need this? */
; do_pending_stack_adjust ();
;
; emit_move_insn (operands[0], operands[1]);
;
; emit_insn (gen_tsthi (operands[0]));
; emit_insn (gen_bge (label1));
;
; emit_insn (gen_neghi(operands[0], operands[0])
;
; emit_barrier ();
;
; emit_label (label);
;
; /* allow REG_NOTES to be set on last insn (labels don't have enough
; fields, and can't be used for REG_NOTES anyway). */
; emit_use (stack_pointer_rtx);
; DONE;
;}")
;; negate insns
@ -1134,41 +1135,51 @@
"{negd|negf} %0"
[(set_attr "length" "2,4")])
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "general_operand" "0")))]
(define_insn "negdi2"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
(neg:DI (match_operand:DI 1 "general_operand" "0,0")))]
""
{
rtx exops[4][2];
pdp11_expand_operands (operands, exops, 1, NULL, either);
rtx lateoperands[2];
lateoperands[0] = operands[0];
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
lateoperands[1] = operands[1];
operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
output_asm_insn (\"com %0\", lateoperands);
output_asm_insn (\"com %0\", operands);
output_asm_insn (\"add $1, %0\", operands);
output_asm_insn (\"adc %0\", lateoperands);
output_asm_insn (\"com %0\", exops[3]);
output_asm_insn (\"com %0\", exops[2]);
output_asm_insn (\"com %0\", exops[1]);
output_asm_insn (\"com %0\", exops[0]);
output_asm_insn (\"add $1, %0\", exops[3]);
output_asm_insn (\"adc %0\", exops[2]);
output_asm_insn (\"adc %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
return \"\";
}
[(set_attr "length" "14")])
[(set_attr "length" "18,34")])
(define_insn "neghi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(neg:HI (match_operand:HI 1 "general_operand" "0,0")))]
(define_insn "negsi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
(neg:SI (match_operand:SI 1 "general_operand" "0,0")))]
""
"neg %0"
[(set_attr "length" "2,4")])
{
rtx exops[2][2];
pdp11_expand_operands (operands, exops, 1, NULL, either);
(define_insn "negqi2"
[(set (match_operand:QI 0 "nonimmediate_operand" "=rR,Q")
(neg:QI (match_operand:QI 1 "general_operand" "0,0")))]
output_asm_insn (\"com %0\", exops[1]);
output_asm_insn (\"com %0\", exops[0]);
output_asm_insn (\"add $1, %0\", exops[1]);
output_asm_insn (\"adc %0\", exops[0]);
return \"\";
}
[(set_attr "length" "12,20")])
(define_insn "neg<mode>2"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
""
"negb %0"
"neg<isfx> %0"
[(set_attr "length" "2,4")])