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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [or32/] [or32.c] - Diff between revs 154 and 816

Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Subroutines for insn-output.c for GNU compiler.  OpenRISC 1000 version.
/* Subroutines for insn-output.c for GNU compiler.  OpenRISC 1000 version.
   Copyright (C) 1987, 1992, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
   Copyright (C) 1987, 1992, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
   2005  Free Software Foundation, Inc
   2005  Free Software Foundation, Inc
   Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999.
   Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999.
   Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005.
   Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005.
 
 
This file is part of GNU CC.
This file is part of GNU CC.
 
 
GNU CC is free software; you can redistribute it and/or modify
GNU CC 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 1, or (at your option)
the Free Software Foundation; either version 1, or (at your option)
any later version.
any later version.
 
 
GNU CC is distributed in the hope that it will be useful,
GNU CC 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 GNU CC; see the file COPYING.  If not, write to
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */
Boston, MA 02111-1307, USA.  */
 
 
#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 "tree.h"
#include "tree.h"
#include "obstack.h"
#include "obstack.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 "output.h"
#include "output.h"
#include "insn-attr.h"
#include "insn-attr.h"
#include "flags.h"
#include "flags.h"
#include "reload.h"
#include "reload.h"
#include "function.h"
#include "function.h"
#include "expr.h"
#include "expr.h"
#include "optabs.h"
#include "optabs.h"
#include "toplev.h"
#include "toplev.h"
#include "recog.h"
#include "recog.h"
#include "ggc.h"
#include "ggc.h"
#include "except.h"
#include "except.h"
#include "c-pragma.h"
#include "c-pragma.h"
#include "integrate.h"
#include "integrate.h"
#include "tm_p.h"
#include "tm_p.h"
#include "target.h"
#include "target.h"
#include "target-def.h"
#include "target-def.h"
#include "debug.h"
#include "debug.h"
#include "langhooks.h"
#include "langhooks.h"
 
 
/* Set thist to nonzero if you want l.nop instruction in delay slot
/* Set thist to nonzero if you want l.nop instruction in delay slot
   of l.jr instruction in epilogue. */
   of l.jr instruction in epilogue. */
#define  NOP_DELAY_SLOT_FILL 0
#define  NOP_DELAY_SLOT_FILL 0
 
 
/* This is the pseudo register number that holds the comparison flags */
/* This is the pseudo register number that holds the comparison flags */
 
 
#define FLAGS_REG 32
#define FLAGS_REG 32
 
 
/* Save information from a "cmpxx" operation until the branch or scc is
/* Save information from a "cmpxx" operation until the branch or scc is
   emitted.  */
   emitted.  */
rtx or32_compare_op0, or32_compare_op1;
rtx or32_compare_op0, or32_compare_op1;
 
 
/* used in function prologue/epilogue generation */
/* used in function prologue/epilogue generation */
extern int leaf_function;
extern int leaf_function;
 
 
rtx or32_expand_compare (enum rtx_code code, rtx op0, rtx op1);
rtx or32_expand_compare (enum rtx_code code, rtx op0, rtx op1);
void output_ascii_pseudo_op (FILE *, const unsigned char *, int);
void output_ascii_pseudo_op (FILE *, const unsigned char *, int);
 
 
/* Local function prototypes */
/* Local function prototypes */
static bool or32_save_reg_p (int regno);
static bool or32_save_reg_p (int regno);
HOST_WIDE_INT or32_compute_frame_size (HOST_WIDE_INT size);
HOST_WIDE_INT or32_compute_frame_size (HOST_WIDE_INT size);
static rtx emit_frame_insn (rtx insn);
static rtx emit_frame_insn (rtx insn);
static rtx indexed_memory (rtx base, HOST_WIDE_INT disp);
static rtx indexed_memory (rtx base, HOST_WIDE_INT disp);
static int or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond,
static int or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond,
                                rtx false_cond);
                                rtx false_cond);
 
 
static void or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars);
static void or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars);
#undef TARGET_ASM_FUNCTION_PROLOGUE
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE or32_output_function_prologue
#define TARGET_ASM_FUNCTION_PROLOGUE or32_output_function_prologue
 
 
static void or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars);
static void or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars);
#undef TARGET_ASM_FUNCTION_EPILOGUE
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE or32_output_function_epilogue
#define TARGET_ASM_FUNCTION_EPILOGUE or32_output_function_epilogue
 
 
static bool or32_function_ok_for_sibcall (tree decl, tree exp);
static bool or32_function_ok_for_sibcall (tree decl, tree exp);
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall
#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall
 
 
static bool or32_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
static bool or32_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
#undef TARGET_PASS_BY_REFERENCE
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE or32_pass_by_reference
#define TARGET_PASS_BY_REFERENCE or32_pass_by_reference
 
 
static int or32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
static int or32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);
#undef TARGET_ARG_PARTIAL_BYTES
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES or32_arg_partial_bytes
#define TARGET_ARG_PARTIAL_BYTES or32_arg_partial_bytes
 
 
/* Initialize the GCC target structure.  */
/* Initialize the GCC target structure.  */
 
 
/* Define this macro if an argument declared as `char' or `short' in a
/* Define this macro if an argument declared as `char' or `short' in a
   prototype should actually be passed as an `int'.  In addition to
   prototype should actually be passed as an `int'.  In addition to
   avoiding errors in certain cases of mismatch, it also makes for
   avoiding errors in certain cases of mismatch, it also makes for
   better code on certain machines. */
   better code on certain machines. */
#undef TARGET_PROMOTE_PROTOTYPES
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
 
 
/* Define this if function arguments should also be promoted using the above
/* Define this if function arguments should also be promoted using the above
   procedure.  */
   procedure.  */
