OSDN Git Service

* common.opt (main_input_filename, main_input_basename,
[pf3gnuchains/gcc-fork.git] / gcc / config / pdp11 / pdp11.c
index 61da8c4..35a76fa 100644 (file)
 /* Subroutines for gcc2 for pdp11.
-   Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005,
+   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
    Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
+#include "function.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "recog.h"
-
-/*
-#define FPU_REG_P(X)   ((X)>=8 && (X)<14)
-#define CPU_REG_P(X)   ((X)>=0 && (X)<8)
-*/
+#include "tree.h"
+#include "expr.h"
+#include "diagnostic-core.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+#include "df.h"
 
 /* this is the current value returned by the macro FIRST_PARM_OFFSET 
    defined in tm.h */
 int current_first_parm_offset;
 
-/* This is where the condition code register lives.  */
-/* rtx cc0_reg_rtx; - no longer needed? */
-
-static rtx find_addr_reg (); 
+/* Routines to encode/decode pdp11 floats */
+static void encode_pdp11_f (const struct real_format *fmt,
+                           long *, const REAL_VALUE_TYPE *);
+static void decode_pdp11_f (const struct real_format *,
+                           REAL_VALUE_TYPE *, const long *);
+static void encode_pdp11_d (const struct real_format *fmt,
+                           long *, const REAL_VALUE_TYPE *);
+static void decode_pdp11_d (const struct real_format *,
+                           REAL_VALUE_TYPE *, const long *);
+
+/* These two are taken from the corresponding vax descriptors
+   in real.c, changing only the encode/decode routine pointers.  */
+const struct real_format pdp11_f_format =
+  {
+    encode_pdp11_f,
+    decode_pdp11_f,
+    2,
+    24,
+    24,
+    -127,
+    127,
+    15,
+    15,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false
+  };
+
+const struct real_format pdp11_d_format =
+  {
+    encode_pdp11_d,
+    decode_pdp11_d,
+    2,
+    56,
+    56,
+    -127,
+    127,
+    15,
+    15,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false
+  };
+
+static void
+encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+               const REAL_VALUE_TYPE *r)
+{
+  (*vax_f_format.encode) (fmt, buf, r);
+  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
+}
 
-/* Nonzero if OP is a valid second operand for an arithmetic insn.  */
+static void
+decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
+               REAL_VALUE_TYPE *r, const long *buf)
+{
+  long tbuf;
+  tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
+  (*vax_f_format.decode) (fmt, r, &tbuf);
+}
 
-int
-arith_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static void
+encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+               const REAL_VALUE_TYPE *r)
 {
-  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
+  (*vax_d_format.encode) (fmt, buf, r);
+  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
+  buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
 }
 
-int
-const_immediate_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static void
+decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
+               REAL_VALUE_TYPE *r, const long *buf)
 {
-  return (GET_CODE (op) == CONST_INT);
+  long tbuf[2];
+  tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
+  tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
+  (*vax_d_format.decode) (fmt, r, tbuf);
 }
 
-int 
-immediate15_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+/* This is where the condition code register lives.  */
+/* rtx cc0_reg_rtx; - no longer needed? */
+
+static bool pdp11_handle_option (size_t, const char *, int);
+static void pdp11_option_init_struct (struct gcc_options *);
+static rtx find_addr_reg (rtx); 
+static const char *singlemove_string (rtx *);
+static bool pdp11_assemble_integer (rtx, unsigned int, int);
+static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
+static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static bool pdp11_rtx_costs (rtx, int, int, int *, bool);
+static bool pdp11_return_in_memory (const_tree, const_tree);
+static rtx pdp11_function_value (const_tree, const_tree, bool);
+static rtx pdp11_libcall_value (enum machine_mode, const_rtx);
+static bool pdp11_function_value_regno_p (const unsigned int);
+static void pdp11_trampoline_init (rtx, tree, rtx);
+static rtx pdp11_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+                              const_tree, bool);
+static void pdp11_function_arg_advance (CUMULATIVE_ARGS *,
+                                       enum machine_mode, const_tree, bool);
+static void pdp11_conditional_register_usage (void);
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
+
+static const struct default_options pdp11_option_optimization_table[] =
+  {
+    { OPT_LEVELS_3_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+    { OPT_LEVELS_NONE, 0, NULL, 0 }
+  };
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_BYTE_OP
+#define TARGET_ASM_BYTE_OP NULL
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP NULL
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP NULL
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER pdp11_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
+
+#undef TARGET_ASM_OPEN_PAREN
+#define TARGET_ASM_OPEN_PAREN "["
+#undef TARGET_ASM_CLOSE_PAREN
+#define TARGET_ASM_CLOSE_PAREN "]"
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS \
+  (MASK_FPU | MASK_45 | TARGET_UNIX_ASM_DEFAULT)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION pdp11_handle_option
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE pdp11_option_optimization_table
+#undef TARGET_OPTION_INIT_STRUCT
+#define TARGET_OPTION_INIT_STRUCT pdp11_option_init_struct
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS pdp11_rtx_costs
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG pdp11_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE pdp11_function_arg_advance
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE pdp11_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE pdp11_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P pdp11_function_value_regno_p
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init
+
+#undef  TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD pdp11_secondary_reload
+
+#undef  TARGET_REGISTER_MOVE_COST 
+#define TARGET_REGISTER_MOVE_COST pdp11_register_move_cost
+
+#undef  TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS pdp11_preferred_reload_class
+
+#undef  TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS pdp11_preferred_output_reload_class
+
+#undef  TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P pdp11_legitimate_address_p
+
+#undef  TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE pdp11_conditional_register_usage
+\f
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
+                    int value ATTRIBUTE_UNUSED)
 {
-    return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
+  switch (code)
+    {
+    case OPT_m10:
+      target_flags &= ~(MASK_40 | MASK_45);
+      return true;
+
+    default:
+      return true;
+    }
 }
 
-int
-expand_shift_operand (op, mode)
-  rtx op;
-  enum machine_mode mode;
+/* Implement TARGET_OPTION_INIT_STRUCT.  */
+
+static void
+pdp11_option_init_struct (struct gcc_options *opts)
 {
-    return (GET_CODE (op) == CONST_INT 
-           && abs (INTVAL(op)) > 1 
-           && abs (INTVAL(op)) <= 4);
+  opts->x_flag_finite_math_only = 0;
+  opts->x_flag_trapping_math = 0;
+  opts->x_flag_signaling_nans = 0;
 }
 
 /*
@@ -92,32 +270,31 @@ expand_shift_operand (op, mode)
    knowing which registers should not be saved even if used.  
 */
 
