2a887ba076
gnu/dist/gcc/config/sh/sh.c rev. 1.7 sh.h rev. 1.5 sh.md rev. 1.7
746 lines
25 KiB
Text
746 lines
25 KiB
Text
--- gcc/config/sh/sh.c.orig Wed Feb 24 10:44:34 1999
|
||
+++ gcc/config/sh/sh.c Mon Jan 22 21:09:51 2001
|
||
@@ -22,6 +22,8 @@
|
||
Improved by Jim Wilson (wilson@cygnus.com). */
|
||
|
||
#include "config.h"
|
||
+#include "system.h"
|
||
+#include "insn-config.h"
|
||
|
||
#include <stdio.h>
|
||
|
||
@@ -29,11 +31,15 @@
|
||
#include "tree.h"
|
||
#include "flags.h"
|
||
#include "insn-flags.h"
|
||
+#include "except.h"
|
||
#include "expr.h"
|
||
+#include "function.h"
|
||
#include "regs.h"
|
||
#include "hard-reg-set.h"
|
||
#include "output.h"
|
||
#include "insn-attr.h"
|
||
+#include "toplev.h"
|
||
+#include "recog.h"
|
||
|
||
int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
|
||
|
||
@@ -131,7 +137,8 @@
|
||
switch (GET_CODE (x))
|
||
{
|
||
case REG:
|
||
- fprintf (stream, "@%s", reg_names[REGNO (x)]);
|
||
+ case SUBREG:
|
||
+ fprintf (stream, "@%s", reg_names[true_regnum (x)]);
|
||
break;
|
||
|
||
case PLUS:
|
||
@@ -143,13 +150,19 @@
|
||
{
|
||
case CONST_INT:
|
||
fprintf (stream, "@(%d,%s)", INTVAL (index),
|
||
- reg_names[REGNO (base)]);
|
||
+ reg_names[true_regnum (base)]);
|
||
break;
|
||
|
||
case REG:
|
||
- fprintf (stream, "@(r0,%s)",
|
||
- reg_names[MAX (REGNO (base), REGNO (index))]);
|
||
+ case SUBREG:
|
||
+ {
|
||
+ int base_num = true_regnum (base);
|
||
+ int index_num = true_regnum (index);
|
||
+
|
||
+ fprintf (stream, "@(r0,%s)",
|
||
+ reg_names[MAX (base_num,index_num)]);
|
||
break;
|
||
+ }
|
||
|
||
default:
|
||
debug_rtx (x);
|
||
@@ -159,11 +172,11 @@
|
||
break;
|
||
|
||
case PRE_DEC:
|
||
- fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
|
||
+ fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]);
|
||
break;
|
||
|
||
case POST_INC:
|
||
- fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
|
||
+ fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]);
|
||
break;
|
||
|
||
default:
|
||
@@ -230,16 +243,31 @@
|
||
fputs (reg_names[REGNO (x) + 1], (stream));
|
||
break;
|
||
case MEM:
|
||
- print_operand_address (stream,
|
||
- XEXP (adj_offsettable_operand (x, 4), 0));
|
||
+ if (GET_CODE (XEXP (x, 0)) != PRE_DEC
|
||
+ && GET_CODE (XEXP (x, 0)) != POST_INC)
|
||
+ x = adj_offsettable_operand (x, 4);
|
||
+ print_operand_address (stream, XEXP (x, 0));
|
||
break;
|
||
}
|
||
break;
|
||
+ case 'o':
|
||
+ switch (GET_CODE (x))
|
||
+ {
|
||
+ case PLUS: fputs ("add", stream); break;
|
||
+ case MINUS: fputs ("sub", stream); break;
|
||
+ case MULT: fputs ("mul", stream); break;
|
||
+ case DIV: fputs ("div", stream); break;
|
||
+ }
|
||
+ break;
|
||
default:
|
||
switch (GET_CODE (x))
|
||
{
|
||
case REG:
|
||
- fputs (reg_names[REGNO (x)], (stream));
|
||
+ if (REGNO (x) >= FIRST_FP_REG && REGNO (x) <= LAST_FP_REG
|
||
+ && GET_MODE_SIZE (GET_MODE (x)) > 4)
|
||
+ fprintf ((stream), "d%s", reg_names[REGNO (x)]+1);
|
||
+ else
|
||
+ fputs (reg_names[REGNO (x)], (stream));
|
||
break;
|
||
case MEM:
|
||
output_address (XEXP (x, 0));
|
||
@@ -402,6 +430,7 @@
|
||
if ((code != EQ && code != NE
|
||
&& (sh_compare_op1 != const0_rtx
|
||
|| code == GTU || code == GEU || code == LTU || code == LEU))
|
||
+ || (mode == DImode && sh_compare_op1 != const0_rtx)
|
||
|| TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT)
|
||
sh_compare_op1 = force_reg (mode, sh_compare_op1);
|
||
|
||
@@ -694,9 +723,9 @@
|
||
|
||
char *
|
||
output_ieee_ccmpeq (insn, operands)
|
||
- rtx insn, operands;
|
||
+ rtx insn, *operands;
|
||
{
|
||
- output_branchy_insn (NE, "bt\t%l9\\;fcmp/eq\t%1,%0", insn, operands);
|
||
+ return output_branchy_insn (NE, "bt\t%l9\\;fcmp/eq\t%1,%0", insn, operands);
|
||
}
|
||
|
||
/* Output to FILE the start of the assembler file. */
|
||
@@ -1602,8 +1631,16 @@
|
||
case 5:
|
||
{
|
||
int i = 16 - size;
|
||
- emit_insn (gen_shl_sext_ext (dest, source, GEN_INT (16 - insize),
|
||
- GEN_INT (16)));
|
||
+ if (! rtx_equal_function_value_matters
|
||
+ && ! reload_in_progress && ! reload_completed)
|
||
+ emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
|
||
+ else
|
||
+ {
|
||
+ operands[0] = dest;
|
||
+ operands[2] = GEN_INT (16 - insize);
|
||
+ gen_shifty_hi_op (ASHIFT, operands);
|
||
+ emit_insn (gen_extendhisi2 (dest, gen_lowpart (HImode, dest)));
|
||
+ }
|
||
/* Don't use gen_ashrsi3 because it generates new pseudos. */
|
||
while (--i >= 0)
|
||
gen_ashift (ASHIFTRT, 1, dest);
|
||
@@ -2124,7 +2161,7 @@
|
||
for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
|
||
{
|
||
part = XVECEXP (pattern, 0, i);
|
||
- if (part == reg_part)
|
||
+ if (part == reg_part || GET_CODE (part) == CLOBBER)
|
||
continue;
|
||
if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
|
||
&& GET_CODE (SET_DEST (part)) == REG)
|
||
@@ -2464,6 +2501,13 @@
|
||
}
|
||
else
|
||
jump = emit_jump_insn_after (gen_return (), insn);
|
||
+ /* Emit a barrier so that reorg knows that any following instructions
|
||
+ are not reachable via a fall-through path.
|
||
+ But don't do this when not optimizing, since we wouldn't supress the
|
||
+ alignment for the barrier then, and could end up with out-of-range
|
||
+ pc-relative loads. */
|
||
+ if (optimize)
|
||
+ emit_barrier_after (jump);
|
||
emit_label_after (bp->near_label, insn);
|
||
JUMP_LABEL (jump) = bp->far_label;
|
||
if (! invert_jump (insn, label))
|
||
@@ -2481,7 +2525,7 @@
|
||
|
||
for (insn = first; insn; insn = NEXT_INSN (insn))
|
||
{
|
||
- rtx vec_lab, pat, prev, prevpat, x;
|
||
+ rtx vec_lab, pat, prev, prevpat, x, braf_label;
|
||
|
||
if (GET_CODE (insn) != JUMP_INSN
|
||
|| GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
|
||
@@ -2504,10 +2548,15 @@
|
||
if (GET_CODE (x) == LABEL_REF && XEXP (x, 0) == vec_lab)
|
||
break;
|
||
}
|
||
+
|
||
+ /* Emit the reference label of the braf where it belongs, right after
|
||
+ the casesi_jump_2 (i.e. braf). */
|
||
+ braf_label = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
|
||
+ emit_label_after (braf_label, prev);
|
||
+
|
||
/* Fix up the ADDR_DIF_VEC to be relative
|
||
to the reference address of the braf. */
|
||
- XEXP (XEXP (pat, 0), 0)
|
||
- = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
|
||
+ XEXP (XEXP (pat, 0), 0) = braf_label;
|
||
}
|
||
}
|
||
|
||
--- gcc/config/sh/sh.h.orig Mon Jun 1 23:25:44 1998
|
||
+++ gcc/config/sh/sh.h Mon Jan 22 21:09:51 2001
|
||
@@ -1143,7 +1143,8 @@
|
||
else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \
|
||
&& BASE_REGISTER_RTX_P (XEXP ((X), 0))) \
|
||
goto LABEL; \
|
||
- else if (GET_CODE (X) == PLUS && MODE != PSImode) \
|
||
+ else if (GET_CODE (X) == PLUS \
|
||
+ && ((MODE) != PSImode || reload_completed)) \
|
||
{ \
|
||
rtx xop0 = XEXP ((X), 0); \
|
||
rtx xop1 = XEXP ((X), 1); \
|
||
@@ -1465,7 +1466,7 @@
|
||
and another. */
|
||
|
||
#define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
|
||
- ((DSTCLASS) == PR_REG ? 10 \
|
||
+ ((DSTCLASS) == PR_REGS ? 10 \
|
||
: (((DSTCLASS) == FP_REGS && (SRCCLASS) == GENERAL_REGS) \
|
||
|| ((DSTCLASS) == GENERAL_REGS && (SRCCLASS) == FP_REGS)) ? 4 \
|
||
: 1)
|
||
@@ -1566,10 +1567,10 @@
|
||
}
|
||
|
||
#define ASM_OUTPUT_REG_PUSH(file, v) \
|
||
- fprintf ((file), "\tmov.l\tr%s,-@r15\n", (v));
|
||
+ fprintf ((file), "\tmov.l\tr%d,@-r15\n", (v));
|
||
|
||
#define ASM_OUTPUT_REG_POP(file, v) \
|
||
- fprintf ((file), "\tmov.l\t@r15+,r%s\n", (v));
|
||
+ fprintf ((file), "\tmov.l\t@r15+,r%d\n", (v));
|
||
|
||
/* The assembler's names for the registers. RFP need not always be used as
|
||
the Real framepointer; it can also be used as a normal general register.
|
||
@@ -1957,3 +1958,5 @@
|
||
#define HAVE_ATEXIT
|
||
|
||
#define SH_DYNAMIC_SHIFT_COST (TARGET_SH3 ? (TARGET_SMALLCODE ? 1 : 2) : 20)
|
||
+
|
||
+#define DWARF_LINE_MIN_INSTR_LENGTH 2
|
||
--- gcc/config/sh/sh.md.orig Thu Apr 23 22:37:16 1998
|
||
+++ gcc/config/sh/sh.md Mon Jan 22 21:09:51 2001
|
||
@@ -661,7 +661,7 @@
|
||
;; This reload would clobber the value in r0 we are trying to store.
|
||
;; If we let reload allocate r0, then this problem can never happen.
|
||
|
||
-(define_insn ""
|
||
+(define_insn "udivsi3_i1"
|
||
[(set (match_operand:SI 0 "register_operand" "=z")
|
||
(udiv:SI (reg:SI 4) (reg:SI 5)))
|
||
(clobber (reg:SI 18))
|
||
@@ -674,9 +674,9 @@
|
||
(set_attr "needs_delay_slot" "yes")])
|
||
|
||
(define_expand "udivsi3"
|
||
- [(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
|
||
+ [(set (match_dup 3) (symbol_ref:SI "__udivsi3"))
|
||
+ (set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
|
||
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
|
||
- (set (match_dup 3) (symbol_ref:SI "__udivsi3"))
|
||
(parallel [(set (match_operand:SI 0 "register_operand" "")
|
||
(udiv:SI (reg:SI 4)
|
||
(reg:SI 5)))
|
||
@@ -685,9 +685,26 @@
|
||
(clobber (reg:SI 4))
|
||
(use (match_dup 3))])]
|
||
""
|
||
- "operands[3] = gen_reg_rtx(SImode);")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
|
||
-(define_insn ""
|
||
+ operands[3] = gen_reg_rtx(SImode);
|
||
+ /* Emit the move of the address to a pseudo outside of the libcall. */
|
||
+ emit_move_insn (operands[3],
|
||
+ gen_rtx_SYMBOL_REF (SImode, \"__udivsi3\"));
|
||
+ last = gen_udivsi3_i1 (operands[0], operands[3]);
|
||
+ first = emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
|
||
+ emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]);
|
||
+ last = emit_insn (last);
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
+
|
||
+(define_insn "divsi3_i1"
|
||
[(set (match_operand:SI 0 "register_operand" "=z")
|
||
(div:SI (reg:SI 4) (reg:SI 5)))
|
||
(clobber (reg:SI 18))
|
||
@@ -702,9 +719,9 @@
|
||
(set_attr "needs_delay_slot" "yes")])
|
||
|
||
(define_expand "divsi3"
|
||
- [(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
|
||
+ [(set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
|
||
+ (set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
|
||
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
|
||
- (set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
|
||
(parallel [(set (match_operand:SI 0 "register_operand" "")
|
||
(div:SI (reg:SI 4)
|
||
(reg:SI 5)))
|
||
@@ -715,13 +732,29 @@
|
||
(clobber (reg:SI 3))
|
||
(use (match_dup 3))])]
|
||
""
|
||
- "operands[3] = gen_reg_rtx(SImode);")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
+
|
||
+ operands[3] = gen_reg_rtx(SImode);
|
||
+ /* Emit the move of the address to a pseudo outside of the libcall. */
|
||
+ emit_move_insn (operands[3], gen_rtx_SYMBOL_REF (SImode, \"__sdivsi3\"));
|
||
+ last = gen_divsi3_i1 (operands[0], operands[3]);
|
||
+ first = emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
|
||
+ emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]);
|
||
+ last = emit_insn (last);
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
|
||
;; -------------------------------------------------------------------------
|
||
;; Multiplication instructions
|
||
;; -------------------------------------------------------------------------
|
||
|
||
-(define_insn ""
|
||
+(define_insn "umulhisi3_i"
|
||
[(set (reg:SI 21)
|
||
(mult:SI (zero_extend:SI (match_operand:HI 0 "arith_reg_operand" "r"))
|
||
(zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r"))))]
|
||
@@ -729,7 +762,7 @@
|
||
"mulu %1,%0"
|
||
[(set_attr "type" "smpy")])
|
||
|
||
-(define_insn ""
|
||
+(define_insn "mulhisi3_i"
|
||
[(set (reg:SI 21)
|
||
(mult:SI (sign_extend:SI
|
||
(match_operand:HI 0 "arith_reg_operand" "r"))
|
||
@@ -748,7 +781,18 @@
|
||
(set (match_operand:SI 0 "arith_reg_operand" "")
|
||
(reg:SI 21))]
|
||
""
|
||
- "")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
+
|
||
+ first = emit_insn (gen_mulhisi3_i (operands[1], operands[2]));
|
||
+ last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 21));
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
|
||
(define_expand "umulhisi3"
|
||
[(set (reg:SI 21)
|
||
@@ -759,7 +803,18 @@
|
||
(set (match_operand:SI 0 "arith_reg_operand" "")
|
||
(reg:SI 21))]
|
||
""
|
||
- "")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
+
|
||
+ first = emit_insn (gen_umulhisi3_i (operands[1], operands[2]));
|
||
+ last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 21));
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
|
||
;; mulsi3 on the SH2 can be done in one instruction, on the SH1 we generate
|
||
;; a call to a routine which clobbers known registers.
|
||
@@ -782,7 +837,6 @@
|
||
(define_expand "mulsi3_call"
|
||
[(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
|
||
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
|
||
- (set (match_dup 3) (symbol_ref:SI "__mulsi3"))
|
||
(parallel[(set (match_operand:SI 0 "register_operand" "")
|
||
(mult:SI (reg:SI 4)
|
||
(reg:SI 5)))
|
||
@@ -792,9 +846,9 @@
|
||
(clobber (reg:SI 3))
|
||
(clobber (reg:SI 2))
|
||
(clobber (reg:SI 1))
|
||
- (use (match_dup 3))])]
|
||
+ (use (match_operand:SI 3 "register_operand" ""))])]
|
||
""
|
||
- "operands[3] = gen_reg_rtx(SImode);")
|
||
+ "")
|
||
|
||
(define_insn "mul_l"
|
||
[(set (reg:SI 21)
|
||
@@ -813,82 +867,120 @@
|
||
""
|
||
"
|
||
{
|
||
+ rtx first, last;
|
||
+
|
||
if (!TARGET_SH2)
|
||
{
|
||
- FAIL;
|
||
- /* ??? Does this give worse or better code? */
|
||
- emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2]));
|
||
- DONE;
|
||
+ /* The address must be set outside the libcall,
|
||
+ since it goes into a pseudo. */
|
||
+ rtx addr = force_reg (SImode, gen_rtx_SYMBOL_REF (SImode, \"__mulsi3\"));
|
||
+ rtx insns = gen_mulsi3_call (operands[0], operands[1], operands[2], addr);
|
||
+ first = XVECEXP (insns, 0, 0);
|
||
+ last = XVECEXP (insns, 0, XVECLEN (insns, 0) - 1);
|
||
+ emit_insn (insns);
|
||
}
|
||
+ else
|
||
+ {
|
||
+ rtx macl = gen_rtx_REG (SImode, MACL_REG);
|
||
+
|
||
+ first = emit_insn (gen_mul_l (operands[1], operands[2]));
|
||
+ /* consec_sets_giv can only recognize the first insn that sets a
|
||
+ giv as the giv insn. So we must tag this also with a REG_EQUAL
|
||
+ note. */
|
||
+ last = emit_insn (gen_movsi_i ((operands[0]), macl));
|
||
+ }
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
}")
|
||
|
||
(define_insn "mulsidi3_i"
|
||
- [(set (reg:DI 20)
|
||
- (mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
- (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))))]
|
||
+ [(set (reg:SI 20)
|
||
+ (truncate:SI
|
||
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
+ (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r")))
|
||
+ (const_int 32))))
|
||
+ (set (reg:SI 21)
|
||
+ (mult:SI (match_dup 0)
|
||
+ (match_dup 1)))]
|
||
"TARGET_SH2"
|
||
"dmuls.l %1,%0"
|
||
[(set_attr "type" "dmpy")])
|
||
|
||
-(define_expand "mulsidi3"
|
||
- [(set (reg:DI 20)
|
||
+(define_insn "mulsidi3"
|
||
+ [(set (match_operand:DI 0 "arith_reg_operand" "=r")
|
||
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
|
||
+ (sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
|
||
+ (clobber (reg:DI 20))]
|
||
+ "TARGET_SH2"
|
||
+ "#")
|
||
+
|
||
+(define_split
|
||
+ [(set (match_operand:DI 0 "arith_reg_operand" "")
|
||
(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
|
||
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
|
||
- (set (match_operand:DI 0 "arith_reg_operand" "")
|
||
- (reg:DI 20))]
|
||
+ (clobber (reg:DI 20))]
|
||
"TARGET_SH2"
|
||
+ [(const_int 0)]
|
||
"
|
||
{
|
||
- /* We must swap the two words when copying them from MACH/MACL to the
|
||
- output register. */
|
||
- if (TARGET_LITTLE_ENDIAN)
|
||
- {
|
||
- rtx low_dst = operand_subword (operands[0], 0, 1, DImode);
|
||
- rtx high_dst = operand_subword (operands[0], 1, 1, DImode);
|
||
-
|
||
- emit_insn (gen_mulsidi3_i (operands[1], operands[2]));
|
||
-
|
||
- emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0]));
|
||
- emit_move_insn (low_dst, gen_rtx (REG, SImode, 21));
|
||
- emit_move_insn (high_dst, gen_rtx (REG, SImode, 20));
|
||
- DONE;
|
||
- }
|
||
+ rtx low_dst = gen_lowpart (SImode, operands[0]);
|
||
+ rtx high_dst = gen_highpart (SImode, operands[0]);
|
||
+
|
||
+ emit_insn (gen_mulsidi3_i (operands[1], operands[2]));
|
||
+
|
||
+ emit_move_insn (low_dst, gen_rtx_REG (SImode, 21));
|
||
+ emit_move_insn (high_dst, gen_rtx_REG (SImode, 20));
|
||
+ /* We need something to tag the possible REG_EQUAL notes on to. */
|
||
+ emit_move_insn (operands[0], operands[0]);
|
||
+ DONE;
|
||
}")
|
||
|
||
(define_insn "umulsidi3_i"
|
||
- [(set (reg:DI 20)
|
||
- (mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
- (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))))]
|
||
+ [(set (reg:SI 20)
|
||
+ (truncate:SI
|
||
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
+ (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r")))
|
||
+ (const_int 32))))
|
||
+ (set (reg:SI 21)
|
||
+ (mult:SI (match_dup 0)
|
||
+ (match_dup 1)))]
|
||
"TARGET_SH2"
|
||
"dmulu.l %1,%0"
|
||
[(set_attr "type" "dmpy")])
|
||
|
||
-(define_expand "umulsidi3"
|
||
- [(set (reg:DI 20)
|
||
+(define_insn "umulsidi3"
|
||
+ [(set (match_operand:DI 0 "arith_reg_operand" "=r")
|
||
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
|
||
+ (zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
|
||
+ (clobber (reg:DI 20))]
|
||
+ "TARGET_SH2"
|
||
+ "#")
|
||
+
|
||
+(define_split
|
||
+ [(set (match_operand:DI 0 "arith_reg_operand" "")
|
||
(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
|
||
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
|
||
- (set (match_operand:DI 0 "arith_reg_operand" "")
|
||
- (reg:DI 20))]
|
||
+ (clobber (reg:DI 20))]
|
||
"TARGET_SH2"
|
||
+ [(const_int 0)]
|
||
"
|
||
{
|
||
- /* We must swap the two words when copying them from MACH/MACL to the
|
||
- output register. */
|
||
- if (TARGET_LITTLE_ENDIAN)
|
||
- {
|
||
- rtx low_dst = operand_subword (operands[0], 0, 1, DImode);
|
||
- rtx high_dst = operand_subword (operands[0], 1, 1, DImode);
|
||
-
|
||
- emit_insn (gen_umulsidi3_i (operands[1], operands[2]));
|
||
-
|
||
- emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0]));
|
||
- emit_move_insn (low_dst, gen_rtx (REG, SImode, 21));
|
||
- emit_move_insn (high_dst, gen_rtx (REG, SImode, 20));
|
||
- DONE;
|
||
- }
|
||
+ rtx low_dst = gen_lowpart (SImode, operands[0]);
|
||
+ rtx high_dst = gen_highpart (SImode, operands[0]);
|
||
+
|
||
+ emit_insn (gen_umulsidi3_i (operands[1], operands[2]));
|
||
+
|
||
+ emit_move_insn (low_dst, gen_rtx_REG (SImode, 21));
|
||
+ emit_move_insn (high_dst, gen_rtx_REG (SImode, 20));
|
||
+ /* We need something to tag the possible REG_EQUAL notes on to. */
|
||
+ emit_move_insn (operands[0], operands[0]);
|
||
+ DONE;
|
||
}")
|
||
|
||
-(define_insn ""
|
||
+(define_insn "smulsi3_highpart_i"
|
||
[(set (reg:SI 20)
|
||
(truncate:SI
|
||
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
@@ -909,9 +1001,27 @@
|
||
(set (match_operand:SI 0 "arith_reg_operand" "")
|
||
(reg:SI 20))]
|
||
"TARGET_SH2"
|
||
- "")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
|
||
-(define_insn ""
|
||
+ first = emit_insn (gen_smulsi3_highpart_i (operands[1], operands[2]));
|
||
+ last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 20));
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ /* expand_binop can't find a suitable code in mul_highpart_optab to
|
||
+ make a REG_EQUAL note from, so make one here.
|
||
+ ??? Alternatively, we could put this at the calling site of expand_binop,
|
||
+ i.e. expand_mult_highpart. */
|
||
+ REG_NOTES (last)
|
||
+ = gen_rtx_EXPR_LIST (REG_EQUAL, copy_rtx (SET_SRC (single_set (first))),
|
||
+ REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
+
|
||
+(define_insn "umulsi3_highpart_i"
|
||
[(set (reg:SI 20)
|
||
(truncate:SI
|
||
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
@@ -932,7 +1042,18 @@
|
||
(set (match_operand:SI 0 "arith_reg_operand" "")
|
||
(reg:SI 20))]
|
||
"TARGET_SH2"
|
||
- "")
|
||
+ "
|
||
+{
|
||
+ rtx first, last;
|
||
+
|
||
+ first = emit_insn (gen_umulsi3_highpart_i (operands[1], operands[2]));
|
||
+ last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 20));
|
||
+ /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
|
||
+ invariant code motion can move it. */
|
||
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
|
||
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
|
||
+ DONE;
|
||
+}")
|
||
|
||
;; -------------------------------------------------------------------------
|
||
;; Logical operations
|
||
@@ -1825,19 +1946,20 @@
|
||
""
|
||
"sett")
|
||
|
||
-;; t/r is first, so that it will be preferred over r/r when reloading a move
|
||
-;; of a pseudo-reg into the T reg
|
||
+;; t/r must come after r/r, lest reload will try to reload stuff like
|
||
+;; (set (subreg:SI (mem:QI (plus:SI (reg:SI 15 r15) (const_int 12)) 0) 0)
|
||
+;; (made from (set (subreg:SI (reg:QI 73) 0) ) into T.
|
||
(define_insn "movsi_i"
|
||
- [(set (match_operand:SI 0 "general_movdst_operand" "=t,r,r,r,r,r,m,<,<,xl,x,l,r")
|
||
- (match_operand:SI 1 "general_movsrc_operand" "r,Q,rI,m,xl,t,r,x,l,r,>,>,i"))]
|
||
+ [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,r")
|
||
+ (match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,xl,t,r,x,l,r,>,>,i"))]
|
||
"
|
||
! TARGET_SH3E
|
||
&& (register_operand (operands[0], SImode)
|
||
|| register_operand (operands[1], SImode))"
|
||
"@
|
||
- cmp/pl %1
|
||
mov.l %1,%0
|
||
mov %1,%0
|
||
+ cmp/pl %1
|
||
mov.l %1,%0
|
||
sts %1,%0
|
||
movt %0
|
||
@@ -1848,7 +1970,7 @@
|
||
lds.l %1,%0
|
||
lds.l %1,%0
|
||
fake %1,%0"
|
||
- [(set_attr "type" "*,pcload_si,move,load_si,move,move,store,store,pstore,move,load,pload,pcload_si")
|
||
+ [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,pcload_si")
|
||
(set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*")])
|
||
|
||
;; t/r must come after r/r, lest reload will try to reload stuff like
|
||
@@ -1856,8 +1978,8 @@
|
||
;; ??? This allows moves from macl to fpul to be recognized, but these moves
|
||
;; will require a reload.
|
||
(define_insn "movsi_ie"
|
||
- [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,r,y,r,y")
|
||
- (match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,m,xl,t,r,x,l,r,>,>,i,r,y,y"))]
|
||
+ [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,y,r,y,r,y")
|
||
+ (match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,xl,t,r,x,l,r,>,>,>,i,r,y,y"))]
|
||
"TARGET_SH3E
|
||
&& (register_operand (operands[0], SImode)
|
||
|| register_operand (operands[1], SImode))"
|
||
@@ -1874,16 +1996,17 @@
|
||
lds %1,%0
|
||
lds.l %1,%0
|
||
lds.l %1,%0
|
||
+ lds.l %1,%0
|
||
fake %1,%0
|
||
lds %1,%0
|
||
sts %1,%0
|
||
! move optimized away"
|
||
- [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,pcload_si,gp_fpul,gp_fpul,nil")
|
||
- (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
|
||
+ [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,load,pcload_si,gp_fpul,gp_fpul,nil")
|
||
+ (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
|
||
|
||
(define_insn "movsi_i_lowpart"
|
||
[(set (strict_low_part (match_operand:SI 0 "general_movdst_operand" "=r,r,r,r,r,m,r"))
|
||
- (match_operand:SI 1 "general_movsrc_operand" "Q,rI,m,xl,t,r,i"))]
|
||
+ (match_operand:SI 1 "general_movsrc_operand" "Q,rI,mr,xl,t,r,i"))]
|
||
"register_operand (operands[0], SImode)
|
||
|| register_operand (operands[1], SImode)"
|
||
"@
|
||
@@ -2087,7 +2210,8 @@
|
||
FAIL;
|
||
reg = XEXP (addr, 0);
|
||
const_int = XEXP (addr, 1);
|
||
- if (GET_CODE (reg) != REG || GET_CODE (const_int) != CONST_INT)
|
||
+ if (! (BASE_REGISTER_RTX_P (reg) && INDEX_REGISTER_RTX_P (operands[2])
|
||
+ && GET_CODE (const_int) == CONST_INT))
|
||
FAIL;
|
||
emit_move_insn (operands[2], const_int);
|
||
emit_move_insn (operands[0],
|
||
@@ -2113,7 +2237,8 @@
|
||
FAIL;
|
||
reg = XEXP (addr, 0);
|
||
const_int = XEXP (addr, 1);
|
||
- if (GET_CODE (reg) != REG || GET_CODE (const_int) != CONST_INT)
|
||
+ if (! (BASE_REGISTER_RTX_P (reg) && INDEX_REGISTER_RTX_P (operands[2])
|
||
+ && GET_CODE (const_int) == CONST_INT))
|
||
FAIL;
|
||
emit_move_insn (operands[2], const_int);
|
||
emit_move_insn (change_address (operands[1], VOIDmode,
|
||
@@ -2249,7 +2374,7 @@
|
||
;; This one has the additional purpose to record a possible scratch register
|
||
;; for the following branch.
|
||
(define_insn "indirect_jump_scratch"
|
||
- [(set (match_operand 0 "register_operand" "r")
|
||
+ [(set (match_operand 0 "register_operand" "=r")
|
||
(unspec [(match_operand 1 "const_int_operand" "")] 4))]
|
||
""
|
||
""
|
||
@@ -2478,7 +2603,7 @@
|
||
{
|
||
int i;
|
||
|
||
- emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_rtx));
|
||
+ emit_call_insn (gen_call (operands[0], const0_rtx));
|
||
|
||
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
||
{
|
||
@@ -2974,6 +3099,7 @@
|
||
(use (match_operand:SI 0 "arith_reg_operand" "r"))
|
||
(use (reg:SI 6))
|
||
(clobber (reg:SI 17))
|
||
+ (clobber (reg:SI 18))
|
||
(clobber (reg:SI 4))
|
||
(clobber (reg:SI 5))
|
||
(clobber (reg:SI 6))
|
||
@@ -3144,10 +3270,9 @@
|
||
|
||
size /= 8;
|
||
orig_address = XEXP (operands[0], 0);
|
||
- addr_target = gen_reg_rtx (SImode);
|
||
shift_reg = gen_reg_rtx (SImode);
|
||
emit_insn (gen_movsi (shift_reg, operands[3]));
|
||
- emit_insn (gen_addsi3 (addr_target, orig_address, GEN_INT (size - 1)));
|
||
+ addr_target = copy_addr_to_reg (plus_constant (orig_address, size - 1));
|
||
|
||
operands[0] = change_address (operands[0], QImode, addr_target);
|
||
emit_insn (gen_movqi (operands[0], gen_rtx (SUBREG, QImode, shift_reg, 0)));
|