OSDN Git Service

Bulk ns32k patch from Ian Dall. See ChangeLog for details.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Nov 1998 23:34:42 +0000 (23:34 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Nov 1998 23:34:42 +0000 (23:34 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@23887 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/README.NS32K
gcc/config/ns32k/netbsd.h
gcc/config/ns32k/ns32k.c
gcc/config/ns32k/ns32k.h
gcc/config/ns32k/ns32k.md
gcc/invoke.texi

index a37aa33..e206ac6 100644 (file)
@@ -1,3 +1,102 @@
+Wed Nov 25 23:32:02 1998  Ian Dall  <Ian.Dall@dsto.defence.gov.au>
+                         Matthias Pfaller  <leo@dachau.marco.de>
+
+       * invoke.texi (Option Summary, NS32K Options): add description
+       of NS32K specific options.
+
+       * ns32k.md (tstdf, cmpdf, movdf, truncdfsf2, fixdfqi2, fixdfhi2,
+       fixdfsi2, fixunsdfqi2, fixunsdfhi2, fixunsdfsi2, fix_truncdfqi2,
+       fix_truncdfhi2, fix_truncdfsi2, adddf3, subdf3, muldf3, divdf3,
+       negdf2, absdf2): Use l instead of f since the double class and
+       float class are no longer the same.
+       (cmpsi, truncsiqi2, truncsihi2, addsi3, subsi3, mulsi3, umulsidi3,
+       divsi3, modsi3, andsi3, iorsi3, xorsi3, negsi2, one_cmplsi2,
+       ashlsi3, ashlhi3, ashlqi3, rotlsi3, rotlhi3, rotlqi3, abssi2,...):
+       use "g" instead of "rmn" since LEGITIMATE_PIC_OPERAND has been
+       fixed.
+       (cmpsi, cmphi, cmpqi): use general_operand instead of
+       non_immediate_operand. Removes erroneous assumption that can't
+       compare constants.
+       (movsf, movsi, movhi, movqi,...): New register numbering scheme.
+       (movsi, addsi3): Use NS32K_DISPLACEMENT_P instead of hard coded
+       constants.
+       (movstrsi, movstrsi1, movstrsi2): completely new block move
+       scheme.
+       (...): Patterns to exploit multiply-add instructions.
+       (udivmodsi4, udivmodsi_internal4, udivmodhi4,
+       udivmoddihi4_internal, udivmodqi4, udivmoddiqi4_internal): new
+       patterns to exploit extended divide insns.
+       (udivsi3, udivhi3, udivqi3): remove since superceded by udivmodsi
+       etc patterns.
+
+       * ns32k.h (FUNCTION_VALUE, LIBCALL_VALUE): Use f0 for complex
+       float return values as well as simple scalar floats.
+       (TARGET_32381, TARGET_MULT_ADD, TARGET_SWITCHES):
+       support new flag to denote 32381 fpu.
+       (OVERRIDE_OPTIONS): 32381 is a strict superset of 32081.
+       (CONDITIONAL_REGISTER_USAGE): disable extra 32381 registers if not
+       compling for 32381.
+       (FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS,
+       REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES, OUTPUT_REGISTER_NAMES,
+       REG_ALLOC_ORDER, DBX_REGISTER_NUMBER, R0_REGNUM, F0_REGNUM,
+       L1_REGNUM, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM,
+       LONG_FP_REGS_P, ARG_POINTER_REGNUM, reg_class, REG_CLASS_NAMES,
+       REG_CLASS_CONTENTS, SUBSET_P,REGNO_REG_CLASS,
+       REG_CLASS_FROM_LETTER, FUNCTION_PROLOGUE, FUNCTION_EPILOGUE,
+       REGNO_OK_FOR_INDEX_P, FP_REG_P, REG_OK_FOR_INDEX_P,
+       REG_OK_FOR_BASE_P, MEM_REG): new register scheme to include 32381
+       fpu registers and special register classes for new 32381
+       instructions dotf and polyf.
+       (MODES_TIEABLE_P): Allow all integer modes, notably DI and SI, to
+       be tieable.
+       (INCOMING_RETURN_ADDR_RTX, RETURN_ADDR_RTX,
+       INCOMING_FRAME_SP_OFFSET): New macros in case DWARF support is
+       required.
+       (SMALL_REGISTER_CLASSES): Make dependant on -mmult-add option.
+       (MOVE_RATIO): Set to zero because of smart movstrsi implimentation.
+       (REGISTER_MOVE_COST): move code to register_move_cost function for
+       ease of coding and debugging.
+       (CLASS_LIKELY_SPILLED_P): Under new register scheme class
+       LONG_FLOAT_REGO is likely spilled but not caught by default
+       definition.
+       (CONSTANT_ADDRESS_P, CONSTANT_ADDRESS_NO_LABEL_P): use macro
+       instead of hard coded numbers in range check.
+       (ASM_OUTPUT_LABELREF_AS_INT): delete since unused.
+       (...): Add prototypes for functions in ns32k.c but disable because
+       of problems when ns32k.h is included in machine independant files.
+       
+       * ns32k.c: include "system.h", "tree.h", "expr.h", "flags.h".
+       (ns32k_reg_class_contents, regcass_map, ns32k_out_reg_names,
+       hard_regno_mode_ok, secondary_reload_class,
+       print_operand, print_operand_address): new register scheme to
+       include 32381 fpu registers and special register classes for new
+       32381 instructions dotf and polyf.
+       (gen_indexed_expr): Make static to keep namespace clean.
+       (check_reg): remove since never called.
+       (move_tail, expand_block_move): helper functions for "movstrsi"
+       block move insn.
+       (register_move_cost): Helper function for REGISTER_MOVE_COST macro.
+       Increase cost of moves which go via memory.
+       * netbsd.h (TARGET_DEFAULT): Set (new) 32381 fpu flag.
+       (CPP_PREDEFINES): nolonger predefine "unix".
+
+       * ns32k.md (movsi, movsi, adddi3, subdi3, subsi3, subhi3, subqi3,...):
+       Remove erroneous %$. print_operand() can work out from the rtx is
+       an immediate prefix is required.
+
+       * ns32k.h (RETURN_POPS_ARGS, VALID_MACHINE_DECL_ATTRIBUTE,
+       VALID_MACHINE_TYPE_ATTRIBUTE, COMP_TYPE_ATTRIBUTES,
+       SET_DEFAULT_TYPE_ATTRIBUTES): Support for -mrtd calling
+       convention.
+       (LEGITIMATE_PIC_OPERAND_P, SYMBOLIC_CONST): Correct handling of
+       pic operands.
+
+       * ns32k.c (symbolic_reference_mentioned_p, print_operand):
+       Correct handling of pic operands.
+       (ns32k_valid_decl_attribute_p, ns32k_valid_type_attribute_p,
+       ns32k_comp_type_attributes, ns32k_return_pops_args): Support for
+       -mrtd calling convention.
+
 Wed Nov 25 23:42:20 1998  Tom Tromey  <tromey@cygnus.com>
 
        * gcc.c (option_map): Recognize --output-class-directory.
@@ -13,7 +112,6 @@ Thu Nov 26 18:26:21 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
        too large to be immediate constants.  Also use it to find terms
        common to initial and final iteration values that can be removed.
 
-
 Thu Nov 26 18:05:04 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
 
        * loop.h (struct loop_info): Define new structure.
@@ -42,7 +140,6 @@ Thu Nov 26 18:05:04 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
        (loop_unroll_factor): Replace global array by element in
        loop_info structure.
 
-
 Thu Nov 26 17:49:29 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
 
        * loop.c (check_dbra_loop): Update JUMP_LABEL field of jump insn
@@ -87,7 +184,6 @@ Thu Nov 26 15:16:05 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
        (valid_parallel_operands_4, valid_parallel_operands_5,
        valid_parallel_operands_6): Reject pattern if the register destination
        of the first set is used as part of an address in the second set.
-       
 
 Thu Nov 26 14:56:32 1998  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
 
index 93c5bea..8e3610e 100644 (file)
@@ -1,6 +1,55 @@
 This file describes the implementation notes of the GNU C Compiler for
 the National Semiconductor 32032 chip (and 32000 family).
 
+Much of this file was obsolete. It described restrictions caused by
+bugs in early versions of of the ns32032 chip and by bugs in sequent
+assemblers and linkers of the time.
+
+Many (all?) of the chip bugs were fixed in later revisions and
+certainly fixed by later chips in the same series (ns32332 and
+ns32532).
+
+Conditional code to support sequent assembler and/or linker restrictions
+has not been removed deliberately, but has probably not been tested in
+a *very* long time.
+
+Support for one sequent assembler bug has *not* been retained.
+It was necessary to say:
+
+       addr _x,rn
+       cmpd _p,rn
+
+rather than:
+
+       cmpd _p,@_x
+
+
+This used to be forced by the use of "rmn" register constraints rather
+than "g". This is bad for other platforms which do not have this
+restraint.
+
+It is likely that there are no Balance 8000's still in operation, but
+if there are and the assembler bug was never fixed then the easiest
+way to run gcc would be to also run gas.
+
+The code required by the sequent assembler is still generated when the
+-fpic flag is in effect and this is forced by the appropriate
+definition of LEGITIMATE_PIC_OPERAND_P. If support for the old sequent
+assembler bug is required, then this could be achieved by adding the
+test from LEGITIMATE_PIC_OPERAND to the GO_IF_LEGITIMATE_ADDRESS
+definition. Of course, this should be conditional on something in the
+sequent.h config file.
+
+The original contents of this file appear below as an historical note.
+SEQUENT_ADDRESS_BUG mentioned below has been replaced by
+INDEX_RATHER_THAN_BASE. Note that merlin.h still defines
+SEQUENT_ADDRESS_BUG even though it is not used anywhere. Since it has
+been like this for a long time, presumably either the
+SEQUENT_ADDRESS_BUG is not required for the merlin, or no one is using
+gcc on the merlin anymore.
+
+HISTORICAL NOTE
+
 The 32032 machine description and configuration file for this compiler
 is, for NS32000 family machine, primarily machine independent.
 However, since this release still depends on vendor-supplied
index cef68d8..bc86e31 100644 (file)
@@ -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> */
 
index 8c2fb1f..af89e59 100644 (file)
@@ -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));
 }
