OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.2.2/] [gcc/] [config/] [pdp11/] [pdp11.c] - Diff between revs 38 and 154

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 38 Rev 154
/* Subroutines for gcc2 for pdp11.
/* Subroutines for gcc2 for pdp11.
   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005,
   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005,
   2007 Free Software Foundation, Inc.
   2007 Free Software Foundation, Inc.
   Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
   Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC 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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
the Free Software Foundation; either version 3, or (at your option)
any later version.
any later version.
 
 
GCC 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
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "rtl.h"
#include "rtl.h"
#include "regs.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "real.h"
#include "real.h"
#include "insn-config.h"
#include "insn-config.h"
#include "conditions.h"
#include "conditions.h"
#include "function.h"
#include "function.h"
#include "output.h"
#include "output.h"
#include "insn-attr.h"
#include "insn-attr.h"
#include "flags.h"
#include "flags.h"
#include "recog.h"
#include "recog.h"
#include "tree.h"
#include "tree.h"
#include "expr.h"
#include "expr.h"
#include "toplev.h"
#include "toplev.h"
#include "tm_p.h"
#include "tm_p.h"
#include "target.h"
#include "target.h"
#include "target-def.h"
#include "target-def.h"
 
 
/*
/*
#define FPU_REG_P(X)    ((X)>=8 && (X)<14)
#define FPU_REG_P(X)    ((X)>=8 && (X)<14)
#define CPU_REG_P(X)    ((X)>=0 && (X)<8)
#define CPU_REG_P(X)    ((X)>=0 && (X)<8)
*/
*/
 
 
/* this is the current value returned by the macro FIRST_PARM_OFFSET
/* this is the current value returned by the macro FIRST_PARM_OFFSET
   defined in tm.h */
   defined in tm.h */
int current_first_parm_offset;
int current_first_parm_offset;
 
 
/* Routines to encode/decode pdp11 floats */
/* Routines to encode/decode pdp11 floats */
static void encode_pdp11_f (const struct real_format *fmt,
static void encode_pdp11_f (const struct real_format *fmt,
                            long *, const REAL_VALUE_TYPE *);
                            long *, const REAL_VALUE_TYPE *);
static void decode_pdp11_f (const struct real_format *,
static void decode_pdp11_f (const struct real_format *,
                            REAL_VALUE_TYPE *, const long *);
                            REAL_VALUE_TYPE *, const long *);
static void encode_pdp11_d (const struct real_format *fmt,
static void encode_pdp11_d (const struct real_format *fmt,
                            long *, const REAL_VALUE_TYPE *);
                            long *, const REAL_VALUE_TYPE *);
static void decode_pdp11_d (const struct real_format *,
static void decode_pdp11_d (const struct real_format *,
                            REAL_VALUE_TYPE *, const long *);
                            REAL_VALUE_TYPE *, const long *);
 
 
/* These two are taken from the corresponding vax descriptors
/* These two are taken from the corresponding vax descriptors
   in real.c, changing only the encode/decode routine pointers.  */
   in real.c, changing only the encode/decode routine pointers.  */
const struct real_format pdp11_f_format =
const struct real_format pdp11_f_format =
  {
  {
    encode_pdp11_f,
    encode_pdp11_f,
    decode_pdp11_f,
    decode_pdp11_f,
    2,
    2,
    1,
    1,
    24,
    24,
    24,
    24,
    -127,
    -127,
    127,
    127,
    15,
    15,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false
    false
  };
  };
 
 
const struct real_format pdp11_d_format =
const struct real_format pdp11_d_format =
  {
  {
    encode_pdp11_d,
    encode_pdp11_d,
    decode_pdp11_d,
    decode_pdp11_d,
    2,
    2,
    1,
    1,
    56,
    56,
    56,
    56,
    -127,
    -127,
    127,
    127,
    15,
    15,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false
    false
  };
  };
 
 
static void
static void
encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
                const REAL_VALUE_TYPE *r)
                const REAL_VALUE_TYPE *r)
{
{
  (*vax_f_format.encode) (fmt, buf, r);
  (*vax_f_format.encode) (fmt, buf, r);
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
}
}
 
 
static void
static void
decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
                REAL_VALUE_TYPE *r, const long *buf)
                REAL_VALUE_TYPE *r, const long *buf)
{
{
  long tbuf;
  long tbuf;
  tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  (*vax_f_format.decode) (fmt, r, &tbuf);
  (*vax_f_format.decode) (fmt, r, &tbuf);
}
}
 
 
static void
static void
encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
                const REAL_VALUE_TYPE *r)
                const REAL_VALUE_TYPE *r)
{
{
  (*vax_d_format.encode) (fmt, buf, r);
  (*vax_d_format.encode) (fmt, buf, r);
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
  buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
}
}
 
 
static void
static void
decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
                REAL_VALUE_TYPE *r, const long *buf)
                REAL_VALUE_TYPE *r, const long *buf)
{
{
  long tbuf[2];
  long tbuf[2];
  tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
  tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
  tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
  (*vax_d_format.decode) (fmt, r, tbuf);
  (*vax_d_format.decode) (fmt, r, tbuf);
}
}
 
 
/* This is where the condition code register lives.  */
/* This is where the condition code register lives.  */
/* rtx cc0_reg_rtx; - no longer needed? */
/* rtx cc0_reg_rtx; - no longer needed? */
 
 
static bool pdp11_handle_option (size_t, const char *, int);
static bool pdp11_handle_option (size_t, const char *, int);
static rtx find_addr_reg (rtx);
static rtx find_addr_reg (rtx);
static const char *singlemove_string (rtx *);
static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int);
static bool pdp11_assemble_integer (rtx, unsigned int, int);
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
static bool pdp11_rtx_costs (rtx, int, int, int *);
static bool pdp11_rtx_costs (rtx, int, int, int *);
static bool pdp11_return_in_memory (tree, tree);
static bool pdp11_return_in_memory (tree, tree);


/* Initialize the GCC target structure.  */
/* Initialize the GCC target structure.  */
#undef TARGET_ASM_BYTE_OP
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP NULL
#define TARGET_ASM_BYTE_OP NULL
#undef TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP NULL
#define TARGET_ASM_ALIGNED_HI_OP NULL
#undef TARGET_ASM_ALIGNED_SI_OP
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP NULL
#define TARGET_ASM_ALIGNED_SI_OP NULL
#undef TARGET_ASM_INTEGER
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER pdp11_assemble_integer
#define TARGET_ASM_INTEGER pdp11_assemble_integer
 
 
#undef TARGET_ASM_FUNCTION_PROLOGUE
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
 
 
#undef TARGET_ASM_OPEN_PAREN
#undef TARGET_ASM_OPEN_PAREN
#define TARGET_ASM_OPEN_PAREN "["
#define TARGET_ASM_OPEN_PAREN "["
#undef TARGET_ASM_CLOSE_PAREN
#undef TARGET_ASM_CLOSE_PAREN
#define TARGET_ASM_CLOSE_PAREN "]"
#define TARGET_ASM_CLOSE_PAREN "]"
 
 
#undef TARGET_DEFAULT_TARGET_FLAGS
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS \
#define TARGET_DEFAULT_TARGET_FLAGS \
  (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT)
  (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT)
#undef TARGET_HANDLE_OPTION
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION pdp11_handle_option
#define TARGET_HANDLE_OPTION pdp11_handle_option
 
 
#undef TARGET_RTX_COSTS
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS pdp11_rtx_costs
#define TARGET_RTX_COSTS pdp11_rtx_costs
 
 
#undef TARGET_RETURN_IN_MEMORY
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
 
 
struct gcc_target targetm = TARGET_INITIALIZER;
struct gcc_target targetm = TARGET_INITIALIZER;