-void 
-output_function_prologue(stream, size)
-  FILE *stream;
-  int size;
+static void
+pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
 {                                                             
-    int fsize = ((size) + 1) & ~1;                                     
+    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
     int regno;
-
     int via_ac = -1;
-    
-    fprintf (stream, "\n\t;    /* function prologue %s*/\n", current_function_name);           
+
+    fprintf (stream,
+            "\n\t;     /* function prologue %s*/\n",
+            current_function_name ());
 
     /* if we are outputting code for main, 
        the switch FPU to right mode if TARGET_FPU */
-    if ( (strcmp ("main", current_function_name) == 0)
-        && TARGET_FPU)
+    if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
     {
-       fprintf(stream, "\t;/* switch cpu to double float, single integer */\n");
+       fprintf(stream,
+               "\t;/* switch cpu to double float, single integer */\n");
        fprintf(stream, "\tsetd\n");
        fprintf(stream, "\tseti\n\n");
     }
     
     if (frame_pointer_needed)                                  
     {                                                          
-       fprintf(stream, "\tmov fp, -(sp)\n");                   
-       fprintf(stream, "\tmov sp, fp\n");                              
+       fprintf(stream, "\tmov r5, -(sp)\n");                   
+       fprintf(stream, "\tmov sp, r5\n");                              
     }                                                          
     else                                                               
     {                                                          
@@ -126,11 +303,11 @@ output_function_prologue(stream, size)
 
     /* make frame */
     if (fsize)                                                 
-       fprintf (stream, "\tsub $%d, sp\n", fsize);                     
+       asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
 
     /* save CPU registers  */
-    for (regno = 0; regno < 8; regno++)                                
-       if (regs_ever_live[regno] && ! call_used_regs[regno])   
+    for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++)                               
+      if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])      
            if (! ((regno == FRAME_POINTER_REGNUM)                      
                   && frame_pointer_needed))                            
                fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);        
@@ -139,28 +316,27 @@ output_function_prologue(stream, size)
     /* via_ac specifies the ac to use for saving ac4, ac5 */
     via_ac = -1;
     
-    for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 
+    for (regno = AC0_REGNUM; regno <= AC5_REGNUM ; regno++) 
     {
        /* ac0 - ac3 */                                         
        if (LOAD_FPU_REG_P(regno)
-           && regs_ever_live[regno] 
+           && df_regs_ever_live_p (regno) 
            && ! call_used_regs[regno])
        {
-           fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
+           fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
            via_ac = regno;
        }
        
        /* maybe make ac4, ac5 call used regs?? */
        /* ac4 - ac5 */
        if (NO_LOAD_FPU_REG_P(regno)
-           && regs_ever_live[regno]
+           && df_regs_ever_live_p (regno)
            && ! call_used_regs[regno])
        {
-           if (via_ac == -1)
-               abort();
-           
-           fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
-           fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
+         gcc_assert (via_ac != -1);
+         fprintf (stream, "\tldd %s, %s\n",
+                  reg_names[regno], reg_names[via_ac]);
+         fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
        }
     }
 
@@ -186,13 +362,10 @@ output_function_prologue(stream, size)
 
    maybe as option if you want to generate code for kernel mode? */
 
-
-void 
-output_function_epilogue(stream, size)
-  FILE *stream;
-  int size;
+static void
+pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
 {                                                              
-    int fsize = ((size) + 1) & ~1;                                     
+    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
     int i, j, k;
 
     int via_ac;
@@ -202,100 +375,102 @@ output_function_epilogue(stream, size)
     if (frame_pointer_needed)                                  
     {                                                          
        /* hope this is safe - m68k does it also .... */                
-       regs_ever_live[FRAME_POINTER_REGNUM] = 0;                       
+        df_set_regs_ever_live (FRAME_POINTER_REGNUM, false);
                                                                
-       for (i =7, j = 0 ; i >= 0 ; i--)                                
-           if (regs_ever_live[i] && ! call_used_regs[i])               
+       for (i = PC_REGNUM, j = 0 ; i >= 0 ; i--)                               
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])           
                j++;
        
        /* remember # of pushed bytes for CPU regs */
        k = 2*j;
        
-       for (i =7 ; i >= 0 ; i--)                                       
-           if (regs_ever_live[i] && ! call_used_regs[i])               
-               fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
+       /* change fp -> r5 due to the compile error on libgcc2.c */
+       for (i = PC_REGNUM ; i >= R0_REGNUM ; i--)                                      
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])           
+               fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n",
+                       (-fsize-2*j--)&0xffff, reg_names[i]);
 
        /* get ACs */                                           
-       via_ac = FIRST_PSEUDO_REGISTER -1;
+       via_ac = AC5_REGNUM;
        
-       for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
-           if (regs_ever_live[i] && ! call_used_regs[i])
+       for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
            {
                via_ac = i;
                k += 8;
            }
        
-       for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
+       for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
        {
            if (LOAD_FPU_REG_P(i)
-               && regs_ever_live[i]
+               && df_regs_ever_live_p (i)
                && ! call_used_regs[i])
            {
-               fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
+               fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n",
+                       (-fsize-k)&0xffff, reg_names[i]);
                k -= 8;
            }
            
            if (NO_LOAD_FPU_REG_P(i)
-               && regs_ever_live[i]
+               && df_regs_ever_live_p (i)
                && ! call_used_regs[i])
            {
-               if (! LOAD_FPU_REG_P(via_ac))
-                   abort();
+               gcc_assert (LOAD_FPU_REG_P(via_ac));
                    
-               fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
-               fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
+               fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n",
+                       (-fsize-k)&0xffff, reg_names[via_ac]);
+               fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                k -= 8;
            }
        }
        
-       fprintf(stream, "\tmov fp, sp\n");                              
-       fprintf (stream, "\tmov (sp)+, fp\n");                          
+       fprintf(stream, "\tmov r5, sp\n");                              
+       fprintf (stream, "\tmov (sp)+, r5\n");                          
     }                                                          
     else                                                               
     {             
-       via_ac = FIRST_PSEUDO_REGISTER -1;
+      via_ac = AC5_REGNUM;
        
        /* get ACs */
-       for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
-           if (regs_ever_live[i] && call_used_regs[i])
+       for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
                via_ac = i;
        
-       for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
+       for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
        {
            if (LOAD_FPU_REG_P(i)
-               && regs_ever_live[i]
+               && df_regs_ever_live_p (i)
                && ! call_used_regs[i])
-             fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
+             fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
            
            if (NO_LOAD_FPU_REG_P(i)
-               && regs_ever_live[i]
+               && df_regs_ever_live_p (i)
                && ! call_used_regs[i])
            {
-               if (! LOAD_FPU_REG_P(via_ac))
-                   abort();
+               gcc_assert (LOAD_FPU_REG_P(via_ac));
                    
-               fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
-               fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
+               fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
+               fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
            }
        }
 
-       for (i=7; i >= 0; i--)                                  
-           if (regs_ever_live[i] && !call_used_regs[i])                
+       for (i = PC_REGNUM; i >= 0; i--)                                        
+         if (df_regs_ever_live_p (i) && !call_used_regs[i])            
                fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);     
                                                                
        if (fsize)                                              