#undef TARGET_PROMOTE_FUNCTION_ARGS
#undef TARGET_PROMOTE_FUNCTION_ARGS
#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
 
 
/* Likewise, if the function return value is promoted.  */
/* Likewise, if the function return value is promoted.  */
#undef TARGET_PROMOTE_FUNCTION_RETURN
#undef TARGET_PROMOTE_FUNCTION_RETURN
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
 
 
struct gcc_target targetm = TARGET_INITIALIZER;
struct gcc_target targetm = TARGET_INITIALIZER;
 
 
/* Stack layout we use for pushing and poping saved registers */
/* Stack layout we use for pushing and poping saved registers */
struct or32_frame_info
struct or32_frame_info
{
{
  bool save_lr_p;
  bool save_lr_p;
  int lr_save_offset;
  int lr_save_offset;
  bool save_fp_p;
  bool save_fp_p;
  int fp_save_offset;
  int fp_save_offset;
  int gpr_size;
  int gpr_size;
  int gpr_offset;
  int gpr_offset;
  int total_size;
  int total_size;
  int vars_size;
  int vars_size;
  int args_size;
  int args_size;
  HOST_WIDE_INT mask;
  HOST_WIDE_INT mask;
};
};
 
 
static struct or32_frame_info frame_info;
static struct or32_frame_info frame_info;
 
 
/* Add a REG_MAYBE_DEAD note to the insn.  */
/* Add a REG_MAYBE_DEAD note to the insn.  */
static void
static void
or32_maybe_dead (rtx insn)
or32_maybe_dead (rtx insn)
{
{
  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
                                        const0_rtx, REG_NOTES (insn));
                                        const0_rtx, REG_NOTES (insn));
}
}
 
 
int
int
or32_print_operand_punct_valid_p (int code)
or32_print_operand_punct_valid_p (int code)
{
{
  switch (code)
  switch (code)
    {
    {
    case '(':                   /* idea taken from sparc; output nop for %( if
    case '(':                   /* idea taken from sparc; output nop for %( if
                                   not optimizing or the slot is not filled. */
                                   not optimizing or the slot is not filled. */
    case '%':
    case '%':
      return 1;
      return 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
void
void
or32_print_operand_address (FILE * file, register rtx addr)
or32_print_operand_address (FILE * file, register rtx addr)
{
{
  register rtx reg1, reg2, breg, ireg;
  register rtx reg1, reg2, breg, ireg;
  rtx offset;
  rtx offset;
 
 
  switch (GET_CODE (addr))
  switch (GET_CODE (addr))
    {
    {
    case MEM:
    case MEM:
      if (GET_CODE (XEXP (addr, 0)) == REG)
      if (GET_CODE (XEXP (addr, 0)) == REG)
        fprintf (file, "%s", reg_names[REGNO (addr)]);
        fprintf (file, "%s", reg_names[REGNO (addr)]);
      else
      else
        abort ();
        abort ();
      break;
      break;
 
 
    case REG:
    case REG:
      fprintf (file, "0(%s)", reg_names[REGNO (addr)]);
      fprintf (file, "0(%s)", reg_names[REGNO (addr)]);
      break;
      break;
 
 
    case PLUS:
    case PLUS:
      reg1 = 0;
      reg1 = 0;
      reg2 = 0;
      reg2 = 0;
      ireg = 0;
      ireg = 0;
      breg = 0;
      breg = 0;
      offset = 0;
      offset = 0;
      if (GET_CODE (XEXP (addr, 0)) == REG)
      if (GET_CODE (XEXP (addr, 0)) == REG)
        {
        {
          offset = XEXP (addr, 1);
          offset = XEXP (addr, 1);
          addr = XEXP (addr, 0);
          addr = XEXP (addr, 0);
        }
        }
      else if (GET_CODE (XEXP (addr, 1)) == REG)
      else if (GET_CODE (XEXP (addr, 1)) == REG)
        {
        {
          offset = XEXP (addr, 0);
          offset = XEXP (addr, 0);
          addr = XEXP (addr, 1);
          addr = XEXP (addr, 1);
        }
        }
      output_address (offset);
      output_address (offset);
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
      fprintf (file, "(%s)", reg_names[REGNO (addr)]);
      break;
      break;
 
 
    default:
    default:
      /* fprintf(file, "{%d}", GET_CODE (addr)); */
      /* fprintf(file, "{%d}", GET_CODE (addr)); */
      output_addr_const (file, addr);
      output_addr_const (file, addr);
    }
    }
}
}
 
 
/* Calulcate and return stack size for current function.  */
/* Calulcate and return stack size for current function.  */
static int
static int
calculate_stack_size (int vars, int *lr_save_area,
calculate_stack_size (int vars, int *lr_save_area,
                      int *fp_save_area, int *gpr_save_area, int *save_area)
                      int *fp_save_area, int *gpr_save_area, int *save_area)
{
{
  int regno;
  int regno;
 
 
  *gpr_save_area = 0;
  *gpr_save_area = 0;
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
    {
      if (regs_ever_live[regno] && !call_used_regs[regno])
      if (regs_ever_live[regno] && !call_used_regs[regno])
        *gpr_save_area += 4;
        *gpr_save_area += 4;
    }
    }
 
 
  *lr_save_area = (!current_function_is_leaf
  *lr_save_area = (!current_function_is_leaf
                   || regs_ever_live[LINK_REGNUM]) ? 4 : 0;
                   || regs_ever_live[LINK_REGNUM]) ? 4 : 0;
  *fp_save_area = frame_pointer_needed ? 4 : 0;
  *fp_save_area = frame_pointer_needed ? 4 : 0;
 
 
  *save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
  *save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
                + *lr_save_area + *fp_save_area);
                + *lr_save_area + *fp_save_area);
 
 
  return
  return
    (OR32_ALIGN (current_function_outgoing_args_size, 4)
    (OR32_ALIGN (current_function_outgoing_args_size, 4)
     + *lr_save_area + *fp_save_area + *gpr_save_area + OR32_ALIGN (vars, 4));
     + *lr_save_area + *fp_save_area + *gpr_save_area + OR32_ALIGN (vars, 4));
}
}
 
 
/* Set up the stack and frame pointer (if desired) for the
/* Set up the stack and frame pointer (if desired) for the
   function.  */
   function.  */
static void
static void
or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars)
or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars)
{
{
  int save_area;
  int save_area;
  int gpr_save_area;
  int gpr_save_area;
  int lr_save_area;
  int lr_save_area;
  int fp_save_area;
  int fp_save_area;
  int stack_size;
  int stack_size;
  int regno;
  int regno;
 
 
  if (TARGET_MASK_SCHED_LOGUE)
  if (TARGET_MASK_SCHED_LOGUE)
    return;
    return;
 
 
#if 0
#if 0
  save_area = 0;
  save_area = 0;
 
 
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
    {
      if (regs_ever_live[regno] && !call_used_regs[regno])
      if (regs_ever_live[regno] && !call_used_regs[regno])
        {
        {
          save_area += 1;
          save_area += 1;
        }
        }
    }
    }
 
 
  if (save_area != 0)
  if (save_area != 0)
    fprintf (file, "\tl.nop \t0x%x\n", 0x100 + save_area);
    fprintf (file, "\tl.nop \t0x%x\n", 0x100 + save_area);
 
 
  return;
  return;
#endif
#endif
 
 
  if (vars < 0)
  if (vars < 0)
    abort ();
    abort ();
 
 
  stack_size = calculate_stack_size
  stack_size = calculate_stack_size
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
 
 
  fprintf (file,
  fprintf (file,
           "\n\t# gpr_save_area %d vars %ld current_function_outgoing_args_size %d\n",
           "\n\t# gpr_save_area %d vars %ld current_function_outgoing_args_size %d\n",
           gpr_save_area, vars, current_function_outgoing_args_size);
           gpr_save_area, vars, current_function_outgoing_args_size);
 
 
  if (stack_size >= 0x8000)
  if (stack_size >= 0x8000)
    {
    {
      fprintf (file, "\tl.movhi   \tr%d,hi(%d)\n", GP_ARG_RETURN, stack_size);
      fprintf (file, "\tl.movhi   \tr%d,hi(%d)\n", GP_ARG_RETURN, stack_size);
      fprintf (file, "\tl.ori   \tr%d,r%d,lo(%d)\n", GP_ARG_RETURN,
      fprintf (file, "\tl.ori   \tr%d,r%d,lo(%d)\n", GP_ARG_RETURN,
               GP_ARG_RETURN, stack_size);
               GP_ARG_RETURN, stack_size);
      fprintf (file, "\tl.sub   \tr%d,r%d,r%d\n", STACK_POINTER_REGNUM,
      fprintf (file, "\tl.sub   \tr%d,r%d,r%d\n", STACK_POINTER_REGNUM,
               STACK_POINTER_REGNUM, GP_ARG_RETURN);
               STACK_POINTER_REGNUM, GP_ARG_RETURN);
    }
    }
  else if (stack_size > 0)
  else if (stack_size > 0)
    {
    {
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
               STACK_POINTER_REGNUM, -stack_size);
               STACK_POINTER_REGNUM, -stack_size);
    }
    }
 
 
  if (fp_save_area)
  if (fp_save_area)
    {
    {
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
               OR32_ALIGN (current_function_outgoing_args_size, 4)
               OR32_ALIGN (current_function_outgoing_args_size, 4)
               + lr_save_area, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM);
               + lr_save_area, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM);
      if (stack_size >= 0x8000)
      if (stack_size >= 0x8000)
        fprintf (file, "\tl.add   \tr%d,r%d,r%d\n", FRAME_POINTER_REGNUM,
        fprintf (file, "\tl.add   \tr%d,r%d,r%d\n", FRAME_POINTER_REGNUM,
                 STACK_POINTER_REGNUM, GP_ARG_RETURN);
                 STACK_POINTER_REGNUM, GP_ARG_RETURN);
      else
      else
        fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", FRAME_POINTER_REGNUM,
        fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", FRAME_POINTER_REGNUM,
                 STACK_POINTER_REGNUM, stack_size);
                 STACK_POINTER_REGNUM, stack_size);
    }
    }
 
 
  if (lr_save_area)
  if (lr_save_area)
    {
    {
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
      fprintf (file, "\tl.sw     \t%d(r%d),r%d\n",
               OR32_ALIGN (current_function_outgoing_args_size, 4),
               OR32_ALIGN (current_function_outgoing_args_size, 4),
               STACK_POINTER_REGNUM, LINK_REGNUM);
               STACK_POINTER_REGNUM, LINK_REGNUM);
    }
    }
 
 
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
               + lr_save_area + fp_save_area);
               + lr_save_area + fp_save_area);
 
 
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
    {
      if (regs_ever_live[regno] && !call_used_regs[regno])
      if (regs_ever_live[regno] && !call_used_regs[regno])
        {
        {
          fprintf (file, "\tl.sw    \t%d(r%d),r%d\n", save_area,
          fprintf (file, "\tl.sw    \t%d(r%d),r%d\n", save_area,
                   STACK_POINTER_REGNUM, regno);
                   STACK_POINTER_REGNUM, regno);
          save_area += 4;
          save_area += 4;
        }
        }
    }
    }
}
}
 
 
/* Do any necessary cleanup after a function to restore stack, frame,
/* Do any necessary cleanup after a function to restore stack, frame,
   and regs.  */
   and regs.  */