/* Implement TARGET_HANDLE_OPTION.  */
/* Implement TARGET_HANDLE_OPTION.  */
 
 
static bool
static bool
pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
                     int value ATTRIBUTE_UNUSED)
                     int value ATTRIBUTE_UNUSED)
{
{
  switch (code)
  switch (code)
    {
    {
    case OPT_m10:
    case OPT_m10:
      target_flags &= ~(MASK_40 | MASK_45);
      target_flags &= ~(MASK_40 | MASK_45);
      return true;
      return true;
 
 
    default:
    default:
      return true;
      return true;
    }
    }
}
}
 
 
/* Nonzero if OP is a valid second operand for an arithmetic insn.  */
/* Nonzero if OP is a valid second operand for an arithmetic insn.  */
 
 
int
int
arith_operand (rtx op, enum machine_mode mode)
arith_operand (rtx op, enum machine_mode mode)
{
{
  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
}
}
 
 
int
int
const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
  return (GET_CODE (op) == CONST_INT);
  return (GET_CODE (op) == CONST_INT);
}
}
 
 
int
int
immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
    return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
    return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
}
}
 
 
int
int
expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
    return (GET_CODE (op) == CONST_INT
    return (GET_CODE (op) == CONST_INT
            && abs (INTVAL(op)) > 1
            && abs (INTVAL(op)) > 1
            && abs (INTVAL(op)) <= 4);
            && abs (INTVAL(op)) <= 4);
}
}
 
 
/*
/*
   stream is a stdio stream to output the code to.
   stream is a stdio stream to output the code to.
   size is an int: how many units of temporary storage to allocate.
   size is an int: how many units of temporary storage to allocate.
   Refer to the array `regs_ever_live' to determine which registers
   Refer to the array `regs_ever_live' to determine which registers
   to save; `regs_ever_live[I]' is nonzero if register number I
   to save; `regs_ever_live[I]' is nonzero if register number I
   is ever used in the function.  This macro is responsible for
   is ever used in the function.  This macro is responsible for
   knowing which registers should not be saved even if used.
   knowing which registers should not be saved even if used.
*/
*/
 
 
#ifdef TWO_BSD
#ifdef TWO_BSD
 
 
static void
static void
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
{
{
  fprintf (stream, "\tjsr       r5, csv\n");
  fprintf (stream, "\tjsr       r5, csv\n");
  if (size)
  if (size)
    {
    {
      fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
      fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
      if (size > 2)
      if (size > 2)
        asm_fprintf (stream, "\tsub $%#wo, sp\n", size - 2);
        asm_fprintf (stream, "\tsub $%#wo, sp\n", size - 2);
 
 
    }
    }
}
}
 
 
#else  /* !TWO_BSD */
#else  /* !TWO_BSD */
 
 
static void
static void
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
{
{
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
    int regno;
    int regno;
    int via_ac = -1;
    int via_ac = -1;
 
 
    fprintf (stream,
    fprintf (stream,
             "\n\t;     /* function prologue %s*/\n",
             "\n\t;     /* function prologue %s*/\n",
             current_function_name ());
             current_function_name ());
 
 
    /* if we are outputting code for main,
    /* if we are outputting code for main,
       the switch FPU to right mode if TARGET_FPU */
       the switch FPU to right mode if TARGET_FPU */
    if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
    if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
    {
    {
        fprintf(stream,
        fprintf(stream,
                "\t;/* switch cpu to double float, single integer */\n");
                "\t;/* switch cpu to double float, single integer */\n");
        fprintf(stream, "\tsetd\n");
        fprintf(stream, "\tsetd\n");
        fprintf(stream, "\tseti\n\n");
        fprintf(stream, "\tseti\n\n");
    }
    }
 
 
    if (frame_pointer_needed)
    if (frame_pointer_needed)
    {
    {
        fprintf(stream, "\tmov r5, -(sp)\n");
        fprintf(stream, "\tmov r5, -(sp)\n");
        fprintf(stream, "\tmov sp, r5\n");
        fprintf(stream, "\tmov sp, r5\n");
    }
    }
    else
    else
    {
    {
        /* DON'T SAVE FP */
        /* DON'T SAVE FP */
    }
    }
 
 
    /* make frame */
    /* make frame */
    if (fsize)
    if (fsize)
        asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
        asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
 
 
    /* save CPU registers  */
    /* save CPU registers  */
    for (regno = 0; regno < 8; regno++)
    for (regno = 0; regno < 8; regno++)
        if (regs_ever_live[regno] && ! call_used_regs[regno])
        if (regs_ever_live[regno] && ! call_used_regs[regno])
            if (! ((regno == FRAME_POINTER_REGNUM)
            if (! ((regno == FRAME_POINTER_REGNUM)
                   && frame_pointer_needed))
                   && frame_pointer_needed))
                fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
                fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
    /* fpu regs saving */
    /* fpu regs saving */
 
 
    /* via_ac specifies the ac to use for saving ac4, ac5 */
    /* via_ac specifies the ac to use for saving ac4, ac5 */
    via_ac = -1;
    via_ac = -1;
 
 
    for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
    for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
    {
    {
        /* ac0 - ac3 */
        /* ac0 - ac3 */
        if (LOAD_FPU_REG_P(regno)
        if (LOAD_FPU_REG_P(regno)
            && regs_ever_live[regno]
            && regs_ever_live[regno]
            && ! call_used_regs[regno])
            && ! call_used_regs[regno])
        {
        {
            fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
            fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
            via_ac = regno;
            via_ac = regno;
        }
        }
 
 
        /* maybe make ac4, ac5 call used regs?? */
        /* maybe make ac4, ac5 call used regs?? */
        /* ac4 - ac5 */
        /* ac4 - ac5 */
        if (NO_LOAD_FPU_REG_P(regno)
        if (NO_LOAD_FPU_REG_P(regno)
            && regs_ever_live[regno]
            && regs_ever_live[regno]
            && ! call_used_regs[regno])
            && ! call_used_regs[regno])
        {
        {
          gcc_assert (via_ac != -1);
          gcc_assert (via_ac != -1);
          fprintf (stream, "\tldd %s, %s\n",
          fprintf (stream, "\tldd %s, %s\n",
                   reg_names[regno], reg_names[via_ac]);
                   reg_names[regno], reg_names[via_ac]);
          fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
          fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
        }
        }
    }
    }
 
 
    fprintf (stream, "\t;/* end of prologue */\n\n");
    fprintf (stream, "\t;/* end of prologue */\n\n");
}
}
 
 
#endif /* !TWO_BSD */
#endif /* !TWO_BSD */
 
 
/*
/*
   The function epilogue should not depend on the current stack pointer!
   The function epilogue should not depend on the current stack pointer!
   It should use the frame pointer only.  This is mandatory because
   It should use the frame pointer only.  This is mandatory because
   of alloca; we also take advantage of it to omit stack adjustments
   of alloca; we also take advantage of it to omit stack adjustments
   before returning.  */
   before returning.  */
 
 
/* maybe we can make leaf functions faster by switching to the
/* maybe we can make leaf functions faster by switching to the
   second register file - this way we don't have to save regs!
   second register file - this way we don't have to save regs!
   leaf functions are ~ 50% of all functions (dynamically!)
   leaf functions are ~ 50% of all functions (dynamically!)
 
 
   set/clear bit 11 (dec. 2048) of status word for switching register files -
   set/clear bit 11 (dec. 2048) of status word for switching register files -
   but how can we do this? the pdp11/45 manual says bit may only
   but how can we do this? the pdp11/45 manual says bit may only
   be set (p.24), but not cleared!
   be set (p.24), but not cleared!
 
 
   switching to kernel is probably more expensive, so we'll leave it
   switching to kernel is probably more expensive, so we'll leave it
   like this and not use the second set of registers...
   like this and not use the second set of registers...
 
 
   maybe as option if you want to generate code for kernel mode? */
   maybe as option if you want to generate code for kernel mode? */
 
 
#ifdef TWO_BSD
#ifdef TWO_BSD
 
 
static void
static void
pdp11_output_function_epilogue (FILE *stream,
pdp11_output_function_epilogue (FILE *stream,
                                HOST_WIDE_INT size ATTRIBUTE_UNUSED)
                                HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
{
  fprintf (stream, "\t/* SP ignored by cret? */\n");
  fprintf (stream, "\t/* SP ignored by cret? */\n");
  fprintf (stream, "\tjmp cret\n");
  fprintf (stream, "\tjmp cret\n");
}
}
 
 
#else  /* !TWO_BSD */
#else  /* !TWO_BSD */
 
 
static void
static void
pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
{
{
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
    HOST_WIDE_INT fsize = ((size) + 1) & ~1;
    int i, j, k;
    int i, j, k;
 
 
    int via_ac;
    int via_ac;
 
 
    fprintf (stream, "\n\t;     /*function epilogue */\n");
    fprintf (stream, "\n\t;     /*function epilogue */\n");
 
 
    if (frame_pointer_needed)
    if (frame_pointer_needed)
    {
    {
        /* hope this is safe - m68k does it also .... */
        /* hope this is safe - m68k does it also .... */
        regs_ever_live[FRAME_POINTER_REGNUM] = 0;
        regs_ever_live[FRAME_POINTER_REGNUM] = 0;
 
 
        for (i =7, j = 0 ; i >= 0 ; i--)
        for (i =7, j = 0 ; i >= 0 ; i--)
            if (regs_ever_live[i] && ! call_used_regs[i])
            if (regs_ever_live[i] && ! call_used_regs[i])
                j++;
                j++;
 
 
        /* remember # of pushed bytes for CPU regs */
        /* remember # of pushed bytes for CPU regs */
        k = 2*j;
        k = 2*j;
 
 
        /* change fp -> r5 due to the compile error on libgcc2.c */
        /* change fp -> r5 due to the compile error on libgcc2.c */
        for (i =7 ; i >= 0 ; i--)
        for (i =7 ; i >= 0 ; i--)
            if (regs_ever_live[i] && ! call_used_regs[i])
            if (regs_ever_live[i] && ! call_used_regs[i])
                fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
                fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
 
 
        /* get ACs */
        /* get ACs */
        via_ac = FIRST_PSEUDO_REGISTER -1;
        via_ac = FIRST_PSEUDO_REGISTER -1;
 
 
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
            if (regs_ever_live[i] && ! call_used_regs[i])
            if (regs_ever_live[i] && ! call_used_regs[i])
            {
            {
                via_ac = i;
                via_ac = i;
                k += 8;
                k += 8;
            }
            }
 
 
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        {
        {
            if (LOAD_FPU_REG_P(i)
            if (LOAD_FPU_REG_P(i)
                && regs_ever_live[i]
                && regs_ever_live[i]
                && ! call_used_regs[i])
                && ! call_used_regs[i])
            {
            {
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
                k -= 8;
                k -= 8;
            }
            }
 
 
            if (NO_LOAD_FPU_REG_P(i)
            if (NO_LOAD_FPU_REG_P(i)
                && regs_ever_live[i]
                && regs_ever_live[i]
                && ! call_used_regs[i])
                && ! call_used_regs[i])
            {
            {
                gcc_assert (LOAD_FPU_REG_P(via_ac));
                gcc_assert (LOAD_FPU_REG_P(via_ac));
 
 
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
                fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                k -= 8;
                k -= 8;
            }
            }
        }
        }
 
 
        fprintf(stream, "\tmov r5, sp\n");
        fprintf(stream, "\tmov r5, sp\n");
        fprintf (stream, "\tmov (sp)+, r5\n");
        fprintf (stream, "\tmov (sp)+, r5\n");
    }
    }
    else
    else
    {
    {
        via_ac = FIRST_PSEUDO_REGISTER -1;
        via_ac = FIRST_PSEUDO_REGISTER -1;
 
 
        /* get ACs */
        /* get ACs */
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
            if (regs_ever_live[i] && call_used_regs[i])
            if (regs_ever_live[i] && call_used_regs[i])
                via_ac = i;
                via_ac = i;
 
 
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
        {
        {
            if (LOAD_FPU_REG_P(i)
            if (LOAD_FPU_REG_P(i)
                && regs_ever_live[i]
                && regs_ever_live[i]
                && ! call_used_regs[i])
                && ! call_used_regs[i])
              fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
              fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
 
 
            if (NO_LOAD_FPU_REG_P(i)
            if (NO_LOAD_FPU_REG_P(i)
                && regs_ever_live[i]
                && regs_ever_live[i]
                && ! call_used_regs[i])
                && ! call_used_regs[i])
            {
            {
                gcc_assert (LOAD_FPU_REG_P(via_ac));
                gcc_assert (LOAD_FPU_REG_P(via_ac));
 
 
                fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
                fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
            }
            }
        }
        }
 
 
        for (i=7; i >= 0; i--)
        for (i=7; i >= 0; i--)
            if (regs_ever_live[i] && !call_used_regs[i])
            if (regs_ever_live[i] && !call_used_regs[i])
                fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
                fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
 
 
        if (fsize)
        if (fsize)
            fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
            fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
    }
    }
 
 
    fprintf (stream, "\trts pc\n");
    fprintf (stream, "\trts pc\n");
    fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
    fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
}
}
 
 
#endif /* !TWO_BSD */
#endif /* !TWO_BSD */
 
 
/* Return the best assembler insn template
/* Return the best assembler insn template
   for moving operands[1] into operands[0] as a fullword.  */
   for moving operands[1] into operands[0] as a fullword.  */
static const char *
static const char *
singlemove_string (rtx *operands)
singlemove_string (rtx *operands)
{
{
  if (operands[1] != const0_rtx)
  if (operands[1] != const0_rtx)
    return "mov %1,%0";
    return "mov %1,%0";
 
 
  return "clr %0";
  return "clr %0";
}
}
 
 


/* Output assembler code to perform a doubleword move insn
/* Output assembler code to perform a doubleword move insn
   with operands OPERANDS.  */
   with operands OPERANDS.  */
 
 
const char *
const char *
output_move_double (rtx *operands)
output_move_double (rtx *operands)
{
{
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  rtx latehalf[2];
  rtx latehalf[2];
  rtx addreg0 = 0, addreg1 = 0;
  rtx addreg0 = 0, addreg1 = 0;
 
 
  /* First classify both operands.  */
  /* First classify both operands.  */
 
 
  if (REG_P (operands[0]))
  if (REG_P (operands[0]))
    optype0 = REGOP;
    optype0 = REGOP;
  else if (offsettable_memref_p (operands[0]))
  else if (offsettable_memref_p (operands[0]))
    optype0 = OFFSOP;
    optype0 = OFFSOP;
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
    optype0 = POPOP;
    optype0 = POPOP;
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
    optype0 = PUSHOP;
    optype0 = PUSHOP;
  else if (GET_CODE (operands[0]) == MEM)
  else if (GET_CODE (operands[0]) == MEM)
    optype0 = MEMOP;
    optype0 = MEMOP;
  else
  else
    optype0 = RNDOP;
    optype0 = RNDOP;
 
 
  if (REG_P (operands[1]))
  if (REG_P (operands[1]))
    optype1 = REGOP;
    optype1 = REGOP;
  else if (CONSTANT_P (operands[1])
  else if (CONSTANT_P (operands[1])
#if 0
#if 0
           || GET_CODE (operands[1]) == CONST_DOUBLE
           || GET_CODE (operands[1]) == CONST_DOUBLE
#endif
#endif
           )
           )
    optype1 = CNSTOP;
    optype1 = CNSTOP;
  else if (offsettable_memref_p (operands[1]))
  else if (offsettable_memref_p (operands[1]))
    optype1 = OFFSOP;
    optype1 = OFFSOP;
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
    optype1 = POPOP;
    optype1 = POPOP;
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
    optype1 = PUSHOP;
    optype1 = PUSHOP;
  else if (GET_CODE (operands[1]) == MEM)
  else if (GET_CODE (operands[1]) == MEM)
    optype1 = MEMOP;
    optype1 = MEMOP;
  else
  else
    optype1 = RNDOP;
    optype1 = RNDOP;
 
 
  /* Check for the cases that the operand constraints are not
  /* Check for the cases that the operand constraints are not
     supposed to allow to happen.  Abort if we get one,
     supposed to allow to happen.  Abort if we get one,
     because generating code for these cases is painful.  */
     because generating code for these cases is painful.  */
 
 
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
 
 
  /* If one operand is decrementing and one is incrementing
  /* If one operand is decrementing and one is incrementing
     decrement the former register explicitly
     decrement the former register explicitly
     and change that operand into ordinary indexing.  */
     and change that operand into ordinary indexing.  */
 
 
  if (optype0 == PUSHOP && optype1 == POPOP)
  if (optype0 == PUSHOP && optype1 == POPOP)
    {
    {
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
      output_asm_insn ("sub $4,%0", operands);
      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;
      optype0 = OFFSOP;
    }
    }
  if (optype0 == POPOP && optype1 == PUSHOP)
  if (optype0 == POPOP && optype1 == PUSHOP)
    {
    {
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
      output_asm_insn ("sub $4,%1", operands);
      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;
      optype1 = OFFSOP;
    }
    }
 
 
  /* If an operand is an unoffsettable memory ref, find a register
  /* If an operand is an unoffsettable memory ref, find a register
     we can increment temporarily to make it refer to the second word.  */
     we can increment temporarily to make it refer to the second word.  */
 
 
  if (optype0 == MEMOP)
  if (optype0 == MEMOP)
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
 
 
  if (optype1 == MEMOP)
  if (optype1 == MEMOP)
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
 
 
  /* Ok, we can do one word at a time.
  /* Ok, we can do one word at a time.
     Normally we do the low-numbered word first,
     Normally we do the low-numbered word first,
     but if either operand is autodecrementing then we
     but if either operand is autodecrementing then we
     do the high-numbered word first.
     do the high-numbered word first.
 
 
     In either case, set up in LATEHALF the operands to use
     In either case, set up in LATEHALF the operands to use
     for the high-numbered word and in some cases alter the
     for the high-numbered word and in some cases alter the
     operands in OPERANDS to be suitable for the low-numbered word.  */
     operands in OPERANDS to be suitable for the low-numbered word.  */
 
 
  if (optype0 == REGOP)
  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)
  else if (optype0 == OFFSOP)
    latehalf[0] = adjust_address (operands[0], HImode, 2);
    latehalf[0] = adjust_address (operands[0], HImode, 2);
  else
  else
    latehalf[0] = operands[0];
    latehalf[0] = operands[0];
 
 
  if (optype1 == REGOP)
  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)
  else if (optype1 == OFFSOP)
    latehalf[1] = adjust_address (operands[1], HImode, 2);
    latehalf[1] = adjust_address (operands[1], HImode, 2);
  else if (optype1 == CNSTOP)
  else if (optype1 == CNSTOP)
    {
    {
        if (CONSTANT_P (operands[1]))
        if (CONSTANT_P (operands[1]))
        {
        {
            /* now the mess begins, high word is in lower word???
            /* now the mess begins, high word is in lower word???
 
 
               that's what ashc makes me think, but I don't remember :-( */
               that's what ashc makes me think, but I don't remember :-( */
            latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
            latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
            operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
            operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
        }
        }
        else
        else
          /* immediate 32 bit values not allowed */
          /* immediate 32 bit values not allowed */
          gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE);
          gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE);
    }
    }
  else
  else
    latehalf[1] = operands[1];
    latehalf[1] = operands[1];
 
 
  /* If insn is effectively movd N(sp),-(sp) then we will do the
  /* If insn is effectively movd N(sp),-(sp) then we will do the
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
     for the low word as well, to compensate for the first decrement of sp.  */
     for the low word as well, to compensate for the first decrement of sp.  */
  if (optype0 == PUSHOP
  if (optype0 == PUSHOP
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
    operands[1] = latehalf[1];
    operands[1] = latehalf[1];
 
 
  /* If one or both operands autodecrementing,
  /* If one or both operands autodecrementing,
     do the two words, high-numbered first.  */
     do the two words, high-numbered first.  */
 
 
  /* Likewise,  the first move would clobber the source of the second one,
  /* Likewise,  the first move would clobber the source of the second one,
     do them in the other order.  This happens only for registers;
     do them in the other order.  This happens only for registers;
     such overlap can't happen in memory unless the user explicitly
     such overlap can't happen in memory unless the user explicitly
     sets it up, and that is an undefined circumstance.  */
     sets it up, and that is an undefined circumstance.  */
 
 
  if (optype0 == PUSHOP || optype1 == PUSHOP
  if (optype0 == PUSHOP || optype1 == PUSHOP
      || (optype0 == REGOP && optype1 == REGOP
      || (optype0 == REGOP && optype1 == REGOP
          && REGNO (operands[0]) == REGNO (latehalf[1])))
          && REGNO (operands[0]) == REGNO (latehalf[1])))
    {
    {
      /* Make any unoffsettable addresses point at high-numbered word.  */
      /* Make any unoffsettable addresses point at high-numbered word.  */
      if (addreg0)
      if (addreg0)
        output_asm_insn ("add $2,%0", &addreg0);
        output_asm_insn ("add $2,%0", &addreg0);
      if (addreg1)
      if (addreg1)
        output_asm_insn ("add $2,%0", &addreg1);
        output_asm_insn ("add $2,%0", &addreg1);
 
 
      /* Do that word.  */
      /* Do that word.  */
      output_asm_insn (singlemove_string (latehalf), latehalf);
      output_asm_insn (singlemove_string (latehalf), latehalf);
 
 
      /* Undo the adds we just did.  */
      /* Undo the adds we just did.  */
      if (addreg0)
      if (addreg0)
        output_asm_insn ("sub $2,%0", &addreg0);
        output_asm_insn ("sub $2,%0", &addreg0);
      if (addreg1)
      if (addreg1)
        output_asm_insn ("sub $2,%0", &addreg1);
        output_asm_insn ("sub $2,%0", &addreg1);
 
 
      /* Do low-numbered word.  */
      /* Do low-numbered word.  */
      return singlemove_string (operands);
      return singlemove_string (operands);
    }
    }
 
 
  /* Normal case: do the two words, low-numbered first.  */
  /* Normal case: do the two words, low-numbered first.  */
 
 
  output_asm_insn (singlemove_string (operands), operands);
  output_asm_insn (singlemove_string (operands), operands);
 
 
  /* Make any unoffsettable addresses point at high-numbered word.  */
  /* Make any unoffsettable addresses point at high-numbered word.  */
  if (addreg0)
  if (addreg0)
    output_asm_insn ("add $2,%0", &addreg0);
    output_asm_insn ("add $2,%0", &addreg0);
  if (addreg1)
  if (addreg1)
    output_asm_insn ("add $2,%0", &addreg1);
    output_asm_insn ("add $2,%0", &addreg1);
 
 
  /* Do that word.  */
  /* Do that word.  */
  output_asm_insn (singlemove_string (latehalf), latehalf);
  output_asm_insn (singlemove_string (latehalf), latehalf);
 
 
  /* Undo the adds we just did.  */
  /* Undo the adds we just did.  */
  if (addreg0)
  if (addreg0)
    output_asm_insn ("sub $2,%0", &addreg0);
    output_asm_insn ("sub $2,%0", &addreg0);
  if (addreg1)
  if (addreg1)
    output_asm_insn ("sub $2,%0", &addreg1);
    output_asm_insn ("sub $2,%0", &addreg1);
 
 
  return "";
  return "";
}
}
/* Output assembler code to perform a quadword move insn
/* Output assembler code to perform a quadword move insn
   with operands OPERANDS.  */
   with operands OPERANDS.  */
 
 