+
 \f
 /* 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;
+\f
+#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;
 }
+\f
 
 /* Returns 1 if OP contains a global symbol reference */
 
@@ -466,10 +604,142 @@ global_symbolic_reference_mentioned_p (op, f)
 }
 
 \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;
+}
+\f
+/* 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;
+}
+
+\f
+/* 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;
+}
+\f
 /* 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);
+       }
     }
 }
 \f
@@ -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
     }
index d2e81d1..d409ac2 100644 (file)
@@ -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)
+
 \f
 /* 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)
 \f
@@ -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)
 \f
 /* 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;}
 \f
+/* 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) */
+\f
 /* 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:
index e44cccc..161b74e 100644 (file)
 ;; 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;
   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")))]
   ""
   "*
 {
 
 (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")))]
   ""
   "*
 
 (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")))]
   ""
   "*
 
 (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")
 
   "TARGET_32081"
   "cmpf %0,%1")
 \f
+;; 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"))]
   ""
   "*
 {
 {
   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\";
 
 ;; 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")
 
 
   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\";
        {
          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)
     {
         * 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)
        {
     }
   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\";
     }
   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\";
   return \"movb %1,%0\";
 }")
 \f
-;; 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
-}")
 \f
 ;; Extension and truncation insns.
 ;; Those for integer source operand
 
 (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")
 
   "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")
 
   "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")
   "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")
 ; 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")
 
 (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")
 
 
 (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")
 
 
 (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")
 \f
+;; 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")
 
   "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"
   "*
   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")
            {
              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 \"\";
        }
   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\";
 ;;- 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")
 
   "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"
            {
              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 \"\";
        }
 (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)
       int i = INTVAL (operands[2]);
 
       if (i <= 8 && i >= -7)
-        return \"addqd %$%n2,%0\";
+        return \"addqd %n2,%0\";
     }
   return \"subd %2,%0\";
 }")
       int i = INTVAL (operands[2]);
 
       if (i <= 8 && i >= -7)
-        return \"addqw %$%n2,%0\";
+        return \"addqw %n2,%0\";
     }
   return \"subw %2,%0\";
 }")
 {
   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\";
 }")
 
       int i = INTVAL (operands[2]);
 
       if (i <= 8 && i >= -7)
-       return \"addqb %$%n2,%0\";
+       return \"addqb %n2,%0\";
     }
   return \"subb %2,%0\";
 }")
 {
   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\";
 }")
 \f
 ;;- 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")
 
   "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")
 
        (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")
 \f
+;; 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")
+\f
 ;;- 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")
 
   "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")
 
                (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\";
-}")
-
+\f
 ;; 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")
 
   ""
   "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")
 \f
 ;;- 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")))]
   ""
   "*
 {
   ""
   "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")
 \f
 ;;- 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")))]
   ""
   "*
 {
 
 ;;- 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")))]
   ""
   "*
 {
   "xorb %2,%0")
 \f
 (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")
 
   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")
 
   ""
   "negb %1,%0")
 \f
+;; 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")
 
 ;; 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)
 (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)
 (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)
        (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")
        (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")
        (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")
        (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")
        (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")
        (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")
 
 ;; 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")
 
        (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")
        (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")
        (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")
 ;;; 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")
 \f
 ;; 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")
        (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)
   "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")
 
 ;; 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);
 ;; 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);
 ;; 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);
 ;; 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);
 ;; 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
 ;; 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")
   "*
 {
   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
        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
index 6b041fe..5ce08e0 100644 (file)
@@ -393,6 +393,11 @@ in the following sections.
 -mprolog-function -mno-prolog-function -mspace
 -mtda=@var{n} -msda=@var{n} -mzda=@var{n}
 -mv850 -mbig-switch
+
+@emph{NS32K Options}
+-m32032 -m32332 -m32532 -m32081 -m32381 -mmult-add -mnomult-add
+-msoft-float -mrtd -mnortd -mregparam -mnoregparam -msb -mnosb
+-mbitfield -mnobitfield -mhimem -mnohimem
 @end smallexample
 
 @item Code Generation Options
@@ -3055,6 +3060,7 @@ that macro, which enables you to change the defaults.
 * System V Options::
 * V850 Options::
 * ARC Options::
+* NS32K Options::
 @end menu
 
 @node M680x0 Options
@@ -5678,6 +5684,121 @@ by default.  This can be overridden with the @code{section} attribute.
 
 @end table
 
+@node NS32K Options
+@subsection NS32K Options
+@cindex NS32K options
+
+These are the @samp{-m} options defined for the 32000 series.  The default
+values for these options depends on which style of 32000 was selected when
+the compiler was configured; the defaults for the most common choices are
+given below.
+
+@table @code
+@item -m32032
+@itemx -m32032
+Generate output for a 32032.  This is the default
+when the compiler is configured for 32032 and 32016 based systems.
+
+@item -m32332
+@itemx -m32332
+Generate output for a 32332.  This is the default
+when the compiler is configured for 32332-based systems.
+
+@item -m32532
+@itemx -m32532
+Generate output for a 32532.  This is the default
+when the compiler is configured for 32532-based systems.
+
+@item -m32081
+Generate output containing 32081 instructions for floating point.
+This is the default for all systems.
+
+@item -m32381
+Generate output containing 32381 instructions for floating point.  This
+also implies @samp{-m32081}. The 32381 is only compatible with the 32332
+and 32532 cpus. This is the default for the pc532-netbsd configuration.
+
+@item -mmulti-add
+Try and generate multiply-add floating point instructions @code{polyF}
+and @code{dotF}. This option is only available if the @samp{-m32381}
+option is in effect. Using these instructions requires changes to to
+register allocation which generally has a negative impact on
+performance.  This option should only be enabled when compiling code
+particularly likely to make heavy use of multiply-add instructions.
+
+@item -mnomulti-add
+Do not try and generate multiply-add floating point instructions
+@code{polyF} and @code{dotF}. This is the default on all platforms.
+
+@item -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries may not be available.
+
+@item -mnobitfield
+Do not use the bit-field instructions. On some machines it is faster to
+use shifting and masking operations. This is the default for the pc532.
+
+@item -mbitfield
+Do use the bit-field instructions. This is the default for all platforms
+except the pc532.
+
+@item -mrtd
+Use a different function-calling convention, in which functions
+that take a fixed number of arguments return pop their
+arguments on return with the @code{ret} instruction.
+
+This calling convention is incompatible with the one normally
+used on Unix, so you cannot use it if you need to call libraries
+compiled with the Unix compiler.
+
+Also, you must provide function prototypes for all functions that
+take variable numbers of arguments (including @code{printf});
+otherwise incorrect code will be generated for calls to those
+functions.
+
+In addition, seriously incorrect code will result if you call a
+function with too many arguments.  (Normally, extra arguments are
+harmlessly ignored.)
+
+This option takes its name from the 680x0 @code{rtd} instruction.
+
+
+@item -mregparam
+Use a different function-calling convention where the first two arguments
+are passed in registers.
+
+This calling convention is incompatible with the one normally
+used on Unix, so you cannot use it if you need to call libraries
+compiled with the Unix compiler.
+
+@item -mnoregparam
+Do not pass any arguments in registers. This is the default for all
+targets.
+
+@item -msb
+It is OK to use the sb as an index register which is always loaded with
+zero. This is the default for the pc532-netbsd target.
+
+@item -mnosb
+The sb register is not available for use or has not been initialized to
+zero by the run time system. This is the default for all targets except
+the pc532-netbsd. It is also implied whenever @samp{-mhimem} or
+@samp{-fpic} is set.
+
+@item -mhimem
+Many ns32000 series addressing modes use displacements of up to 512MB.
+If an address is above 512MB then displacements from zero can not be used.
+This option causes code to be generated which can be loaded above 512MB.
+This may be useful for operating systems or ROM code.
+
+@item -mnohimem
+Assume code will be loaded in the first 512MB of virtual address space.
+This is the default for all platforms.
+
+
+@end table
+
+
 
 @node Code Gen Options
 @section Options for Code Generation Conventions