static void
static void
or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars)
or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars)
{
{
  int save_area;
  int save_area;
  int gpr_save_area;
  int gpr_save_area;
  int lr_save_area;
  int lr_save_area;
  int fp_save_area;
  int fp_save_area;
  int stack_size;
  int stack_size;
  int regno;
  int regno;
 
 
  if (TARGET_MASK_SCHED_LOGUE)
  if (TARGET_MASK_SCHED_LOGUE)
    return;
    return;
 
 
#if 0
#if 0
  save_area = 0;
  save_area = 0;
 
 
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
    {
      if (regs_ever_live[regno] && !call_used_regs[regno])
      if (regs_ever_live[regno] && !call_used_regs[regno])
        {
        {
          save_area += 1;
          save_area += 1;
        }
        }
    }
    }
 
 
  fprintf (file, "\tl.nop \t0x%x\n", 0x200 + save_area);
  fprintf (file, "\tl.nop \t0x%x\n", 0x200 + save_area);
  return;
  return;
#endif
#endif
 
 
  stack_size = calculate_stack_size
  stack_size = calculate_stack_size
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
    (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area);
 
 
  if (lr_save_area)
  if (lr_save_area)
    {
    {
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", LINK_REGNUM,
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", LINK_REGNUM,
               OR32_ALIGN (current_function_outgoing_args_size, 4),
               OR32_ALIGN (current_function_outgoing_args_size, 4),
               STACK_POINTER_REGNUM);
               STACK_POINTER_REGNUM);
    }
    }
  if (fp_save_area)
  if (fp_save_area)
    {
    {
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", FRAME_POINTER_REGNUM,
      fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", FRAME_POINTER_REGNUM,
               OR32_ALIGN (current_function_outgoing_args_size, 4)
               OR32_ALIGN (current_function_outgoing_args_size, 4)
               + lr_save_area, STACK_POINTER_REGNUM);
               + lr_save_area, STACK_POINTER_REGNUM);
    }
    }
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
  save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4)
               + lr_save_area + fp_save_area);
               + lr_save_area + fp_save_area);
 
 
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
    {
      if (regs_ever_live[regno] && !call_used_regs[regno])
      if (regs_ever_live[regno] && !call_used_regs[regno])
        {
        {
          fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", regno, save_area,
          fprintf (file, "\tl.lwz    \tr%d,%d(r%d)\n", regno, save_area,
                   STACK_POINTER_REGNUM);
                   STACK_POINTER_REGNUM);
          save_area += 4;
          save_area += 4;
        }
        }
    }
    }
 
 
  if (stack_size >= 0x8000)
  if (stack_size >= 0x8000)
    {
    {
      fprintf (file, "\tl.movhi   \tr3,hi(%d)\n", stack_size);
      fprintf (file, "\tl.movhi   \tr3,hi(%d)\n", stack_size);
      fprintf (file, "\tl.ori   \tr3,r3,lo(%d)\n", stack_size);
      fprintf (file, "\tl.ori   \tr3,r3,lo(%d)\n", stack_size);
 
 
      if (!TARGET_MASK_ALIGNED_JUMPS)
      if (!TARGET_MASK_ALIGNED_JUMPS)
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
      else
      else
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
                 LINK_REGNUM);
                 LINK_REGNUM);
 
 
      fprintf (file, "\tl.add   \tr%d,r%d,r3\n", STACK_POINTER_REGNUM,
      fprintf (file, "\tl.add   \tr%d,r%d,r3\n", STACK_POINTER_REGNUM,
               STACK_POINTER_REGNUM);
               STACK_POINTER_REGNUM);
    }
    }
  else if (stack_size > 0)
  else if (stack_size > 0)
    {
    {
      if (!TARGET_MASK_ALIGNED_JUMPS)
      if (!TARGET_MASK_ALIGNED_JUMPS)
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
      else
      else
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
                 LINK_REGNUM);
                 LINK_REGNUM);
 
 
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
      fprintf (file, "\tl.addi   \tr%d,r%d,%d\n", STACK_POINTER_REGNUM,
               STACK_POINTER_REGNUM, stack_size);
               STACK_POINTER_REGNUM, stack_size);
    }
    }
  else
  else
    {
    {
      if (!TARGET_MASK_ALIGNED_JUMPS)
      if (!TARGET_MASK_ALIGNED_JUMPS)
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
        fprintf (file, "\tl.jr  \tr%d\n", LINK_REGNUM);
      else
      else
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
        fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr  \tr%d\n",
                 LINK_REGNUM);
                 LINK_REGNUM);
 
 
      fprintf (file, "\tl.nop\n");
      fprintf (file, "\tl.nop\n");
    }
    }
 
 
#if 0
#if 0
  fprintf (file, ".endproc _%s\n", get_function_name ());
  fprintf (file, ".endproc _%s\n", get_function_name ());
#endif
#endif
}
}
 
 
/* Compuate full frame size and layout.  SIZE is the size of the
/* Compuate full frame size and layout.  SIZE is the size of the
   functions local variables.  Store information in FRAME_INFO and
   functions local variables.  Store information in FRAME_INFO and
   return total size of stack frame.  */
   return total size of stack frame.  */
 
 