-           fprintf((stream), "\tadd $%d, sp\n", fsize);                
+           fprintf((stream), "\tadd $%#" HOST_WIDE_INT_PRINT "o, sp\n",
+                   (fsize)&0xffff);                    
     }                  
                                        
     fprintf (stream, "\trts pc\n");                                    
     fprintf (stream, "\t;/* end of epilogue*/\n\n\n");         
 }
-       
+
 /* Return the best assembler insn template
    for moving operands[1] into operands[0] as a fullword.  */
-static char *
-singlemove_string (operands)
-     rtx *operands;
+static const char *
+singlemove_string (rtx *operands)
 {
   if (operands[1] != const0_rtx)
     return "mov %1,%0";
@@ -307,9 +482,8 @@ singlemove_string (operands)
 /* Output assembler code to perform a doubleword move insn
    with operands OPERANDS.  */
 
-char *
-output_move_double (operands)
-     rtx *operands;
+const char *
+output_move_double (rtx *operands)
 {
   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
   rtx latehalf[2];
@@ -332,10 +506,11 @@ output_move_double (operands)
 
   if (REG_P (operands[1]))
     optype1 = REGOP;
-  else if (CONSTANT_P (operands[1]))
+  else if (CONSTANT_P (operands[1])
 #if 0
-          || GET_CODE (operands[1]) == CONST_DOUBLE)
+          || GET_CODE (operands[1]) == CONST_DOUBLE
 #endif
+          )
     optype1 = CNSTOP;
   else if (offsettable_memref_p (operands[1]))
     optype1 = OFFSOP;
@@ -352,8 +527,7 @@ output_move_double (operands)
      supposed to allow to happen.  Abort if we get one,
      because generating code for these cases is painful.  */
 
-  if (optype0 == RNDOP || optype1 == RNDOP)
-    abort ();
+  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
 
   /* If one operand is decrementing and one is incrementing
      decrement the former register explicitly
@@ -363,14 +537,14 @@ output_move_double (operands)
     {
       operands[0] = XEXP (XEXP (operands[0], 0), 0);
       output_asm_insn ("sub $4,%0", operands);
-      operands[0] = gen_rtx (MEM, SImode, operands[0]);
+      operands[0] = gen_rtx_MEM (SImode, operands[0]);
       optype0 = OFFSOP;
     }
   if (optype0 == POPOP && optype1 == PUSHOP)
     {
       operands[1] = XEXP (XEXP (operands[1], 0), 0);
       output_asm_insn ("sub $4,%1", operands);
-      operands[1] = gen_rtx (MEM, SImode, operands[1]);
+      operands[1] = gen_rtx_MEM (SImode, operands[1]);
       optype1 = OFFSOP;
     }
 
@@ -393,16 +567,16 @@ output_move_double (operands)
      operands in OPERANDS to be suitable for the low-numbered word.  */
 
   if (optype0 == REGOP)
-    latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
+    latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
   else if (optype0 == OFFSOP)
-    latehalf[0] = adj_offsettable_operand (operands[0], 2);
+    latehalf[0] = adjust_address (operands[0], HImode, 2);
   else
     latehalf[0] = operands[0];
 
   if (optype1 == REGOP)
-    latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
+    latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
   else if (optype1 == OFFSOP)
-    latehalf[1] = adj_offsettable_operand (operands[1], 2);
+    latehalf[1] = adjust_address (operands[1], HImode, 2);
   else if (optype1 == CNSTOP)
     {
        if (CONSTANT_P (operands[1]))
@@ -410,14 +584,12 @@ output_move_double (operands)
            /* now the mess begins, high word is in lower word??? 
 
               that's what ashc makes me think, but I don't remember :-( */
-           latehalf[1] = GEN_INT (INTVAL(operands[1])>>16);
-           operands[1] = GEN_INT (INTVAL(operands[1])&0xff);
-       }
-      else if (GET_CODE (operands[1]) == CONST_DOUBLE)
-       {
-           /* immediate 32 bit values not allowed */
-           abort();
+           latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
+           operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
        }
+       else
+         /* immediate 32-bit values not allowed */
+         gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE);
     }
   else
     latehalf[1] = operands[1];
@@ -485,15 +657,14 @@ output_move_double (operands)
 /* Output assembler code to perform a quadword move insn
    with operands OPERANDS.  */
 
