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:
parent
a23980bdb6
commit
30442c59aa
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")])
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue