OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc1/] [gcc/] [config/] [or32/] [or32.c] - Diff between revs 282 and 332

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 282 Rev 332
Line 52... Line 52...
#include "langhooks.h"
#include "langhooks.h"
#include "df.h"
#include "df.h"
#include "dwarf2.h"
#include "dwarf2.h"
 
 
 
 
 
/* ========================================================================== */
 
/* Local macros                                                               */
 
 
 
/* Construct a l.movhi instruction for the given reg and value */
 
#define OR32_MOVHI(rd, k)                                               \
 
  ((0x6 << 26) | ((rd) << 21) | (k))
 
 
 
/* Construct a l.ori instruction for the given two regs and value */
 
#define OR32_ORI(rd, ra, k)                                             \
 
  ((0x2a << 26) | ((rd) << 21) | ((ra) << 16) | (k))
 
 
 
/* Construct a l.lwz instruction for the given two registers and offset */
 
#define OR32_LWZ(rd, ra, i)                                             \
 
  ((0x21 << 26) | ((rd) << 21) | ((ra) << 16) | (i))
 
 
 
/* Construct a l.jr instruction for the given register */
 
#define OR32_JR(rb)                                                     \
 
  ((0x11 << 26) | ((rb) << 11))
 
 
/* ========================================================================== */
/* ========================================================================== */
/* Static variables (i.e. global to this file only.                           */
/* Static variables (i.e. global to this file only.                           */
 
 
 
 
Line 459... Line 477...
      return (num <= OR32_LAST_INT_REG) || (num >= FIRST_PSEUDO_REGISTER);
      return (num <= OR32_LAST_INT_REG) || (num >= FIRST_PSEUDO_REGISTER);
    }
    }
}       /* or32_regnum_ok_for_base_p () */
}       /* or32_regnum_ok_for_base_p () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Emit a move from SRC to DEST.
 
 
 
   Assume that the move expanders can handle all moves if !can_create_pseudo_p
 
   ().  The distinction is important because, unlike emit_move_insn, the move
 
   expanders know how to force Pmode objects into the constant pool even when
 
   the constant pool address is not itself legitimate.
 
 
 
   @param[in] dest  Destination of the move.
 
   @param[in] src   Source for the move.
 
 
 
   @return  RTX for the move.                                                 */
 
/* -------------------------------------------------------------------------- */
 
rtx
 
or32_emit_move (rtx dest, rtx src)
 
{
 
  return (can_create_pseudo_p ()
 
          ? emit_move_insn (dest, src)
 
          : emit_move_insn_1 (dest, src));
 
 
 
}       /* or32_emit_move () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Emit an instruction of the form (set TARGET (CODE OP0 OP1)).
 
 
 
   @param[in] code    The code for the operation.
 
   @param[in] target  Destination for the set operation.
 
   @param[in] op0     First operand.
 
   @param[in] op1     Second operand.                                         */
 
/* -------------------------------------------------------------------------- */
 
static void
 
or32_emit_binary (enum rtx_code  code,
 
                  rtx            target,
 
                  rtx            op0,
 
                  rtx            op1)
 
{
 
  emit_insn (gen_rtx_SET (VOIDmode, target,
 
                          gen_rtx_fmt_ee (code, GET_MODE (target), op0, op1)));
 
 
 
}       /* or32_emit_binary () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Compute the result of an operation into a new register.
 
 
 
   Compute ("code" "op0" "op1") and store the result in a new register of mode
 
   "mode".
 
 
 
   @param[in] mode  Mode of the result
 
   @parma[in] code  RTX for the operation to perform
 
   @param[in] op0   RTX for the first operand
 
   @param[in] op1   RTX for the second operand
 
 
 
   @return  The RTX for the new register.                                     */
 
/* -------------------------------------------------------------------------- */
 
static rtx
 
or32_force_binary (enum machine_mode  mode,
 
                   enum rtx_code      code,
 
                   rtx                op0,
 
                   rtx                op1)
 
