aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/ns32k
diff options
context:
space:
mode:
authorIan Dall <Ian.Dall@dsto.defence.gov.au>1998-11-25 23:34:42 +0000
committerRichard Henderson <rth@gcc.gnu.org>1998-11-25 15:34:42 -0800
commit8357595779418585b4390bb66be518b32374965a (patch)
tree67aa038fe8d8b1eef82738fc896e6e5674ceb31b /gcc/config/ns32k
parent36696297f1a68d0789ec6cf07ac23cf640bd61ce (diff)
downloadgcc-8357595779418585b4390bb66be518b32374965a.zip
gcc-8357595779418585b4390bb66be518b32374965a.tar.gz
gcc-8357595779418585b4390bb66be518b32374965a.tar.bz2
Bulk ns32k patch from Ian Dall. See ChangeLog for details.
Co-Authored-By: Matthias Pfaller <leo@dachau.marco.de> From-SVN: r23887
Diffstat (limited to 'gcc/config/ns32k')
-rw-r--r--gcc/config/ns32k/netbsd.h7
-rw-r--r--gcc/config/ns32k/ns32k.c500
-rw-r--r--gcc/config/ns32k/ns32k.h488
-rw-r--r--gcc/config/ns32k/ns32k.md700
4 files changed, 1212 insertions, 483 deletions
diff --git a/gcc/config/ns32k/netbsd.h b/gcc/config/ns32k/netbsd.h
index cef68d8..bc86e31 100644
--- a/gcc/config/ns32k/netbsd.h
+++ b/gcc/config/ns32k/netbsd.h
@@ -24,9 +24,10 @@ Boston, MA 02111-1307, USA.
/* Compile for the floating point unit & 32532 by default;
Don't assume SB is zero;
- Don't use bitfield instructions; */
+ Don't use bitfield instructions;
+ FPU is 32381; */
-#define TARGET_DEFAULT (1 + 24 + 32 + 64)
+#define TARGET_DEFAULT (1 + 24 + 32 + 64 + 256)
/* 32-bit alignment for efficiency */
@@ -68,7 +69,7 @@ Boston, MA 02111-1307, USA.
/* Names to predefine in the preprocessor for this target machine. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)"
+#define CPP_PREDEFINES "-Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -D__KPRINTF_ATTRIBUTE__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)"
/* Make gcc agree with <machine/ansi.h> */
diff --git a/gcc/config/ns32k/ns32k.c b/gcc/config/ns32k/ns32k.c
index 8c2fb1f..af89e59 100644
--- a/gcc/config/ns32k/ns32k.c
+++ b/gcc/config/ns32k/ns32k.c
@@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */
/* Some output-actions in ns32k.md need these. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
@@ -30,11 +30,33 @@ Boston, MA 02111-1307, USA. */
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
+#include "tree.h"
+#include "expr.h"
+#include "flags.h"
#ifdef OSF_OS
int ns32k_num_files = 0;
#endif
+/* This duplicates reg_class_contens in reg_class.c, but maybe that isn't
+ initialized in time. Also this is more convenient as an array of ints.
+ We know that HARD_REG_SET fits in an unsigned int */
+
+unsigned int ns32k_reg_class_contents[N_REG_CLASSES] = REG_CLASS_CONTENTS;
+
+enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
+{
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
+ FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
+ FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+ FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+ FRAME_POINTER_REG, STACK_POINTER_REG
+};
+
+char *ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
+
void
trace (s, s1, s2)
char *s, *s1, *s2;
@@ -42,78 +64,67 @@ trace (s, s1, s2)
fprintf (stderr, s, s1, s2);
}
-/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
+/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
int
hard_regno_mode_ok (regno, mode)
int regno;
enum machine_mode mode;
{
- switch (mode)
+ int size = GET_MODE_UNIT_SIZE(mode);
+
+ if (FLOAT_MODE_P(mode))
{
- case QImode:
- case HImode:
- case PSImode:
- case SImode:
- case PDImode:
- case VOIDmode:
- case BLKmode:
- if (regno < 8 || regno == 16 || regno == 17)
+ if (size == UNITS_PER_WORD && regno < L1_REGNUM)
return 1;
- else
- return 0;
-
- case DImode:
- if (regno < 8 && (regno & 1) == 0)
+ if (size == UNITS_PER_WORD * 2
+ && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
return 1;
- else
- return 0;
-
- case SFmode:
- case SCmode:
- if (TARGET_32081)
- {
- if (regno < 16)
- return 1;
- else
- return 0;
- }
- else
- {
- if (regno < 8)
- return 1;
- else
- return 0;
- }
-
- case DFmode:
- case DCmode:
- if ((regno & 1) == 0)
- {
- if (TARGET_32081)
- {
- if (regno < 16)
- return 1;
- else
- return 0;
- }
- else
- {
- if (regno < 8)
- return 1;
- else
- return 0;
- }
- }
- else
- return 0;
+ return 0;
}
-
- /* Used to abort here, but simply saying "no" handles TImode
- much better. */
+ if (size == UNITS_PER_WORD * 2
+ && (regno & 1) == 0 && regno < F0_REGNUM)
+ return 1;
+ if (size <= UNITS_PER_WORD
+ && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
+ || regno == STACK_POINTER_REGNUM))
+ return 1;
return 0;
}
+int register_move_cost(CLASS1, CLASS2)
+ enum reg_class CLASS1;
+ enum reg_class CLASS2;
+{
+ if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
+ return 2;
+ if((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
+ || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)))
+ return 8;
+ if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
+ || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
+ return 6;
+ if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
+ || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
+ return 6;
+ return 2;
+}
+
+#if 0
+/* We made the insn definitions copy from floating point to general
+ registers via the stack. */
+int secondary_memory_needed(CLASS1, CLASS2, M)
+ enum reg_class CLASS1;
+ enum reg_class CLASS2;
+ enum machine_mode M;
+{
+ int ret = ((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
+ || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)));
+ return ret;
+}
+#endif
+
+
/* ADDRESS_COST calls this. This function is not optimal
for the 32032 & 32332, but it probably is better than
the default. */
@@ -146,8 +157,10 @@ calc_address_cost (operand)
case POST_DEC:
case PRE_DEC:
break;
- case MULT:
case MEM:
+ cost += calc_address_cost (XEXP (operand, 0));
+ break;
+ case MULT:
case PLUS:
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
{
@@ -174,30 +187,18 @@ secondary_reload_class (class, mode, in)
if (regno >= FIRST_PSEUDO_REGISTER)
regno = -1;
- /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
- into anything. */
- if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
- return NO_REGS;
-
- /* Constants, memory, and FP registers can go into FP registers. */
- if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
- return NO_REGS;
-
-#if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
- so it's cleaner to use PREFERRED_RELOAD_CLASS
- to make the right things happen. */
- if (regno >= 16 && class == GEN_AND_MEM_REGS)
+ if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
+ || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
+ return GENERAL_REGS;
+ else
return NO_REGS;
-#endif
-
- /* Otherwise, we need GENERAL_REGS. */
- return GENERAL_REGS;
}
+
/* Generate the rtx that comes from an address expression in the md file */
/* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
scale must be converted from an exponent (from ASHIFT) to a
multiplier (for MULT). */
-rtx
+static rtx
gen_indexed_expr (base, index, scale)
rtx base, index, scale;
{
@@ -226,6 +227,7 @@ reg_or_mem_operand (op, mode)
|| GET_CODE (op) == SUBREG
|| GET_CODE (op) == MEM));
}
+
/* Split one or more DImode RTL references into pairs of SImode
references. The RTL can be REG, offsettable MEM, integer constant, or
@@ -404,27 +406,163 @@ output_move_double (operands)
return singlemove_string (operands);
}
-int
-check_reg (oper, reg)
- rtx oper;
- int reg;
+
+#define MAX_UNALIGNED_COPY (32)
+/* Expand string/block move operations.
+
+ operands[0] is the pointer to the destination.
+ operands[1] is the pointer to the source.
+ operands[2] is the number of bytes to move.
+ operands[3] is the alignment. */
+
+static void
+move_tail(operands, bytes, offset)
+ rtx operands[];
+ int bytes;
+ int offset;
{
- register int i;
+ if (bytes & 2)
+ {
+ rtx src, dest;
+ dest = change_address(operands[0], HImode,
+ plus_constant(XEXP(operands[0], 0), offset));
+ src = change_address(operands[1], HImode,
+ plus_constant(XEXP(operands[1], 0), offset));
+ emit_move_insn(dest, src);
+ offset += 2;
+ }
+ if (bytes & 1)
+ {
+ rtx src, dest;
+ dest = change_address(operands[0], QImode,
+ plus_constant(XEXP(operands[0], 0), offset));
+ src = change_address(operands[1], QImode,
+ plus_constant(XEXP(operands[1], 0), offset));
+ emit_move_insn(dest, src);
+ }
+}
- if (oper == 0)
- return 0;
- switch (GET_CODE(oper))
+void
+expand_block_move (operands)
+ rtx operands[];
+{
+ rtx bytes_rtx = operands[2];
+ rtx align_rtx = operands[3];
+ int constp = (GET_CODE (bytes_rtx) == CONST_INT);
+ int bytes = (constp ? INTVAL (bytes_rtx) : 0);
+ int align = INTVAL (align_rtx);
+ rtx src_reg = gen_rtx(REG, Pmode, 1);
+ rtx dest_reg = gen_rtx(REG, Pmode, 2);
+ rtx count_reg = gen_rtx(REG, SImode, 0);
+ rtx insn;
+
+ if (constp && bytes <= 0)
+ return;
+
+ if (constp && bytes < 20)
{
- case REG:
- return (REGNO(oper) == reg) ? 1 : 0;
- case MEM:
- return check_reg(XEXP(oper, 0), reg);
- case PLUS:
- case MULT:
- return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
+ int words = bytes >> 2;
+ if (words)
+ if (words < 3 || flag_unroll_loops)
+ {
+ int offset = 0;
+ for (; words; words--, offset += 4)
+ {
+ rtx src, dest;
+ dest = change_address(operands[0], SImode,
+ plus_constant(XEXP(operands[0], 0), offset));
+ src = change_address(operands[1], SImode,
+ plus_constant(XEXP(operands[1], 0), offset));
+ emit_move_insn(dest, src);
+ }
+ }
+ else
+ {
+ /* Use movmd. It is slower than multiple movd's but more
+ compact. It is also slower than movsd for large copies
+ but causes less registers reloading so is better than movsd
+ for small copies. */
+ rtx src, dest;
+ dest = copy_addr_to_reg (XEXP(operands[0], 0));
+ src = copy_addr_to_reg (XEXP(operands[1], 0));
+
+ emit_insn(gen_movstrsi2(dest, src, GEN_INT(words)));
+ }
+ move_tail(operands, bytes & 3, bytes & ~3);
+ return;
+ }
+
+ if (align > UNITS_PER_WORD)
+ align = UNITS_PER_WORD;
+
+ /* Move the address into scratch registers. */
+ emit_insn(gen_rtx(CLOBBER, VOIDmode, dest_reg));
+ emit_move_insn(dest_reg, XEXP (operands[0], 0));
+ emit_insn(gen_rtx(CLOBBER, VOIDmode, src_reg));
+ emit_move_insn(src_reg, XEXP (operands[1], 0));
+ emit_insn(gen_rtx(CLOBBER, VOIDmode, count_reg));
+
+ if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
+ {
+ rtx bytes_reg;
+
+ /* constant no of bytes and aligned or small enough copy to not bother
+ * aligning. Emit insns to copy by words.
+ */
+ if (bytes >> 2)
+ {
+ emit_move_insn(count_reg, GEN_INT(bytes >> 2));
+ emit_insn(gen_movstrsi1 (GEN_INT(4)));
+ }
+ /* insns to copy rest */
+ move_tail(operands, bytes & 3, bytes & ~3);
+ }
+ else if (align == UNITS_PER_WORD)
+ {
+ /* insns to copy by words */
+ emit_insn(gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT(2)));
+ emit_insn(gen_movstrsi1 (GEN_INT(4)));
+ /* insns to copy rest */
+ emit_insn(gen_andsi3 (count_reg, bytes_rtx, GEN_INT(3)));
+ emit_insn(gen_movstrsi1 (const1_rtx));
+ }
+ else
+ {
+ /* Not aligned and we may have a lot to copy so it is worth
+ * aligning.
+ */
+ rtx aligned_label = gen_label_rtx ();
+ rtx bytes_reg;
+
+ bytes_reg = copy_to_mode_reg(SImode, bytes_rtx);
+ if (!constp)
+ {
+ /* Emit insns to test and skip over the alignment if it is
+ * not worth it. This doubles as a test to ensure that the alignment
+ * operation can't copy too many bytes
+ */
+ emit_insn(gen_cmpsi (bytes_reg, GEN_INT(MAX_UNALIGNED_COPY)));
+ emit_jump_insn (gen_blt (aligned_label));
+ }
+
+ /* Emit insns to do alignment at run time */
+ emit_insn(gen_negsi2 (count_reg, src_reg));
+ emit_insn(gen_andsi3 (count_reg, count_reg, GEN_INT(3)));
+ emit_insn(gen_subsi3 (bytes_reg, bytes_reg, count_reg));
+ emit_insn(gen_movstrsi1 (const1_rtx));
+ if (!constp)
+ emit_label (aligned_label);
+
+ /* insns to copy by words */
+ emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT(2)));
+ emit_insn(gen_movstrsi1 (GEN_INT(4)));
+
+ /* insns to copy rest */
+ emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT(3)));
+ emit_insn(gen_movstrsi1 (const1_rtx));
}
- return 0;
}
+
/* Returns 1 if OP contains a global symbol reference */
@@ -466,10 +604,142 @@ global_symbolic_reference_mentioned_p (op, f)
}
+/* Returns 1 if OP contains a symbol reference */
+
+int
+symbolic_reference_mentioned_p (op)
+ rtx op;
+{
+ register char *fmt;
+ register int i;
+
+ if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
+ return 1;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (op));
+ for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ register int j;
+
+ for (j = XVECLEN (op, i) - 1; j >= 0; j--)
+ if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
+ attribute for DECL. The attributes in ATTRIBUTES have previously been
+ assigned to DECL. */
+
+int
+ns32k_valid_decl_attribute_p (decl, attributes, identifier, args)
+ tree decl;
+ tree attributes;
+ tree identifier;
+ tree args;
+{
+ return 0;
+}
+
+/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
+ attribute for TYPE. The attributes in ATTRIBUTES have previously been
+ assigned to TYPE. */
+
+int
+ns32k_valid_type_attribute_p (type, attributes, identifier, args)
+ tree type;
+ tree attributes;
+ tree identifier;
+ tree args;
+{
+ if (TREE_CODE (type) != FUNCTION_TYPE
+ && TREE_CODE (type) != FIELD_DECL
+ && TREE_CODE (type) != TYPE_DECL)
+ return 0;
+
+ /* Stdcall attribute says callee is responsible for popping arguments
+ if they are not variable. */
+ if (is_attribute_p ("stdcall", identifier))
+ return (args == NULL_TREE);
+
+ /* Cdecl attribute says the callee is a normal C declaration */
+ if (is_attribute_p ("cdecl", identifier))
+ return (args == NULL_TREE);
+
+ return 0;
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+ are compatible, and 2 if they are nearly compatible (which causes a
+ warning to be generated). */
+
+int
+ns32k_comp_type_attributes (type1, type2)
+ tree type1;
+ tree type2;
+{
+ return 1;
+}
+
+
+/* Value is the number of bytes of arguments automatically
+ popped when returning from a subroutine call.
+ FUNDECL is the declaration node of the function (as a tree),
+ FUNTYPE is the data type of the function (as a tree),
+ or for a library call it is an identifier node for the subroutine name.
+ SIZE is the number of bytes of arguments passed on the stack.
+
+ On the ns32k, the RET insn may be used to pop them if the number
+ of args is fixed, but if the number is variable then the caller
+ must pop them all. RET can't be used for library calls now
+ because the library is compiled with the Unix compiler.
+ Use of RET is a selectable option, since it is incompatible with
+ standard Unix calling sequences. If the option is not selected,
+ the caller must always pop the args.
+
+ The attribute stdcall is equivalent to RET on a per module basis. */
+
+int
+ns32k_return_pops_args (fundecl, funtype, size)
+ tree fundecl;
+ tree funtype;
+ int size;
+{
+ int rtd = TARGET_RTD;
+
+ if (TREE_CODE (funtype) == IDENTIFIER_NODE)
+ return rtd ? size : 0;
+
+ /* Cdecl functions override -mrtd, and never pop the stack */
+ if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
+ return 0;
+
+ /* Stdcall functions will pop the stack if not variable args */
+ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
+ rtd = 1;
+
+ if (rtd)
+ {
+ if (TYPE_ARG_TYPES (funtype) == NULL_TREE
+ || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
+ return size;
+ }
+
+ return 0;
+}
+
/* PRINT_OPERAND is defined to call this function,
which is easier to debug than putting all the code in
a macro definition in ns32k.h. */
+/* XXX time 12% of cpu time is in fprintf for non optimizing */
void
print_operand (file, x, code)
FILE *file;
@@ -481,7 +751,7 @@ print_operand (file, x, code)
else if (code == '?')
PUT_EXTERNAL_PREFIX (file);
else if (GET_CODE (x) == REG)
- fprintf (file, "%s", reg_names[REGNO (x)]);
+ fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
else if (GET_CODE (x) == MEM)
{
rtx tmp = XEXP (x, 0);
@@ -528,11 +798,30 @@ print_operand (file, x, code)
}
else
{
+ if (flag_pic
+ && GET_CODE (x) == CONST
+ && symbolic_reference_mentioned_p (x))
+ {
+ fprintf(stderr, "illegal constant for pic-mode: \n");
+ print_rtl(stderr, x);
+ fprintf(stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
+ GET_CODE (x), CONST, symbolic_reference_mentioned_p(x));
+ abort ();
+ }
+ else if (flag_pic
+ && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
+ {
+ output_addr_const (file, x);
+ fprintf (file, "(sb)");
+ }
+ else
+ {
#ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
- if (GET_CODE (x) == CONST_INT)
+ if (GET_CODE (x) == CONST_INT)
#endif
- PUT_IMMEDIATE_PREFIX (file);
- output_addr_const (file, x);
+ PUT_IMMEDIATE_PREFIX (file);
+ output_addr_const (file, x);
+ }
}
}
@@ -545,6 +834,7 @@ print_operand (file, x, code)
figure out how it worked.
90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
+void
print_operand_address (file, addr)
register FILE *file;
register rtx addr;
@@ -597,7 +887,7 @@ print_operand_address (file, addr)
base = tmp;
break;
case REG:
- if (REGNO (tmp) < 8)
+ if (REGNO (tmp) < F0_REGNUM)
if (base)
{
indexexp = tmp;
@@ -728,7 +1018,7 @@ print_operand_address (file, addr)
(disp(sb)) (MEM ...)
*/
case REG:
- fprintf (file, "(%s)", reg_names[REGNO (base)]);
+ fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
break;
case SYMBOL_REF:
if (! flag_pic)
@@ -785,7 +1075,7 @@ print_operand_address (file, addr)
fprintf (file, "(");
output_addr_const (file, offset);
if (base)
- fprintf (file, "(%s)", reg_names[REGNO (base)]);
+ fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
else if (TARGET_SB)
fprintf (file, "(sb)");
else
@@ -816,16 +1106,16 @@ print_operand_address (file, addr)
}
else
scale = 0;
- if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
+ if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
abort ();
#ifdef UTEK_ASM
fprintf (file, "[%c`%s]",
scales[scale],
- reg_names[REGNO (indexexp)]);
+ ns32k_out_reg_names[REGNO (indexexp)]);
#else
fprintf (file, "[%s:%c]",
- reg_names[REGNO (indexexp)],
+ ns32k_out_reg_names[REGNO (indexexp)],
scales[scale]);
#endif
}
diff --git a/gcc/config/ns32k/ns32k.h b/gcc/config/ns32k/ns32k.h
index d2e81d1..d409ac2 100644
--- a/gcc/config/ns32k/ns32k.h
+++ b/gcc/config/ns32k/ns32k.h
@@ -23,8 +23,6 @@ Boston, MA 02111-1307, USA. */
/* Note that some other tm.h files include this one and then override
many of the definitions that relate to assembler syntax. */
-extern enum reg_class secondary_reload_class();
-
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dns32000 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)"
@@ -66,6 +64,18 @@ extern int target_flags;
/* Compile 32081 insns for floating point (not library calls). */
#define TARGET_32081 (target_flags & 1)
+#define TARGET_32381 (target_flags & 256)
+
+/* The use of multiply-add instructions is optional because it can
+ * cause an abort due to being unable to find a spill register. The
+ * main problem is that the multiply-add instructions require f0 and
+ * f0 is not available for spilling because it is "explicitly
+ * mentioned" in the rtl for function return values. This can be fixed
+ * by defining SMALL_REGISTER_CLASSES, but that causes worse code for
+ * the (more common) integer case. We really need better reload code.
+ */
+
+#define TARGET_MULT_ADD (target_flags & 512)
/* Compile using rtd insn calling sequence.
This will not work unless you use prototypes at least
@@ -93,9 +103,9 @@ extern int target_flags;
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE. */
-#define TARGET_SWITCHES \
+#define TARGET_SWITCHES \
{ { "32081", 1}, \
- { "soft-float", -1}, \
+ { "soft-float", -257}, \
{ "rtd", 2}, \
{ "nortd", -2}, \
{ "regparm", 4}, \
@@ -110,17 +120,66 @@ extern int target_flags;
{ "nobitfield", 64}, \
{ "himem", 128}, \
{ "nohimem", -128}, \
+ { "32381", 256}, \
+ { "mult-add", 512}, \
+ { "nomult-add", -512}, \
{ "", TARGET_DEFAULT}}
+
/* TARGET_DEFAULT is defined in encore.h, pc532.h, etc. */
/* When we are generating PIC, the sb is used as a pointer
- to the GOT. */
+ to the GOT. 32381 is a superset of 32081 */
-#define OVERRIDE_OPTIONS \
-{ \
+#define OVERRIDE_OPTIONS \
+{ \
if (flag_pic || TARGET_HIMEM) target_flags |= 32; \
+ if (TARGET_32381) target_flags |= 1; \
+ else target_flags &= ~512; \
}
+/* Zero or more C statements that may conditionally modify two
+ variables `fixed_regs' and `call_used_regs' (both of type `char
+ []') after they have been initialized from the two preceding
+ macros.
+
+ This is necessary in case the fixed or call-clobbered registers
+ depend on target flags.
+
+ You need not define this macro if it has no work to do.
+
+ If the usage of an entire class of registers depends on the target
+ flags, you may indicate this to GCC by using this macro to modify
+ `fixed_regs' and `call_used_regs' to 1 for each of the registers in
+ the classes which should not be used by GCC. Also define the macro
+ `REG_CLASS_FROM_LETTER' to return `NO_REGS' if it is called with a
+ letter for a class that shouldn't be used.
+
+ (However, if this class is not included in `GENERAL_REGS' and all
+ of the insn patterns whose constraints permit this class are
+ controlled by target switches, then GCC will automatically avoid
+ using these registers when the target switches are opposed to
+ them.) */
+
+#define CONDITIONAL_REGISTER_USAGE \
+do \
+ { \
+ if (!TARGET_32081) \
+ { \
+ int regno; \
+ \
+ for (regno = F0_REGNUM; regno <= F0_REGNUM + 8; regno++) \
+ fixed_regs[regno] = call_used_regs[regno] = 1; \
+ } \
+ if (!TARGET_32381) \
+ { \
+ int regno; \
+ \
+ for (regno = L1_REGNUM; regno <= L1_REGNUM + 8; regno++) \
+ fixed_regs[regno] = call_used_regs[regno] = 1; \
+ } \
+ } \
+while (0)
+
/* target machine storage layout */
@@ -190,13 +249,14 @@ extern int target_flags;
from 0 to just below FIRST_PSEUDO_REGISTER.
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
-#define FIRST_PSEUDO_REGISTER 18
+#define FIRST_PSEUDO_REGISTER 26
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On the ns32k, these are the FP, SP, (SB and PC are not included here). */
#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1}
/* 1 for registers not available across function calls.
@@ -207,13 +267,70 @@ extern int target_flags;
Aside from that, you can include as many other registers as you like. */
#define CALL_USED_REGISTERS {1, 1, 1, 0, 0, 0, 0, 0, \
1, 1, 1, 1, 0, 0, 0, 0, \
+ 1, 1, 0, 0, 0, 0, 0, 0, \
1, 1}
+/* How to refer to registers in assembler output.
+ This sequence is indexed by compiler's hard-register-number (see above). */
+
+#define REGISTER_NAMES \
+{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "l1", "l1h","l3", "l3h","l5", "l5h","l7", "l7h", \
+ "fp", "sp"}
+
+
+#define ADDITIONAL_REGISTER_NAMES \
+{{"l0", 8}, {"l2", 10}, {"l4", 12}, {"l6", 14}}
+
+/* l0-7 are not recognized by the assembler. These are the names to use,
+ * but we don't want ambiguous names in REGISTER_NAMES
+ */
+#define OUTPUT_REGISTER_NAMES \
+{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f1", "l1h","f3", "l3h","f5", "l5h","f7", "f7h", \
+ "fp", "sp"}
+
+#define REG_ALLOC_ORDER \
+{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 10, 11, 18, 12, 13, 20, 14, 15, 22, 24, 25, 17, 19, 23}
+
+/* How to renumber registers for dbx and gdb.
+ NS32000 may need more change in the numeration. XXX */
+
+#define DBX_REGISTER_NUMBER(REGNO) \
+ ((REGNO) < L1_REGNUM? (REGNO) \
+ : (REGNO) < FRAME_POINTER_REGNUM? (REGNO) - L1_REGNUM + 22 \
+ : (REGNO) == FRAME_POINTER_REGNUM? 17 \
+ : 16)
+
+
+
+
+#define R0_REGNUM 0
+#define F0_REGNUM 8
+#define L1_REGNUM 16
+
+/* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
+/* NS32000 pc is not overloaded on a register. */
+/* #define PC_REGNUM */
+
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM 25
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 24
+
+
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
- On the ns32k, all registers are 32 bits long. */
+ On the ns32k, all registers are 32 bits long except for the 32381 "long"
+ registers but we treat those as pairs */
+#define LONG_FP_REGS_P(REGNO) ((REGNO) >= L1_REGNUM && (REGNO) < L1_REGNUM + 8)
#define HARD_REGNO_NREGS(REGNO, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
@@ -223,22 +340,19 @@ extern int target_flags;
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
- for any hard reg, then this must be 0 for correct output. */
-#define MODES_TIEABLE_P(MODE1, MODE2) \
- (((MODE1) == DFmode || (MODE1) == DCmode || (MODE1) == DImode) == \
- ((MODE2) == DFmode || (MODE2) == DCmode || (MODE2) == DImode))
+ for any hard reg, then this must be 0 for correct output.
-/* Specify the registers used for certain standard purposes.
- The values of these macros are register numbers. */
-
-/* NS32000 pc is not overloaded on a register. */
-/* #define PC_REGNUM */
+ Early documentation says SI and DI are not tieable if some reg can
+ be OK for SI but not for DI. However other ports (mips, i860, mvs
+ and tahoe) don't meet the above criterion. Evidently the real
+ requirement is somewhat laxer. Documentation was changed for gcc
+ 2.8 but was not picked up by egcs (at least egcs 1.0). Having all
+ integer modes tieable definitely generates faster code. */
-/* Register to use for pushing function arguments. */
-#define STACK_POINTER_REGNUM 17
-
-/* Base register for access to local variables of the function. */
-#define FRAME_POINTER_REGNUM 16
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((FLOAT_MODE_P(MODE1) && FLOAT_MODE_P(MODE2) \
+ && (GET_MODE_UNIT_SIZE(MODE1) == GET_MODE_UNIT_SIZE(MODE2))) \
+ || (!FLOAT_MODE_P(MODE1) && !FLOAT_MODE_P(MODE2)))
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
@@ -247,7 +361,7 @@ extern int target_flags;
#define FRAME_POINTER_REQUIRED 0
/* Base register for access to arguments of the function. */
-#define ARG_POINTER_REGNUM 16
+#define ARG_POINTER_REGNUM 24
/* Register in which static-chain is passed to a function. */
#define STATIC_CHAIN_REGNUM 1
@@ -275,37 +389,39 @@ extern int target_flags;
For any two classes, it is very desirable that there be another
class that represents their union. */
-
-enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
- FRAME_POINTER_REG, STACK_POINTER_REG,
- GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES };
+
+enum reg_class
+{ NO_REGS, GENERAL_REGS, FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS,
+ FP_REGS, GEN_AND_FP_REGS, FRAME_POINTER_REG, STACK_POINTER_REG,
+ GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
- {"NO_REGS", "GENERAL_REGS", "FLOAT_REGS", "GEN_AND_FP_REGS", \
- "FRAME_POINTER_REG", "STACK_POINTER_REG", "GEN_AND_MEM_REGS", "ALL_REGS" }
+ {"NO_REGS", "GENERAL_REGS", "FLOAT_REG0", "LONG_FLOAT_REG0", "FLOAT_REGS", \
+ "FP_REGS", "GEN_AND_FP_REGS", "FRAME_POINTER_REG", "STACK_POINTER_REG", \
+ "GEN_AND_MEM_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
-#define REG_CLASS_CONTENTS {0, 0x00ff, 0xff00, 0xffff, \
- 0x10000, 0x20000, 0x300ff, 0x3ffff }
+#define REG_CLASS_CONTENTS {0, 0x00ff, 0x100, 0x300, 0xff00, \
+ 0xffff00, 0xffffff, 0x1000000, 0x2000000, \
+ 0x30000ff, 0x3ffffff }
+
+#define SUBSET_P(CLASS1, CLASS2) \
+ ((ns32k_reg_class_contents[CLASS1] & ~ns32k_reg_class_contents[CLASS2]) \
+ == 0)
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
-#define REGNO_REG_CLASS(REGNO) \
- ((REGNO) < 8 ? GENERAL_REGS \
- : (REGNO) < 16 ? FLOAT_REGS \
- : (REGNO) == 16 ? FRAME_POINTER_REG \
- : (REGNO) == 17 ? STACK_POINTER_REG \
- : NO_REGS)
+#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
/* The class value for index registers, and the one for base regs. */
@@ -314,10 +430,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
/* Get reg_class from a letter such as appears in the machine description. */
-#define REG_CLASS_FROM_LETTER(C) \
- ((C) == 'f' ? FLOAT_REGS \
- : (C) == 'x' ? FRAME_POINTER_REG \
- : (C) == 'y' ? STACK_POINTER_REG \
+#define REG_CLASS_FROM_LETTER(C) \
+ ((C) == 'u' ? FLOAT_REG0 \
+ : (C) == 'v' ? LONG_FLOAT_REG0 \
+ : (C) == 'f' ? FLOAT_REGS \
+ : (C) == 'l' ? FP_REGS \
+ : (C) == 'x' ? FRAME_POINTER_REG \
+ : (C) == 'y' ? STACK_POINTER_REG \
: NO_REGS)
/* The letters I, J, K, L and M in a register constraint string
@@ -353,13 +472,15 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
/* We return GENERAL_REGS instead of GEN_AND_MEM_REGS.
The latter offers no real additional possibilities
- and can cause spurious secondary reloading. */
+ and can cause spurious secondary reloading. */
+
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
((CLASS) == GEN_AND_MEM_REGS ? GENERAL_REGS : (CLASS))
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On the 32000, this is the size of MODE in words */
+
#define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
@@ -381,6 +502,46 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
of the first local allocated. */
#define STARTING_FRAME_OFFSET 0
+/* A C expression whose value is RTL representing the location of the
+ incoming return address at the beginning of any function, before
+ the prologue. This RTL is either a `REG', indicating that the
+ return value is saved in `REG', or a `MEM' representing a location
+ in the stack.
+
+ You only need to define this macro if you want to support call
+ frame debugging information like that provided by DWARF 2.
+
+ Before the prologue, RA is at 0(sp). */
+
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx (MEM, VOIDmode, gen_rtx (REG, VOIDmode, STACK_POINTER_REGNUM))
+
+/* A C expression whose value is RTL representing the value of the
+ return address for the frame COUNT steps up from the current frame,
+ after the prologue. FRAMEADDR is the frame pointer of the COUNT
+ frame, or the frame pointer of the COUNT - 1 frame if
+ `RETURN_ADDR_IN_PREVIOUS_FRAME' is defined.
+
+ After the prologue, RA is at 4(fp) in the current frame. */
+
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ (gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, (FRAME), GEN_INT(4))))
+
+/* A C expression whose value is an integer giving the offset, in
+ bytes, from the value of the stack pointer register to the top of
+ the stack frame at the beginning of any function, before the
+ prologue. The top of the frame is defined to be the value of the
+ stack pointer in the previous frame, just before the call
+ instruction.
+
+ You only need to define this macro if you want to support call
+ frame debugging information like that provided by DWARF 2. */
+
+#define INCOMING_FRAME_SP_OFFSET 4
+
+/* Offset of the CFA from the argument pointer register value. */
+#define ARG_POINTER_CFA_OFFSET 8
+
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
On the 32000, sp@- in a byte insn really pushes a BYTE. */
@@ -402,14 +563,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
because the library is compiled with the Unix compiler.
Use of RET is a selectable option, since it is incompatible with
standard Unix calling sequences. If the option is not selected,
- the caller must always pop the args. */
+ the caller must always pop the args.
+
+ The attribute stdcall is equivalent to RTD on a per module basis. */
-#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- ((TARGET_RTD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \
- && (TYPE_ARG_TYPES (FUNTYPE) == 0 \
- || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
- == void_type_node))) \
- ? (SIZE) : 0)
+#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
+ (ns32k_return_pops_args (FUNDECL, FUNTYPE, SIZE))
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
@@ -417,23 +576,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
otherwise, FUNC is 0. */
/* On the 32000 the return value is in R0,
- or perhaps in F0 is there is fp support. */
+ or perhaps in F0 if there is fp support. */
-#define FUNCTION_VALUE(VALTYPE, FUNC) \
- (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_32081 \
- ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \
- : gen_rtx (REG, TYPE_MODE (VALTYPE), 0))
+#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE(TYPE_MODE (VALTYPE))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
/* On the 32000 the return value is in R0,
- or perhaps F0 is there is fp support. */
+ or perhaps F0 is there is fp support. */
#define LIBCALL_VALUE(MODE) \
- (((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \
- ? gen_rtx (REG, MODE, 8) \
- : gen_rtx (REG, MODE, 0))
+ gen_rtx (REG, MODE, \
+ FLOAT_MODE_P(MODE) && TARGET_32081 ? F0_REGNUM: R0_REGNUM)
/* Define this if PCC uses the nonreentrant convention for returning
structure and union values. */
@@ -554,18 +709,18 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ register int regno, g_regs_used = 0; \
int used_regs_buf[8], *bufp = used_regs_buf; \
- int used_fregs_buf[8], *fbufp = used_fregs_buf; \
+ int used_fregs_buf[17], *fbufp = used_fregs_buf; \
extern char call_used_regs[]; \
extern int current_function_uses_pic_offset_table, flag_pic; \
MAIN_FUNCTION_PROLOGUE; \
- for (regno = 0; regno < 8; regno++) \
+ for (regno = R0_REGNUM; regno < F0_REGNUM; regno++) \
if (regs_ever_live[regno] \
&& ! call_used_regs[regno]) \
{ \
*bufp++ = regno; g_regs_used++; \
} \
*bufp = -1; \
- for (; regno < 16; regno++) \
+ for (; regno < FRAME_POINTER_REGNUM; regno++) \
if (regs_ever_live[regno] && !call_used_regs[regno]) \
{ \
*fbufp++ = regno; \
@@ -600,11 +755,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
fbufp = used_fregs_buf; \
while (*fbufp >= 0) \
{ \
- if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \
- fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \
+ if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \
+ fprintf (FILE, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]); \
else \
{ \
- fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \
+ fprintf (FILE, "\tmovl %s,tos\n", \
+ ns32k_out_reg_names[fbufp[0]]); \
fbufp += 2; \
} \
} \
@@ -678,19 +834,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ register int regno, g_regs_used = 0, f_regs_used = 0; \
int used_regs_buf[8], *bufp = used_regs_buf; \
- int used_fregs_buf[8], *fbufp = used_fregs_buf; \
+ int used_fregs_buf[17], *fbufp = used_fregs_buf; \
extern char call_used_regs[]; \
extern int current_function_uses_pic_offset_table, flag_pic; \
if (flag_pic && current_function_uses_pic_offset_table) \
fprintf (FILE, "\tlprd sb,tos\n"); \
*fbufp++ = -2; \
- for (regno = 8; regno < 16; regno++) \
+ for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++) \
if (regs_ever_live[regno] && !call_used_regs[regno]) \
{ \
*fbufp++ = regno; f_regs_used++; \
} \
fbufp--; \
- for (regno = 0; regno < 8; regno++) \
+ for (regno = 0; regno < F0_REGNUM; regno++) \
if (regs_ever_live[regno] \
&& ! call_used_regs[regno]) \
{ \
@@ -698,12 +854,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
} \
while (fbufp > used_fregs_buf) \
{ \
- if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \
+ if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \
{ \
- fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \
+ fprintf (FILE, "\tmovl tos,%s\n", \
+ ns32k_out_reg_names[fbufp[-1]]); \
fbufp -= 2; \
} \
- else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \
+ else fprintf (FILE, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]); \
} \
if (frame_pointer_needed) \
fprintf (FILE, "\texit ["); \
@@ -742,9 +899,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
int regno; \
int offset = -4; \
extern int current_function_uses_pic_offset_table, flag_pic; \
- for (regno = 0; regno < 16; regno++) \
+ for (regno = 0; regno < L1_REGNUM; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 4; \
+ for (; regno < FRAME_POINTER_REGNUM; regno++) \
+ if (regs_ever_live[regno] && ! call_used_regs[regno]) \
+ offset += 8; \
if (flag_pic && current_function_uses_pic_offset_table) \
offset += 4; \
(DEPTH) = (offset + get_frame_size () \
@@ -824,12 +984,13 @@ __transfer_from_trampoline () \
/* note that FP and SP cannot be used as an index. What about PC? */
#define REGNO_OK_FOR_INDEX_P(REGNO) \
-((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8)
+((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM)
#define REGNO_OK_FOR_BASE_P(REGNO) \
-((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \
+((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM \
|| (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM)
-#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16)
+#define FP_REG_P(X) \
+ (GET_CODE (X) == REG && REGNO (X) >= F0_REGNUM && REGNO (X) < FRAME_POINTER_REGNUM)
/* Maximum number of registers that can appear in a valid memory address. */
@@ -838,19 +999,18 @@ __transfer_from_trampoline () \
/* Recognize any constant value that is a valid address.
This might not work on future ns32k processors as negative
displacements are not officially allowed but a mode reserved
- to National. This works on processors up to 32532, though. */
+ to National. This works on processors up to 32532, though,
+ and we don't expect any new ones in the series ;-( */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST \
|| (GET_CODE (X) == CONST_INT \
- && ((unsigned)INTVAL (X) >= 0xe0000000 \
- || (unsigned)INTVAL (X) < 0x20000000)))
+ && NS32K_DISPLACEMENT_P (INTVAL (X))))
#define CONSTANT_ADDRESS_NO_LABEL_P(X) \
(GET_CODE (X) == CONST_INT \
- && ((unsigned)INTVAL (X) >= 0xe0000000 \
- || (unsigned)INTVAL (X) < 0x20000000))
+ && NS32K_DISPLACEMENT_P (INTVAL (X)))
/* Return the register class of a scratch register needed to copy IN into
or out of a register in CLASS in MODE. If it can be done directly,
@@ -859,6 +1019,42 @@ __transfer_from_trampoline () \
#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
secondary_reload_class (CLASS, MODE, IN)
+/* Certain machines have the property that some registers cannot be
+ copied to some other registers without using memory. Define this
+ macro on those machines to be a C expression that is non-zero if
+ objects of mode M in registers of CLASS1 can only be copied to
+ registers of class CLASS2 by storing a register of CLASS1 into
+ memory and loading that memory location into a register of CLASS2.
+
+ On the ns32k, floating point regs can only be loaded through memory
+
+ The movdf and movsf insns in ns32k.md copy between general and
+ floating registers using the stack. In principle, we could get
+ better code not allowing that case in the constraints and defining
+ SECONDARY_MEMORY_NEEDED in practice, though the stack slots used
+ are not available for optimization. */
+
+#if 0
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, M) \
+ secondary_memory_needed(CLASS1, CLASS2, M)
+#endif
+
+/* SMALL_REGISTER_CLASSES is true only if we have said we are using the
+ * multiply-add instructions.
+ */
+#define SMALL_REGISTER_CLASSES (target_flags & 512)
+
+/* A C expression whose value is nonzero if pseudos that have been
+ assigned to registers of class CLASS would likely be spilled
+ because registers of CLASS are needed for spill registers.
+
+ The default definition won't do because class LONG_FLOAT_REG0 has two
+ registers which are always acessed as a pair */
+
+#define CLASS_LIKELY_SPILLED_P(CLASS) \
+ (reg_class_size[(int) (CLASS)] == 1 || (CLASS) == LONG_FLOAT_REG0)
+
+
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
@@ -882,10 +1078,10 @@ __transfer_from_trampoline () \
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) \
- (REGNO (X) < 8 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+ (REGNO (X) < F0_REGNUM || REGNO (X) >= FIRST_PSEUDO_REGISTER)
/* Nonzero if X is a hard reg that can be used as a base reg
of if it is a pseudo reg. */
-#define REG_OK_FOR_BASE_P(X) (REGNO (X) < 8 || REGNO (X) >= FRAME_POINTER_REGNUM)
+#define REG_OK_FOR_BASE_P(X) (REGNO (X) < F0_REGNUM || REGNO (X) >= FRAME_POINTER_REGNUM)
/* Nonzero if X is a floating point reg or a pseudo reg. */
#else
@@ -936,7 +1132,8 @@ __transfer_from_trampoline () \
/* Check for frame pointer or stack pointer. */
#define MEM_REG(X) \
- (GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2)
+ (GET_CODE (X) == REG && (REGNO (X) == FRAME_POINTER_REGNUM \
+ || REGNO(X) == STACK_POINTER_REGNUM))
/* A memory ref whose address is the FP or SP, with optional integer offset,
or (on certain machines) a constant address. */
@@ -1040,15 +1237,21 @@ __transfer_from_trampoline () \
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
/* Nonzero if the constant value X is a legitimate general operand
- when generating PIC code. It is given that flag_pic is on and
+ when generating PIC code. It is given that flag_pic is on and
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
extern int current_function_uses_pic_offset_table, flag_pic;
#define LEGITIMATE_PIC_OPERAND_P(X) \
(((! current_function_uses_pic_offset_table \
- && global_symbolic_reference_mentioned_p (X, 1))? \
+ && symbolic_reference_mentioned_p (X))? \
(current_function_uses_pic_offset_table = 1):0 \
- ), 1)
+ ), (! SYMBOLIC_CONST (X) \
+ || GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF))
+
+#define SYMBOLIC_CONST(X) \
+(GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == LABEL_REF \
+ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
/* Define this macro if references to a symbol must be treated
differently depending on something about the variable or
@@ -1082,6 +1285,33 @@ while (0)
{ if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \
goto LABEL;}
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for DECL.
+ The attributes in ATTRIBUTES have previously been assigned to DECL. */
+
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
+ (ns32k_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
+
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for TYPE.
+ The attributes in ATTRIBUTES have previously been assigned to TYPE. */
+
+#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \
+ (ns32k_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
+
+/* If defined, a C expression whose value is zero if the attributes on
+ TYPE1 and TYPE2 are incompatible, one if they are compatible, and
+ two if they are nearly compatible (which causes a warning to be
+ generated). */
+
+#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
+ (ns32k_comp_type_attributes (TYPE1, TYPE2))
+
+/* If defined, a C statement that assigns default attributes to newly
+ defined TYPE. */
+
+/* #define SET_DEFAULT_TYPE_ATTRIBUTES (TYPE) */
+
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction.
HI mode is more efficient but the range is not wide enough for
@@ -1107,6 +1337,12 @@ while (0)
in one reasonably fast instruction. */
#define MOVE_MAX 4
+/* The number of scalar move insns which should be generated instead
+ of a string move insn or a library call.
+
+ We have a smart movstrsi insn */
+#define MOVE_RATIO 0
+
/* Define this if zero-extension is slow (more than one real instruction). */
/* #define SLOW_ZERO_EXTEND */
@@ -1226,16 +1462,13 @@ while (0)
/* Describe the costs of the following register moves which are discouraged:
1.) Moves between the Floating point registers and the frame pointer and stack pointer
2.) Moves between the stack pointer and the frame pointer
- 3.) Moves between the floating point and general registers */
+ 3.) Moves between the floating point and general registers
+
+ These all involve two memory references. This is worse than a memory
+ to memory move (default cost 4)
+ */
-#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
- ((((CLASS1) == FLOAT_REGS && ((CLASS2) == STACK_POINTER_REG || (CLASS2) == FRAME_POINTER_REG)) \
- || ((CLASS2) == FLOAT_REGS && ((CLASS1) == STACK_POINTER_REG || (CLASS1) == FRAME_POINTER_REG)) \
- || ((CLASS1) == STACK_POINTER_REG && (CLASS2) == FRAME_POINTER_REG) \
- || ((CLASS2) == STACK_POINTER_REG && (CLASS1) == FRAME_POINTER_REG) \
- || ((CLASS1) == FLOAT_REGS && (CLASS2) == GENERAL_REGS) \
- || ((CLASS1) == GENERAL_REGS && (CLASS2) == FLOAT_REGS)) \
- ? 4 : 2)
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) register_move_cost(CLASS1, CLASS2)
#define OUTPUT_JUMP(NORMAL, NO_OV) \
{ if (cc_status.flags & CC_NO_OVERFLOW) \
@@ -1307,12 +1540,8 @@ while (0)
/* This is how to output an assembler line defining an external/static
address which is not in tree format (for collect.c). */
-#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \
-do { \
- fprintf (STREAM, "\t.long\t"); \
- ASM_OUTPUT_LABELREF (STREAM, NAME); \
- fprintf (STREAM, "\n"); \
-} while (0)
+/* The prefix to add to user-visible assembler symbols. */
+#define USER_LABEL_PREFIX "_"
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
@@ -1326,19 +1555,6 @@ do { \
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tmovd tos,%s\n", reg_names[REGNO])
-/* How to refer to registers in assembler output.
- This sequence is indexed by compiler's hard-register-number (see above). */
-
-#define REGISTER_NAMES \
-{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
- "fp", "sp"}
-
-/* How to renumber registers for dbx and gdb.
- NS32000 may need more change in the numeration. */
-
-#define DBX_REGISTER_NUMBER(REGNO) ((REGNO < 8) ? (REGNO)+4 : (REGNO))
-
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
@@ -1365,9 +1581,11 @@ do { \
} while (0)
#endif
-/* The prefix to add to user-visible assembler symbols. */
+/* This is how to output a reference to a user-level label named NAME.
+ `assemble_name' uses this. */
-#define USER_LABEL_PREFIX "_"
+#define ASM_OUTPUT_LABELREF(FILE,NAME) \
+ fprintf (FILE, "_%s", NAME)
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
@@ -1463,11 +1681,39 @@ do { \
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR)
-/* Define functions in ns32k.c and used in insn-output.c. */
-
-extern char *output_move_double ();
-extern char *output_shift_insn ();
-extern char *output_move_dconst ();
+/* Prototypes for functions in ns32k.c */
+
+/* Prototypes would be nice, but for now it causes too many problems.
+ This file gets included in places where the types (such as "rtx"
+ and enum machine_mode) are not defined. */
+#define NS32K_PROTO(ARGS) ()
+
+int hard_regno_mode_ok NS32K_PROTO((int regno, enum machine_mode mode));
+int register_move_cost NS32K_PROTO((enum reg_class CLASS1, enum reg_class CLASS2));
+int calc_address_cost NS32K_PROTO((rtx operand));
+enum reg_class secondary_reload_class NS32K_PROTO((enum reg_class class,
+ enum machine_mode mode, rtx in));
+int reg_or_mem_operand NS32K_PROTO((register rtx op, enum machine_mode mode));
+
+void split_di NS32K_PROTO((rtx operands[], int num, rtx lo_half[], hi_half[]));
+
+void expand_block_move NS32K_PROTO((rtx operands[]));
+int global_symbolic_reference_mentioned_p NS32K_PROTO((rtx op, int f));
+int ns32k_comp_type_attributes NS32K_PROTO((tree type1, tree type2));
+int ns32k_return_pops_args NS32K_PROTO((tree fundecl, tree funtype, int size));
+int ns32k_valid_decl_attribute_p NS32K_PROTO((tree decl, tree attributes,
+ tree identifier, tree args));
+int ns32k_valid_type_attribute_p NS32K_PROTO((tree decl, tree attributes,
+ tree identifier, tree args));
+void print_operand NS32K_PROTO((FILE *file, rtx x, char code));
+void print_operand_address NS32K_PROTO((register FILE *file, register rtx addr));
+char *output_move_dconst NS32K_PROTO((int n, char *s));
+char *output_move_double NS32K_PROTO((rtx *operands));
+char *output_shift_insn NS32K_PROTO((rtx *operands));
+
+extern unsigned int ns32k_reg_class_contents[N_REG_CLASSES];
+extern char *ns32k_out_reg_names[];
+extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
/*
Local variables:
diff --git a/gcc/config/ns32k/ns32k.md b/gcc/config/ns32k/ns32k.md
index e44cccc..161b74e 100644
--- a/gcc/config/ns32k/ns32k.md
+++ b/gcc/config/ns32k/ns32k.md
@@ -39,7 +39,20 @@
;; We don't want to allow a constant operand for test insns because
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
-
+;;
+;; In order for pic mode to work we cannot generate, for example
+;;
+;; addd _x+5,r1
+;;
+;; instead we must force gcc to generate something like
+;;
+;; addr 5(_x(sb)),r0
+;; addd r0,r1
+;;
+;; This was done through operand constraints (using "rmn" in place of "g"),
+;; but with the proper definition of LEGITIMATE_PIC_OPERAND (ns32k.h)
+;; this is unnecessary.
+;;
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
@@ -69,7 +82,7 @@
(define_insn "tstdf"
[(set (cc0)
- (match_operand:DF 0 "general_operand" "fmF"))]
+ (match_operand:DF 0 "general_operand" "lmF"))]
"TARGET_32081"
"*
{ cc_status.flags |= CC_REVERSED;
@@ -85,10 +98,11 @@
operands[1] = CONST0_RTX (SFmode);
return \"cmpf %1,%0\"; }")
+;; See note 1
(define_insn "cmpsi"
[(set (cc0)
- (compare (match_operand:SI 0 "nonimmediate_operand" "rmn")
- (match_operand:SI 1 "general_operand" "rmn")))]
+ (compare (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g")))]
""
"*
{
@@ -113,7 +127,7 @@
(define_insn "cmphi"
[(set (cc0)
- (compare (match_operand:HI 0 "nonimmediate_operand" "g")
+ (compare (match_operand:HI 0 "general_operand" "g")
(match_operand:HI 1 "general_operand" "g")))]
""
"*
@@ -145,7 +159,7 @@
(define_insn "cmpqi"
[(set (cc0)
- (compare (match_operand:QI 0 "nonimmediate_operand" "g")
+ (compare (match_operand:QI 0 "general_operand" "g")
(match_operand:QI 1 "general_operand" "g")))]
""
"*
@@ -177,8 +191,8 @@
(define_insn "cmpdf"
[(set (cc0)
- (compare (match_operand:DF 0 "general_operand" "fmF")
- (match_operand:DF 1 "general_operand" "fmF")))]
+ (compare (match_operand:DF 0 "general_operand" "lmF")
+ (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"cmpl %0,%1")
@@ -189,9 +203,14 @@
"TARGET_32081"
"cmpf %0,%1")
+;; movdf and movsf copy between general and floating registers using
+;; the stack. In principle, we could get better code not allowing
+;; that case in the constraints and defining SECONDARY_MEMORY_NEEDED
+;; in practice, though the stack slots used are not available for
+;; optimization.
(define_insn "movdf"
- [(set (match_operand:DF 0 "general_operand" "=fg<")
- (match_operand:DF 1 "general_operand" "fFg"))]
+ [(set (match_operand:DF 0 "general_operand" "=lg<")
+ (match_operand:DF 1 "general_operand" "lFg"))]
""
"*
{
@@ -231,7 +250,7 @@
{
if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,tos\;movf tos,%0\";
else
return \"movf %1,%0\";
@@ -308,8 +327,8 @@
;; This special case must precede movsi.
(define_insn ""
- [(set (reg:SI 17)
- (match_operand:SI 0 "general_operand" "rmn"))]
+ [(set (reg:SI 25)
+ (match_operand:SI 0 "general_operand" "g"))]
""
"lprd sp,%0")
@@ -323,7 +342,7 @@
if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,tos\;movf tos,%0\";
else
return \"movf %1,%0\";
@@ -347,16 +366,16 @@
{
if (i <= 7 && i >= -8)
return \"movqd %1,%0\";
- if (i <= 0x1fffffff && i >= -0x20000000)
+ if (NS32K_DISPLACEMENT_P (i))
#if defined (GNX_V3) || defined (UTEK_ASM)
return \"addr %c1,%0\";
#else
return \"addr @%c1,%0\";
#endif
- return \"movd %$%1,%0\";
+ return \"movd %1,%0\";
}
else
- return output_move_dconst(i, \"%$%1,%0\");
+ return output_move_dconst(i, \"%1,%0\");
}
else if (GET_CODE (operands[1]) == CONST && ! flag_pic)
{
@@ -364,11 +383,11 @@
* that case addr might lead to overflow. For PIC symbolic
* address loads always have to be done with addr.
*/
- return \"movd %$%1,%0\";
+ return \"movd %1,%0\";
}
else if (GET_CODE (operands[1]) == REG)
{
- if (REGNO (operands[1]) < 16)
+ if (REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,%0\";
else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM)
{
@@ -426,7 +445,7 @@
}
else if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movwf %1,tos\;movf tos,%0\";
else
return \"movwf %1,%0\";
@@ -472,7 +491,7 @@
}
else if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movbf %1,tos\;movf tos,%0\";
else
return \"movbf %1,%0\";
@@ -499,75 +518,63 @@
return \"movb %1,%0\";
}")
-;; This is here to accept 4 arguments and pass the first 3 along
-;; to the movstrsi1 pattern that really does the work.
+;; Block moves
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+;;
+;; Strategy: Use define_expand to
+;; either emit insns directly if it can be done simply or
+;; emit rtl to match movstrsi1 which has extra scratch registers
+;; which can be used to generate more complex code.
+
(define_expand "movstrsi"
- [(set (match_operand:BLK 0 "general_operand" "=g")
- (match_operand:BLK 1 "general_operand" "g"))
- (use (match_operand:SI 2 "general_operand" "rmn"))
- (match_operand 3 "" "")]
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" ""))
+ (use (match_operand:SI 2 "general_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
""
"
- emit_insn (gen_movstrsi1 (operands[0], operands[1], operands[2]));
- DONE;
-")
+{
+ if (operands[0]) /* avoid unused code messages */
+ {
+ expand_block_move (operands);
+ DONE;
+ }
+}")
+
+;; Special Registers:
+;; r0 count
+;; r1 from
+;; r2 to
+;; r3 match
+
-;; The definition of this insn does not really explain what it does,
-;; but it should suffice
-;; that anything generated as this insn will be recognized as one
-;; and that it won't successfully combine with anything.
(define_insn "movstrsi1"
- [(set (match_operand:BLK 0 "general_operand" "=g")
- (match_operand:BLK 1 "general_operand" "g"))
- (use (match_operand:SI 2 "general_operand" "rmn"))
- (clobber (reg:SI 0))
- (clobber (reg:SI 1))
- (clobber (reg:SI 2))]
+ [(set (mem:BLK (reg:SI 2))
+ (mem:BLK (reg:SI 1)))
+ (use (reg:SI 0))
+ (set (reg:SI 2) (plus:SI (reg:SI 2) (mult:SI (reg:SI 0) (match_operand:SI 0 "const_int_operand" ""))))
+ (set (reg:SI 1) (plus:SI (reg:SI 1) (mult:SI (reg:SI 0) (match_dup 0))))
+ (set (reg:SI 0) (const_int 0))]
""
"*
-{
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- abort ();
- operands[0] = XEXP (operands[0], 0);
- operands[1] = XEXP (operands[1], 0);
- if (GET_CODE (operands[0]) == MEM)
- if (GET_CODE (operands[1]) == MEM)
- output_asm_insn (\"movd %0,r2\;movd %1,r1\", operands);
- else
- output_asm_insn (\"movd %0,r2\;addr %a1,r1\", operands);
- else if (GET_CODE (operands[1]) == MEM)
- output_asm_insn (\"addr %a0,r2\;movd %1,r1\", operands);
- else
- output_asm_insn (\"addr %a0,r2\;addr %a1,r1\", operands);
+ {
+ int align = INTVAL(operands[0]);
+ if (align == 4)
+ return \"movsd\";
+ else
+ return \"movsb\";
+ }")
+
+(define_insn "movstrsi2"
+ [(set (mem:BLK (match_operand:SI 0 "address_operand" "g"))
+ (mem:BLK (match_operand:SI 1 "address_operand" "g")))
+ (use (match_operand 2 "immediate_operand" "i"))]
+ ""
+ "movmd %a1,%a0,%2")
-#ifdef UTEK_ASM
- if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0)
- {
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 2);
- if ((unsigned) INTVAL (operands[2]) <= 7)
- return \"movqd %2,r0\;movsd $0\";
- else
- return \"movd %2,r0\;movsd $0\";
- }
- else
- {
- return \"movd %2,r0\;movsb $0\";
- }
-#else
- if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0)
- {
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 2);
- if ((unsigned) INTVAL (operands[2]) <= 7)
- return \"movqd %2,r0\;movsd\";
- else
- return \"movd %2,r0\;movsd\";
- }
- else
- {
- return \"movd %2,r0\;movsb\";
- }
-#endif
-}")
;; Extension and truncation insns.
;; Those for integer source operand
@@ -575,13 +582,13 @@
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rmn")))]
+ (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))]
""
"movb %1,%0")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rmn")))]
+ (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))]
""
"movw %1,%0")
@@ -610,14 +617,14 @@
"movxbd %1,%0")
(define_insn "extendsfdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))]
"TARGET_32081"
"movfl %1,%0")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=fm<")
- (float_truncate:SF (match_operand:DF 1 "general_operand" "fmF")))]
+ (float_truncate:SF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"movlf %1,%0")
@@ -657,7 +664,7 @@
"movdf %1,%0")
(define_insn "floatsidf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float:DF (match_operand:SI 1 "general_operand" "rm")))]
"TARGET_32081"
"movdl %1,%0")
@@ -669,7 +676,7 @@
"movwf %1,%0")
(define_insn "floathidf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float:DF (match_operand:HI 1 "general_operand" "rm")))]
"TARGET_32081"
"movwl %1,%0")
@@ -683,7 +690,7 @@
; Some assemblers warn that this insn doesn't work.
; Maybe they know something we don't.
;(define_insn "floatqidf2"
-; [(set (match_operand:DF 0 "general_operand" "=fm<")
+; [(set (match_operand:DF 0 "general_operand" "=lm<")
; (float:DF (match_operand:QI 1 "general_operand" "rm")))]
; "TARGET_32081"
; "movbl %1,%0")
@@ -711,19 +718,19 @@
(define_insn "fixdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fixdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fixdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"truncld %1,%0")
@@ -749,19 +756,19 @@
(define_insn "fixunsdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fixunsdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fixunsdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"truncld %1,%0")
@@ -786,28 +793,69 @@
(define_insn "fix_truncdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (fix:QI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:QI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fix_truncdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (fix:HI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:HI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (fix:SI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:SI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"truncld %1,%0")
+;; Multiply-add instructions
+(define_insn ""
+ [(set (match_operand:DF 0 "general_operand" "=v,v")
+ (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF,0")
+ (match_operand:DF 2 "general_operand" "lmF,lmF"))
+ (match_operand:DF 3 "general_operand" "0,lmF")))]
+ "TARGET_MULT_ADD"
+ "@
+ dotl %1,%2
+ polyl %2,%3")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "general_operand" "=u,u")
+ (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF,0")
+ (match_operand:SF 2 "general_operand" "fmF,fmF"))
+ (match_operand:SF 3 "general_operand" "0,fmF")))]
+ "TARGET_MULT_ADD"
+ "@
+ dotf %1,%2
+ polyf %2,%3")
+
+
+;; Multiply-sub instructions
+(define_insn ""
+ [(set (match_operand:DF 0 "general_operand" "=v")
+ (minus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF")
+ (match_operand:DF 2 "general_operand" "lmF"))
+ (match_operand:DF 3 "general_operand" "0")))]
+ "TARGET_MULT_ADD"
+ "@
+ negl %0,%0\;dotl %1,%2")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "general_operand" "=u")
+ (minus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF")
+ (match_operand:SF 2 "general_operand" "fmF"))
+ (match_operand:SF 3 "general_operand" "0")))]
+ "TARGET_MULT_ADD"
+ "@
+ negf %0,%0\;dotf %1,%2")
+
;;- All kinds of add instructions.
(define_insn "adddf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(plus:DF (match_operand:DF 1 "general_operand" "%0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"addl %2,%0")
@@ -820,8 +868,8 @@
"addf %2,%0")
(define_insn ""
- [(set (reg:SI 17)
- (plus:SI (reg:SI 17)
+ [(set (reg:SI 25)
+ (plus:SI (reg:SI 25)
(match_operand:SI 0 "immediate_operand" "i")))]
"GET_CODE (operands[0]) == CONST_INT"
"*
@@ -837,23 +885,23 @@
if (! TARGET_32532)
{
if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64)
- return \"adjspb %$%n0\";
+ return \"adjspb %n0\";
else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192)
- return \"adjspw %$%n0\";
+ return \"adjspw %n0\";
}
- return \"adjspd %$%n0\";
+ return \"adjspd %n0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g<")
- (plus:SI (reg:SI 16)
+ (plus:SI (reg:SI 24)
(match_operand:SI 1 "immediate_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT"
"addr %c1(fp),%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g<")
- (plus:SI (reg:SI 17)
+ (plus:SI (reg:SI 25)
(match_operand:SI 1 "immediate_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT"
"addr %c1(sp),%0")
@@ -882,14 +930,14 @@
{
i = INTVAL (xops[3]);
if (i <= 7 && i >= -8)
- output_asm_insn (\"addqd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %3,%1\", xops);
else
- output_asm_insn (\"addd %$%3,%1\", xops);
+ output_asm_insn (\"addd %3,%1\", xops);
}
else
{
- output_asm_insn (\"addqd %$%2,%0\", xops);
- output_asm_insn (\"addcd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %2,%0\", xops);
+ output_asm_insn (\"addcd %3,%1\", xops);
}
return \"\";
}
@@ -899,29 +947,40 @@
return \"\";
}")
+;; See Note 1
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=g,=g&<")
(plus:SI (match_operand:SI 1 "general_operand" "%0,r")
- (match_operand:SI 2 "general_operand" "rmn,n")))]
+ (match_operand:SI 2 "general_operand" "g,i")))]
""
"*
{
if (which_alternative == 1)
{
- int i = INTVAL (operands[2]);
- if (NS32K_DISPLACEMENT_P (i))
- return \"addr %c2(%1),%0\";
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int i = INTVAL (operands[2]);
+ if (NS32K_DISPLACEMENT_P (i))
+ return \"addr %c2(%1),%0\";
+ else
+ return \"movd %1,%0\;addd %2,%0\";
+ }
else
- return \"movd %1,%0\;addd %2,%0\";
+ {
+ if (flag_pic)
+ return \"addr %a2[%1:b],%0\";
+ else
+ return \"addr %c2(%1),%0\";
+ }
}
- if (GET_CODE (operands[2]) == CONST_INT)
+ else if (GET_CODE (operands[2]) == CONST_INT)
{
int i = INTVAL (operands[2]);
if (i <= 7 && i >= -8)
return \"addqd %2,%0\";
else if (! TARGET_32532 && GET_CODE (operands[0]) == REG
- && i <= 0x1fffffff && i >= -0x20000000)
+ && NS32K_DISPLACEMENT_P (i))
return \"addr %c2(%0),%0\";
}
return \"addd %2,%0\";
@@ -986,9 +1045,9 @@
;;- All kinds of subtract instructions.
(define_insn "subdf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(minus:DF (match_operand:DF 1 "general_operand" "0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"subl %2,%0")
@@ -1000,16 +1059,16 @@
"subf %2,%0")
(define_insn ""
- [(set (reg:SI 17)
- (minus:SI (reg:SI 17)
+ [(set (reg:SI 25)
+ (minus:SI (reg:SI 25)
(match_operand:SI 0 "immediate_operand" "i")))]
"GET_CODE (operands[0]) == CONST_INT"
"*
{
if (! TARGET_32532 && GET_CODE(operands[0]) == CONST_INT
&& INTVAL(operands[0]) < 64 && INTVAL(operands[0]) > -64)
- return \"adjspb %$%0\";
- return \"adjspd %$%0\";
+ return \"adjspb %0\";
+ return \"adjspd %0\";
}")
(define_insn "subdi3"
@@ -1036,14 +1095,14 @@
{
i = INTVAL (xops[3]);
if (i <= 8 && i >= -7)
- output_asm_insn (\"addqd %$%n3,%1\", xops);
+ output_asm_insn (\"addqd %n3,%1\", xops);
else
- output_asm_insn (\"subd %$%3,%1\", xops);
+ output_asm_insn (\"subd %3,%1\", xops);
}
else
{
- output_asm_insn (\"addqd %$%n2,%0\", xops);
- output_asm_insn (\"subcd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %n2,%0\", xops);
+ output_asm_insn (\"subcd %3,%1\", xops);
}
return \"\";
}
@@ -1056,7 +1115,7 @@
(define_insn "subsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(minus:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
@@ -1064,7 +1123,7 @@
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqd %$%n2,%0\";
+ return \"addqd %n2,%0\";
}
return \"subd %2,%0\";
}")
@@ -1080,7 +1139,7 @@
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqw %$%n2,%0\";
+ return \"addqw %n2,%0\";
}
return \"subw %2,%0\";
}")
@@ -1094,7 +1153,7 @@
{
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9)
- return \"addqw %$%n2,%0\";
+ return \"addqw %n2,%0\";
return \"subw %2,%0\";
}")
@@ -1109,7 +1168,7 @@
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqb %$%n2,%0\";
+ return \"addqb %n2,%0\";
}
return \"subb %2,%0\";
}")
@@ -1123,16 +1182,16 @@
{
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9)
- return \"addqb %$%n2,%0\";
+ return \"addqb %n2,%0\";
return \"subb %2,%0\";
}")
;;- Multiply instructions.
(define_insn "muldf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(mult:DF (match_operand:DF 1 "general_operand" "%0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"mull %2,%0")
@@ -1143,10 +1202,11 @@
"TARGET_32081"
"mulf %2,%0")
+;; See note 1
(define_insn "mulsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"muld %2,%0")
@@ -1169,16 +1229,195 @@
(mult:DI (zero_extend:DI
(match_operand:SI 1 "nonimmediate_operand" "0"))
(zero_extend:DI
- (match_operand:SI 2 "nonimmediate_operand" "rmn"))))]
+ (match_operand:SI 2 "nonimmediate_operand" "g"))))]
""
"meid %2,%0")
+;; divmod insns: We can only do the unsigned case.
+(define_expand "udivmodsi4"
+ [(parallel
+ [(set (match_operand:SI 0 "reg_or_mem_operand" "")
+ (udiv:SI (match_operand:SI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (set (match_operand:SI 3 "reg_or_mem_operand" "")
+ (umod:SI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(SImode, temp), operands[1]);
+ emit_move_insn(gen_highpart(SImode, temp), const0_rtx);
+ emit_insn(gen_udivmoddisi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divsi, modsi;
+ divsi = gen_rtx (UDIV, SImode, operands[1], operands[2]);
+ modsi = gen_rtx (UMOD, SImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divsi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modsi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx (IOR, DImode, moddi,
+ gen_rtx (ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(SImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(SImode, temp));
+ DONE;
+}")
+
+;; If we try and describe what this does, we have to zero-expand an
+;; operand, which prevents it being a constant (VOIDmode) (see udivmoddisi4
+;; below. This udivmoddisi4_internal never matches anything and is only
+;; ever used when explicitly emitted by a define_expand.
+(define_insn "udivmoddisi4_internal"
+ [(set (match_operand:DI 0 "reg_or_mem_operand" "=rm")
+ (unspec:SI [(match_operand:DI 1 "reg_or_mem_operand" "0")
+ (match_operand:SI 2 "general_operand" "g")] 0))]
+ ""
+ "deid %2,%0")
+
+;; Retain this insn which *does* have a pattern indicating what it does,
+;; just in case the compiler is smart enough to recognize a substitution.
+(define_insn "udivmoddisi4"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "=rm") 1)
+ (truncate:SI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:SI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:SI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deid %2,%0")
+
+;; Part word variants. These seem to never be used at the moment (gcc
+;; 2.7.2.2). The code generation prefers to zero extend hi's and qi's
+;; and use signed div and mod. Keep these insns incase that changes.
+;; divmod should have an advantage when both div and mod are needed. However,
+;; divmod uses two registers, so maybe the compiler knows best.
+
+(define_expand "udivmodhi4"
+ [(parallel
+ [(set (match_operand:HI 0 "reg_or_mem_operand" "")
+ (udiv:HI (match_operand:HI 1 "general_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (set (match_operand:HI 3 "reg_or_mem_operand" "")
+ (umod:HI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(HImode, temp), operands[1]);
+ emit_move_insn(gen_highpart (HImode, temp), const0_rtx);
+ operands[2] = force_reg(HImode, operands[2]);
+ emit_insn(gen_udivmoddihi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divhi, modhi;
+ divhi = gen_rtx (UDIV, HImode, operands[1], operands[2]);
+ modhi = gen_rtx (UMOD, HImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divhi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modhi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx(IOR, DImode, moddi,
+ gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(HImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(HImode, temp));
+ DONE;
+}")
+
+;; deiw wants two hi's in seperate registers or else they can be adjacent
+;; in memory. DI mode will ensure two registers are available, but if we
+;; want to allow memory as an operand we would need SI mode. There is no
+;; way to do this, so just restrict operand 0 and 1 to be in registers.
+(define_insn "udivmoddihi4_internal"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:DI 1 "register_operand" "0")
+ (match_operand:HI 2 "general_operand" "g")] 0))]
+ ""
+ "deiw %2,%0")
+
+(define_insn "udivmoddihi4"
+ [(set (subreg:HI (match_operand:DI 0 "register_operand" "=r") 1)
+ (truncate:HI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:HI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:HI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:HI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deiw %2,%0")
+
+(define_expand "udivmodqi4"
+ [(parallel
+ [(set (match_operand:QI 0 "reg_or_mem_operand" "")
+ (udiv:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (set (match_operand:QI 3 "reg_or_mem_operand" "")
+ (umod:QI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(QImode, temp), operands[1]);
+ emit_move_insn(gen_highpart(QImode, temp), const0_rtx);
+ operands[2] = force_reg(QImode, operands[2]);
+ emit_insn(gen_udivmoddiqi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divqi, modqi;
+ divqi = gen_rtx (UDIV, QImode, operands[1], operands[2]);
+ modqi = gen_rtx (UMOD, QImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divqi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modqi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx(IOR, DImode, moddi,
+ gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(QImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(QImode, temp));
+ DONE;
+}")
+
+;; deib wants two qi's in seperate registers or else they can be adjacent
+;; in memory. DI mode will ensure two registers are available, but if we
+;; want to allow memory as an operand we would need HI mode. There is no
+;; way to do this, so just restrict operand 0 and 1 to be in registers.
+(define_insn "udivmoddiqi4_internal"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:QI [(match_operand:DI 1 "reg_or_mem_operand" "0")
+ (match_operand:QI 2 "general_operand" "g")] 0))]
+ ""
+ "deib %2,%0")
+
+(define_insn "udivmoddiqi4"
+ [(set (subreg:QI (match_operand:DI 0 "register_operand" "=r") 1)
+ (truncate:QI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:QI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:QI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:QI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deib %2,%0")
+
;;- Divide instructions.
(define_insn "divdf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(div:DF (match_operand:DF 1 "general_operand" "0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"divl %2,%0")
@@ -1189,10 +1428,11 @@
"TARGET_32081"
"divf %2,%0")
+;; See note 1
(define_insn "divsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(div:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"quod %2,%0")
@@ -1209,46 +1449,14 @@
(match_operand:QI 2 "general_operand" "g")))]
""
"quob %2,%0")
-
-(define_insn "udivsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (udiv:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:SI 2 "general_operand" "rmn")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- return \"deid %2,%0\;movd %1,%0\";
-}")
-
-(define_insn "udivhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (udiv:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:HI 2 "general_operand" "g")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
- return \"deiw %2,%0\;movw %1,%0\";
-}")
-
-(define_insn "udivqi3"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (udiv:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:QI 2 "general_operand" "g")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, QImode, REGNO (operands[0]) + 1);
- return \"deib %2,%0\;movb %1,%0\";
-}")
-
+
;; Remainder instructions.
+;; See note 1
(define_insn "modsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(mod:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"remd %2,%0")
@@ -1266,43 +1474,14 @@
""
"remb %2,%0")
-(define_insn "umodsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (umod:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:SI 2 "general_operand" "rmn")))]
- ""
- "deid %2,%0")
-
-(define_insn "umodhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (umod:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:HI 2 "general_operand" "g")))]
- ""
- "deiw %2,%0")
-
-(define_insn "umodqi3"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (umod:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:QI 2 "general_operand" "g")))]
- ""
- "deib %2,%0")
-
-; This isn't be usable in its current form.
-;(define_insn "udivmoddisi4"
-; [(set (subreg:SI (match_operand:DI 0 "general_operand" "=r") 1)
-; (udiv:SI (match_operand:DI 1 "general_operand" "0")
-; (match_operand:SI 2 "general_operand" "rmn")))
-; (set (subreg:SI (match_dup 0) 0)
-; (umod:SI (match_dup 1) (match_dup 2)))]
-; ""
-; "deid %2,%0")
;;- Logical Instructions: AND
+;; See note 1
(define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(and:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
@@ -1360,9 +1539,10 @@
""
"andb %2,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
- (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn"))
+ (and:SI (not:SI (match_operand:SI 1 "general_operand" "g"))
(match_operand:SI 2 "general_operand" "0")))]
""
"bicd %1,%0")
@@ -1383,10 +1563,11 @@
;;- Bit set instructions.
+;; See note 1
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(ior:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
@@ -1421,10 +1602,11 @@
;;- xor instructions.
+;; See note 1
(define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(xor:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
@@ -1458,8 +1640,8 @@
"xorb %2,%0")
(define_insn "negdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
- (neg:DF (match_operand:DF 1 "general_operand" "fmF")))]
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
+ (neg:DF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"negl %1,%0")
@@ -1497,9 +1679,10 @@
return \"\";
}")
+;; See note 1
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (neg:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (neg:SI (match_operand:SI 1 "general_operand" "g")))]
""
"negd %1,%0")
@@ -1515,9 +1698,10 @@
""
"negb %1,%0")
+;; See note 1
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (not:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (not:SI (match_operand:SI 1 "general_operand" "g")))]
""
"comd %1,%0")
@@ -1540,10 +1724,11 @@
;; than elsewhere.
;; alternative 0 never matches on the 32532
+;; See note 1
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "general_operand" "=g,g")
(ashift:SI (match_operand:SI 1 "general_operand" "r,0")
- (match_operand:SI 2 "general_operand" "I,rmn")))]
+ (match_operand:SI 2 "general_operand" "I,g")))]
""
"*
{ if (TARGET_32532)
@@ -1555,7 +1740,7 @@
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
@@ -1574,7 +1759,7 @@
(define_insn "ashlqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(ashift:QI (match_operand:QI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
@@ -1607,7 +1792,7 @@
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashd %$%n2,%0")
+ "ashd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
@@ -1632,7 +1817,7 @@
(ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashw %$%n2,%0")
+ "ashw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
@@ -1657,7 +1842,7 @@
(ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashb %$%n2,%0")
+ "ashb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
@@ -1685,7 +1870,7 @@
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshd %$%n2,%0")
+ "lshd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
@@ -1710,7 +1895,7 @@
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshw %$%n2,%0")
+ "lshw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
@@ -1735,7 +1920,7 @@
(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshb %$%n2,%0")
+ "lshb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
@@ -1746,24 +1931,25 @@
;; Rotate instructions
+;; See note 1
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(rotate:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotd %2,%0")
(define_insn "rotlhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(rotate:HI (match_operand:HI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotw %2,%0")
(define_insn "rotlqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(rotate:QI (match_operand:QI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotb %2,%0")
@@ -1784,7 +1970,7 @@
(rotatert:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotd %$%n2,%0")
+ "rotd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
@@ -1809,7 +1995,7 @@
(rotatert:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotw %$%n2,%0")
+ "rotw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
@@ -1834,7 +2020,7 @@
(rotatert:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotb %$%n2,%0")
+ "rotb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
@@ -1871,53 +2057,58 @@
;;; Index insns. These are about the same speed as multiply-add counterparts.
;;; but slower then using power-of-2 shifts if we can use them
;
+;;; See note 1
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
-; (plus:SI (match_operand:SI 1 "general_operand" "rmn")
+; (plus:SI (match_operand:SI 1 "general_operand" "g")
; (mult:SI (match_operand:SI 2 "register_operand" "0")
-; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (const_int 1)))))]
+; (plus:SI (match_operand:SI 3 "general_operand" "g") (const_int 1)))))]
; "GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) > 8"
; "indexd %0,%3,%1")
;
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
-; (plus:SI (match_operand:SI 2 "general_operand" "rmn") (const_int 1)))
-; (match_operand:SI 3 "general_operand" "rmn")))]
+; (plus:SI (match_operand:SI 2 "general_operand" "g") (const_int 1)))
+; (match_operand:SI 3 "general_operand" "g")))]
; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8"
; "indexd %0,%2,%3")
;; Set, Clear, and Invert bit
+;; See note 1
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(const_int 1))]
""
"sbitd %1,%0")
+;; See note 1
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(const_int 0))]
""
"cbitd %1,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "+g")
(xor:SI (ashift:SI (const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(match_dup 0)))]
""
"ibitd %1,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
(xor:QI (subreg:QI
(ashift:SI (const_int 1)
- (match_operand:QI 1 "general_operand" "rmn")) 0)
+ (match_operand:QI 1 "general_operand" "g")) 0)
(match_dup 0)))]
""
"ibitb %1,%0")
@@ -2308,7 +2499,7 @@
(minus:SI (match_dup 0)
(match_dup 1)))]
"INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8"
- "acbd %$%n1,%0,%l2")
+ "acbd %n1,%0,%l2")
(define_insn ""
[(set (pc)
@@ -2450,14 +2641,15 @@
"absf %1,%0")
(define_insn "absdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
- (abs:DF (match_operand:DF 1 "general_operand" "fmF")))]
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
+ (abs:DF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"absl %1,%0")
+;; See note 1
(define_insn "abssi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (abs:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (abs:SI (match_operand:SI 1 "general_operand" "g")))]
""
"absd %1,%0")
@@ -2745,14 +2937,14 @@
;; Speed up stack adjust followed by a HI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(match_operand:HI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzwd %1,tos\", operands);
@@ -2762,14 +2954,14 @@
;; Speed up stack adjust followed by a zero_extend:HI(QI) fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(zero_extend:HI (match_operand:QI 1 "general_operand" "g")))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzbd %1,tos\", operands);
@@ -2779,14 +2971,14 @@
;; Speed up stack adjust followed by a sign_extend:HI(QI) fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(sign_extend:HI (match_operand:QI 1 "general_operand" "g")))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movxbd %1,tos\", operands);
@@ -2796,14 +2988,14 @@
;; Speed up stack adjust followed by a QI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -3)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -3)))
(set (match_operand:QI 0 "push_operand" "=m")
(match_operand:QI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzbd %1,tos\", operands);
@@ -2813,14 +3005,14 @@
;; Speed up stack adjust followed by a SI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 4)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 4)))
(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,0(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,0(sp)\"),
operands);
else if (GET_CODE (operands[1]) != REG
&& GET_CODE (operands[1]) != MEM
@@ -2834,7 +3026,7 @@
;; Speed up stack adjust followed by two fullword fixedpoint pushes.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 8)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 8)))
(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "g"))
(set (match_operand:SI 2 "push_operand" "=m")
@@ -2844,7 +3036,7 @@
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,4(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,4(sp)\"),
operands);
else if (GET_CODE (operands[1]) != REG
&& GET_CODE (operands[1]) != MEM
@@ -2854,7 +3046,7 @@
output_asm_insn (\"movd %1,4(sp)\", operands);
if (GET_CODE (operands[3]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%$%3,0(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%3,0(sp)\"),
operands);
else if (GET_CODE (operands[3]) != REG
&& GET_CODE (operands[3]) != MEM