HOST_WIDE_INT
HOST_WIDE_INT
or32_compute_frame_size (HOST_WIDE_INT size)
or32_compute_frame_size (HOST_WIDE_INT size)
{
{
  HOST_WIDE_INT args_size;
  HOST_WIDE_INT args_size;
  HOST_WIDE_INT vars_size;
  HOST_WIDE_INT vars_size;
  HOST_WIDE_INT stack_offset;
  HOST_WIDE_INT stack_offset;
  int regno;
  int regno;
 
 
  args_size = current_function_outgoing_args_size;
  args_size = current_function_outgoing_args_size;
  vars_size = OR32_ALIGN (size, 4);
  vars_size = OR32_ALIGN (size, 4);
 
 
  frame_info.args_size = args_size;
  frame_info.args_size = args_size;
  frame_info.vars_size = vars_size;
  frame_info.vars_size = vars_size;
 
 
  /* If the function has local variables, we're committed to
  /* If the function has local variables, we're committed to
     allocating it anyway.  Otherwise reclaim it here.  */
     allocating it anyway.  Otherwise reclaim it here.  */
  /* FIXME: Verify this.  Got if from the MIPS port.  */
  /* FIXME: Verify this.  Got if from the MIPS port.  */
  if (vars_size == 0 && current_function_is_leaf)
  if (vars_size == 0 && current_function_is_leaf)
    args_size = 0;
    args_size = 0;
 
 
  stack_offset = args_size;
  stack_offset = args_size;
 
 
  /* Save link register right after possible outgoing arguments.  */
  /* Save link register right after possible outgoing arguments.  */
  if (or32_save_reg_p (LINK_REGNUM))
  if (or32_save_reg_p (LINK_REGNUM))
    {
    {
      frame_info.lr_save_offset = stack_offset;
      frame_info.lr_save_offset = stack_offset;
      frame_info.save_lr_p = true;
      frame_info.save_lr_p = true;
      stack_offset = stack_offset + UNITS_PER_WORD;
      stack_offset = stack_offset + UNITS_PER_WORD;
    }
    }
  else
  else
    frame_info.save_lr_p = false;
    frame_info.save_lr_p = false;
 
 
  /* Save frame pointer right after possible link register.  */
  /* Save frame pointer right after possible link register.  */
  if (or32_save_reg_p (FRAME_POINTER_REGNUM))
  if (or32_save_reg_p (FRAME_POINTER_REGNUM))
    {
    {
      frame_info.fp_save_offset = stack_offset;
      frame_info.fp_save_offset = stack_offset;
      frame_info.save_fp_p = true;
      frame_info.save_fp_p = true;
      stack_offset = stack_offset + UNITS_PER_WORD;
      stack_offset = stack_offset + UNITS_PER_WORD;
    }
    }
  else
  else
    frame_info.save_fp_p = false;
    frame_info.save_fp_p = false;
 
 
  frame_info.gpr_size = 0;
  frame_info.gpr_size = 0;
  frame_info.mask = 0;
  frame_info.mask = 0;
  frame_info.gpr_offset = stack_offset;
  frame_info.gpr_offset = stack_offset;
 
 
  for (regno = 0; regno <= LAST_INT_REG; regno++)
  for (regno = 0; regno <= LAST_INT_REG; regno++)
    {
    {
      if (regno == LINK_REGNUM || regno == FRAME_POINTER_REGNUM)
      if (regno == LINK_REGNUM || regno == FRAME_POINTER_REGNUM)
        /* These has already been saved if so needed.  */
        /* These has already been saved if so needed.  */
        continue;
        continue;
 
 
      if (or32_save_reg_p (regno))
      if (or32_save_reg_p (regno))
        {
        {
          frame_info.gpr_size += UNITS_PER_WORD;
          frame_info.gpr_size += UNITS_PER_WORD;
          frame_info.mask |= (1 << regno);
          frame_info.mask |= (1 << regno);
        }
        }
    }
    }
 
 
  frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0)
  frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0)
                           + (frame_info.save_lr_p ? UNITS_PER_WORD : 0)
                           + (frame_info.save_lr_p ? UNITS_PER_WORD : 0)
                           + args_size + frame_info.gpr_size + vars_size);
                           + args_size + frame_info.gpr_size + vars_size);
 
 
  return frame_info.total_size;
  return frame_info.total_size;
}
}


 
 
/* Return true if current function must save REGNO.  */
/* Return true if current function must save REGNO.  */
static bool
static bool
or32_save_reg_p (int regno)
or32_save_reg_p (int regno)
{
{
  /* No need to save the faked cc0 register.  */
  /* No need to save the faked cc0 register.  */
  if (regno == FLAGS_REG)
  if (regno == FLAGS_REG)
    return false;
    return false;
 
 
  /* Check call-saved registers.  */
  /* Check call-saved registers.  */
  if (regs_ever_live[regno] && !call_used_regs[regno])
  if (regs_ever_live[regno] && !call_used_regs[regno])
    return true;
    return true;
 
 
  /* We need to save the old frame pointer before setting up a new
  /* We need to save the old frame pointer before setting up a new
     one.  */
     one.  */
  if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
  if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
    return true;
    return true;
 
 
  /* We need to save the incoming return address if it is ever clobbered
  /* We need to save the incoming return address if it is ever clobbered
     within the function.  */
     within the function.  */
  if (regno == LINK_REGNUM && regs_ever_live[regno])
  if (regno == LINK_REGNUM && regs_ever_live[regno])
    return true;
    return true;
 
 
  return false;
  return false;
}
}
 
 
/* Emit a frame related insn.  Same as emit_insn, but sets
/* Emit a frame related insn.  Same as emit_insn, but sets
   RTX_FRAME_RELATED_P to one.  */
   RTX_FRAME_RELATED_P to one.  */
 
 
static rtx
static rtx
emit_frame_insn (rtx insn)
emit_frame_insn (rtx insn)
{
{
  insn = emit_insn (insn);
  insn = emit_insn (insn);
  RTX_FRAME_RELATED_P (insn) = 1;
  RTX_FRAME_RELATED_P (insn) = 1;
  return (insn);
  return (insn);
}
}
 
 
static rtx
static rtx
indexed_memory (rtx base, HOST_WIDE_INT disp)
indexed_memory (rtx base, HOST_WIDE_INT disp)
{
{
  return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, GEN_INT (disp)));
  return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, GEN_INT (disp)));
}
}
 
 
/* Called after register allocation to add any instructions needed for
/* Called after register allocation to add any instructions needed for
   the prologue.  Using a prologue insn is favored compared to putting
   the prologue.  Using a prologue insn is favored compared to putting
   all of the instructions in output_function_prologue(), since it
   all of the instructions in output_function_prologue(), since it
   allows the scheduler to intermix instructions with the saves of the
   allows the scheduler to intermix instructions with the saves of the
   caller saved registers.  In some cases, it might be necessary to
   caller saved registers.  In some cases, it might be necessary to
   emit a barrier instruction as the last insn to prevent such
   emit a barrier instruction as the last insn to prevent such
   scheduling.  */
   scheduling.  */
 
 
void
void
or32_expand_prologue (void)
or32_expand_prologue (void)
{
{
  int total_size = or32_compute_frame_size (get_frame_size ());
  int total_size = or32_compute_frame_size (get_frame_size ());
  rtx sp_rtx;
  rtx sp_rtx;
  rtx value_rtx;
  rtx value_rtx;
 
 
  if (!total_size)
  if (!total_size)
    /* No frame needed.  */
    /* No frame needed.  */
    return;
    return;
 
 
  sp_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
  sp_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
 
 
  if (total_size > 32767)
  if (total_size > 32767)
    {
    {
      value_rtx = gen_rtx_REG (Pmode, GP_ARG_RETURN);
      value_rtx = gen_rtx_REG (Pmode, GP_ARG_RETURN);
      emit_frame_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
      emit_frame_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
    }
    }
  else
  else
    value_rtx = GEN_INT (total_size);
    value_rtx = GEN_INT (total_size);
 
 
  /* Update the stack pointer to reflect frame size.  */
  /* Update the stack pointer to reflect frame size.  */
  emit_frame_insn
  emit_frame_insn
    (gen_rtx_SET (Pmode, stack_pointer_rtx,
    (gen_rtx_SET (Pmode, stack_pointer_rtx,
                  gen_rtx_MINUS (Pmode, stack_pointer_rtx, value_rtx)));
                  gen_rtx_MINUS (Pmode, stack_pointer_rtx, value_rtx)));
 
 
  if (frame_info.save_fp_p)
  if (frame_info.save_fp_p)
    {
    {
      emit_frame_insn
      emit_frame_insn
        (gen_rtx_SET (Pmode,
        (gen_rtx_SET (Pmode,
                      indexed_memory (stack_pointer_rtx,
                      indexed_memory (stack_pointer_rtx,
                                      frame_info.fp_save_offset),
                                      frame_info.fp_save_offset),
                      frame_pointer_rtx));
                      frame_pointer_rtx));
 
 
      emit_frame_insn
      emit_frame_insn
        (gen_rtx_SET (Pmode, frame_pointer_rtx,
        (gen_rtx_SET (Pmode, frame_pointer_rtx,
                      gen_rtx_PLUS (Pmode, frame_pointer_rtx, value_rtx)));
                      gen_rtx_PLUS (Pmode, frame_pointer_rtx, value_rtx)));
    }
    }
  if (frame_info.save_lr_p)
  if (frame_info.save_lr_p)
    {
    {
 
 
      emit_frame_insn
      emit_frame_insn
        (gen_rtx_SET (Pmode,
        (gen_rtx_SET (Pmode,
                      indexed_memory (stack_pointer_rtx,
                      indexed_memory (stack_pointer_rtx,
                                      frame_info.lr_save_offset),
                                      frame_info.lr_save_offset),
                      gen_rtx_REG (Pmode, LINK_REGNUM)));
                      gen_rtx_REG (Pmode, LINK_REGNUM)));
    }
    }
  if (frame_info.gpr_size)
  if (frame_info.gpr_size)
    {
    {
      int offset = 0;
      int offset = 0;
      int regno;
      int regno;
 
 
      for (regno = 0; regno <= LAST_INT_REG; regno++)
      for (regno = 0; regno <= LAST_INT_REG; regno++)
        {
        {
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
 
 
          if (!(frame_info.mask & (1 << regno)))
          if (!(frame_info.mask & (1 << regno)))
            continue;
            continue;
 
 
          emit_frame_insn
          emit_frame_insn
            (gen_rtx_SET (Pmode,
            (gen_rtx_SET (Pmode,
                          indexed_memory (stack_pointer_rtx, disp),
                          indexed_memory (stack_pointer_rtx, disp),
                          gen_rtx_REG (Pmode, regno)));
                          gen_rtx_REG (Pmode, regno)));
          offset = offset + UNITS_PER_WORD;
          offset = offset + UNITS_PER_WORD;
        }
        }
    }
    }
}
}
 
 
/* Called after register allocation to add any instructions needed for
/* Called after register allocation to add any instructions needed for
   the epilogue.  Using an epilogue insn is favored compared to
   the epilogue.  Using an epilogue insn is favored compared to
   putting all of the instructions in output_function_epilogue(),
   putting all of the instructions in output_function_epilogue(),
   since it allows the scheduler to intermix instructions with the
   since it allows the scheduler to intermix instructions with the
   restores of the caller saved registers.  In some cases, it might be
   restores of the caller saved registers.  In some cases, it might be
   necessary to emit a barrier instruction as the first insn to
   necessary to emit a barrier instruction as the first insn to
   prevent such scheduling.  */
   prevent such scheduling.  */
 
 