const char *
const char *
output_move_quad (rtx *operands)
output_move_quad (rtx *operands)
{
{
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  rtx latehalf[2];
  rtx latehalf[2];
  rtx addreg0 = 0, addreg1 = 0;
  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]))
  if (REG_P (operands[0]))
    optype0 = REGOP;
    optype0 = REGOP;
  else if (offsettable_memref_p (operands[0]))
  else if (offsettable_memref_p (operands[0]))
    optype0 = OFFSOP;
    optype0 = OFFSOP;
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
    optype0 = POPOP;
    optype0 = POPOP;
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
    optype0 = PUSHOP;
    optype0 = PUSHOP;
  else if (GET_CODE (operands[0]) == MEM)
  else if (GET_CODE (operands[0]) == MEM)
    optype0 = MEMOP;
    optype0 = MEMOP;
  else
  else
    optype0 = RNDOP;
    optype0 = RNDOP;
 
 
  if (REG_P (operands[1]))
  if (REG_P (operands[1]))
    optype1 = REGOP;
    optype1 = REGOP;
  else if (CONSTANT_P (operands[1])
  else if (CONSTANT_P (operands[1])
           || GET_CODE (operands[1]) == CONST_DOUBLE)
           || GET_CODE (operands[1]) == CONST_DOUBLE)
    optype1 = CNSTOP;
    optype1 = CNSTOP;
  else if (offsettable_memref_p (operands[1]))
  else if (offsettable_memref_p (operands[1]))
    optype1 = OFFSOP;
    optype1 = OFFSOP;
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
    optype1 = POPOP;
    optype1 = POPOP;
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
    optype1 = PUSHOP;
    optype1 = PUSHOP;
  else if (GET_CODE (operands[1]) == MEM)
  else if (GET_CODE (operands[1]) == MEM)
    optype1 = MEMOP;
    optype1 = MEMOP;
  else
  else
    optype1 = RNDOP;
    optype1 = RNDOP;
 
 
  /* Check for the cases that the operand constraints are not
  /* Check for the cases that the operand constraints are not
     supposed to allow to happen.  Abort if we get one,
     supposed to allow to happen.  Abort if we get one,
     because generating code for these cases is painful.  */
     because generating code for these cases is painful.  */
 
 
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
  gcc_assert (optype0 != RNDOP && optype1 != RNDOP);
 
 
  /* check if we move a CPU reg to an FPU reg, or vice versa! */
  /* check if we move a CPU reg to an FPU reg, or vice versa! */
  if (optype0 == REGOP && optype1 == REGOP)
  if (optype0 == REGOP && optype1 == REGOP)
      /* bogus - 64 bit cannot reside in CPU! */
      /* bogus - 64 bit cannot reside in CPU! */
      gcc_assert (!CPU_REG_P(REGNO(operands[0]))
      gcc_assert (!CPU_REG_P(REGNO(operands[0]))
                  && !CPU_REG_P (REGNO(operands[1])));
                  && !CPU_REG_P (REGNO(operands[1])));
 
 
  if (optype0 == REGOP || optype1 == REGOP)
  if (optype0 == REGOP || optype1 == REGOP)
  {
  {
      /* check for use of clrd????
      /* check for use of clrd????
         if you ever allow ac4 and ac5 (now we require secondary load)
         if you ever allow ac4 and ac5 (now we require secondary load)
         you must check whether
         you must check whether
         you want to load into them or store from them -
         you want to load into them or store from them -
         then dump ac0 into $help$ movce ac4/5 to ac0, do the
         then dump ac0 into $help$ movce ac4/5 to ac0, do the
         store from ac0, and restore ac0 - if you can find
         store from ac0, and restore ac0 - if you can find
         an unused ac[0-3], use that and you save a store and a load!*/
         an unused ac[0-3], use that and you save a store and a load!*/
 
 
      if (FPU_REG_P(REGNO(operands[0])))
      if (FPU_REG_P(REGNO(operands[0])))
      {
      {
          if (GET_CODE(operands[1]) == CONST_DOUBLE)
          if (GET_CODE(operands[1]) == CONST_DOUBLE)
          {
          {
              REAL_VALUE_TYPE r;
              REAL_VALUE_TYPE r;
              REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
              REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
 
 
              if (REAL_VALUES_EQUAL (r, dconst0))
              if (REAL_VALUES_EQUAL (r, dconst0))
                  return "{clrd|clrf} %0";
                  return "{clrd|clrf} %0";
          }
          }
 
 
          return "{ldd|movf} %1, %0";
          return "{ldd|movf} %1, %0";
      }
      }
 
 
      if (FPU_REG_P(REGNO(operands[1])))
      if (FPU_REG_P(REGNO(operands[1])))
          return "{std|movf} %1, %0";
          return "{std|movf} %1, %0";
  }
  }
 
 
  /* If one operand is decrementing and one is incrementing
  /* If one operand is decrementing and one is incrementing
     decrement the former register explicitly
     decrement the former register explicitly
     and change that operand into ordinary indexing.  */
     and change that operand into ordinary indexing.  */
 
 
  if (optype0 == PUSHOP && optype1 == POPOP)
  if (optype0 == PUSHOP && optype1 == POPOP)
    {
    {
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
      operands[0] = XEXP (XEXP (operands[0], 0), 0);
      output_asm_insn ("sub $8,%0", operands);
      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;
      optype0 = OFFSOP;
    }
    }
  if (optype0 == POPOP && optype1 == PUSHOP)
  if (optype0 == POPOP && optype1 == PUSHOP)
    {
    {
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
      operands[1] = XEXP (XEXP (operands[1], 0), 0);
      output_asm_insn ("sub $8,%1", operands);
      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;
      optype1 = OFFSOP;
    }
    }
 
 
  /* If an operand is an unoffsettable memory ref, find a register
  /* If an operand is an unoffsettable memory ref, find a register
     we can increment temporarily to make it refer to the second word.  */
     we can increment temporarily to make it refer to the second word.  */
 
 
  if (optype0 == MEMOP)
  if (optype0 == MEMOP)
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
    addreg0 = find_addr_reg (XEXP (operands[0], 0));
 
 
  if (optype1 == MEMOP)
  if (optype1 == MEMOP)
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
    addreg1 = find_addr_reg (XEXP (operands[1], 0));
 
 
  /* Ok, we can do one word at a time.
  /* Ok, we can do one word at a time.
     Normally we do the low-numbered word first,
     Normally we do the low-numbered word first,
     but if either operand is autodecrementing then we
     but if either operand is autodecrementing then we
     do the high-numbered word first.
     do the high-numbered word first.
 
 
     In either case, set up in LATEHALF the operands to use
     In either case, set up in LATEHALF the operands to use
     for the high-numbered word and in some cases alter the
     for the high-numbered word and in some cases alter the
     operands in OPERANDS to be suitable for the low-numbered word.  */
     operands in OPERANDS to be suitable for the low-numbered word.  */
 
 
  if (optype0 == REGOP)
  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)
  else if (optype0 == OFFSOP)
    latehalf[0] = adjust_address (operands[0], SImode, 4);
    latehalf[0] = adjust_address (operands[0], SImode, 4);
  else
  else
    latehalf[0] = operands[0];
    latehalf[0] = operands[0];
 
 
  if (optype1 == REGOP)
  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)
  else if (optype1 == OFFSOP)
    latehalf[1] = adjust_address (operands[1], SImode, 4);
    latehalf[1] = adjust_address (operands[1], SImode, 4);
  else if (optype1 == CNSTOP)
  else if (optype1 == CNSTOP)
    {
    {
      if (GET_CODE (operands[1]) == CONST_DOUBLE)
      if (GET_CODE (operands[1]) == CONST_DOUBLE)
        {
        {
          REAL_VALUE_TYPE r;
          REAL_VALUE_TYPE r;
          long dval[2];
          long dval[2];
          REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
          REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
          REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
          REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
          latehalf[1] = GEN_INT (dval[1]);
          latehalf[1] = GEN_INT (dval[1]);
          operands[1] = GEN_INT (dval[0]);
          operands[1] = GEN_INT (dval[0]);
        }
        }
      else if (GET_CODE(operands[1]) == CONST_INT)
      else if (GET_CODE(operands[1]) == CONST_INT)
        {
        {
          latehalf[1] = const0_rtx;
          latehalf[1] = const0_rtx;
        }
        }
      else
      else
        gcc_unreachable ();
        gcc_unreachable ();
    }
    }
  else
  else
    latehalf[1] = operands[1];
    latehalf[1] = operands[1];
 
 
  /* If insn is effectively movd N(sp),-(sp) then we will do the
  /* If insn is effectively movd N(sp),-(sp) then we will do the
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
     for the low word as well, to compensate for the first decrement of sp.  */
     for the low word as well, to compensate for the first decrement of sp.  */
  if (optype0 == PUSHOP
  if (optype0 == PUSHOP
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
    operands[1] = latehalf[1];
    operands[1] = latehalf[1];
 
 
  /* If one or both operands autodecrementing,
  /* If one or both operands autodecrementing,
     do the two words, high-numbered first.  */
     do the two words, high-numbered first.  */
 
 
  /* Likewise,  the first move would clobber the source of the second one,
  /* Likewise,  the first move would clobber the source of the second one,
     do them in the other order.  This happens only for registers;
     do them in the other order.  This happens only for registers;
     such overlap can't happen in memory unless the user explicitly
     such overlap can't happen in memory unless the user explicitly
     sets it up, and that is an undefined circumstance.  */
     sets it up, and that is an undefined circumstance.  */
 
 
  if (optype0 == PUSHOP || optype1 == PUSHOP
  if (optype0 == PUSHOP || optype1 == PUSHOP
      || (optype0 == REGOP && optype1 == REGOP
      || (optype0 == REGOP && optype1 == REGOP
          && REGNO (operands[0]) == REGNO (latehalf[1])))
          && REGNO (operands[0]) == REGNO (latehalf[1])))
    {
    {
      /* Make any unoffsettable addresses point at high-numbered word.  */
      /* Make any unoffsettable addresses point at high-numbered word.  */
      if (addreg0)
      if (addreg0)
        output_asm_insn ("add $4,%0", &addreg0);
        output_asm_insn ("add $4,%0", &addreg0);
      if (addreg1)
      if (addreg1)
        output_asm_insn ("add $4,%0", &addreg1);
        output_asm_insn ("add $4,%0", &addreg1);
 
 
      /* Do that word.  */
      /* Do that word.  */
      output_asm_insn(output_move_double(latehalf), latehalf);
      output_asm_insn(output_move_double(latehalf), latehalf);
 
 
      /* Undo the adds we just did.  */
      /* Undo the adds we just did.  */
      if (addreg0)
      if (addreg0)
        output_asm_insn ("sub $4,%0", &addreg0);
        output_asm_insn ("sub $4,%0", &addreg0);
      if (addreg1)
      if (addreg1)
        output_asm_insn ("sub $4,%0", &addreg1);
        output_asm_insn ("sub $4,%0", &addreg1);
 
 
      /* Do low-numbered word.  */
      /* Do low-numbered word.  */
      return output_move_double (operands);
      return output_move_double (operands);
    }
    }
 
 
  /* Normal case: do the two words, low-numbered first.  */
  /* Normal case: do the two words, low-numbered first.  */
 
 
  output_asm_insn (output_move_double (operands), operands);
  output_asm_insn (output_move_double (operands), operands);
 
 
  /* Make any unoffsettable addresses point at high-numbered word.  */
  /* Make any unoffsettable addresses point at high-numbered word.  */
  if (addreg0)
  if (addreg0)
    output_asm_insn ("add $4,%0", &addreg0);
    output_asm_insn ("add $4,%0", &addreg0);
  if (addreg1)
  if (addreg1)
    output_asm_insn ("add $4,%0", &addreg1);
    output_asm_insn ("add $4,%0", &addreg1);
 
 
  /* Do that word.  */
  /* Do that word.  */
  output_asm_insn (output_move_double (latehalf), latehalf);
  output_asm_insn (output_move_double (latehalf), latehalf);
 
 
  /* Undo the adds we just did.  */
  /* Undo the adds we just did.  */
  if (addreg0)
  if (addreg0)
    output_asm_insn ("sub $4,%0", &addreg0);
    output_asm_insn ("sub $4,%0", &addreg0);
  if (addreg1)
  if (addreg1)
    output_asm_insn ("sub $4,%0", &addreg1);
    output_asm_insn ("sub $4,%0", &addreg1);
 
 
  return "";
  return "";
}
}
 
 