-char *
-output_move_quad (operands)
-     rtx *operands;
+const char *
+output_move_quad (rtx *operands)
 {
   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
   rtx latehalf[2];
   rtx addreg0 = 0, addreg1 = 0;
 
-  output_asm_insn(";; movdi/df: %1 -> %0", operands);
+  output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
   
   if (REG_P (operands[0]))
     optype0 = REGOP;
@@ -528,15 +699,7 @@ output_move_quad (operands)
      supposed to allow to happen.  Abort if we get one,
      because generating code for these cases is painful.  */
 
-  if (optype0 == RNDOP || optype1 == RNDOP)
-    abort ();
-  
-  /* check if we move a CPU reg to an FPU reg, or vice versa! */
-  if (optype0 == REGOP && optype1 == REGOP)
-      /* bogus - 64 bit cannot reside in CPU! */
-      if (CPU_REG_P(REGNO(operands[0]))
-         || CPU_REG_P (REGNO(operands[1])))
-         abort();
+  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
   
   if (optype0 == REGOP || optype1 == REGOP)
   {
@@ -552,19 +715,18 @@ output_move_quad (operands)
       {
          if (GET_CODE(operands[1]) == CONST_DOUBLE)
          {
-             union { double d; int i[2]; } u;
-             u.i[0] = CONST_DOUBLE_LOW (operands[1]); 
-             u.i[1] = CONST_DOUBLE_HIGH (operands[1]); 
-             
-             if (u.d == 0.0)
-                 return "clrd %0";
+             REAL_VALUE_TYPE r;
+             REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+
+             if (REAL_VALUES_EQUAL (r, dconst0))
+                 return "{clrd|clrf} %0";
          }
              
-         return "ldd %1, %0";
+         return "{ldd|movf} %1, %0";
       }
       
       if (FPU_REG_P(REGNO(operands[1])))
-         return "std %1, %0";
+         return "{std|movf} %1, %0";
   }
       
   /* If one operand is decrementing and one is incrementing
@@ -575,14 +737,14 @@ output_move_quad (operands)
     {
       operands[0] = XEXP (XEXP (operands[0], 0), 0);
       output_asm_insn ("sub $8,%0", operands);
-      operands[0] = gen_rtx (MEM, DImode, operands[0]);
+      operands[0] = gen_rtx_MEM (DImode, operands[0]);
       optype0 = OFFSOP;
     }
   if (optype0 == POPOP && optype1 == PUSHOP)
     {
       operands[1] = XEXP (XEXP (operands[1], 0), 0);
       output_asm_insn ("sub $8,%1", operands);
-      operands[1] = gen_rtx (MEM, SImode, operands[1]);
+      operands[1] = gen_rtx_MEM (SImode, operands[1]);
       optype1 = OFFSOP;
     }
 
@@ -605,44 +767,33 @@ output_move_quad (operands)
      operands in OPERANDS to be suitable for the low-numbered word.  */
 
   if (optype0 == REGOP)
-    latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
+    latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
   else if (optype0 == OFFSOP)
-    latehalf[0] = adj_offsettable_operand (operands[0], 4);
+    latehalf[0] = adjust_address (operands[0], SImode, 4);
   else
     latehalf[0] = operands[0];
 
   if (optype1 == REGOP)
-    latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
+    latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
   else if (optype1 == OFFSOP)
-    latehalf[1] = adj_offsettable_operand (operands[1], 4);
+    latehalf[1] = adjust_address (operands[1], SImode, 4);
   else if (optype1 == CNSTOP)
     {
       if (GET_CODE (operands[1]) == CONST_DOUBLE)
        {
-           /* floats only. not yet supported!
-
-            -- compute it into PDP float format, - internally,
-            just use IEEE and ignore possible problems ;-)
-
-            we might get away with it !!!! */
-
-           abort();
-           
-#ifndef HOST_WORDS_BIG_ENDIAN
-         latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
-         operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
-#else /* HOST_WORDS_BIG_ENDIAN */
-         latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
-         operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
-#endif /* HOST_WORDS_BIG_ENDIAN */
+         REAL_VALUE_TYPE r;
+         long dval[2];
+         REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+         REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
+         latehalf[1] = GEN_INT (dval[1]);
+         operands[1] = GEN_INT (dval[0]);
        }
       else if (GET_CODE(operands[1]) == CONST_INT)
-      {
-         latehalf[1] = GEN_INT (0);
-      }
+       {
+         latehalf[1] = const0_rtx;
+       }
       else
-         abort();
-      
+       gcc_unreachable ();
     }
   else
     latehalf[1] = operands[1];
@@ -713,8 +864,7 @@ output_move_quad (operands)
    ADDR can be effectively incremented by incrementing REG.  */
 
 static rtx
-find_addr_reg (addr)
-     rtx addr;
+find_addr_reg (rtx addr)
 {
   while (GET_CODE (addr) == PLUS)
     {
@@ -734,72 +884,63 @@ find_addr_reg (addr)
 \f
 /* Output an ascii string.  */
 void
-output_ascii (file, p, size)
-     FILE *file;
-     char *p;
-     int size;
+output_ascii (FILE *file, const char *p, int size)
 {
   int i;
 
-  fprintf (file, "\t.byte \"");
+  /* This used to output .byte "string", which doesn't work with the UNIX
+     assembler and I think not with DEC ones either.  */
+  fprintf (file, "\t.byte ");
 
   for (i = 0; i < size; i++)
     {
       register int c = p[i];
-      if (c == '\"' || c == '\\')
-       putc ('\\', file);
-      if (c >= ' ' && c < 0177)
-       putc (c, file);
-      else
-       {
-         fprintf (file, "\\%03o", c);
-         /* After an octal-escape, if a digit follows,
-            terminate one string constant and start another.
-            The Vax assembler fails to stop reading the escape
-            after three digits, so this is the only way we
-            can get it to parse the data properly.  */
-         if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
-           fprintf (file, "\"\n\tstring \"");
-       }
+      if (c < 0)
+       c += 256;
+      fprintf (file, "%#o", c);
+      if (i < size - 1)
+       putc (',', file);
     }
-  fprintf (file, "\"\n");
+  putc ('\n', file);
 }
 
 
-/* --- stole from out-vax, needs changes */
-
 void
-print_operand_address (file, addr)
-     FILE *file;
-     register rtx addr;
+print_operand_address (FILE *file, register rtx addr)
 {
-  register rtx reg1, reg2, breg, ireg;
+  register rtx breg;
   rtx offset;
-
+  int again = 0;
+  
  retry:
 
   switch (GET_CODE (addr))
     {
     case MEM:
-      fprintf (file, "@");
+      if (TARGET_UNIX_ASM)
+       fprintf (file, "*");
+      else
+       fprintf (file, "@");
       addr = XEXP (addr, 0);
+      again = 1;
       goto retry;
 
     case REG:
       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
       break;
 
+    case PRE_MODIFY:
     case PRE_DEC:
       fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
+    case POST_MODIFY:
     case POST_INC:
       fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
     case PLUS:
-      reg1 = 0;        reg2 = 0;
-      ireg = 0;        breg = 0;
+      breg = 0;
       offset = 0;
       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
          || GET_CODE (XEXP (addr, 0)) == MEM)
@@ -815,119 +956,231 @@ print_operand_address (file, addr)
        }
       if (GET_CODE (addr) != PLUS)
        ;
-      else if (GET_CODE (XEXP (addr, 0)) == MULT)
-       {
-         reg1 = XEXP (addr, 0);
-         addr = XEXP (addr, 1);
-       }
-      else if (GET_CODE (XEXP (addr, 1)) == MULT)
-       {
-         reg1 = XEXP (addr, 1);
-         addr = XEXP (addr, 0);
-       }
       else if (GET_CODE (XEXP (addr, 0)) == REG)
        {
-         reg1 = XEXP (addr, 0);
+         breg = XEXP (addr, 0);
          addr = XEXP (addr, 1);
        }
       else if (GET_CODE (XEXP (addr, 1)) == REG)
        {
-         reg1 = XEXP (addr, 1);
+         breg = XEXP (addr, 1);
          addr = XEXP (addr, 0);
        }
-      if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
+      if (GET_CODE (addr) == REG)
        {
-         if (reg1 == 0)
-           reg1 = addr;
-         else
-           reg2 = addr;
+         gcc_assert (breg == 0);
+         breg = addr;
          addr = 0;
        }
       if (offset != 0)
        {
-         if (addr != 0) abort ();
+         gcc_assert (addr == 0);
          addr = offset;
        }
-      if (reg1 != 0 && GET_CODE (reg1) == MULT)
-       {
-         breg = reg2;
-         ireg = reg1;
-       }
-      else if (reg2 != 0 && GET_CODE (reg2) == MULT)
-       {
-         breg = reg1;
-         ireg = reg2;
-       }
-      else if (reg2 != 0 || GET_CODE (addr) == MEM)
-       {
-         breg = reg2;
-         ireg = reg1;
-       }
-      else
-       {
-         breg = reg1;
-         ireg = reg2;
-       }
       if (addr != 0)
-       output_address (addr);
+       output_addr_const_pdp11 (file, addr);
       if (breg != 0)
        {
-         if (GET_CODE (breg) != REG)
-           abort ();
+         gcc_assert (GET_CODE (breg) == REG);
          fprintf (file, "(%s)", reg_names[REGNO (breg)]);
        }
-      if (ireg != 0)
-       {
-         if (GET_CODE (ireg) == MULT)
-           ireg = XEXP (ireg, 0);
-         if (GET_CODE (ireg) != REG)
-           abort ();
-         abort();
-         fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
-       }
       break;
 
     default:
-      output_addr_const (file, addr);
+      if (!again && GET_CODE (addr) == CONST_INT)
+       {
+         /* Absolute (integer number) address.  */
+         if (!TARGET_UNIX_ASM)
+           fprintf (file, "@$");
+       }
+      output_addr_const_pdp11 (file, addr);
     }
 }
 
+/* Target hook to assemble integer objects.  We need to use the
+   pdp-specific version of output_addr_const.  */
+
+static bool
+pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
+{
+  if (aligned_p)
+    switch (size)
+      {
+      case 1:
+       fprintf (asm_out_file, "\t.byte\t");
+       output_addr_const_pdp11 (asm_out_file, GEN_INT (INTVAL (x) & 0xff));
+;
+       fprintf (asm_out_file, " /* char */\n");
+       return true;
+
+      case 2:
+       fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
+       output_addr_const_pdp11 (asm_out_file, x);
+       fprintf (asm_out_file, " /* short */\n");
+       return true;
+      }
+  return default_assemble_integer (x, size, aligned_p);
+}
+
+
 /* register move costs, indexed by regs */
 
-static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
+static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
 {
              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
 
 /* NO */     {  0,   0,   0,    0,    0,    0,   0},
-/* MUL */    {  0,   2,   2,   10,   22,   22,  22},
-/* GEN */    {  0,   2,   2,   10,   22,   22,  22},
-/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
-/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
-/* FPU */    {  0,  22,  22,    2,    2,    2,  22},
-/* ALL */    {  0,  22,  22,   10,   22,   22,  22}
+/* MUL */    {  0,   2,   2,   22,   22,   22,  22},
+/* GEN */    {  0,   2,   2,   22,   22,   22,  22},
+/* LFPU */   {  0,  22,  22,    2,    2,    2,  22},
+/* NLFPU */  {  0,  22,  22,    2,   10,   10,  22},
+/* FPU */    {  0,  22,  22,    2,   10,   10,  22},
+/* ALL */    {  0,  22,  22,   22,   22,   22,  22}
 }  ;
 
 
 /* -- note that some moves are tremendously expensive, 
    because they require lots of tricks! do we have to 
    charge the costs incurred by secondary reload class 
-   -- as we do here with 22 -- or not ? */
+   -- as we do here with 10 -- or not ? */
 
-int 
-register_move_cost(c1, c2)
-  enum reg_class c1, c2;
+static int 
+pdp11_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+                         reg_class_t c1, reg_class_t c2)
 {
     return move_costs[(int)c1][(int)c2];
 }
 