void
void
or32_expand_epilogue (int sibcall)
or32_expand_epilogue (int sibcall)
{
{
  int total_size = or32_compute_frame_size (get_frame_size ());
  int total_size = or32_compute_frame_size (get_frame_size ());
  rtx value_rtx;
  rtx value_rtx;
 
 
  if (total_size > 32767)
  if (total_size > 32767)
    {
    {
      value_rtx = gen_rtx_REG (Pmode, 3);
      value_rtx = gen_rtx_REG (Pmode, 3);
 
 
      emit_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
      emit_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size)));
    }
    }
  else
  else
    value_rtx = GEN_INT (total_size);
    value_rtx = GEN_INT (total_size);
 
 
  if (frame_info.save_lr_p)
  if (frame_info.save_lr_p)
    {
    {
      or32_maybe_dead
      or32_maybe_dead
        (emit_insn
        (emit_insn
         (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM),
         (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM),
                       indexed_memory (stack_pointer_rtx,
                       indexed_memory (stack_pointer_rtx,
                                       frame_info.lr_save_offset))));
                                       frame_info.lr_save_offset))));
    }
    }
  if (frame_info.save_fp_p)
  if (frame_info.save_fp_p)
    {
    {
      emit_insn
      emit_insn
        (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
        (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
                      indexed_memory (stack_pointer_rtx,
                      indexed_memory (stack_pointer_rtx,
                                      frame_info.fp_save_offset)));
                                      frame_info.fp_save_offset)));
    }
    }
 
 
  if (frame_info.gpr_size)
  if (frame_info.gpr_size)
    {
    {
      int offset = 0;
      int offset = 0;
      int regno;
      int regno;
 
 
      for (regno = 0; regno <= LAST_INT_REG; regno++)
      for (regno = 0; regno <= LAST_INT_REG; regno++)
        {
        {
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
          HOST_WIDE_INT disp = frame_info.gpr_offset + offset;
 
 
          if (!(frame_info.mask & (1 << regno)))
          if (!(frame_info.mask & (1 << regno)))
            continue;
            continue;
 
 
          emit_insn
          emit_insn
            (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno),
            (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno),
                          indexed_memory (stack_pointer_rtx, disp)));
                          indexed_memory (stack_pointer_rtx, disp)));
          offset = offset + UNITS_PER_WORD;
          offset = offset + UNITS_PER_WORD;
        }
        }
    }
    }
 
 
  if (total_size)
  if (total_size)
    {
    {
      emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx,
      emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx,
                              gen_rtx_PLUS (Pmode,
                              gen_rtx_PLUS (Pmode,
                                            stack_pointer_rtx, value_rtx)));
                                            stack_pointer_rtx, value_rtx)));
    }
    }
 
 
  if (!sibcall)
  if (!sibcall)
    emit_jump_insn (gen_return_internal (gen_rtx_REG( Pmode, 9)));
    emit_jump_insn (gen_return_internal (gen_rtx_REG( Pmode, 9)));
}
}
 
 
 
 
void
void
or32_print_operand (FILE * file, rtx x, int code)
or32_print_operand (FILE * file, rtx x, int code)
{
{
  if (code == 'r' && GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG)
  if (code == 'r' && GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG)
    fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
    fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
  else if (code == '(')
  else if (code == '(')
    {
    {
      if (dbr_sequence_length ())
      if (dbr_sequence_length ())
        fprintf (file, "\t# delay slot filled");
        fprintf (file, "\t# delay slot filled");
      else
      else
        fprintf (file, "\n\tl.nop\t\t\t# nop delay slot");
        fprintf (file, "\n\tl.nop\t\t\t# nop delay slot");
    }
    }
  else if (code == 'C')
  else if (code == 'C')
    {
    {
      switch (GET_CODE (x))
      switch (GET_CODE (x))
        {
        {
        case EQ:
        case EQ:
          fputs ("eq", file);
          fputs ("eq", file);
          break;
          break;
        case NE:
        case NE:
          fputs ("ne", file);
          fputs ("ne", file);
          break;
          break;
        case GT:
        case GT:
          fputs ("gts", file);
          fputs ("gts", file);
          break;
          break;
        case GE:
        case GE:
          fputs ("ges", file);
          fputs ("ges", file);
          break;
          break;
        case LT:
        case LT:
          fputs ("lts", file);
          fputs ("lts", file);
          break;
          break;
        case LE:
        case LE:
          fputs ("les", file);
          fputs ("les", file);
          break;
          break;
        case GTU:
        case GTU:
          fputs ("gtu", file);
          fputs ("gtu", file);
          break;
          break;
        case GEU:
        case GEU:
          fputs ("geu", file);
          fputs ("geu", file);
          break;
          break;
        case LTU:
        case LTU:
          fputs ("ltu", file);
          fputs ("ltu", file);
          break;
          break;
        case LEU:
        case LEU:
          fputs ("leu", file);
          fputs ("leu", file);
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
    }
    }
  else if (code == 'H')
  else if (code == 'H')
    {
    {
      if (GET_CODE (x) == REG)
      if (GET_CODE (x) == REG)
        fprintf (file, "%s", reg_names[REGNO (x) + 1]);
        fprintf (file, "%s", reg_names[REGNO (x) + 1]);
      else
      else
        abort ();
        abort ();
    }
    }
  else if (GET_CODE (x) == REG)
  else if (GET_CODE (x) == REG)
    fprintf (file, "%s", reg_names[REGNO (x)]);
    fprintf (file, "%s", reg_names[REGNO (x)]);
  else if (GET_CODE (x) == MEM)
  else if (GET_CODE (x) == MEM)
    output_address (XEXP (x, 0));
    output_address (XEXP (x, 0));
  else
  else
    output_addr_const (file, x);
    output_addr_const (file, x);
}
}
 
 
/* Generate assembler code for a movdi/movdf */
/* Generate assembler code for a movdi/movdf */
 
 
const char *
const char *
or32_output_move_double (rtx * operands)
or32_output_move_double (rtx * operands)
{
{
  rtx xoperands[3];
  rtx xoperands[3];
 
 
  switch (GET_CODE (operands[0]))
  switch (GET_CODE (operands[0]))
    {
    {
    case REG:
    case REG:
      if (GET_CODE (operands[1]) == REG)
      if (GET_CODE (operands[1]) == REG)
        {
        {
          if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
          if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
            {
            {
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
              return "";
              return "";
            }
            }
          else
          else
            {
            {
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
              output_asm_insn ("\tl.or    \t%0, %1, r0", operands);
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
              output_asm_insn ("\tl.or    \t%H0, %H1, r0", operands);
              return "";
              return "";
            }
            }
        }
        }
      else if (GET_CODE (operands[1]) == MEM)
      else if (GET_CODE (operands[1]) == MEM)
        {
        {
          xoperands[1] = XEXP (operands[1], 0);
          xoperands[1] = XEXP (operands[1], 0);
          if (GET_CODE (xoperands[1]) == REG)
          if (GET_CODE (xoperands[1]) == REG)
            {
            {
              xoperands[0] = operands[0];
              xoperands[0] = operands[0];
              if (REGNO (xoperands[0]) == REGNO (xoperands[1]))
              if (REGNO (xoperands[0]) == REGNO (xoperands[1]))
                {
                {
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
                  return "";
                  return "";
                }
                }
              else
              else
                {
                {
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%0, 0(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
                  output_asm_insn ("\tl.lwz   \t%H0, 4(%1)", xoperands);
                  return "";
                  return "";
                }
                }
            }
            }
          else if (GET_CODE (xoperands[1]) == PLUS)
          else if (GET_CODE (xoperands[1]) == PLUS)
            {
            {
              if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 1)) == REG)
              if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 1)) == REG)
                {
                {
                  xoperands[0] = operands[0];
                  xoperands[0] = operands[0];
                  xoperands[1] = XEXP (xoperands[1], 0);
                  xoperands[1] = XEXP (xoperands[1], 0);
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
                    {
                    {
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                                       xoperands);
                                       xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      return "";
                      return "";
                    }
                    }
                  else
                  else
                    {
                    {
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                                       xoperands);
                                       xoperands);
                      return "";
                      return "";
                    }
                    }
                }
                }
              else if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 0)) ==
              else if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 0)) ==
                       REG)
                       REG)
                {
                {
                  xoperands[0] = operands[0];
                  xoperands[0] = operands[0];
                  xoperands[1] = XEXP (xoperands[1], 1);
                  xoperands[1] = XEXP (xoperands[1], 1);
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
                  if (REGNO (xoperands[0]) == REGNO (xoperands[2]))
                    {
                    {
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                                       xoperands);
                                       xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      return "";
                      return "";
                    }
                    }
                  else
                  else
                    {
                    {
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%0, %1(%2)", xoperands);
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                      output_asm_insn ("\tl.lwz   \t%H0, %1+4(%2)",
                                       xoperands);
                                       xoperands);
                      return "";
                      return "";
                    }
                    }
                }
                }
              else
              else
                abort ();
                abort ();
            }
            }
          else
          else
            abort ();
            abort ();
        }
        }
      else if (GET_CODE (operands[1]) == CONST_INT)
      else if (GET_CODE (operands[1]) == CONST_INT)
        {
        {
          if (INTVAL (operands[1]) < 0)
          if (INTVAL (operands[1]) < 0)
            output_asm_insn ("\tl.addi  \t%0, r0, -1", operands);
            output_asm_insn ("\tl.addi  \t%0, r0, -1", operands);
          else
          else
            output_asm_insn ("\tl.or    \t%0, r0, r0", operands);
            output_asm_insn ("\tl.or    \t%0, r0, r0", operands);
          output_asm_insn ("\tl.movhi \t%H0, hi(%1)", operands);
          output_asm_insn ("\tl.movhi \t%H0, hi(%1)", operands);
          output_asm_insn ("\tl.ori   \t%H0, %H0, lo(%1)", operands);
          output_asm_insn ("\tl.ori   \t%H0, %H0, lo(%1)", operands);
          return "";
          return "";
        }
        }
      else
      else
        abort ();
        abort ();
    case MEM:
    case MEM:
      xoperands[0] = XEXP (operands[0], 0);
      xoperands[0] = XEXP (operands[0], 0);
      if (GET_CODE (xoperands[0]) == REG)
      if (GET_CODE (xoperands[0]) == REG)
        {
        {
          xoperands[1] = operands[1];
          xoperands[1] = operands[1];
          output_asm_insn ("\tl.sw    \t0(%0), %1", xoperands);
          output_asm_insn ("\tl.sw    \t0(%0), %1", xoperands);
          output_asm_insn ("\tl.sw    \t4(%0), %H1", xoperands);
          output_asm_insn ("\tl.sw    \t4(%0), %H1", xoperands);
          return "";
          return "";
        }
        }
      else if (GET_CODE (xoperands[0]) == PLUS)
      else if (GET_CODE (xoperands[0]) == PLUS)
        {
        {
          if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 1)) == REG)
          if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 1)) == REG)
            {
            {
              xoperands[0] = XEXP (xoperands[0], 0);
              xoperands[0] = XEXP (xoperands[0], 0);
              xoperands[2] = operands[1];
              xoperands[2] = operands[1];
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
              return "";
              return "";
            }
            }
          else if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 0)) == REG)
          else if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 0)) == REG)
            {
            {
              xoperands[0] = XEXP (xoperands[0], 1);
              xoperands[0] = XEXP (xoperands[0], 1);
              xoperands[2] = operands[1];
              xoperands[2] = operands[1];
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
              output_asm_insn ("\tl.sw    \t%0(%1), %2", xoperands);
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
              output_asm_insn ("\tl.sw    \t%0+4(%1), %H2", xoperands);
              return "";
              return "";
            }
            }
          else
          else
            abort ();
            abort ();
        }
        }
      else
      else
        abort ();
        abort ();
    default:
    default:
      abort ();
      abort ();
    }
    }
}
}
 
 
enum rtx_code
enum rtx_code
or32_reverse_condition (enum machine_mode mode ATTRIBUTE_UNUSED,
or32_reverse_condition (enum machine_mode mode ATTRIBUTE_UNUSED,
                        enum rtx_code code)
                        enum rtx_code code)
{
{
  return reverse_condition (code);
  return reverse_condition (code);
}
}
 
 
enum machine_mode
enum machine_mode
or32_cc_mode (enum rtx_code code,
or32_cc_mode (enum rtx_code code,
              rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
              rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
{
{
 
 
  switch (code)
  switch (code)
    {
    {
    case EQ:
    case EQ:
      return CCEQmode;
      return CCEQmode;
    case NE:
    case NE:
      return CCNEmode;
      return CCNEmode;
    case GEU:
    case GEU:
      return CCGEUmode;
      return CCGEUmode;
    case GTU:
    case GTU:
      return CCGTUmode;
      return CCGTUmode;
    case LTU:
    case LTU:
      return CCLTUmode;
      return CCLTUmode;
    case LEU:
    case LEU:
      return CCLEUmode;
      return CCLEUmode;
    case GE:
    case GE:
      return CCGEmode;
      return CCGEmode;
    case LT:
    case LT:
      return CCLTmode;
      return CCLTmode;
    case GT:
    case GT:
      return CCGTmode;
      return CCGTmode;
    case LE:
    case LE:
      return CCLEmode;
      return CCLEmode;
 
 
    default:
    default:
      abort ();
      abort ();
    }
    }
}
}
 
 
/* Generate insn patterns to do an integer compare of OPERANDS.  */
/* Generate insn patterns to do an integer compare of OPERANDS.  */
 
 
static rtx
static rtx
or32_expand_int_compare (enum rtx_code code, rtx op0, rtx op1)
or32_expand_int_compare (enum rtx_code code, rtx op0, rtx op1)
{
{
  enum machine_mode cmpmode;
  enum machine_mode cmpmode;
  rtx tmp, flags;
  rtx tmp, flags;
 
 
  cmpmode = SELECT_CC_MODE (code, op0, op1);
  cmpmode = SELECT_CC_MODE (code, op0, op1);
  flags = gen_rtx_REG (cmpmode, FLAGS_REG);
  flags = gen_rtx_REG (cmpmode, FLAGS_REG);
 
 
  /* This is very simple, but making the interface the same as in the
  /* This is very simple, but making the interface the same as in the
     FP case makes the rest of the code easier.  */
     FP case makes the rest of the code easier.  */
  tmp = gen_rtx_COMPARE (cmpmode, op0, op1);
  tmp = gen_rtx_COMPARE (cmpmode, op0, op1);
  emit_insn (gen_rtx_SET (VOIDmode, flags, tmp));
  emit_insn (gen_rtx_SET (VOIDmode, flags, tmp));
 
 
  /* Return the test that should be put into the flags user, i.e.
  /* Return the test that should be put into the flags user, i.e.
     the bcc, scc, or cmov instruction.  */
     the bcc, scc, or cmov instruction.  */
  return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
  return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
}
}
 
 
rtx
rtx
or32_expand_compare (enum rtx_code code, rtx op0, rtx op1)
or32_expand_compare (enum rtx_code code, rtx op0, rtx op1)
{
{
  return or32_expand_int_compare (code, op0, op1);
  return or32_expand_int_compare (code, op0, op1);
}
}
 
 
void
void
or32_expand_branch (enum rtx_code code, rtx label)
or32_expand_branch (enum rtx_code code, rtx label)
{
{
  rtx tmp;
  rtx tmp;
 
 
  switch (GET_MODE (or32_compare_op0))
  switch (GET_MODE (or32_compare_op0))
    {
    {
    case SImode:
    case SImode:
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
                                  tmp,
                                  tmp,
                                  gen_rtx_LABEL_REF (VOIDmode, label),
                                  gen_rtx_LABEL_REF (VOIDmode, label),
                                  pc_rtx);
                                  pc_rtx);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
      return;
      return;
 
 
    case SFmode:
    case SFmode:
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
      tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1);
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
                                  tmp,
                                  tmp,
                                  gen_rtx_LABEL_REF (VOIDmode, label),
                                  gen_rtx_LABEL_REF (VOIDmode, label),
                                  pc_rtx);
                                  pc_rtx);
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
      return;
      return;
 
 
    default:
    default:
      abort ();
      abort ();
    }
    }
 
 
}
}
 
 
static int
static int
or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
{
{
  rtx condition_rtx, cr;
  rtx condition_rtx, cr;
 
 
  if ((GET_MODE (or32_compare_op0) != SImode) &&
  if ((GET_MODE (or32_compare_op0) != SImode) &&
      (GET_MODE (or32_compare_op0) != HImode) &&
      (GET_MODE (or32_compare_op0) != HImode) &&
      (GET_MODE (or32_compare_op0) != QImode))
      (GET_MODE (or32_compare_op0) != QImode))
    return 0;
    return 0;
 
 
  /* We still have to do the compare, because cmov doesn't do a
  /* We still have to do the compare, because cmov doesn't do a
     compare, it just looks at the FLAG bit set by a previous compare
     compare, it just looks at the FLAG bit set by a previous compare
     instruction.  */
     instruction.  */
 
 
  condition_rtx = or32_expand_compare (GET_CODE (op),
  condition_rtx = or32_expand_compare (GET_CODE (op),
                                       or32_compare_op0, or32_compare_op1);
                                       or32_compare_op0, or32_compare_op1);
 
 
  cr = XEXP (condition_rtx, 0);
  cr = XEXP (condition_rtx, 0);
 
 
  emit_insn (gen_cmov (dest, condition_rtx, true_cond, false_cond, cr));
  emit_insn (gen_cmov (dest, condition_rtx, true_cond, false_cond, cr));
 
 
  return 1;
  return 1;
}
}
 
 
 
 
/* Emit a conditional move: move TRUE_COND to DEST if OP of the
/* Emit a conditional move: move TRUE_COND to DEST if OP of the
   operands of the last comparison is nonzero/true, FALSE_COND if it
   operands of the last comparison is nonzero/true, FALSE_COND if it
   is zero/false.  Return 0 if the hardware has no such operation.  */
   is zero/false.  Return 0 if the hardware has no such operation.  */
 
 