/* Return a REG that occurs in ADDR with coefficient 1.
/* Return a REG that occurs in ADDR with coefficient 1.
   ADDR can be effectively incremented by incrementing REG.  */
   ADDR can be effectively incremented by incrementing REG.  */
 
 
static rtx
static rtx
find_addr_reg (rtx addr)
find_addr_reg (rtx addr)
{
{
  while (GET_CODE (addr) == PLUS)
  while (GET_CODE (addr) == PLUS)
    {
    {
      if (GET_CODE (XEXP (addr, 0)) == REG)
      if (GET_CODE (XEXP (addr, 0)) == REG)
        addr = XEXP (addr, 0);
        addr = XEXP (addr, 0);
      if (GET_CODE (XEXP (addr, 1)) == REG)
      if (GET_CODE (XEXP (addr, 1)) == REG)
        addr = XEXP (addr, 1);
        addr = XEXP (addr, 1);
      if (CONSTANT_P (XEXP (addr, 0)))
      if (CONSTANT_P (XEXP (addr, 0)))
        addr = XEXP (addr, 1);
        addr = XEXP (addr, 1);
      if (CONSTANT_P (XEXP (addr, 1)))
      if (CONSTANT_P (XEXP (addr, 1)))
        addr = XEXP (addr, 0);
        addr = XEXP (addr, 0);
    }
    }
  if (GET_CODE (addr) == REG)
  if (GET_CODE (addr) == REG)
    return addr;
    return addr;
  return 0;
  return 0;
}
}


/* Output an ascii string.  */
/* Output an ascii string.  */
void
void
output_ascii (FILE *file, const char *p, int size)
output_ascii (FILE *file, const char *p, int size)
{
{
  int i;
  int i;
 
 
  /* This used to output .byte "string", which doesn't work with the UNIX
  /* This used to output .byte "string", which doesn't work with the UNIX
     assembler and I think not with DEC ones either.  */
     assembler and I think not with DEC ones either.  */
  fprintf (file, "\t.byte ");
  fprintf (file, "\t.byte ");
 
 
  for (i = 0; i < size; i++)
  for (i = 0; i < size; i++)
    {
    {
      register int c = p[i];
      register int c = p[i];
      if (c < 0)
      if (c < 0)
        c += 256;
        c += 256;
      fprintf (file, "%#o", c);
      fprintf (file, "%#o", c);
      if (i < size - 1)
      if (i < size - 1)
        putc (',', file);
        putc (',', file);
    }
    }
  putc ('\n', file);
  putc ('\n', file);
}
}
 
 
 
 
/* --- stole from out-vax, needs changes */
/* --- stole from out-vax, needs changes */
 
 
void
void
print_operand_address (FILE *file, register rtx addr)
print_operand_address (FILE *file, register rtx addr)
{
{
  register rtx reg1, reg2, breg, ireg;
  register rtx reg1, reg2, breg, ireg;
  rtx offset;
  rtx offset;
 
 
 retry:
 retry:
 
 
  switch (GET_CODE (addr))
  switch (GET_CODE (addr))
    {
    {
    case MEM:
    case MEM:
      if (TARGET_UNIX_ASM)
      if (TARGET_UNIX_ASM)
        fprintf (file, "*");
        fprintf (file, "*");
      else
      else
        fprintf (file, "@");
        fprintf (file, "@");
      addr = XEXP (addr, 0);
      addr = XEXP (addr, 0);
      goto retry;
      goto retry;
 
 
    case REG:
    case REG:
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
      break;
      break;
 
 
    case PRE_MODIFY:
    case PRE_MODIFY:
    case PRE_DEC:
    case PRE_DEC:
      fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
      fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
      break;
      break;
 
 
    case POST_MODIFY:
    case POST_MODIFY:
    case POST_INC:
    case POST_INC:
      fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
      fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
      break;
      break;
 
 
    case PLUS:
    case PLUS:
      reg1 = 0;  reg2 = 0;
      reg1 = 0;  reg2 = 0;
      ireg = 0;  breg = 0;
      ireg = 0;  breg = 0;
      offset = 0;
      offset = 0;
      if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
      if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
          || GET_CODE (XEXP (addr, 0)) == MEM)
          || GET_CODE (XEXP (addr, 0)) == MEM)
        {
        {
          offset = XEXP (addr, 0);
          offset = XEXP (addr, 0);
          addr = XEXP (addr, 1);
          addr = XEXP (addr, 1);
        }
        }
      else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
      else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
               || GET_CODE (XEXP (addr, 1)) == MEM)
               || GET_CODE (XEXP (addr, 1)) == MEM)
        {
        {
          offset = XEXP (addr, 1);
          offset = XEXP (addr, 1);
          addr = XEXP (addr, 0);
          addr = XEXP (addr, 0);
        }
        }
      if (GET_CODE (addr) != PLUS)
      if (GET_CODE (addr) != PLUS)
        ;
        ;
      else if (GET_CODE (XEXP (addr, 0)) == MULT)
      else if (GET_CODE (XEXP (addr, 0)) == MULT)
        {
        {
          reg1 = XEXP (addr, 0);
          reg1 = XEXP (addr, 0);
          addr = XEXP (addr, 1);
          addr = XEXP (addr, 1);
        }
        }
      else if (GET_CODE (XEXP (addr, 1)) == MULT)
      else if (GET_CODE (XEXP (addr, 1)) == MULT)
        {
        {
          reg1 = XEXP (addr, 1);
          reg1 = XEXP (addr, 1);
          addr = XEXP (addr, 0);
          addr = XEXP (addr, 0);
        }
        }
      else if (GET_CODE (XEXP (addr, 0)) == REG)
      else if (GET_CODE (XEXP (addr, 0)) == REG)
        {
        {
          reg1 = XEXP (addr, 0);
          reg1 = XEXP (addr, 0);
          addr = XEXP (addr, 1);
          addr = XEXP (addr, 1);
        }
        }
      else if (GET_CODE (XEXP (addr, 1)) == REG)
      else if (GET_CODE (XEXP (addr, 1)) == REG)
        {
        {
          reg1 = XEXP (addr, 1);
          reg1 = XEXP (addr, 1);
          addr = XEXP (addr, 0);
          addr = XEXP (addr, 0);
        }
        }
      if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
      if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
        {
        {
          if (reg1 == 0)
          if (reg1 == 0)
            reg1 = addr;
            reg1 = addr;
          else
          else
            reg2 = addr;
            reg2 = addr;
          addr = 0;
          addr = 0;
        }
        }
      if (offset != 0)
      if (offset != 0)
        {
        {
          gcc_assert (addr == 0);
          gcc_assert (addr == 0);
          addr = offset;
          addr = offset;
        }
        }
      if (reg1 != 0 && GET_CODE (reg1) == MULT)
      if (reg1 != 0 && GET_CODE (reg1) == MULT)
        {
        {
          breg = reg2;
          breg = reg2;
          ireg = reg1;
          ireg = reg1;
        }
        }
      else if (reg2 != 0 && GET_CODE (reg2) == MULT)
      else if (reg2 != 0 && GET_CODE (reg2) == MULT)
        {
        {
          breg = reg1;
          breg = reg1;
          ireg = reg2;
          ireg = reg2;
        }
        }
      else if (reg2 != 0 || GET_CODE (addr) == MEM)
      else if (reg2 != 0 || GET_CODE (addr) == MEM)
        {
        {
          breg = reg2;
          breg = reg2;
          ireg = reg1;
          ireg = reg1;
        }
        }
      else
      else
        {
        {
          breg = reg1;
          breg = reg1;
          ireg = reg2;
          ireg = reg2;
        }
        }
      if (addr != 0)
      if (addr != 0)
        output_address (addr);
        output_address (addr);
      if (breg != 0)
      if (breg != 0)
        {
        {
          gcc_assert (GET_CODE (breg) == REG);
          gcc_assert (GET_CODE (breg) == REG);
          fprintf (file, "(%s)", reg_names[REGNO (breg)]);
          fprintf (file, "(%s)", reg_names[REGNO (breg)]);
        }
        }
      if (ireg != 0)
      if (ireg != 0)
        {
        {
          if (GET_CODE (ireg) == MULT)
          if (GET_CODE (ireg) == MULT)
            ireg = XEXP (ireg, 0);
            ireg = XEXP (ireg, 0);
          gcc_assert (GET_CODE (ireg) == REG);
          gcc_assert (GET_CODE (ireg) == REG);
          gcc_unreachable(); /* ??? */
          gcc_unreachable(); /* ??? */
          fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
          fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
        }
        }
      break;
      break;
 
 
    default:
    default:
      output_addr_const_pdp11 (file, addr);
      output_addr_const_pdp11 (file, addr);
    }
    }
}
}
 
 
/* Target hook to assemble integer objects.  We need to use the
/* Target hook to assemble integer objects.  We need to use the
   pdp-specific version of output_addr_const.  */
   pdp-specific version of output_addr_const.  */
 
 