-char *
-output_jump(pos, neg, length)
-  int length;
-  char *pos, *neg;
+static bool
+pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
+                bool speed ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case CONST_INT:
+      if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
+       {
+         *total = 0;
+         return true;
+       }
+      /* FALLTHRU */
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      /* Twice as expensive as REG.  */
+      *total = 2;
+      return true;
+
+    case CONST_DOUBLE:
+      /* Twice (or 4 times) as expensive as 16 bit.  */
+      *total = 4;
+      return true;
+
+    case MULT:
+      /* ??? There is something wrong in MULT because MULT is not 
+         as cheap as total = 2 even if we can shift!  */
+      /* If optimizing for size make mult etc cheap, but not 1, so when 
+         in doubt the faster insn is chosen.  */
+      if (optimize_size)
+        *total = COSTS_N_INSNS (2);
+      else
+        *total = COSTS_N_INSNS (11);
+      return false;
+
+    case DIV:
+      if (optimize_size)
+        *total = COSTS_N_INSNS (2);
+      else
+        *total = COSTS_N_INSNS (25);
+      return false;
+
+    case MOD:
+      if (optimize_size)
+        *total = COSTS_N_INSNS (2);
+      else
+        *total = COSTS_N_INSNS (26);
+      return false;
+
+    case ABS:
+      /* Equivalent to length, so same for optimize_size.  */
+      *total = COSTS_N_INSNS (3);
+      return false;
+
+    case ZERO_EXTEND:
+      /* Only used for qi->hi.  */
+      *total = COSTS_N_INSNS (1);
+      return false;
+
+    case SIGN_EXTEND:
+      if (GET_MODE (x) == HImode)
+       *total = COSTS_N_INSNS (1);
+      else if (GET_MODE (x) == SImode)
+       *total = COSTS_N_INSNS (6);
+      else
+       *total = COSTS_N_INSNS (2);
+      return false;
+
+    case ASHIFT:
+    case LSHIFTRT:
+    case ASHIFTRT:
+      if (optimize_size)
+        *total = COSTS_N_INSNS (1);
+      else if (GET_MODE (x) ==  QImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           *total = COSTS_N_INSNS (8); /* worst case */
+          else
+           *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
+        }
+      else if (GET_MODE (x) == HImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+            {
+             if (abs (INTVAL (XEXP (x, 1))) == 1)
+                *total = COSTS_N_INSNS (1);
+              else
+               *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
+            }
+          else
+            *total = COSTS_N_INSNS (10); /* worst case */
+        }
+      else if (GET_MODE (x) == SImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+           *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
+          else /* worst case */
+            *total = COSTS_N_INSNS (18);
+        }
+      return false;
+
+    default:
+      return false;
+    }
+}
+
+const char *
+output_jump (enum rtx_code code, int inv, int length)
 {
     static int x = 0;
     
     static char buf[1000];
+    const char *pos, *neg;
+
+    switch (code)
+      {
+      case EQ: pos = "beq", neg = "bne"; break;
+      case NE: pos = "bne", neg = "beq"; break;
+      case GT: pos = "bgt", neg = "ble"; break;
+      case GTU: pos = "bhi", neg = "blos"; break;
+      case LT: pos = "blt", neg = "bge"; break;
+      case LTU: pos = "blo", neg = "bhis"; break;
+      case GE: pos = "bge", neg = "blt"; break;
+      case GEU: pos = "bhis", neg = "blo"; break;
+      case LE: pos = "ble", neg = "bgt"; break;
+      case LEU: pos = "blos", neg = "bhi"; break;
+      default: gcc_unreachable ();
+      }
 
 #if 0
 /* currently we don't need this, because the tstdf and cmpdf 
@@ -941,16 +1194,15 @@ output_jump(pos, neg, length)
        
     switch (length)
     {
-      case 1:
+      case 2:
        
-       strcpy(buf, pos);
-       strcat(buf, " %l0");
+       sprintf(buf, "%s %%l1", inv ? neg : pos);
        
        return buf;
        
-      case 3:
+      case 6:
        
-       sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
+       sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x);
        
        x++;
        
@@ -958,15 +1210,13 @@ output_jump(pos, neg, length)
        
       default:
        
-       abort();
+       gcc_unreachable ();
     }
     
 }
 
 void
-notice_update_cc_on_set(exp, insn)
-  rtx exp;
-  rtx insn;
+notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
 {
     if (GET_CODE (SET_DEST (exp)) == CC0)
     { 
@@ -1035,9 +1285,8 @@ notice_update_cc_on_set(exp, insn)
 }
 
 
-int simple_memory_operand(op, mode)
-  rtx op;
-  enum machine_mode mode;
+int
+simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
     rtx addr;
 
@@ -1109,9 +1358,8 @@ int simple_memory_operand(op, mode)
  */
 
  
-char *
-output_block_move(operands)
-  rtx *operands;
+const char *
+output_block_move(rtx *operands)
 {
     static int count = 0;
     char buf[200];
@@ -1348,70 +1596,545 @@ output_block_move(operands)
     return "";
 }
 
-/* for future use */
+/* This function checks whether a real value can be encoded as
+   a literal, i.e., addressing mode 27.  In that mode, real values
+   are one word values, so the remaining 48 bits have to be zero.  */
 int
-comparison_operator_index(op)
-  rtx op;
+legitimate_const_double_p (rtx address)
 {
-    switch (GET_CODE(op))
+  REAL_VALUE_TYPE r;
+  long sval[2];
+  REAL_VALUE_FROM_CONST_DOUBLE (r, address);
+  REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
+  if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
+    return 1;
+  return 0;
+}
+
+/* Implement CANNOT_CHANGE_MODE_CLASS.  */
+bool
+pdp11_cannot_change_mode_class (enum machine_mode from,
+                               enum machine_mode to,
+                               enum reg_class rclass)
+{
+  /* Also, FPU registers contain a whole float value and the parts of
+     it are not separately accessible.
+
+     So we disallow all mode changes involving FPRs.  */
+  if (FLOAT_MODE_P (from) != FLOAT_MODE_P (to))
+    return true;
+  
+  return reg_classes_intersect_p (FPU_REGS, rclass);
+}
+
+/* TARGET_PREFERRED_RELOAD_CLASS
+
+   Given an rtx X being reloaded into a reg required to be
+   in class CLASS, return the class of reg to actually use.
+   In general this is just CLASS; but on some machines
+   in some cases it is preferable to use a more restrictive class.  
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_reload_class (rtx x, reg_class_t rclass)
+{
+  if (rclass == FPU_REGS)
+    return LOAD_FPU_REGS;
+  if (rclass == ALL_REGS)
     {
-      case NE:
-       return 0;
-       
-      case EQ:
-       return 1;
-       
-      case GE:
-       return 2;
-       
-      case GT:
-       return 3;
-       
-      case LE:
-       return 4;
-       
-      case LT:
-       return 5;
-       
-      case GEU:
-       return 6;
-       
-      case GTU:
-       return 7;
+      if (FLOAT_MODE_P (GET_MODE (x)))
+       return LOAD_FPU_REGS;
+      else
+       return GENERAL_REGS;
+    }
+  return rclass;
+}
 
-      case LEU:
-       return 8;
-       
-      case LTU:
-       return 9;
-       
-      default:
-       return -1;
+/* TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+
+   Given an rtx X being reloaded into a reg required to be
+   in class CLASS, return the class of reg to actually use.
+   In general this is just CLASS; but on some machines
+   in some cases it is preferable to use a more restrictive class.  
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_output_reload_class (rtx x, reg_class_t rclass)
+{
+  if (rclass == FPU_REGS)
+    return LOAD_FPU_REGS;
+  if (rclass == ALL_REGS)
+    {
+      if (FLOAT_MODE_P (GET_MODE (x)))
+       return LOAD_FPU_REGS;
+      else
+       return GENERAL_REGS;
     }
-}    
-       
-/* tests whether the rtx is a comparison operator */
-int
-comp_operator (op, mode)
-  rtx op;
-  enum machine_mode mode;
+  return rclass;
+}
+
+
+/* TARGET_SECONDARY_RELOAD.
+
+   FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an 
+   intermediate register (AC0-AC3: LOAD_FPU_REGS).  Everything else
+   can be loade/stored directly.  */
+static reg_class_t 
+pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
+                       rtx x,
+                       reg_class_t reload_class,
+                       enum machine_mode reload_mode ATTRIBUTE_UNUSED,
+                       secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+  if (reload_class != NO_LOAD_FPU_REGS || GET_CODE (x) != REG ||
+      REGNO_REG_CLASS (REGNO (x)) == LOAD_FPU_REGS)
+    return NO_REGS;
+  
+  return LOAD_FPU_REGS;
+}
+
+/* Target routine to check if register to register move requires memory.
+
+   The answer is yes if we're going between general register and FPU 
+   registers.  The mode doesn't matter in making this check.
+*/
+bool 
+pdp11_secondary_memory_needed (reg_class_t c1, reg_class_t c2, 
+                              enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-    return comparison_operator_index(op) >= 0;
+  int fromfloat = (c1 == LOAD_FPU_REGS || c1 == NO_LOAD_FPU_REGS || 
+                  c1 == FPU_REGS);
+  int tofloat = (c2 == LOAD_FPU_REGS || c2 == NO_LOAD_FPU_REGS || 
+                c2 == FPU_REGS);
+  
+  return (fromfloat != tofloat);
 }
 