int
int
or32_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
or32_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
{
{
  enum machine_mode result_mode = GET_MODE (dest);
  enum machine_mode result_mode = GET_MODE (dest);
 
 
  if (GET_MODE (true_cond) != result_mode)
  if (GET_MODE (true_cond) != result_mode)
    return 0;
    return 0;
 
 
  if (GET_MODE (false_cond) != result_mode)
  if (GET_MODE (false_cond) != result_mode)
    return 0;
    return 0;
 
 
  /* First, work out if the hardware can do this at all */
  /* First, work out if the hardware can do this at all */
  return or32_emit_int_cmove (dest, op, true_cond, false_cond);
  return or32_emit_int_cmove (dest, op, true_cond, false_cond);
}
}
 
 
const char *
const char *
or32_output_bf (rtx * operands)
or32_output_bf (rtx * operands)
{
{
  enum rtx_code code;
  enum rtx_code code;
  enum machine_mode mode_calc, mode_got;
  enum machine_mode mode_calc, mode_got;
 
 
  code = GET_CODE (operands[1]);
  code = GET_CODE (operands[1]);
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
  mode_got = GET_MODE (operands[2]);
  mode_got = GET_MODE (operands[2]);
 
 
  if (!TARGET_MASK_ALIGNED_JUMPS)
  if (!TARGET_MASK_ALIGNED_JUMPS)
    {
    {
      if (mode_calc != mode_got)
      if (mode_calc != mode_got)
        return "l.bnf   \t%l0%(";
        return "l.bnf   \t%l0%(";
      else
      else
        return "l.bf    \t%l0%(";
        return "l.bf    \t%l0%(";
    }
    }
  else
  else
    {
    {
      if (mode_calc != mode_got)
      if (mode_calc != mode_got)
        return "\t.balignl 0x8,0x15000015,0x4;l.bnf   \t%l0%(";
        return "\t.balignl 0x8,0x15000015,0x4;l.bnf   \t%l0%(";
      else
      else
        return "\t.balignl 0x8,0x15000015,0x4;l.bf    \t%l0%(";
        return "\t.balignl 0x8,0x15000015,0x4;l.bf    \t%l0%(";
    }
    }
}
}
 
 
const char *
const char *
or32_output_cmov (rtx * operands)
or32_output_cmov (rtx * operands)
{
{
  enum rtx_code code;
  enum rtx_code code;
  enum machine_mode mode_calc, mode_got;
  enum machine_mode mode_calc, mode_got;
 
 
  code = GET_CODE (operands[1]);
  code = GET_CODE (operands[1]);
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
  mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1);
  mode_got = GET_MODE (operands[4]);
  mode_got = GET_MODE (operands[4]);
 
 
  if (mode_calc != mode_got)
  if (mode_calc != mode_got)
    return "l.cmov  \t%0,%3,%2";        /* reversed */
    return "l.cmov  \t%0,%3,%2";        /* reversed */
  else
  else
    return "l.cmov  \t%0,%2,%3";
    return "l.cmov  \t%0,%2,%3";
}
}
 
 
/* Any function is ok for sibcall optimization if we allow this optimization
/* Any function is ok for sibcall optimization if we allow this optimization
 */
 */