static bool
static bool
pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
{
  if (aligned_p)
  if (aligned_p)
    switch (size)
    switch (size)
      {
      {
      case 1:
      case 1:
        fprintf (asm_out_file, "\t.byte\t");
        fprintf (asm_out_file, "\t.byte\t");
        output_addr_const_pdp11 (asm_out_file, x);
        output_addr_const_pdp11 (asm_out_file, x);
        fprintf (asm_out_file, " /* char */\n");
        fprintf (asm_out_file, " /* char */\n");
        return true;
        return true;
 
 
      case 2:
      case 2:
        fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
        fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
        output_addr_const_pdp11 (asm_out_file, x);
        output_addr_const_pdp11 (asm_out_file, x);
        fprintf (asm_out_file, " /* short */\n");
        fprintf (asm_out_file, " /* short */\n");
        return true;
        return true;
      }
      }
  return default_assemble_integer (x, size, aligned_p);
  return default_assemble_integer (x, size, aligned_p);
}
}
 
 
 
 
/* register move costs, indexed by regs */
/* register move costs, indexed by regs */
 
 
static const 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  MUL  GEN  LFPU  NLFPU FPU ALL */
 
 
/* NO */     {  0,   0,   0,    0,    0,    0,   0},
/* NO */     {  0,   0,   0,    0,    0,    0,   0},
/* MUL */    {  0,   2,   2,   10,   22,   22,  22},
/* MUL */    {  0,   2,   2,   10,   22,   22,  22},
/* GEN */    {  0,   2,   2,   10,   22,   22,  22},
/* GEN */    {  0,   2,   2,   10,   22,   22,  22},
/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
/* FPU */    {  0,  22,  22,    2,    2,    2,  22},
/* FPU */    {  0,  22,  22,    2,    2,    2,  22},
/* ALL */    {  0,  22,  22,   10,   22,   22,  22}
/* ALL */    {  0,  22,  22,   10,   22,   22,  22}
}  ;
}  ;
 
 
 
 
/* -- note that some moves are tremendously expensive,
/* -- note that some moves are tremendously expensive,
   because they require lots of tricks! do we have to
   because they require lots of tricks! do we have to
   charge the costs incurred by secondary reload class
   charge the costs incurred by secondary reload class
   -- as we do here with 22 -- or not ? */
   -- as we do here with 22 -- or not ? */
 
 
