aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/mn10300/mn10300.c171
-rw-r--r--gcc/config/mn10300/mn10300.h23
-rw-r--r--gcc/config/mn10300/mn10300.md383
3 files changed, 491 insertions, 86 deletions
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 1ae2a27..10e7ae3 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -1,5 +1,5 @@
/* Subroutines for insn-output.c for Matsushita MN10300 series
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GNU CC.
@@ -36,6 +36,26 @@ Boston, MA 02111-1307, USA. */
#include "tree.h"
#include "obstack.h"
+/* Global registers known to hold the value zero.
+
+ Normally we'd depend on CSE and combine to put zero into a
+ register and re-use it.
+
+ However, on the mn10x00 processors we implicitly use the constant
+ zero in tst instructions, so we might be able to do better by
+ loading the value into a register in the prologue, then re-useing
+ that register throughout the function.
+
+ We could perform similar optimizations for other constants, but with
+ gcse due soon, it doesn't seem worth the effort.
+
+ These variables hold a rtx for a register known to hold the value
+ zero throughout the entire function, or NULL if no register of
+ the appropriate class has such a value throughout the life of the
+ function. */
+rtx zero_dreg;
+rtx zero_areg;
+
void
asm_file_start (file)
FILE *file;
@@ -339,15 +359,124 @@ can_use_return_insn ()
&& !frame_pointer_needed);
}
+/* Count the number of tst insns which compare a data or address
+ register with zero. */
+static void
+count_tst_insns (dreg_countp, areg_countp)
+ int *dreg_countp;
+ int *areg_countp;
+{
+ rtx insn;
+
+ /* Assume no tst insns exist. */
+ *dreg_countp = 0;
+ *areg_countp = 0;
+
+ /* If not optimizing, then quit now. */
+ if (!optimize)
+ return;
+
+ /* Walk through all the insns. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ rtx pat;
+
+ /* Ignore anything that is not a normal INSN. */
+ if (GET_CODE (insn) != INSN)
+ continue;
+
+ /* Ignore anything that isn't a SET. */
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) != SET)
+ continue;
+
+ /* Check for a tst insn. */
+ if (SET_DEST (pat) == cc0_rtx
+ && GET_CODE (SET_SRC (pat)) == REG)
+ {
+ if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == DATA_REGS)
+ (*dreg_countp)++;
+
+ if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS)
+ (*areg_countp)++;
+ }
+
+ /* Setting an address register to zero can also be optimized,
+ so count it just like a tst insn. */
+ if (GET_CODE (SET_DEST (pat)) == REG
+ && GET_CODE (SET_SRC (pat)) == CONST_INT
+ && INTVAL (SET_SRC (pat)) == 0
+ && REGNO_REG_CLASS (REGNO (SET_DEST (pat))) == ADDRESS_REGS)
+ (*areg_countp)++;
+ }
+}
+
void
expand_prologue ()
{
unsigned int size;
- /* We have to end the current sequence so leaf_function_p will
- work. We then start a new sequence to hold the prologue/epilogue. */
+ /* We have to end the current sequence so leaf_function_p and
+ count_tst_insns will work. We then start a new sequence to
+ hold the prologue/epilogue. */
end_sequence ();
+ /* Determine if it is profitable to put the value zero into a register
+ for the entire function. If so, set ZERO_DREG and ZERO_AREG. */
+ if (regs_ever_live[2] || regs_ever_live[3]
+ || regs_ever_live[6] || regs_ever_live[7]
+ || frame_pointer_needed)
+ {
+ int dreg_count, areg_count;
+
+ /* Get a count of the number of tst insns which use address and
+ data registers. */
+ count_tst_insns (&dreg_count, &areg_count);
+
+ /* If there's more than one tst insn using a data register, then
+ this optimization is a win. */
+ if (dreg_count > 1
+ && (!regs_ever_live[2] || !regs_ever_live[3]))
+ {
+ if (!regs_ever_live[2])
+ {
+ regs_ever_live[2] = 1;
+ zero_dreg = gen_rtx (REG, SImode, 2);
+ }
+ else
+ {
+ regs_ever_live[3] = 1;
+ zero_dreg = gen_rtx (REG, SImode, 3);
+ }
+ }
+ else
+ zero_dreg = NULL_RTX;
+
+ /* If there's more than two tst insns using an address register,
+ then this optimization is a win. */
+ if (areg_count > 2
+ && (!regs_ever_live[6] || !regs_ever_live[7]))
+ {
+ if (!regs_ever_live[6])
+ {
+ regs_ever_live[6] = 1;
+ zero_areg = gen_rtx (REG, SImode, 6);
+ }
+ else
+ {
+ regs_ever_live[7] = 1;
+ zero_areg = gen_rtx (REG, SImode, 7);
+ }
+ }
+ else
+ zero_areg = NULL_RTX;
+ }
+ else
+ {
+ zero_dreg = NULL_RTX;
+ zero_areg = NULL_RTX;
+ }
+
/* SIZE includes the fixed stack space needed for function calls. */
size = get_frame_size () + (!leaf_function_p () ? 12 : 0);
@@ -384,6 +513,13 @@ expand_prologue ()
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-size)));
+
+ /* Load zeros into registers as needed. */
+ if (zero_dreg)
+ emit_move_insn (zero_dreg, const0_rtx);
+
+ if (zero_areg)
+ emit_move_insn (zero_areg, const0_rtx);
}
void
@@ -713,14 +849,36 @@ char *
output_tst (operand, insn)
rtx operand, insn;
{
-
rtx temp;
int past_call = 0;
+ /* If we have a data register which is known to be zero throughout
+ the function, then use it instead of doing a search. */
+ if (zero_dreg && REGNO_REG_CLASS (REGNO (operand)) == DATA_REGS)
+ {
+ rtx xoperands[2];
+ xoperands[0] = operand;
+ xoperands[1] = zero_dreg;
+
+ output_asm_insn ("cmp %1,%0", xoperands);
+ return "";
+ }
+
+ /* Similarly for address registers. */
+ if (zero_areg && REGNO_REG_CLASS (REGNO (operand)) == ADDRESS_REGS)
+ {
+ rtx xoperands[2];
+ xoperands[0] = operand;
+ xoperands[1] = zero_areg;
+
+ output_asm_insn ("cmp %1,%0", xoperands);
+ return "";
+ }
+
/* We can save a byte if we can find a register which has the value
zero in it. */
temp = PREV_INSN (insn);
- while (temp)
+ while (optimize && temp)
{
rtx set;
@@ -759,7 +917,8 @@ output_tst (operand, insn)
if (REG_P (SET_DEST (set))
&& SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
&& !reg_set_between_p (SET_DEST (set), temp, insn)
- && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == DATA_REGS
+ && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
+ == REGNO_REG_CLASS (REGNO (operand)))
&& REGNO (SET_DEST (set)) != REGNO (operand)
&& (!past_call
|| !call_used_regs[REGNO (SET_DEST (set))]))
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index d850641..c36c6c4 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler.
Matsushita MN10300 series
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GNU CC.
@@ -37,6 +37,10 @@ Boston, MA 02111-1307, USA. */
extern int target_flags;
+/* Global registers known to hold the value zero. */
+extern struct rtx_def *zero_dreg;
+extern struct rtx_def *zero_areg;
+
/* Macros used in the machine description to test the flags. */
/* Macro to define tables used to set the flags.
@@ -404,8 +408,7 @@ enum reg_class {
OFFSET = initial_offset (FROM, TO)
#define FRAME_POINTER_REQUIRED \
- !(leaf_function_p ())
-
+ !(leaf_function_p () || current_function_outgoing_args_size == 0)
#define CAN_DEBUG_WITHOUT_FP
/* A guess for the MN10300. */
@@ -562,6 +565,20 @@ extern struct rtx_def *function_arg ();
emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x18)), \
(FNADDR)); \
}
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame.
+
+ On the mn10300, the return address is not at a constant location
+ due to the frame layout. Luckily, it is at a constant offset from
+ the argument pointer, so we define RETURN_ADDR_RTX to return a
+ MEM using arg_pointer_rtx. Reload will replace arg_pointer_rtx
+ with a reference to the stack/frame pointer + an appropriate offset. */
+
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ ((COUNT == 0) \
+ ? gen_rtx (MEM, Pmode, arg_pointer_rtx) \
+ : (rtx) 0)
+
/* Emit code for a call to builtin_saveregs. We must emit USE insns which
reference the 2 integer arg registers.
Ordinarily they are not call used registers, but they are for
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 98f4536..13628ecf 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1,4 +1,4 @@
-;; GCC machine description for Matsushita MN10300
+; GCC machine description for Matsushita MN10300
;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
;; Contributed by Jeff Law (law@cygnus.com).
@@ -59,21 +59,45 @@
}")
(define_insn ""
- [(set (match_operand:QI 0 "general_operand" "=d,a,d,d,a,d,a,d,m")
- (match_operand:QI 1 "general_operand" "0,0,I,a,d,di,ia,m,d"))]
+ [(set (match_operand:QI 0 "general_operand" "=d,a,d,a,d,a,d,a,d,m")
+ (match_operand:QI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))]
"register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)"
- "@
- nop
- nop
- clr %0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- movbu %1,%0
- movbu %1,%0"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ return \"nop\";
+ case 2:
+ return \"clr %0\";
+ case 3:
+ if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %1,%0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%0\", xoperands);
+ return \"\";
+ }
+
+ /* FALLTHROUGH */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return \"mov %1,%0\";
+ case 8:
+ case 9:
+ return \"movbu %1,%0\";
+ }
+}"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
;; movhi
@@ -90,21 +114,45 @@
}")
(define_insn ""
- [(set (match_operand:HI 0 "general_operand" "=d,a,d,d,a,d,a,d,m")
- (match_operand:HI 1 "general_operand" "0,0,I,a,d,di,ia,m,d"))]
+ [(set (match_operand:HI 0 "general_operand" "=d,a,d,a,d,a,d,a,d,m")
+ (match_operand:HI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))]
"register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode)"
- "@
- nop
- nop
- clr %0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- movhu %1,%0
- movhu %1,%0"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ return \"nop\";
+ case 2:
+ return \"clr %0\";
+ case 3:
+ if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %1,%0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%0\", xoperands);
+ return \"\";
+ }
+
+ /* FALLTHROUGH */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return \"mov %1,%0\";
+ case 8:
+ case 9:
+ return \"movhu %1,%0\";
+ }
+}"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
;; movsi and helpers
@@ -121,25 +169,50 @@
}")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a,aR,x")
- (match_operand:SI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim,x,aR"))]
+ [(set (match_operand:SI 0 "general_operand"
+ "=d,a,d,a,dm,dm,am,am,d,d,a,a,aR,x")
+ (match_operand:SI 1 "general_operand"
+ "0,0,I,I,d,a,d,a,dim,aim,dim,aim,x,aR"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
- "@
- nop
- nop
- clr %0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0
- mov %1,%0"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ return \"nop\";
+ case 2:
+ return \"clr %0\";
+ case 3:
+ if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %1,%0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%0\", xoperands);
+ return \"\";
+ }
+
+ /* FALLTHROUGH */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ return \"mov %1,%0\";
+ }
+}"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
@@ -154,17 +227,40 @@
}")
(define_insn ""
- [(set (match_operand:SF 0 "general_operand" "=d,a,d,dam,da")
- (match_operand:SF 1 "general_operand" "0,0,G,da,daim"))]
+ [(set (match_operand:SF 0 "general_operand" "=d,a,d,a,dam,da")
+ (match_operand:SF 1 "general_operand" "0,0,G,G,da,daim"))]
"register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)"
- "@
- nop
- nop
- clr %0
- mov %1,%0
- mov %1,%0"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit")])
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ return \"nop\";
+ case 2:
+ return \"clr %0\";
+ case 3:
+ if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %1,%0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%0\", xoperands);
+ return \"\";
+ }
+
+ /* FALLTHROUGH */
+ case 4:
+ case 5:
+ return \"mov %1,%0\";
+ }
+}"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit")])
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
@@ -179,8 +275,10 @@
}")
(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
- (match_operand:DI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim"))]
+ [(set (match_operand:DI 0 "general_operand"
+ "=d,a,d,a,dm,dm,am,am,d,d,a,a")
+ (match_operand:DI 1 "general_operand"
+ "0,0,I,I,d,a,d,a,dim,aim,dim,aim"))]
"register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)"
"*
@@ -198,6 +296,17 @@
return \"clr %L0\;clr %H0\";
case 3:
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg ? zero_areg : operands[1];
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
+ return \"\";
+ }
case 4:
case 5:
case 6:
@@ -205,6 +314,7 @@
case 8:
case 9:
case 10:
+ case 11:
if (GET_CODE (operands[1]) == CONST_INT)
{
val[0] = INTVAL (operands[1]);
@@ -243,28 +353,75 @@
return \"mov %L1,%L0\;mov %H1,%H0\";
}
+ else if (GET_CODE (operands[1]) == MEM
+ && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
+ && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = XEXP (operands[1], 0);
+
+ output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
+ xoperands);
+ return \"\";
+ }
else
{
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == 0
- && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %L0\", operands);
+ && val[0] == 0)
+ {
+ if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+ output_asm_insn (\"clr %L0\", operands);
+ else if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %L0,%L0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%L0\", xoperands);
+ }
+ else
+ output_asm_insn (\"mov %L1,%L0\", operands);
+ }
else
output_asm_insn (\"mov %L1,%L0\", operands);
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[1] == 0
- && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %H0\", operands);
+ && val[1] == 0)
+ {
+ if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+ output_asm_insn (\"clr %H0\", operands);
+ else if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %H0,%H0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%H0\", xoperands);
+ }
+ else
+ output_asm_insn (\"mov %H1,%H0\", operands);
+ }
+ else if ((GET_CODE (operands[1]) == CONST_INT
+ || GET_CODE (operands[1]) == CONST_DOUBLE)
+ && val[0] == val[1])
+ output_asm_insn (\"mov %L0,%H0\", operands);
else
output_asm_insn (\"mov %H1,%H0\", operands);
return \"\";
}
}
}"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
@@ -279,8 +436,10 @@
}")
(define_insn ""
- [(set (match_operand:DF 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
- (match_operand:DF 1 "general_operand" "0,0,G,d,a,d,a,dim,aim,dim,aim"))]
+ [(set (match_operand:DF 0 "general_operand"
+ "=d,a,d,a,dm,dm,am,am,d,d,a,a")
+ (match_operand:DF 1 "general_operand"
+ "0,0,G,G,d,a,d,a,dim,aim,dim,aim"))]
"register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode)"
"*
@@ -298,6 +457,17 @@
return \"clr %L0\;clr %H0\";
case 3:
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg ? zero_areg : operands[1];
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
+ return \"\";
+ }
case 4:
case 5:
case 6:
@@ -305,6 +475,7 @@
case 8:
case 9:
case 10:
+ case 11:
if (GET_CODE (operands[1]) == CONST_INT)
{
val[0] = INTVAL (operands[1]);
@@ -343,28 +514,75 @@
return \"mov %L1,%L0\;mov %H1,%H0\";
}
+ else if (GET_CODE (operands[1]) == MEM
+ && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
+ && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = XEXP (operands[1], 0);
+
+ output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
+ xoperands);
+ return \"\";
+ }
else
{
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[0] == 0
- && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %L0\", operands);
+ && val[0] == 0)
+ {
+ if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+ output_asm_insn (\"clr %L0\", operands);
+ else if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %L0,%L0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%L0\", xoperands);
+ }
+ else
+ output_asm_insn (\"mov %L1,%L0\", operands);
+ }
else
output_asm_insn (\"mov %L1,%L0\", operands);
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
- && val[1] == 0
- && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
- output_asm_insn (\"clr %H0\", operands);
+ && val[1] == 0)
+ {
+ if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
+ output_asm_insn (\"clr %H0\", operands);
+ else if (zero_areg)
+ {
+ rtx xoperands[2];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = zero_areg;
+ if (rtx_equal_p (xoperands[0], xoperands[1]))
+ output_asm_insn (\"sub %H0,%H0\", xoperands);
+ else
+ output_asm_insn (\"mov %1,%H0\", xoperands);
+ }
+ else
+ output_asm_insn (\"mov %H1,%H0\", operands);
+ }
+ else if ((GET_CODE (operands[1]) == CONST_INT
+ || GET_CODE (operands[1]) == CONST_DOUBLE)
+ && val[0] == val[1])
+ output_asm_insn (\"mov %L0,%H0\", operands);
else
output_asm_insn (\"mov %H1,%H0\", operands);
return \"\";
}
}
}"
- [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
@@ -428,17 +646,18 @@
}")
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=d,a,a,da,x")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
- (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i")))]
+ [(set (match_operand:SI 0 "register_operand" "=d,a,a,da,x,!&da")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,da")
+ (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i,da")))]
""
"@
inc %0
inc %0
inc4 %0
add %2,%0
- add %2,%0"
- [(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit")])
+ add %2,%0
+ mov %2,%0\;add %1,%0"
+ [(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit,none_0hit")])
(define_expand "adddi3"
[(set (reg:DI 0) (match_operand:DI 1 "register_operand" ""))
@@ -1131,7 +1350,17 @@
(define_insn "return"
[(return)]
"can_use_return_insn ()"
- "rets"
+ "*
+{
+ rtx next = next_active_insn (insn);
+
+ if (next
+ && GET_CODE (next) == JUMP_INSN
+ && GET_CODE (PATTERN (next)) == RETURN)
+ return \"\";
+ else
+ return \"rets\";
+}"
[(set_attr "cc" "clobber")])
;; Try to combine consecutive updates of the stack pointer (or any