static bool
static bool
or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
                              tree exp ATTRIBUTE_UNUSED)
                              tree exp ATTRIBUTE_UNUSED)
{
{
  return TARGET_MASK_SIBCALL;
  return TARGET_MASK_SIBCALL;
}
}
 
 
/* All aggregates and arguments greater than 8 bytes are passed this way.  */
/* All aggregates and arguments greater than 8 bytes are passed this way.  */
static bool
static bool
or32_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
or32_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED,
                                          tree type, bool named ATTRIBUTE_UNUSED)
                                          tree type, bool named ATTRIBUTE_UNUSED)
{
{
  return (type && (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8));
  return (type && (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8));
}
}
 
 
static int
static int
or32_arg_partial_bytes (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
or32_arg_partial_bytes (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED,
                        tree type ATTRIBUTE_UNUSED,
                        tree type ATTRIBUTE_UNUSED,
                        bool named ATTRIBUTE_UNUSED)
                        bool named ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 0;
}
}
 
 
/* For now this is very simple way for sibcall support */
/* For now this is very simple way for sibcall support */
 
 
void
void
or32_expand_sibcall (rtx result ATTRIBUTE_UNUSED, rtx addr, rtx args_size)
or32_expand_sibcall (rtx result ATTRIBUTE_UNUSED, rtx addr, rtx args_size)
{
{
  emit_call_insn (gen_sibcall_internal (addr, args_size));
  emit_call_insn (gen_sibcall_internal (addr, args_size));
}
}
 
 
 
 
/* We know it can't be done in one insn when we get here,
/* We know it can't be done in one insn when we get here,
   the movsi expander guarantees this.  */
   the movsi expander guarantees this.  */