int
int
register_move_cost(c1, c2)
register_move_cost(c1, c2)
  enum reg_class c1, c2;
  enum reg_class c1, c2;
{
{
    return move_costs[(int)c1][(int)c2];
    return move_costs[(int)c1][(int)c2];
}
}
 
 
static bool
static bool
pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
{
{
  switch (code)
  switch (code)
    {
    {
    case CONST_INT:
    case CONST_INT:
      if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
      if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
        {
        {
          *total = 0;
          *total = 0;
          return true;
          return true;
        }
        }
      /* FALLTHRU */
      /* FALLTHRU */
 
 
    case CONST:
    case CONST:
    case LABEL_REF:
    case LABEL_REF:
    case SYMBOL_REF:
    case SYMBOL_REF:
      /* Twice as expensive as REG.  */
      /* Twice as expensive as REG.  */
      *total = 2;
      *total = 2;
      return true;
      return true;
 
 
    case CONST_DOUBLE:
    case CONST_DOUBLE:
      /* Twice (or 4 times) as expensive as 16 bit.  */
      /* Twice (or 4 times) as expensive as 16 bit.  */
      *total = 4;
      *total = 4;
      return true;
      return true;
 
 
    case MULT:
    case MULT:
      /* ??? There is something wrong in MULT because MULT is not
      /* ??? There is something wrong in MULT because MULT is not
         as cheap as total = 2 even if we can shift!  */
         as cheap as total = 2 even if we can shift!  */
      /* If optimizing for size make mult etc cheap, but not 1, so when
      /* If optimizing for size make mult etc cheap, but not 1, so when
         in doubt the faster insn is chosen.  */
         in doubt the faster insn is chosen.  */
      if (optimize_size)
      if (optimize_size)
        *total = COSTS_N_INSNS (2);
        *total = COSTS_N_INSNS (2);
      else
      else
        *total = COSTS_N_INSNS (11);
        *total = COSTS_N_INSNS (11);
      return false;
      return false;
 
 
    case DIV:
    case DIV:
      if (optimize_size)
      if (optimize_size)
        *total = COSTS_N_INSNS (2);
        *total = COSTS_N_INSNS (2);
      else
      else
        *total = COSTS_N_INSNS (25);
        *total = COSTS_N_INSNS (25);
      return false;
      return false;
 
 
    case MOD:
    case MOD:
      if (optimize_size)
      if (optimize_size)
        *total = COSTS_N_INSNS (2);
        *total = COSTS_N_INSNS (2);
      else
      else
        *total = COSTS_N_INSNS (26);
        *total = COSTS_N_INSNS (26);
      return false;
      return false;
 
 
    case ABS:
    case ABS:
      /* Equivalent to length, so same for optimize_size.  */
      /* Equivalent to length, so same for optimize_size.  */
      *total = COSTS_N_INSNS (3);
      *total = COSTS_N_INSNS (3);
      return false;
      return false;
 
 
    case ZERO_EXTEND:
    case ZERO_EXTEND:
      /* Only used for qi->hi.  */
      /* Only used for qi->hi.  */
      *total = COSTS_N_INSNS (1);
      *total = COSTS_N_INSNS (1);
      return false;
      return false;
 
 
    case SIGN_EXTEND:
    case SIGN_EXTEND:
      if (GET_MODE (x) == HImode)
      if (GET_MODE (x) == HImode)
        *total = COSTS_N_INSNS (1);
        *total = COSTS_N_INSNS (1);
      else if (GET_MODE (x) == SImode)
      else if (GET_MODE (x) == SImode)
        *total = COSTS_N_INSNS (6);
        *total = COSTS_N_INSNS (6);
      else
      else
        *total = COSTS_N_INSNS (2);
        *total = COSTS_N_INSNS (2);
      return false;
      return false;
 
 
    case ASHIFT:
    case ASHIFT:
    case LSHIFTRT:
    case LSHIFTRT:
    case ASHIFTRT:
    case ASHIFTRT:
      if (optimize_size)
      if (optimize_size)
        *total = COSTS_N_INSNS (1);
        *total = COSTS_N_INSNS (1);
      else if (GET_MODE (x) ==  QImode)
      else if (GET_MODE (x) ==  QImode)
        {
        {
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            *total = COSTS_N_INSNS (8); /* worst case */
            *total = COSTS_N_INSNS (8); /* worst case */
          else
          else
            *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
            *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
        }
        }
      else if (GET_MODE (x) == HImode)
      else if (GET_MODE (x) == HImode)
        {
        {
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
            {
            {
              if (abs (INTVAL (XEXP (x, 1))) == 1)
              if (abs (INTVAL (XEXP (x, 1))) == 1)
                *total = COSTS_N_INSNS (1);
                *total = COSTS_N_INSNS (1);
              else
              else
                *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
                *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
            }
            }
          else
          else
            *total = COSTS_N_INSNS (10); /* worst case */
            *total = COSTS_N_INSNS (10); /* worst case */
        }
        }
      else if (GET_MODE (x) == SImode)
      else if (GET_MODE (x) == SImode)
        {
        {
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
            *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
            *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
          else /* worst case */
          else /* worst case */
            *total = COSTS_N_INSNS (18);
            *total = COSTS_N_INSNS (18);
        }
        }
      return false;
      return false;
 
 
    default:
    default:
      return false;
      return false;
    }
    }
}
}
 
 
const char *
const char *
output_jump (const char *pos, const char *neg, int length)
output_jump (const char *pos, const char *neg, int length)
{
{
    static int x = 0;
    static int x = 0;
 
 
    static char buf[1000];
    static char buf[1000];
 
 
#if 0
#if 0
/* currently we don't need this, because the tstdf and cmpdf
/* currently we don't need this, because the tstdf and cmpdf
   copy the condition code immediately, and other float operations are not
   copy the condition code immediately, and other float operations are not
   yet recognized as changing the FCC - if so, then the length-cost of all
   yet recognized as changing the FCC - if so, then the length-cost of all
   jump insns increases by one, because we have to potentially copy the
   jump insns increases by one, because we have to potentially copy the
   FCC! */
   FCC! */
    if (cc_status.flags & CC_IN_FPU)
    if (cc_status.flags & CC_IN_FPU)
        output_asm_insn("cfcc", NULL);
        output_asm_insn("cfcc", NULL);
#endif
#endif
 
 
    switch (length)
    switch (length)
    {
    {
      case 1:
      case 1:
 
 
        strcpy(buf, pos);
        strcpy(buf, pos);
        strcat(buf, " %l0");
        strcat(buf, " %l0");
 
 
        return buf;
        return buf;
 
 
      case 3:
      case 3:
 
 
        sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
        sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
 
 
        x++;
        x++;
 
 
        return buf;
        return buf;
 
 
      default:
      default:
 
 
        gcc_unreachable ();
        gcc_unreachable ();
    }
    }
 
 
}
}
 
 
void
void
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
{
{
    if (GET_CODE (SET_DEST (exp)) == CC0)
    if (GET_CODE (SET_DEST (exp)) == CC0)
    {
    {
        cc_status.flags = 0;
        cc_status.flags = 0;
        cc_status.value1 = SET_DEST (exp);
        cc_status.value1 = SET_DEST (exp);
        cc_status.value2 = SET_SRC (exp);
        cc_status.value2 = SET_SRC (exp);
 
 
/*
/*
        if (GET_MODE(SET_SRC(exp)) == DFmode)
        if (GET_MODE(SET_SRC(exp)) == DFmode)
            cc_status.flags |= CC_IN_FPU;
            cc_status.flags |= CC_IN_FPU;
*/
*/
    }
    }
    else if ((GET_CODE (SET_DEST (exp)) == REG
    else if ((GET_CODE (SET_DEST (exp)) == REG
              || GET_CODE (SET_DEST (exp)) == MEM)
              || GET_CODE (SET_DEST (exp)) == MEM)
             && GET_CODE (SET_SRC (exp)) != PC
             && GET_CODE (SET_SRC (exp)) != PC
             && (GET_MODE (SET_DEST(exp)) == HImode
             && (GET_MODE (SET_DEST(exp)) == HImode
                 || GET_MODE (SET_DEST(exp)) == QImode)
                 || GET_MODE (SET_DEST(exp)) == QImode)
                && (GET_CODE (SET_SRC(exp)) == PLUS
                && (GET_CODE (SET_SRC(exp)) == PLUS
                    || GET_CODE (SET_SRC(exp)) == MINUS
                    || GET_CODE (SET_SRC(exp)) == MINUS
                    || GET_CODE (SET_SRC(exp)) == AND
                    || GET_CODE (SET_SRC(exp)) == AND
                    || GET_CODE (SET_SRC(exp)) == IOR
                    || GET_CODE (SET_SRC(exp)) == IOR
                    || GET_CODE (SET_SRC(exp)) == XOR
                    || GET_CODE (SET_SRC(exp)) == XOR
                    || GET_CODE (SET_SRC(exp)) == NOT
                    || GET_CODE (SET_SRC(exp)) == NOT
                    || GET_CODE (SET_SRC(exp)) == NEG
                    || GET_CODE (SET_SRC(exp)) == NEG
                        || GET_CODE (SET_SRC(exp)) == REG
                        || GET_CODE (SET_SRC(exp)) == REG
                    || GET_CODE (SET_SRC(exp)) == MEM))
                    || GET_CODE (SET_SRC(exp)) == MEM))
    {
    {
        cc_status.flags = 0;
        cc_status.flags = 0;
        cc_status.value1 = SET_SRC (exp);
        cc_status.value1 = SET_SRC (exp);
        cc_status.value2 = SET_DEST (exp);
        cc_status.value2 = SET_DEST (exp);
 
 
        if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
        if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
            && cc_status.value2
            && cc_status.value2
            && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
            && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
            cc_status.value2 = 0;
            cc_status.value2 = 0;
        if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
        if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
            && cc_status.value2
            && cc_status.value2
            && GET_CODE (cc_status.value2) == MEM)
            && GET_CODE (cc_status.value2) == MEM)
            cc_status.value2 = 0;
            cc_status.value2 = 0;
    }
    }
    else if (GET_CODE (SET_SRC (exp)) == CALL)
    else if (GET_CODE (SET_SRC (exp)) == CALL)
    {
    {
        CC_STATUS_INIT;
        CC_STATUS_INIT;
    }
    }
    else if (GET_CODE (SET_DEST (exp)) == REG)
    else if (GET_CODE (SET_DEST (exp)) == REG)
        /* what's this ? */
        /* what's this ? */
    {
    {
        if ((cc_status.value1
        if ((cc_status.value1
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
            cc_status.value1 = 0;
            cc_status.value1 = 0;
        if ((cc_status.value2
        if ((cc_status.value2
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
            cc_status.value2 = 0;
            cc_status.value2 = 0;
    }
    }
    else if (SET_DEST(exp) == pc_rtx)
    else if (SET_DEST(exp) == pc_rtx)
    {
    {
        /* jump */
        /* jump */
    }
    }
    else /* if (GET_CODE (SET_DEST (exp)) == MEM)       */
    else /* if (GET_CODE (SET_DEST (exp)) == MEM)       */
    {
    {
        /* the last else is a bit paranoiac, but since nearly all instructions
        /* the last else is a bit paranoiac, but since nearly all instructions
           play with condition codes, it's reasonable! */
           play with condition codes, it's reasonable! */
 
 
        CC_STATUS_INIT; /* paranoia*/
        CC_STATUS_INIT; /* paranoia*/
    }
    }
}
}
 
 
 
 
int
int
simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
    rtx addr;
    rtx addr;
 
 
    /* Eliminate non-memory operations */
    /* Eliminate non-memory operations */
    if (GET_CODE (op) != MEM)
    if (GET_CODE (op) != MEM)
        return FALSE;
        return FALSE;
 
 
#if 0
#if 0
    /* dword operations really put out 2 instructions, so eliminate them.  */
    /* dword operations really put out 2 instructions, so eliminate them.  */
    if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
    if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
        return FALSE;
        return FALSE;
#endif
#endif
 
 
    /* Decode the address now.  */
    /* Decode the address now.  */
 
 
  indirection:
  indirection:
 
 
    addr = XEXP (op, 0);
    addr = XEXP (op, 0);
 
 
    switch (GET_CODE (addr))
    switch (GET_CODE (addr))
    {
    {
      case REG:
      case REG:
        /* (R0) - no extra cost */
        /* (R0) - no extra cost */
        return 1;
        return 1;
 
 
      case PRE_DEC:
      case PRE_DEC:
      case POST_INC:
      case POST_INC:
        /* -(R0), (R0)+ - cheap! */
        /* -(R0), (R0)+ - cheap! */
        return 0;
        return 0;
 
 
      case MEM:
      case MEM:
        /* cheap - is encoded in addressing mode info!
        /* cheap - is encoded in addressing mode info!
 
 
           -- except for @(R0), which has to be @0(R0) !!! */
           -- except for @(R0), which has to be @0(R0) !!! */
 
 
        if (GET_CODE (XEXP (addr, 0)) == REG)
        if (GET_CODE (XEXP (addr, 0)) == REG)
            return 0;
            return 0;
 
 
        op=addr;
        op=addr;
        goto indirection;
        goto indirection;
 
 
      case CONST_INT:
      case CONST_INT:
      case LABEL_REF:
      case LABEL_REF:
      case CONST:
      case CONST:
      case SYMBOL_REF:
      case SYMBOL_REF:
        /* @#address - extra cost */
        /* @#address - extra cost */
        return 0;
        return 0;
 
 
      case PLUS:
      case PLUS:
        /* X(R0) - extra cost */
        /* X(R0) - extra cost */
        return 0;
        return 0;
 
 
      default:
      default:
        break;
        break;
    }
    }
 
 
    return FALSE;
    return FALSE;
}
}
 
 
 
 
/*
/*
 * output a block move:
 * output a block move:
 *
 *
 * operands[0]  ... to
 * operands[0]  ... to
 * operands[1]  ... from
 * operands[1]  ... from
 * operands[2]  ... length
 * operands[2]  ... length
 * operands[3]  ... alignment
 * operands[3]  ... alignment
 * operands[4]  ... scratch register
 * operands[4]  ... scratch register
 */
 */
 
 
 
 
const char *
const char *
output_block_move(rtx *operands)
output_block_move(rtx *operands)
{
{
    static int count = 0;
    static int count = 0;
    char buf[200];
    char buf[200];
 
 
    if (GET_CODE(operands[2]) == CONST_INT
    if (GET_CODE(operands[2]) == CONST_INT
        && ! optimize_size)
        && ! optimize_size)
    {
    {
        if (INTVAL(operands[2]) < 16
        if (INTVAL(operands[2]) < 16
            && INTVAL(operands[3]) == 1)
            && INTVAL(operands[3]) == 1)
        {
        {
            register int i;
            register int i;
 
 
            for (i = 1; i <= INTVAL(operands[2]); i++)
            for (i = 1; i <= INTVAL(operands[2]); i++)
                output_asm_insn("movb (%1)+, (%0)+", operands);
                output_asm_insn("movb (%1)+, (%0)+", operands);
 
 
            return "";
            return "";
        }
        }
        else if (INTVAL(operands[2]) < 32)
        else if (INTVAL(operands[2]) < 32)
        {
        {
            register int i;
            register int i;
 
 
            for (i = 1; i <= INTVAL(operands[2])/2; i++)
            for (i = 1; i <= INTVAL(operands[2])/2; i++)
                output_asm_insn("mov (%1)+, (%0)+", operands);
                output_asm_insn("mov (%1)+, (%0)+", operands);
 
 
            /* may I assume that moved quantity is
            /* may I assume that moved quantity is
               multiple of alignment ???
               multiple of alignment ???
 
 
               I HOPE SO !
               I HOPE SO !
            */
            */
 
 
            return "";
            return "";
        }
        }
 
 
 
 
        /* can do other clever things, maybe... */
        /* can do other clever things, maybe... */
    }
    }
 
 
    if (CONSTANT_P(operands[2]) )
    if (CONSTANT_P(operands[2]) )
    {
    {
        /* just move count to scratch */
        /* just move count to scratch */
        output_asm_insn("mov %2, %4", operands);
        output_asm_insn("mov %2, %4", operands);
    }
    }
    else
    else
    {
    {
        /* just clobber the register */
        /* just clobber the register */
        operands[4] = operands[2];
        operands[4] = operands[2];
    }
    }
 
 
 
 
    /* switch over alignment */
    /* switch over alignment */
    switch (INTVAL(operands[3]))
    switch (INTVAL(operands[3]))
    {
    {
      case 1:
      case 1:
 
 
        /*
        /*
          x:
          x:
          movb (%1)+, (%0)+
          movb (%1)+, (%0)+
 
 
          if (TARGET_45)
          if (TARGET_45)
             sob %4,x
             sob %4,x
          else
          else
             dec %4
             dec %4
             bgt x
             bgt x
 
 
        */
        */
 
 
        sprintf(buf, "\nmovestrhi%d:", count);
        sprintf(buf, "\nmovestrhi%d:", count);
        output_asm_insn(buf, NULL);
        output_asm_insn(buf, NULL);
 
 
        output_asm_insn("movb (%1)+, (%0)+", operands);
        output_asm_insn("movb (%1)+, (%0)+", operands);
 
 
        if (TARGET_45)
        if (TARGET_45)
        {
        {
            sprintf(buf, "sob %%4, movestrhi%d", count);
            sprintf(buf, "sob %%4, movestrhi%d", count);
            output_asm_insn(buf, operands);
            output_asm_insn(buf, operands);
        }
        }
        else
        else
        {
        {
            output_asm_insn("dec %4", operands);
            output_asm_insn("dec %4", operands);
 
 
            sprintf(buf, "bgt movestrhi%d", count);
            sprintf(buf, "bgt movestrhi%d", count);
            output_asm_insn(buf, NULL);
            output_asm_insn(buf, NULL);
        }
        }
 
 
        count ++;
        count ++;
        break;
        break;
 
 
      case 2:
      case 2:
 
 
        /*
        /*
           asr %4
           asr %4
 
 
           x:
           x:
 
 
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
 
 
           if (TARGET_45)
           if (TARGET_45)
             sob %4, x
             sob %4, x
           else
           else
             dec %4
             dec %4
             bgt x
             bgt x
        */
        */
 
 
      generate_compact_code:
      generate_compact_code:
 
 
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
 
 
        sprintf(buf, "\nmovestrhi%d:", count);
        sprintf(buf, "\nmovestrhi%d:", count);
        output_asm_insn(buf, NULL);
        output_asm_insn(buf, NULL);
 
 
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
 
 
        if (TARGET_45)
        if (TARGET_45)
        {
        {
            sprintf(buf, "sob %%4, movestrhi%d", count);
            sprintf(buf, "sob %%4, movestrhi%d", count);
            output_asm_insn(buf, operands);
            output_asm_insn(buf, operands);
        }
        }
        else
        else
        {
        {
            output_asm_insn("dec %4", operands);
            output_asm_insn("dec %4", operands);
 
 
            sprintf(buf, "bgt movestrhi%d", count);
            sprintf(buf, "bgt movestrhi%d", count);
            output_asm_insn(buf, NULL);
            output_asm_insn(buf, NULL);
        }
        }
 
 
        count ++;
        count ++;
        break;
        break;
 
 
      case 4:
      case 4:
 
 
        /*
        /*
 
 
           asr %4
           asr %4
           asr %4
           asr %4
 
 
           x:
           x:
 
 
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
 
 
           if (TARGET_45)
           if (TARGET_45)
             sob %4, x
             sob %4, x
           else
           else
             dec %4
             dec %4
             bgt x
             bgt x
        */
        */
 
 
        if (optimize_size)
        if (optimize_size)
            goto generate_compact_code;
            goto generate_compact_code;
 
 
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
 
 
        sprintf(buf, "\nmovestrhi%d:", count);
        sprintf(buf, "\nmovestrhi%d:", count);
        output_asm_insn(buf, NULL);
        output_asm_insn(buf, NULL);
 
 
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
 
 
        if (TARGET_45)
        if (TARGET_45)
        {
        {
            sprintf(buf, "sob %%4, movestrhi%d", count);
            sprintf(buf, "sob %%4, movestrhi%d", count);
            output_asm_insn(buf, operands);
            output_asm_insn(buf, operands);
        }
        }
        else
        else
        {
        {
            output_asm_insn("dec %4", operands);
            output_asm_insn("dec %4", operands);
 
 
            sprintf(buf, "bgt movestrhi%d", count);
            sprintf(buf, "bgt movestrhi%d", count);
            output_asm_insn(buf, NULL);
            output_asm_insn(buf, NULL);
        }
        }
 
 
        count ++;
        count ++;
        break;
        break;
 
 
      default:
      default:
 
 
        /*
        /*
 
 
           asr %4
           asr %4
           asr %4
           asr %4
           asr %4
           asr %4
 
 
           x:
           x:
 
 
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
           mov (%1)+, (%0)+
 
 
           if (TARGET_45)
           if (TARGET_45)
             sob %4, x
             sob %4, x
           else
           else
             dec %4
             dec %4
             bgt x
             bgt x
        */
        */
 
 
 
 
        if (optimize_size)
        if (optimize_size)
            goto generate_compact_code;
            goto generate_compact_code;
 
 
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
        output_asm_insn("asr %4", operands);
 
 
        sprintf(buf, "\nmovestrhi%d:", count);
        sprintf(buf, "\nmovestrhi%d:", count);
        output_asm_insn(buf, NULL);
        output_asm_insn(buf, NULL);
 
 
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
        output_asm_insn("mov (%1)+, (%0)+", operands);
 
 
        if (TARGET_45)
        if (TARGET_45)
        {
        {
            sprintf(buf, "sob %%4, movestrhi%d", count);
            sprintf(buf, "sob %%4, movestrhi%d", count);
            output_asm_insn(buf, operands);
            output_asm_insn(buf, operands);
        }
        }
        else
        else
        {
        {
            output_asm_insn("dec %4", operands);
            output_asm_insn("dec %4", operands);
 
 
            sprintf(buf, "bgt movestrhi%d", count);
            sprintf(buf, "bgt movestrhi%d", count);
            output_asm_insn(buf, NULL);
            output_asm_insn(buf, NULL);
        }
        }
 
 
        count ++;
        count ++;
        break;
        break;
 
 
        ;
        ;
 
 
    }
    }
 
 
    return "";
    return "";
}
}
 
 
int
int
legitimate_address_p (enum machine_mode mode, rtx address)
legitimate_address_p (enum machine_mode mode, rtx address)
{
{
/* #define REG_OK_STRICT */
/* #define REG_OK_STRICT */
    GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
    GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
 
 
    return 0;
    return 0;
 
 
  win:
  win:
    return 1;
    return 1;
 
 
/* #undef REG_OK_STRICT */
/* #undef REG_OK_STRICT */
}
}
 
 
/* This function checks whether a real value can be encoded as
/* This function checks whether a real value can be encoded as
   a literal, i.e., addressing mode 27.  In that mode, real values
   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.  */
   are one word values, so the remaining 48 bits have to be zero.  */
int
int
legitimate_const_double_p (rtx address)
legitimate_const_double_p (rtx address)
{
{
  REAL_VALUE_TYPE r;
  REAL_VALUE_TYPE r;
  long sval[2];
  long sval[2];
  REAL_VALUE_FROM_CONST_DOUBLE (r, address);
  REAL_VALUE_FROM_CONST_DOUBLE (r, address);
  REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
  REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
  if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
  if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
/* A copy of output_addr_const modified for pdp11 expression syntax.
/* 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
   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.
   use, and for debugging output, which we don't support with this port either.
   So this copy should get called whenever needed.
   So this copy should get called whenever needed.
*/
*/
void
void
output_addr_const_pdp11 (FILE *file, rtx x)
output_addr_const_pdp11 (FILE *file, rtx x)
{
{
  char buf[256];
  char buf[256];
 
 
 restart:
 restart:
  switch (GET_CODE (x))
  switch (GET_CODE (x))
    {
    {
    case PC:
    case PC:
      gcc_assert (flag_pic);
      gcc_assert (flag_pic);
      putc ('.', file);
      putc ('.', file);
      break;
      break;
 
 
    case SYMBOL_REF:
    case SYMBOL_REF:
      assemble_name (file, XSTR (x, 0));
      assemble_name (file, XSTR (x, 0));
      break;
      break;
 
 
    case LABEL_REF:
    case LABEL_REF:
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
      assemble_name (file, buf);
      assemble_name (file, buf);
      break;
      break;
 
 
    case CODE_LABEL:
    case CODE_LABEL:
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
      assemble_name (file, buf);
      assemble_name (file, buf);
      break;
      break;
 
 
    case CONST_INT:
    case CONST_INT:
      /* Should we check for constants which are too big?  Maybe cutting
      /* Should we check for constants which are too big?  Maybe cutting
         them off to 16 bits is OK?  */
         them off to 16 bits is OK?  */
      fprintf (file, "%#ho", (unsigned short) INTVAL (x));
      fprintf (file, "%#ho", (unsigned short) INTVAL (x));
      break;
      break;
 
 
    case CONST:
    case CONST:
      /* This used to output parentheses around the expression,
      /* This used to output parentheses around the expression,
         but that does not work on the 386 (either ATT or BSD assembler).  */
         but that does not work on the 386 (either ATT or BSD assembler).  */
      output_addr_const_pdp11 (file, XEXP (x, 0));
      output_addr_const_pdp11 (file, XEXP (x, 0));
      break;
      break;
 
 
    case CONST_DOUBLE:
    case CONST_DOUBLE:
      if (GET_MODE (x) == VOIDmode)
      if (GET_MODE (x) == VOIDmode)
        {
        {
          /* We can use %o if the number is one word and positive.  */
          /* We can use %o if the number is one word and positive.  */
          gcc_assert (!CONST_DOUBLE_HIGH (x));
          gcc_assert (!CONST_DOUBLE_HIGH (x));
          fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
          fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
        }
        }
      else
      else
        /* We can't handle floating point constants;
        /* We can't handle floating point constants;
           PRINT_OPERAND must handle them.  */
           PRINT_OPERAND must handle them.  */
        output_operand_lossage ("floating constant misused");
        output_operand_lossage ("floating constant misused");
      break;
      break;
 
 
    case PLUS:
    case PLUS:
      /* Some assemblers need integer constants to appear last (e.g. masm).  */
      /* Some assemblers need integer constants to appear last (e.g. masm).  */
      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
        {
        {
          output_addr_const_pdp11 (file, XEXP (x, 1));
          output_addr_const_pdp11 (file, XEXP (x, 1));
          if (INTVAL (XEXP (x, 0)) >= 0)
          if (INTVAL (XEXP (x, 0)) >= 0)
            fprintf (file, "+");
            fprintf (file, "+");
          output_addr_const_pdp11 (file, XEXP (x, 0));
          output_addr_const_pdp11 (file, XEXP (x, 0));
        }
        }
      else
      else
        {
        {
          output_addr_const_pdp11 (file, XEXP (x, 0));
          output_addr_const_pdp11 (file, XEXP (x, 0));
          if (INTVAL (XEXP (x, 1)) >= 0)
          if (INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
            fprintf (file, "+");
          output_addr_const_pdp11 (file, XEXP (x, 1));
          output_addr_const_pdp11 (file, XEXP (x, 1));
        }
        }
      break;
      break;
 
 
    case MINUS:
    case MINUS:
      /* Avoid outputting things like x-x or x+5-x,
      /* Avoid outputting things like x-x or x+5-x,
         since some assemblers can't handle that.  */
         since some assemblers can't handle that.  */
      x = simplify_subtraction (x);
      x = simplify_subtraction (x);
      if (GET_CODE (x) != MINUS)
      if (GET_CODE (x) != MINUS)
        goto restart;
        goto restart;
 
 
      output_addr_const_pdp11 (file, XEXP (x, 0));
      output_addr_const_pdp11 (file, XEXP (x, 0));
      fprintf (file, "-");
      fprintf (file, "-");
      if (GET_CODE (XEXP (x, 1)) == CONST_INT
      if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) < 0)
          && INTVAL (XEXP (x, 1)) < 0)
        {
        {
          fprintf (file, targetm.asm_out.open_paren);
          fprintf (file, targetm.asm_out.open_paren);
          output_addr_const_pdp11 (file, XEXP (x, 1));
          output_addr_const_pdp11 (file, XEXP (x, 1));
          fprintf (file, targetm.asm_out.close_paren);
          fprintf (file, targetm.asm_out.close_paren);
        }
        }
      else
      else
        output_addr_const_pdp11 (file, XEXP (x, 1));
        output_addr_const_pdp11 (file, XEXP (x, 1));
      break;
      break;
 
 
    case ZERO_EXTEND:
    case ZERO_EXTEND:
    case SIGN_EXTEND:
    case SIGN_EXTEND:
      output_addr_const_pdp11 (file, XEXP (x, 0));
      output_addr_const_pdp11 (file, XEXP (x, 0));
      break;
      break;
 
 
    default:
    default:
      output_operand_lossage ("invalid expression as operand");
      output_operand_lossage ("invalid expression as operand");
    }
    }
}
}
 
 
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 
static bool
static bool
pdp11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
pdp11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
{
  /* Should probably return DImode and DFmode in memory, lest
  /* Should probably return DImode and DFmode in memory, lest
     we fill up all regs!
     we fill up all regs!
 
 
     have to, else we crash - exception: maybe return result in
     have to, else we crash - exception: maybe return result in
     ac0 if DFmode and FPU present - compatibility problem with
     ac0 if DFmode and FPU present - compatibility problem with
     libraries for non-floating point....  */
     libraries for non-floating point....  */
  return (TYPE_MODE (type) == DImode
  return (TYPE_MODE (type) == DImode
          || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
          || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.