{
 
  rtx  reg;
 
 
 
  reg = gen_reg_rtx (mode);
 
  or32_emit_binary (code, reg, op0, op1);
 
 
 
  return reg;
 
 
 
}       /* or32_force_binary () */
 
 
 
 
 
/* ========================================================================== */
 
/* Global support functions                                                   */
 
 
 
/* -------------------------------------------------------------------------- */
 
/* Return the size in bytes of the trampoline code.
 
 
 
   Padded to TRAMPOLINE_ALIGNMENT bits. The code sequence is documented in
 
   or32_trampoline_init ().
 
 
 
   This is just the code size. the static chain pointer and target function
 
   address immediately follow.
 
 
 
   @return  The size of the trampoline code in bytes.                         */
 
/* -------------------------------------------------------------------------- */
 
int
 
or32_trampoline_code_size (void)
 
{
 
  const int  TRAMP_BYTE_ALIGN = TRAMPOLINE_ALIGNMENT / 8;
 
 
 
  /* Five 32-bit code words are needed */
 
  return (5 * 4 + TRAMP_BYTE_ALIGN - 1) / TRAMP_BYTE_ALIGN * TRAMP_BYTE_ALIGN;
 
 
 
}       /* or32_trampoline_code_size () */
 
 
 
 
/* ========================================================================== */
/* ========================================================================== */
/* Functions to support the Machine Description                               */
/* Functions to support the Machine Description                               */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Line 870... Line 985...
  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 "\tl.bnf\t%l0%(";
        return "l.bnf\t%l0%(";
      else
      else
        return "\tl.bf\t%l0%(";
        return "l.bf\t%l0%(";
    }
    }
  else
  else
    {
    {
      if (mode_calc != mode_got)
      if (mode_calc != mode_got)
        return "\t.balignl\t0x8,0x15000015,0x4\n\tl.bnf\t%l0%(";
        return ".balignl\t0x8,0x15000015,0x4\n\tl.bnf\t%l0%(";
      else
      else
        return "\t.balignl 0x8,0x15000015,0x4;\n\tl.bf\t%l0%(";
        return ".balignl 0x8,0x15000015,0x4;\n\tl.bf\t%l0%(";
    }
    }
}       /* or32_output_bf () */
}       /* or32_output_bf () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Line 1688... Line 1803...
 
 
}       /* or32_legitimate_address_p () */
}       /* or32_legitimate_address_p () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
 
/*!Initialize a trampoline for nested functions.
 
 
 
   A nested function is defined by *two* pieces of information, the address of
 
   the function (like any other function) and a pointer to the frame of the
 
   enclosing function. The latter is required to allow the nested function to
 
   access local variables in the enclosing function's frame.
 
 
 
   This represents a problem, since a function in C is represented as an
 
   address that can be held in a single variable as a pointer. Requiring two
 
   pointers will not fit.
 
 
 
   The solution is documented in "Lexical Closures for C++" by Thomas
 
   M. Breuel (USENIX C++ Conference Proceedings, October 17-21, 1988). The
 
   nested function is represented by a small block of code and data on the
 
   enclosing function's stack frame, which sets up a pointer to the enclosing
 
   function's stack frame (the static chain pointer) in a register defined by
 
   the ABI, and then jumps to the code of the function proper.
 
 
 
   The function can be represented as a single pointer to this block of code,
 
   known as a trampoline, which when called generates both pointers
 
   needed. The nested function (which knows it is a nested function at compile
 
   time) can then generate code to access the enclosing frame via the static
 
   chain register.
 
 
 
   There is a catch that the trampoline is set up as data, but executed as
 
   instructions. The former will be via the data cache, the latter via the
 
   instruction cache. There is a risk that a later trampoline will not be seen
 
   by the instruction cache, so the wrong code will be executed. So the
 
   instruction cache should be flushed for the trampoline address range.
 
 
 
   This hook is called to initialize a trampoline. "m_tramp" is an RTX for the
 
   memory block for the trampoline; "fndecl" is the FUNCTION_DECL for the
 
   nested function; "static_chain" is an RTX for the static chain value that
 
   should be passed to the function when it is called.
 
 
 
   If the target defines TARGET_ASM_TRAMPOLINE_TEMPLATE, then the first thing
 
   this hook should do is emit a block move into "m_tramp" from the memory
 
   block returned by assemble_trampoline_template. Note that the block move
 
   need only cover the constant parts of the trampoline. If the target
 
   isolates the variable parts of the trampoline to the end, not all
 
   TRAMPOLINE_SIZE bytes need be copied.
 
 
 
   If the target requires any other actions, such as flushing caches or
 
   enabling stack execution, these actions should be performed after
 
   initializing the trampoline proper.
 
 
 
   For the OR32, no static chain register is used. We choose to use the return
 
   value (rv) register. The rvh register is used as a temporary. The code is
 
   based on that for MIPS. The trampoline code is:
 
 
 
              l.movhi r12,hi(end_addr)
 
              l.ori   r12,lo(end_addr)
 
              l.lwz   r13,4(r12)
 
              l.jr    r13
 
              l.lwz   r11,0(r12)
 
      end_addr:
 
              .word   <static chain>
 
              .word   <nested_function>
 
 
 
   @note For the OR32 we need to flush the instruction cache, which is a
 
         privileged operation. Needs fixing.
 
 
 
   @param[in] m_tramp      The lowest address of the trampoline on the stack.
 
   @param[in] fndecl       Declaration of the enclosing function.
 
   @param[in] chain_value  Static chain pointer to pass to the nested
 
                           function.                                          */
 