void
void
or32_emit_set_const32 (rtx op0, rtx op1)
or32_emit_set_const32 (rtx op0, rtx op1)
{
{
  enum machine_mode mode = GET_MODE (op0);
  enum machine_mode mode = GET_MODE (op0);
  rtx temp;
  rtx temp;
 
 
 
 
  if (GET_CODE (op1) == CONST_INT)
  if (GET_CODE (op1) == CONST_INT)
    {
    {
      if (CONST_OK_FOR_LETTER_P (INTVAL (op1) & GET_MODE_MASK (mode), 'K') ||
      if (CONST_OK_FOR_LETTER_P (INTVAL (op1) & GET_MODE_MASK (mode), 'K') ||
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'M') ||
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'M') ||
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'I'))
                CONST_OK_FOR_LETTER_P (INTVAL (op1), 'I'))
        abort ();
        abort ();
    }
    }
 
 
 
 
  /* Full 2-insn decomposition is needed.  */
  /* Full 2-insn decomposition is needed.  */
  if (reload_in_progress || reload_completed)
  if (reload_in_progress || reload_completed)
    temp = op0;
    temp = op0;
  else
  else
    temp = gen_reg_rtx (mode);
    temp = gen_reg_rtx (mode);
 
 
  if (GET_CODE (op1) == CONST_INT)
  if (GET_CODE (op1) == CONST_INT)
    {
    {
      /* Emit them as real moves instead of a HIGH/LO_SUM,
      /* Emit them as real moves instead of a HIGH/LO_SUM,
         this way CSE can see everything and reuse intermediate
         this way CSE can see everything and reuse intermediate
         values if it wants.  */
         values if it wants.  */
      emit_insn (gen_rtx_SET (VOIDmode, temp,
      emit_insn (gen_rtx_SET (VOIDmode, temp,
                              GEN_INT (INTVAL (op1)
                              GEN_INT (INTVAL (op1)
                                       & ~(HOST_WIDE_INT) 0xffff)));
                                       & ~(HOST_WIDE_INT) 0xffff)));
 
 
      emit_insn (gen_rtx_SET (VOIDmode,
      emit_insn (gen_rtx_SET (VOIDmode,
                              op0,
                              op0,
                              gen_rtx_IOR (mode, temp,
                              gen_rtx_IOR (mode, temp,
                                           GEN_INT (INTVAL (op1) & 0xffff))));
                                           GEN_INT (INTVAL (op1) & 0xffff))));
    }
    }
  else
  else
    {
    {
 
 
#if 0
#if 0
      /* A symbol, emit in the traditional way.  */
      /* A symbol, emit in the traditional way.  */
 
 
      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, op1)));
      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, op1)));
      emit_insn (gen_rtx_SET (VOIDmode,
      emit_insn (gen_rtx_SET (VOIDmode,
                              op0, gen_rtx_LO_SUM (mode, temp, op1)));
                              op0, gen_rtx_LO_SUM (mode, temp, op1)));
#else
#else
      /* since or32 bfd can not deal with relocs that are not of type
      /* since or32 bfd can not deal with relocs that are not of type
         OR32_CONSTH_RELOC + OR32_CONST_RELOC (ie move high must be
         OR32_CONSTH_RELOC + OR32_CONST_RELOC (ie move high must be
         followed by exactly one lo_sum)
         followed by exactly one lo_sum)
       */
       */
      emit_insn (gen_movsi_insn_big (op0, op1));
      emit_insn (gen_movsi_insn_big (op0, op1));
#endif
#endif
    }
    }
}
}
 
 
 
 
/* Functions returning costs and making code size/performance tradeoffs */
/* Functions returning costs and making code size/performance tradeoffs */
 
 
int
int
or32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
or32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
                         enum reg_class from ATTRIBUTE_UNUSED,
                         enum reg_class from ATTRIBUTE_UNUSED,
                         enum reg_class to ATTRIBUTE_UNUSED)
                         enum reg_class to ATTRIBUTE_UNUSED)
{
{
  return 2;
  return 2;
}
}
 
 
/* A C expressions returning the cost of moving data of MODE from a register to
/* A C expressions returning the cost of moving data of MODE from a register to
   or from memory.  */
   or from memory.  */
 
 
int
int
or32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
or32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
                       enum reg_class class ATTRIBUTE_UNUSED,
                       enum reg_class class ATTRIBUTE_UNUSED,
                       int in ATTRIBUTE_UNUSED)
                       int in ATTRIBUTE_UNUSED)
{
{
  return 2;
  return 2;
}
}
 
 
/* Specify the cost of a branch insn; roughly the number of extra insns that
/* Specify the cost of a branch insn; roughly the number of extra insns that
   should be added to avoid a branch.
   should be added to avoid a branch.
 
 
   Set this to 3 on the or32 since that is roughly the average cost of an
   Set this to 3 on the or32 since that is roughly the average cost of an
   unscheduled conditional branch.
   unscheduled conditional branch.
 
 
   Cost of 2 and 3 give equal and ~0.7% bigger binaries
   Cost of 2 and 3 give equal and ~0.7% bigger binaries
 
 
*/
*/
int
int
or32_branch_cost (void)
or32_branch_cost (void)
{
{
  return 2;
  return 2;
}
}
 
 
/* Stolen from ../arm/arm.c */
/* Stolen from ../arm/arm.c */
#define MAX_ASCII_LEN 51
#define MAX_ASCII_LEN 51
 
 
void
void
output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
{
{
  int i;
  int i;
  int len_so_far = 0;
  int len_so_far = 0;
 
 
  fputs ("\t.ascii\t\"", stream);
  fputs ("\t.ascii\t\"", stream);
 
 
  for (i = 0; i < len; i++)
  for (i = 0; i < len; i++)
    {
    {
      int c = p[i];
      int c = p[i];
 
 
      if (len_so_far >= MAX_ASCII_LEN)
      if (len_so_far >= MAX_ASCII_LEN)
        {
        {
          fputs ("\"\n\t.ascii\t\"", stream);
          fputs ("\"\n\t.ascii\t\"", stream);
          len_so_far = 0;
          len_so_far = 0;
        }
        }
 
 
      if (ISPRINT (c))
      if (ISPRINT (c))
        {
        {
          if (c == '\\' || c == '\"')
          if (c == '\\' || c == '\"')
            {
            {
              putc ('\\', stream);
              putc ('\\', stream);
              len_so_far++;
              len_so_far++;
            }
            }
          putc (c, stream);
          putc (c, stream);
          len_so_far++;
          len_so_far++;
        }
        }
      else
      else
        {
        {
          fprintf (stream, "\\%03o", c);
          fprintf (stream, "\\%03o", c);
          len_so_far += 4;
          len_so_far += 4;
        }
        }
    }
    }
 
 
  fputs ("\"\n", stream);
  fputs ("\"\n", stream);
}
}
 
 

powered by: WebSVN 2.1.0

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