+/* TARGET_LEGITIMATE_ADDRESS_P recognizes an RTL expression
+   that is a valid memory address for an instruction.
+   The MODE argument is the machine mode for the MEM expression
+   that wants to use this address.
+
+*/
+
+static bool
+pdp11_legitimate_address_p (enum machine_mode mode,
+                           rtx operand, bool strict)
+{
+    rtx xfoob;
+
+    /* accept @#address */
+    if (CONSTANT_ADDRESS_P (operand))
+      return true;
+    
+    switch (GET_CODE (operand))
+      {
+      case REG:
+       /* accept (R0) */
+       return !strict || REGNO_OK_FOR_BASE_P (REGNO (operand));
     
+      case PLUS:
+       /* accept X(R0) */
+       return GET_CODE (XEXP (operand, 0)) == REG
+         && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (operand, 0))))
+         && CONSTANT_ADDRESS_P (XEXP (operand, 1));
+
+      case PRE_DEC:
+       /* accept -(R0) */
+       return GET_CODE (XEXP (operand, 0)) == REG
+         && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (operand, 0))));
+
+      case POST_INC:
+       /* accept (R0)+ */
+       return GET_CODE (XEXP (operand, 0)) == REG
+         && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (operand, 0))));
+
+      case PRE_MODIFY:
+       /* accept -(SP) -- which uses PRE_MODIFY for byte mode */
+       return GET_CODE (XEXP (operand, 0)) == REG
+         && REGNO (XEXP (operand, 0)) == STACK_POINTER_REGNUM
+         && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
+         && GET_CODE (XEXP (xfoob, 0)) == REG
+         && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
+         && CONSTANT_P (XEXP (xfoob, 1))
+         && INTVAL (XEXP (xfoob,1)) == -2;
+
+      case POST_MODIFY:
+       /* accept (SP)+ -- which uses POST_MODIFY for byte mode */
+       return GET_CODE (XEXP (operand, 0)) == REG
+         && REGNO (XEXP (operand, 0)) == STACK_POINTER_REGNUM
+         && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
+         && GET_CODE (XEXP (xfoob, 0)) == REG
+         && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
+         && CONSTANT_P (XEXP (xfoob, 1))
+         && INTVAL (XEXP (xfoob,1)) == 2;
+
+      case MEM:
+       /* handle another level of indirection ! */
+       xfoob = XEXP (operand, 0);
+
+       /* (MEM:xx (MEM:xx ())) is not valid for SI, DI and currently
+          also forbidden for float, because we have to handle this 
+          in output_move_double and/or output_move_quad() - we could
+          do it, but currently it's not worth it!!! 
+          now that DFmode cannot go into CPU register file, 
+          maybe I should allow float ... 
+          but then I have to handle memory-to-memory moves in movdf ??  */
+       if (GET_MODE_BITSIZE(mode) > 16)
+         return false;
+
+       /* accept @address */
+       if (CONSTANT_ADDRESS_P (xfoob))
+         return true;
+
+       switch (GET_CODE (xfoob))
+         {
+         case REG:
+           /* accept @(R0) - which is @0(R0) */
+           return !strict || REGNO_OK_FOR_BASE_P(REGNO (xfoob));
+
+         case PLUS:
+           /* accept @X(R0) */
+           return GET_CODE (XEXP (xfoob, 0)) == REG
+             && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (xfoob, 0))))
+             && CONSTANT_ADDRESS_P (XEXP (xfoob, 1));
+
+         case PRE_DEC:
+           /* accept @-(R0) */
+           return GET_CODE (XEXP (xfoob, 0)) == REG
+             && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (xfoob, 0))));
+
+         case POST_INC:
+           /* accept @(R0)+ */
+           return GET_CODE (XEXP (xfoob, 0)) == REG
+             && (!strict || REGNO_OK_FOR_BASE_P (REGNO (XEXP (xfoob, 0))));
+
+         default:
+           /* anything else is invalid */
+           return false;
+         }
+
+      default:
+       /* anything else is invalid */
+       return false;
+      }
+}
+/* Return the class number of the smallest class containing
+   reg number REGNO.  */
+enum reg_class
+pdp11_regno_reg_class (int regno)
+{ 
+  if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
+    return GENERAL_REGS;
+  else if (regno > AC3_REGNUM)
+    return NO_LOAD_FPU_REGS;
+  else if (regno >= AC0_REGNUM)
+    return LOAD_FPU_REGS;
+  else if (regno & 1)
+    return MUL_REGS;
+  else
+    return GENERAL_REGS;
+}
+
+
+static int
+pdp11_sp_frame_offset (void)
+{
+  int offset = 0, regno;
+  offset = get_frame_size();
+  for (regno = 0; regno <= PC_REGNUM; regno++)
+    if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])
+      offset += 2;
+  for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++)
+    if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])
+      offset += 8;
+  
+  return offset;
+}   
+
+/* Return the offset between two registers, one to be eliminated, and the other
+   its replacement, at the start of a routine.  */
+
 int