/* -------------------------------------------------------------------------- */
 
static void
 
or32_trampoline_init (rtx   m_tramp,
 
                      tree  fndecl,
 
                      rtx   chain_value)
 
{
 
  rtx  addr;                            /* Start address of the trampoline */
 
  rtx  end_addr;                        /* End address of the code block */
 
 
 
  rtx  high;                            /* RTX for the high part of end_addr */
 
  rtx  low;                             /* RTX for the low part of end_addr */
 
  rtx  opcode;                          /* RTX for generated opcodes */
 
  rtx  mem;                             /* RTX for trampoline memory */
 
 
 
  rtx trampoline[5];                    /* The trampoline code */
 
 
 
  unsigned int  i;                      /* Index into trampoline */
 
  unsigned int  j;                      /* General counter */
 
 
 
  HOST_WIDE_INT  end_addr_offset;         /* Offset to end of code */
 
  HOST_WIDE_INT  static_chain_offset;     /* Offset to stack chain word */
 
  HOST_WIDE_INT  target_function_offset;  /* Offset to func address word */
 
 
 
  /* Work out the offsets of the pointers from the start of the trampoline
 
     code.  */
 
  end_addr_offset        = or32_trampoline_code_size ();
 
  static_chain_offset    = end_addr_offset;
 
  target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode);
 
 
 
  /* Get pointers in registers to the beginning and end of the code block.  */
 
  addr     = force_reg (Pmode, XEXP (m_tramp, 0));
 
  end_addr = or32_force_binary (Pmode, PLUS, addr, GEN_INT (end_addr_offset));
 
 
 
  /* Build up the code in TRAMPOLINE.
 
 
 
              l.movhi r12,hi(end_addr)
 
              l.ori   r12,lo(end_addr)
 
              l.lwz   r13,4(r12)
 
              l.jr    r13
 
              l.lwz   r11,0(r12)
 
       end_addr:
 
  */
 
 
 
  i = 0;
 
 
 
  /* Break out the high and low parts of the end_addr */
 
  high = expand_simple_binop (SImode, LSHIFTRT, end_addr, GEN_INT (16),
 
                              NULL, false, OPTAB_WIDEN);
 
  low  = convert_to_mode (SImode, gen_lowpart (HImode, end_addr), true);
 
 
 
  /* Emit the l.movhi, adding an operation to OR in the high bits from the
 
     RTX. */
 
  opcode = gen_int_mode (OR32_MOVHI (12, 0), SImode);
 
  trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, high, NULL,
 
                                         false, OPTAB_WIDEN);
 
 
 
  /* Emit the l.ori, adding an operations to OR in the low bits from the
 
     RTX. */
 
  opcode = gen_int_mode (OR32_ORI (12, 12, 0), SImode);
 
  trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, NULL,
 
                                         false, OPTAB_WIDEN);
 
 
 
  /* Emit the l.lwz of the function address. No bits to OR in here, so we can
 
     do the opcode directly. */
 
  trampoline[i++] =
 
    gen_int_mode (OR32_LWZ (13, 12, target_function_offset - end_addr_offset),
 
                  SImode);
 
 
 
  /* Emit the l.jr of the function. No bits to OR in here, so we can do the
 
     opcode directly. */
 
  trampoline[i++] = gen_int_mode (OR32_JR (13), SImode);
 
 
 
  /* Emit the l.lwz of the static chain. No bits to OR in here, so we can
 
     do the opcode directly. */
 
  trampoline[i++] =
 
    gen_int_mode (OR32_LWZ (STATIC_CHAIN_REGNUM, 12,
 
                            static_chain_offset - end_addr_offset), SImode);
 
 
 
  /* Copy the trampoline code.  Leave any padding uninitialized.  */
 
  for (j = 0; j < i; j++)
 
    {
 
      mem = adjust_address (m_tramp, SImode, j * GET_MODE_SIZE (SImode));
 
      or32_emit_move (mem, trampoline[j]);
 
    }
 
 
 
  /* Set up the static chain pointer field.  */
 
  mem = adjust_address (m_tramp, ptr_mode, static_chain_offset);
 
  or32_emit_move (mem, chain_value);
 
 
 
  /* Set up the target function field.  */
 
  mem = adjust_address (m_tramp, ptr_mode, target_function_offset);
 
  or32_emit_move (mem, XEXP (DECL_RTL (fndecl), 0));
 
 
 
  /* Flushing the trampoline from the instruction cache needs to be done
 
     here. */
 
 
 
}       /* or32_trampoline_init () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
/*!Provide support for DW_AT_calling_convention
/*!Provide support for DW_AT_calling_convention
 
 
   Define this to enable the dwarf attribute DW_AT_calling_convention to be
   Define this to enable the dwarf attribute DW_AT_calling_convention to be
   emitted for each function. Instead of an integer return the enum value for
   emitted for each function. Instead of an integer return the enum value for
   the DW_CC_ tag.
   the DW_CC_ tag.
Line 1775... Line 2056...
#define TARGET_PROMOTE_FUNCTION_MODE or32_promote_function_mode
#define TARGET_PROMOTE_FUNCTION_MODE or32_promote_function_mode
 
 
#undef TARGET_LEGITIMATE_ADDRESS_P
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P  or32_legitimate_address_p
#define TARGET_LEGITIMATE_ADDRESS_P  or32_legitimate_address_p
 
 
 
#undef  TARGET_TRAMPOLINE_INIT
 
#define TARGET_TRAMPOLINE_INIT  or32_trampoline_init
 
 
#undef TARGET_DWARF_CALLING_CONVENTION
#undef TARGET_DWARF_CALLING_CONVENTION
#define TARGET_DWARF_CALLING_CONVENTION  or32_dwarf_calling_convention
#define TARGET_DWARF_CALLING_CONVENTION  or32_dwarf_calling_convention
 
 
/* Trampoline stubs are yet to be written. */
/* Trampoline stubs are yet to be written. */
/* #define TARGET_ASM_TRAMPOLINE_TEMPLATE */
/* #define TARGET_ASM_TRAMPOLINE_TEMPLATE */

powered by: WebSVN 2.1.0

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