-legitimate_address_p (mode, address)
-  enum machine_mode mode;
-  rtx address;
+pdp11_initial_elimination_offset (int from, int to)
 {
-/* #define REG_OK_STRICT */
-    GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
-    
+  int spoff;
+  
+  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    return 4;
+  else if (from == FRAME_POINTER_REGNUM
+          && to == HARD_FRAME_POINTER_REGNUM)
     return 0;
-    
-  win:
-    return 1;
+  else
+    {
+      gcc_assert (to == STACK_POINTER_REGNUM);
+
+      /* Get the size of the register save area.  */
+      spoff = pdp11_sp_frame_offset ();
+      if (from == FRAME_POINTER_REGNUM)
+       return spoff;
+
+      gcc_assert (from == ARG_POINTER_REGNUM);
+
+      /* If there is a frame pointer, that is saved too.  */
+      if (frame_pointer_needed)
+       spoff += 2;
+      
+      /* Account for the saved PC in the function call.  */
+      return spoff + 2;
+    }
+}    
+
+/* A copy of output_addr_const modified for pdp11 expression syntax.
+   output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
+   use, and for debugging output, which we don't support with this port either.
+   So this copy should get called whenever needed.
+*/
+void
+output_addr_const_pdp11 (FILE *file, rtx x)
+{
+  char buf[256];
+
+ restart:
+  switch (GET_CODE (x))
+    {
+    case PC:
+      gcc_assert (flag_pic);
+      putc ('.', file);
+      break;
+
+    case SYMBOL_REF:
+      assemble_name (file, XSTR (x, 0));
+      break;
+
+    case LABEL_REF:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
+      assemble_name (file, buf);
+      break;
+
+    case CODE_LABEL:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
+      assemble_name (file, buf);
+      break;
+
+    case CONST_INT:
+      fprintf (file, "%#o", (int) INTVAL (x) & 0xffff);
+      break;
+
+    case CONST:
+      /* This used to output parentheses around the expression,
+        but that does not work on the 386 (either ATT or BSD assembler).  */
+      output_addr_const_pdp11 (file, XEXP (x, 0));
+      break;
+
+    case CONST_DOUBLE:
+      if (GET_MODE (x) == VOIDmode)
+       {
+         /* We can use %o if the number is one word and positive.  */
+         gcc_assert (!CONST_DOUBLE_HIGH (x));
+         fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
+       }
+      else
+       /* We can't handle floating point constants;
+          PRINT_OPERAND must handle them.  */
+       output_operand_lossage ("floating constant misused");
+      break;
+
+    case PLUS:
+      /* Some assemblers need integer constants to appear last (e.g. masm).  */
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+       {
+         output_addr_const_pdp11 (file, XEXP (x, 1));
+         if (INTVAL (XEXP (x, 0)) >= 0)
+           fprintf (file, "+");
+         output_addr_const_pdp11 (file, XEXP (x, 0));
+       }
+      else
+       {
+         output_addr_const_pdp11 (file, XEXP (x, 0));
+         if (INTVAL (XEXP (x, 1)) >= 0)
+           fprintf (file, "+");
+         output_addr_const_pdp11 (file, XEXP (x, 1));
+       }
+      break;
+
+    case MINUS:
+      /* Avoid outputting things like x-x or x+5-x,
+        since some assemblers can't handle that.  */
+      x = simplify_subtraction (x);
+      if (GET_CODE (x) != MINUS)
+       goto restart;
+
+      output_addr_const_pdp11 (file, XEXP (x, 0));
+      fprintf (file, "-");
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) < 0)
+       {
+         fprintf (file, targetm.asm_out.open_paren);
+         output_addr_const_pdp11 (file, XEXP (x, 1));
+         fprintf (file, targetm.asm_out.close_paren);
+       }
+      else
+       output_addr_const_pdp11 (file, XEXP (x, 1));
+      break;
+
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      output_addr_const_pdp11 (file, XEXP (x, 0));
+      break;
+
+    default:
+      output_operand_lossage ("invalid expression as operand");
+    }
+}
+
+/* Worker function for TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+pdp11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  /* Integers 32 bits and under, and scalar floats (if FPU), are returned
+     in registers.  The rest go into memory.  */
+  return (TYPE_MODE (type) == DImode
+         || (FLOAT_MODE_P (TYPE_MODE (type)) && ! TARGET_AC0)
+         || TREE_CODE (type) == VECTOR_TYPE
+         || COMPLEX_MODE_P (TYPE_MODE (type)));
+}
+
+/* Worker function for TARGET_FUNCTION_VALUE.
+
+   On the pdp11 the value is found in R0 (or ac0??? not without FPU!!!! )  */
+
+static rtx
+pdp11_function_value (const_tree valtype, 
+                     const_tree fntype_or_decl ATTRIBUTE_UNUSED,
+                     bool outgoing ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (TYPE_MODE (valtype),
+                     BASE_RETURN_VALUE_REG(TYPE_MODE(valtype)));
+}
+
+/* Worker function for TARGET_LIBCALL_VALUE.  */
+
+static rtx
+pdp11_libcall_value (enum machine_mode mode,
+                     const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return  gen_rtx_REG (mode, BASE_RETURN_VALUE_REG(mode));
+}
+
+/* Worker function for TARGET_FUNCTION_VALUE_REGNO_P.
+
+   On the pdp, the first "output" reg is the only register thus used.
+
+   maybe ac0 ? - as option someday!  */
+
+static bool
+pdp11_function_value_regno_p (const unsigned int regno)
+{
+  return (regno == RETVAL_REGNUM) || (TARGET_AC0 && (regno == AC0_REGNUM));
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT.
+
+   trampoline - how should i do it in separate i+d ? 
+   have some allocate_trampoline magic??? 
+
+   the following should work for shared I/D:
+
+   MOV #STATIC, $4     01270Y  0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM
+   JMP @#FUNCTION      000137  0x0000 <- FUNCTION
+*/
+
+static void
+pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem;
+
+  gcc_assert (!TARGET_SPLIT);
+
+  mem = adjust_address (m_tramp, HImode, 0);
+  emit_move_insn (mem, GEN_INT (012700+STATIC_CHAIN_REGNUM));
+  mem = adjust_address (m_tramp, HImode, 2);
+  emit_move_insn (mem, chain_value);
+  mem = adjust_address (m_tramp, HImode, 4);
+  emit_move_insn (mem, GEN_INT (000137));
+  emit_move_insn (mem, fnaddr);
+}
+
+/* Worker function for TARGET_FUNCTION_ARG.
+
+   Determine where to put an argument to a function.
+   Value is zero to push the argument on the stack,
+   or a hard register in which to store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+    This is null for libcalls where that information may
+    not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+    the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).  */
 
-/* #undef REG_OK_STRICT */
+static rtx
+pdp11_function_arg (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                   enum machine_mode mode ATTRIBUTE_UNUSED,
+                   const_tree type ATTRIBUTE_UNUSED,
+                   bool named ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
+/* Worker function for TARGET_FUNCTION_ARG_ADVANCE.
+
+   Update the data in CUM to advance over an argument of mode MODE and
+   data type TYPE.  (TYPE is null for libcalls where that information
+   may not be available.)  */
+
+static void
+pdp11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                           const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+  *cum += (mode != BLKmode
+          ? GET_MODE_SIZE (mode)
+          : int_size_in_bytes (type));
+}
+
+/* Make sure everything's fine if we *don't* have an FPU.
+   This assumes that putting a register in fixed_regs will keep the
+   compiler's mitts completely off it.  We don't bother to zero it out
+   of register classes.  Also fix incompatible register naming with
+   the UNIX assembler.  */
+
+static void
+pdp11_conditional_register_usage (void)
+{
+  int i;
+  HARD_REG_SET x;
+  if (!TARGET_FPU)
+    {
+      COPY_HARD_REG_SET (x, reg_class_contents[(int)FPU_REGS]);
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ )
+       if (TEST_HARD_REG_BIT (x, i))
+       fixed_regs[i] = call_used_regs[i] = 1;
+    }
+
+  if (TARGET_AC0)
+      call_used_regs[AC0_REGNUM] = 1;
+  if (TARGET_UNIX_ASM)
+    {
+      /* Change names of FPU registers for the UNIX assembler.  */
+      reg_names[8] = "fr0";
+      reg_names[9] = "fr1";
+      reg_names[10] = "fr2";
+      reg_names[11] = "fr3";
+      reg_names[12] = "fr4";
+      reg_names[13] = "fr5";
+    }
 }
+
+struct gcc_target targetm = TARGET_INITIALIZER;