Ejemplo n.º 1
0
void
split_quadword_operands (rtx * operands, rtx * low, int n ATTRIBUTE_UNUSED)
{
  int i;
  /* Split operands.  */

  low[0] = low[1] = low[2] = 0;
  for (i = 0; i < 3; i++)
    {
      if (low[i])
	/* it's already been figured out */;
      else if (GET_CODE (operands[i]) == MEM
	       && (GET_CODE (XEXP (operands[i], 0)) == POST_INC))
	{
	  rtx addr = XEXP (operands[i], 0);
	  operands[i] = low[i] = gen_rtx_MEM (SImode, addr);
	  if (which_alternative == 0 && i == 0)
	    {
	      addr = XEXP (operands[i], 0);
	      operands[i+1] = low[i+1] = gen_rtx_MEM (SImode, addr);
	    }
	}
      else
	{
	  low[i] = operand_subword (operands[i], 0, 0, DImode);
	  operands[i] = operand_subword (operands[i], 1, 0, DImode);
	}
    }
}
Ejemplo n.º 2
0
/* Support function to determine the return address of the function
   'count' frames back up the stack. */
rtx
lm32_return_addr_rtx (int count, rtx frame)
{
    rtx r;
    if (count == 0)
    {
        /* *mjs* This test originally used leaf_function_p (), we now use
        the regs_ever_live test which I *think* is more accurate. */
        if (!df_regs_ever_live_p(RA_REGNUM))
        {
            r = gen_rtx_REG (Pmode, RA_REGNUM);
        }
        else
        {
            r = gen_rtx_MEM (Pmode,
                             gen_rtx_PLUS (Pmode, frame,
                                           GEN_INT(- 2 * UNITS_PER_WORD)));
            set_mem_alias_set (r, get_frame_alias_set ());
        }
    }
    else if (flag_omit_frame_pointer)
        r = NULL_RTX;
    else
    {
        r = gen_rtx_MEM (Pmode,
                         gen_rtx_PLUS (Pmode, frame,
                                       GEN_INT(- 2 * UNITS_PER_WORD)));
        set_mem_alias_set (r, get_frame_alias_set ());
    }
    return r;
}
Ejemplo n.º 3
0
static void
nds32_emit_mem_move_block (int base_regno, int count,
			   rtx *dst_base_reg, rtx *dst_mem,
			   rtx *src_base_reg, rtx *src_mem,
			   bool update_base_reg_p)
{
  rtx new_base_reg;

  emit_insn (nds32_expand_load_multiple (base_regno, count,
					 *src_base_reg, *src_mem,
					 update_base_reg_p, &new_base_reg));
  if (update_base_reg_p)
    {
      *src_base_reg = new_base_reg;
      *src_mem = gen_rtx_MEM (SImode, *src_base_reg);
    }

  emit_insn (nds32_expand_store_multiple (base_regno, count,
					  *dst_base_reg, *dst_mem,
					  update_base_reg_p, &new_base_reg));

  if (update_base_reg_p)
    {
      *dst_base_reg = new_base_reg;
      *dst_mem = gen_rtx_MEM (SImode, *dst_base_reg);
    }
}
Ejemplo n.º 4
0
Archivo: lm32.c Proyecto: boomeer/gcc
/* Support function to determine the return address of the function
   'count' frames back up the stack.  */
rtx
lm32_return_addr_rtx (int count, rtx frame)
{
  rtx r;
  if (count == 0)
    {
      if (!df_regs_ever_live_p (RA_REGNUM))
	r = gen_rtx_REG (Pmode, RA_REGNUM);
      else
	{
	  r = gen_rtx_MEM (Pmode,
			   gen_rtx_PLUS (Pmode, frame,
					 GEN_INT (-2 * UNITS_PER_WORD)));
	  set_mem_alias_set (r, get_frame_alias_set ());
	}
    }
  else if (flag_omit_frame_pointer)
    r = NULL_RTX;
  else
    {
      r = gen_rtx_MEM (Pmode,
		       gen_rtx_PLUS (Pmode, frame,
				     GEN_INT (-2 * UNITS_PER_WORD)));
      set_mem_alias_set (r, get_frame_alias_set ());
    }
  return r;
}
Ejemplo n.º 5
0
Archivo: lm32.c Proyecto: boomeer/gcc
/* Generate and emit RTL to save or restore callee save registers.  */
static void
expand_save_restore (struct lm32_frame_info *info, int op)
{
  unsigned int reg_save_mask = info->reg_save_mask;
  int regno;
  HOST_WIDE_INT offset;
  rtx insn;

  /* Callee saves are below locals and above outgoing arguments.  */
  offset = info->args_size + info->callee_size;
  for (regno = 0; regno <= 31; regno++)
    {
      if ((reg_save_mask & (1 << regno)) != 0)
	{
	  rtx offset_rtx;
	  rtx mem;
	  
	  offset_rtx = GEN_INT (offset);
	  if (satisfies_constraint_K (offset_rtx))
	    {	
              mem = gen_rtx_MEM (word_mode,
                                 gen_rtx_PLUS (Pmode,
                                               stack_pointer_rtx,
                                               offset_rtx));
            }
          else
            {
              /* r10 is caller saved so it can be used as a temp reg.  */
              rtx r10;        
               
              r10 = gen_rtx_REG (word_mode, 10);
              insn = emit_move_insn (r10, offset_rtx);
              if (op == 0)
                RTX_FRAME_RELATED_P (insn) = 1;
              insn = emit_add (r10, r10, stack_pointer_rtx);
              if (op == 0)
                RTX_FRAME_RELATED_P (insn) = 1;                
              mem = gen_rtx_MEM (word_mode, r10);
            }                                                 	    
	    	    
	  if (op == 0)
	    insn = emit_move_insn (mem, gen_rtx_REG (word_mode, regno));
	  else
	    insn = emit_move_insn (gen_rtx_REG (word_mode, regno), mem);
        
	  /* only prologue instructions which set the sp fp or save a
	     register should be marked as frame related.  */
	  if (op == 0)
	    RTX_FRAME_RELATED_P (insn) = 1;
	  offset -= UNITS_PER_WORD;
	}
    }
}
Ejemplo n.º 6
0
static void
moxie_setup_incoming_varargs (cumulative_args_t cum_v,
			      machine_mode mode ATTRIBUTE_UNUSED,
			      tree type ATTRIBUTE_UNUSED,
			      int *pretend_size, int no_rtl)
{
  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
  int regno;
  int regs = 8 - *cum;
  
  *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
  
  if (no_rtl)
    return;
  
  for (regno = *cum; regno < 8; regno++)
    {
      rtx reg = gen_rtx_REG (SImode, regno);
      rtx slot = gen_rtx_PLUS (Pmode,
			       gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
			       GEN_INT (UNITS_PER_WORD * (3 + (regno-2))));
      
      emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
    }
}
Ejemplo n.º 7
0
rtx
nds32_expand_store_multiple (int base_regno, int count,
			     rtx base_addr, rtx basemem,
			     bool update_base_reg_p,
			     rtx *update_base_reg)
{
  int par_index;
  int offset;
  int start_idx;
  rtx result;
  rtx new_addr, mem, reg;

  if (count == 1)
    {
      reg = gen_rtx_REG (SImode, base_regno);
      if (update_base_reg_p)
	{
	  *update_base_reg = gen_reg_rtx (SImode);
	  return gen_unaligned_store_update_base_w (*update_base_reg, base_addr, reg);
	}
      else
	return gen_unaligned_store_w (gen_rtx_MEM (SImode, base_addr), reg);
    }

  /* Create the pattern that is presented in nds32-multiple.md.  */

  if (update_base_reg_p)
    {
      result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
      start_idx = 1;
    }
  else
    {
      result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
      start_idx = 0;
    }

  if (update_base_reg_p)
    {
      offset           = count * 4;
      new_addr         = plus_constant (Pmode, base_addr, offset);
      *update_base_reg = gen_reg_rtx (SImode);

      XVECEXP (result, 0, 0) = gen_rtx_SET (*update_base_reg, new_addr);
    }

  for (par_index = 0; par_index < count; par_index++)
    {
      offset   = par_index * 4;
      /* 4-byte for storing data to memory.  */
      new_addr = plus_constant (Pmode, base_addr, offset);
      mem      = adjust_automodify_address_nv (basemem, SImode,
					       new_addr, offset);
      reg      = gen_rtx_REG (SImode, base_regno + par_index);

      XVECEXP (result, 0, par_index + start_idx) = gen_rtx_SET (mem, reg);
    }

  return result;
}
Ejemplo n.º 8
0
static void
i386_pe_mark_dllimport (tree decl)
{
  const char *oldname;
  char  *newname;
  tree idp;
  rtx rtlname, newrtl;
  rtx symref;

  rtlname = XEXP (DECL_RTL (decl), 0);
  if (GET_CODE (rtlname) == SYMBOL_REF)
    oldname = XSTR (rtlname, 0);
  else if (GET_CODE (rtlname) == MEM
	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
    oldname = XSTR (XEXP (rtlname, 0), 0);
  else
    abort ();
  if (i386_pe_dllexport_name_p (oldname))
    {
      error ("%qs declared as both exported to and imported from a DLL",
             IDENTIFIER_POINTER (DECL_NAME (decl)));
      return;
    }
  else if (i386_pe_dllimport_name_p (oldname))
    {
      /* Already done, but do a sanity check to prevent assembler errors.  */
 /* APPLE LOCAL begin mainline 2005-10-12 */
      if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)
          || !DECL_DLLIMPORT_P (decl))
        {
          error ("%Jfailure in redeclaration of '%D': dllimport'd "
                 "symbol lacks external linkage.", decl, decl);
          abort();
        }
 /* APPLE LOCAL end mainline 2005-10-12 */
      return;
    }

  newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
  sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);

  /* We pass newname through get_identifier to ensure it has a unique
     address.  RTL processing can sometimes peek inside the symbol ref
     and compare the string's addresses to see if two symbols are
     identical.  */
  idp = get_identifier (newname);

  symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
  SYMBOL_REF_DECL (symref) = decl;
  newrtl = gen_rtx_MEM (Pmode,symref);
  XEXP (DECL_RTL (decl), 0) = newrtl;

 /* APPLE LOCAL begin mainline 2005-10-12 */
  DECL_DLLIMPORT_P (decl) = 1;
 /* APPLE LOCAL end mainline 2005-10-12 */
}
Ejemplo n.º 9
0
static void
nds32_emit_post_inc_load_store (rtx reg, rtx base_reg,
				enum machine_mode mode,
				bool load_p)
{
  gcc_assert (GET_MODE (reg) == mode);
  gcc_assert (GET_MODE (base_reg) == Pmode);

  /* Do not gen (set (reg) (mem (post_inc (reg)))) directly here since it may
     not recognize by gcc, so let gcc combine it at auto_inc_dec pass.  */
  if (load_p)
    emit_move_insn (reg,
		    gen_rtx_MEM (mode,
				 base_reg));
  else
    emit_move_insn (gen_rtx_MEM (mode,
				 base_reg),
		    reg);

  emit_move_insn (base_reg,
		  plus_constant(Pmode, base_reg, GET_MODE_SIZE (mode)));
}
Ejemplo n.º 10
0
/* Generate and emit RTL to save or restore callee save registers */
static void
expand_save_restore (struct lm32_frame_info *info, int op)
{
    unsigned int reg_save_mask = info->reg_save_mask;
    int regno;
    HOST_WIDE_INT offset;
    rtx insn;

    /* Callee saves are below locals and above outgoing arguments */
    offset = info->args_size + info->callee_size;
    for (regno = 0; regno <= 31; regno++)
    {
        if ((reg_save_mask & (1 << regno)) != 0)
        {
            if (op == 0)
            {
                insn = emit_move_insn (gen_rtx_MEM (word_mode,
                                                    gen_rtx_PLUS (Pmode,
                                                            stack_pointer_rtx,
                                                            GEN_INT (offset))),
                                       gen_rtx_REG (word_mode, regno));
            }
            else
            {
                insn = emit_move_insn (gen_rtx_REG (word_mode, regno),
                                       gen_rtx_MEM (word_mode,
                                                    gen_rtx_PLUS (Pmode,
                                                            stack_pointer_rtx,
                                                            GEN_INT (offset))));
            }

            /* only prologue instructions which set the sp fp or save a
               register should be marked as frame related */
            if (op==0)
                RTX_FRAME_RELATED_P (insn) = 1;
            offset -= UNITS_PER_WORD;
        }
    }
}
Ejemplo n.º 11
0
static rtx
moxie_static_chain (const_tree ARG_UNUSED (fndecl_or_type), bool incoming_p)
{
  rtx addr, mem;

  if (incoming_p)
    addr = plus_constant (Pmode, arg_pointer_rtx, 2 * UNITS_PER_WORD);
  else
    addr = plus_constant (Pmode, stack_pointer_rtx, -UNITS_PER_WORD);

  mem = gen_rtx_MEM (Pmode, addr);
  MEM_NOTRAP_P (mem) = 1;

  return mem;
}
Ejemplo n.º 12
0
static void
expand_one_error_var (tree var)
{
  enum machine_mode mode = DECL_MODE (var);
  rtx x;

  if (mode == BLKmode)
    x = gen_rtx_MEM (BLKmode, const0_rtx);
  else if (mode == VOIDmode)
    x = const0_rtx;
  else
    x = gen_reg_rtx (mode);

  SET_DECL_RTL (var, x);
}
Ejemplo n.º 13
0
static void
lm32_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                             tree type, int *pretend_size, int no_rtl)
{
    int first_anon_arg;
    tree fntype;
    int stdarg_p;

    fntype = TREE_TYPE (current_function_decl);
    stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
                && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
                    != void_type_node));

    if (stdarg_p)
        first_anon_arg = *cum + LM32_FIRST_ARG_REG;
    else
    {
        /* this is the common case, we have been passed details setup
           for the last named argument, we want to skip over the
           registers, if any used in passing this named paramter in
           order to determine which is the first registers used to pass
           anonymous arguments */
        int size;

        if (mode==BLKmode)
            size = int_size_in_bytes (type);
        else
            size = GET_MODE_SIZE (mode);

        first_anon_arg = *cum + LM32_FIRST_ARG_REG + ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
    }

    if ((first_anon_arg < (LM32_FIRST_ARG_REG + LM32_NUM_ARG_REGS)) && !no_rtl)
    {
        int first_reg_offset = first_anon_arg;
        int size = LM32_FIRST_ARG_REG + LM32_NUM_ARG_REGS - first_anon_arg;
        rtx regblock;

        regblock = gen_rtx_MEM (BLKmode,
                                plus_constant (arg_pointer_rtx,
                                               FIRST_PARM_OFFSET (0)));
        move_block_from_reg (first_reg_offset, regblock, size);

        *pretend_size = size * UNITS_PER_WORD;
    }
}
Ejemplo n.º 14
0
static void
i386_pe_mark_dllimport (tree decl)
{
    const char *oldname;
    char  *newname;
    tree idp;
    rtx rtlname, newrtl;
    rtx symref;

    rtlname = XEXP (DECL_RTL (decl), 0);
    if (GET_CODE (rtlname) == MEM)
        rtlname = XEXP (rtlname, 0);
    gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
    oldname = XSTR (rtlname, 0);
    if (i386_pe_dllexport_name_p (oldname))
    {
        error ("%qs declared as both exported to and imported from a DLL",
               IDENTIFIER_POINTER (DECL_NAME (decl)));
        return;
    }
    else if (i386_pe_dllimport_name_p (oldname))
    {
        /* Already done, but do a sanity check to prevent assembler
        errors.  */
        gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)
                    && DECL_DLLIMPORT_P (decl));
        return;
    }

    newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
    sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);

    /* We pass newname through get_identifier to ensure it has a unique
       address.  RTL processing can sometimes peek inside the symbol ref
       and compare the string's addresses to see if two symbols are
       identical.  */
    idp = get_identifier (newname);

    symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
    SET_SYMBOL_REF_DECL (symref, decl);
    newrtl = gen_rtx_MEM (Pmode,symref);
    XEXP (DECL_RTL (decl), 0) = newrtl;

    DECL_DLLIMPORT_P (decl) = 1;
}
Ejemplo n.º 15
0
static rtx
moxie_static_chain (const_tree fndecl, bool incoming_p)
{
    rtx addr, mem;

    if (!DECL_STATIC_CHAIN (fndecl))
        return NULL;

    if (incoming_p)
        addr = plus_constant (arg_pointer_rtx, 2 * UNITS_PER_WORD);
    else
        addr = plus_constant (stack_pointer_rtx, -UNITS_PER_WORD);

    mem = gen_rtx_MEM (Pmode, addr);
    MEM_NOTRAP_P (mem) = 1;

    return mem;
}
Ejemplo n.º 16
0
static void
expand_one_stack_var_at (tree decl, HOST_WIDE_INT offset)
{
  HOST_WIDE_INT align;
  rtx x;
  
  /* If this fails, we've overflowed the stack frame.  Error nicely?  */
  gcc_assert (offset == trunc_int_for_mode (offset, Pmode));

  x = plus_constant (virtual_stack_vars_rtx, offset);
  x = gen_rtx_MEM (DECL_MODE (decl), x);

  /* Set alignment we actually gave this decl.  */
  offset -= frame_phase;
  align = offset & -offset;
  align *= BITS_PER_UNIT;
  if (align > STACK_BOUNDARY || align == 0)
    align = STACK_BOUNDARY;
  DECL_ALIGN (decl) = align;
  DECL_USER_ALIGN (decl) = 0;

  set_mem_attributes (x, decl, true);
  SET_DECL_RTL (decl, x);
}
Ejemplo n.º 17
0
static bool
nds32_expand_movmemsi_unroll (rtx dstmem, rtx srcmem,
			      rtx total_bytes, rtx alignment)
{
  rtx dst_base_reg, src_base_reg;
  rtx tmp_reg;
  int maximum_bytes;
  int maximum_bytes_per_inst;
  int maximum_regs;
  int start_regno;
  int i, inst_num;
  HOST_WIDE_INT remain_bytes, remain_words;
  bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0;
  bool align_to_2_bytes = (INTVAL (alignment) & 1) == 0;

  /* Because reduced-set regsiters has few registers
     (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31'
      cannot be used for register allocation),
     using 8 registers (32 bytes) for moving memory block
     may easily consume all of them.
     It makes register allocation/spilling hard to work.
     So we only allow maximum=4 registers (16 bytes) for
     moving memory block under reduced-set registers.  */
  if (TARGET_REDUCED_REGS)
    {
      maximum_regs  = 4;
      maximum_bytes = 64;
      start_regno   = 2;
    }
  else
    {
      /* $r25 is $tp so we use up to 8 registers.  */
      maximum_regs  = 8;
      maximum_bytes = 160;
      start_regno   = 16;
    }
  maximum_bytes_per_inst = maximum_regs * UNITS_PER_WORD;

  /* 1. Total_bytes is integer for sure.
     2. Alignment is integer for sure.
     3. Maximum 4 or 10 registers and up to 4 instructions,
	4 * 4 * 4 = 64 bytes, 8 * 4 * 10 = 160 bytes.
     4. The dstmem cannot be volatile memory access.
     5. The srcmem cannot be volatile memory access.
     6. Known shared alignment not align to 4 byte in v3m since lmw/smw *NOT*
	support unalign access with v3m configure.  */
  if (GET_CODE (total_bytes) != CONST_INT
      || GET_CODE (alignment) != CONST_INT
      || INTVAL (total_bytes) > maximum_bytes
      || MEM_VOLATILE_P (dstmem)
      || MEM_VOLATILE_P (srcmem)
      || (TARGET_ISA_V3M && !align_to_4_bytes))
    return false;

  dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0));
  src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0));
  remain_bytes = INTVAL (total_bytes);

  /* Do not update base address for last lmw/smw pair.  */
  inst_num = ((INTVAL (total_bytes) + (maximum_bytes_per_inst - 1))
	      / maximum_bytes_per_inst) - 1;

  for (i = 0; i < inst_num; i++)
    {
      nds32_emit_mem_move_block (start_regno, maximum_regs,
				 &dst_base_reg, &dstmem,
				 &src_base_reg, &srcmem,
				 true);
    }
  remain_bytes -= maximum_bytes_per_inst * inst_num;

  remain_words = remain_bytes / UNITS_PER_WORD;
  remain_bytes = remain_bytes - (remain_words * UNITS_PER_WORD);

  if (remain_words != 0)
    {
      if (remain_bytes != 0)
	nds32_emit_mem_move_block (start_regno, remain_words,
				   &dst_base_reg, &dstmem,
				   &src_base_reg, &srcmem,
				   true);
      else
	{
	  /* Do not update address if no further byte to move.  */
	  if (remain_words == 1)
	   {
	      /* emit move instruction if align to 4 byte and only 1
		 word to move.  */
	      if (align_to_4_bytes)
		nds32_emit_mem_move (srcmem, dstmem, SImode, 0);
	      else
		{
		  tmp_reg = gen_reg_rtx (SImode);
		  emit_insn (
		    gen_unaligned_load_w (tmp_reg,
					  gen_rtx_MEM (SImode, src_base_reg)));
		  emit_insn (
		    gen_unaligned_store_w (gen_rtx_MEM (SImode, dst_base_reg),
					   tmp_reg));
		}
	    }
	  else
	    nds32_emit_mem_move_block (start_regno, remain_words,
				       &dst_base_reg, &dstmem,
				       &src_base_reg, &srcmem,
				       false);
	}
    }

  switch (remain_bytes)
    {
    case 3:
    case 2:
      {
	if (align_to_2_bytes)
	  nds32_emit_mem_move (srcmem, dstmem, HImode, 0);
	else
	  {
	    nds32_emit_mem_move (srcmem, dstmem, QImode, 0);
	    nds32_emit_mem_move (srcmem, dstmem, QImode, 1);
	  }

	if (remain_bytes == 3)
	  nds32_emit_mem_move (srcmem, dstmem, QImode, 2);
	break;
      }
    case 1:
      nds32_emit_mem_move (srcmem, dstmem, QImode, 0);
      break;
    case 0:
      break;
    default:
      gcc_unreachable ();
    }

  /* Successfully create patterns, return true.  */
  return true;
}
Ejemplo n.º 18
0
static bool
nds32_expand_setmem_unroll (rtx dstmem, rtx size, rtx value,
			    rtx align ATTRIBUTE_UNUSED,
			    rtx expected_align ATTRIBUTE_UNUSED,
			    rtx expected_size ATTRIBUTE_UNUSED)
{
  unsigned maximum_regs, maximum_bytes, start_regno, regno;
  rtx value4word;
  rtx dst_base_reg, new_base_reg;
  unsigned HOST_WIDE_INT remain_bytes, remain_words, prepare_regs, fill_per_smw;
  unsigned HOST_WIDE_INT real_size;

  if (TARGET_REDUCED_REGS)
    {
      maximum_regs  = 4;
      maximum_bytes = 64;
      start_regno   = 2;
    }
  else
    {
      maximum_regs  = 8;
      maximum_bytes = 128;
      start_regno   = 16;
    }

  real_size = UINTVAL (size) & GET_MODE_MASK(SImode);

  if (!(CONST_INT_P (size) && real_size <= maximum_bytes))
    return false;

  remain_bytes = real_size;

  gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value));

  value4word = nds32_gen_dup_4_byte_to_word_value (value);

  prepare_regs = remain_bytes / UNITS_PER_WORD;

  dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0));

  if (prepare_regs > maximum_regs)
    prepare_regs = maximum_regs;

  fill_per_smw = prepare_regs * UNITS_PER_WORD;

  regno = start_regno;
  switch (prepare_regs)
    {
    case 2:
    default:
      {
	rtx reg0 = gen_rtx_REG (SImode, regno);
	rtx reg1 = gen_rtx_REG (SImode, regno+1);
	unsigned last_regno = start_regno + prepare_regs - 1;

	emit_move_insn (reg0, value4word);
	emit_move_insn (reg1, value4word);
	rtx regd = gen_rtx_REG (DImode, regno);
	regno += 2;

	/* Try to utilize movd44!  */
	while (regno <= last_regno)
	  {
	    if ((regno + 1) <=last_regno)
	      {
		rtx reg = gen_rtx_REG (DImode, regno);
		emit_move_insn (reg, regd);
		regno += 2;
	      }
	    else
	      {
		rtx reg = gen_rtx_REG (SImode, regno);
		emit_move_insn (reg, reg0);
		regno += 1;
	      }
	  }
	break;
      }
    case 1:
      {
	rtx reg = gen_rtx_REG (SImode, regno++);
	emit_move_insn (reg, value4word);
      }
      break;
    case 0:
      break;
    }

  if (fill_per_smw)
    for (;remain_bytes >= fill_per_smw;remain_bytes -= fill_per_smw)
      {
	emit_insn (nds32_expand_store_multiple (start_regno, prepare_regs,
						dst_base_reg, dstmem,
						true, &new_base_reg));
	dst_base_reg = new_base_reg;
	dstmem = gen_rtx_MEM (SImode, dst_base_reg);
      }

  remain_words = remain_bytes / UNITS_PER_WORD;

  if (remain_words)
    {
      emit_insn (nds32_expand_store_multiple (start_regno, remain_words,
					      dst_base_reg, dstmem,
					      true, &new_base_reg));
      dst_base_reg = new_base_reg;
      dstmem = gen_rtx_MEM (SImode, dst_base_reg);
    }

  remain_bytes = remain_bytes - (remain_words * UNITS_PER_WORD);

  if (remain_bytes)
    {
      value = simplify_gen_subreg (QImode, value4word, SImode,
				   subreg_lowpart_offset(QImode, SImode));
      int offset = 0;
      for (;remain_bytes;--remain_bytes, ++offset)
	{
	  nds32_emit_load_store (value, dstmem, QImode, offset, false);
	}
    }

  return true;
}
Ejemplo n.º 19
0
rtx
fr30_move_double (rtx * operands)
{
  rtx src  = operands[1];
  rtx dest = operands[0];
  enum rtx_code src_code = GET_CODE (src);
  enum rtx_code dest_code = GET_CODE (dest);
  enum machine_mode mode = GET_MODE (dest);
  rtx val;

  start_sequence ();

  if (dest_code == REG)
    {
      if (src_code == REG)
	{
	  int reverse = (REGNO (dest) == REGNO (src) + 1);
	  
	  /* We normally copy the low-numbered register first.  However, if
	     the first register of operand 0 is the same as the second register
	     of operand 1, we must copy in the opposite order.  */
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, reverse, TRUE, mode),
				  operand_subword (src,  reverse, TRUE, mode)));
	  
	  emit_insn (gen_rtx_SET (VOIDmode,
			      operand_subword (dest, !reverse, TRUE, mode),
			      operand_subword (src,  !reverse, TRUE, mode)));
	}
      else if (src_code == MEM)
	{
	  rtx addr = XEXP (src, 0);
	  int dregno = REGNO (dest);
	  rtx dest0 = operand_subword (dest, 0, TRUE, mode);;
	  rtx dest1 = operand_subword (dest, 1, TRUE, mode);;
	  rtx new_mem;
	  
	  gcc_assert (GET_CODE (addr) == REG);
	  
	  /* Copy the address before clobbering it.  See PR 34174.  */
	  emit_insn (gen_rtx_SET (SImode, dest1, addr));
	  emit_insn (gen_rtx_SET (VOIDmode, dest0,
				  adjust_address (src, SImode, 0)));
	  emit_insn (gen_rtx_SET (SImode, dest1,
				  plus_constant (dest1, UNITS_PER_WORD)));

	  new_mem = gen_rtx_MEM (SImode, dest1);
	  MEM_COPY_ATTRIBUTES (new_mem, src);
	      
	  emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
	}
      else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
	{
	  rtx words[2];
	  split_double (src, &words[0], &words[1]);
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 0, TRUE, mode),
				  words[0]));
      
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 1, TRUE, mode),
				  words[1]));
	}
    }
  else if (src_code == REG && dest_code == MEM)
    {
      rtx addr = XEXP (dest, 0);
      rtx src0;
      rtx src1;

      gcc_assert (GET_CODE (addr) == REG);

      src0 = operand_subword (src, 0, TRUE, mode);
      src1 = operand_subword (src, 1, TRUE, mode);

      emit_move_insn (adjust_address (dest, SImode, 0), src0);

      if (REGNO (addr) == STACK_POINTER_REGNUM
	  || REGNO (addr) == FRAME_POINTER_REGNUM)
	emit_insn (gen_rtx_SET (VOIDmode,
				adjust_address (dest, SImode, UNITS_PER_WORD),
				src1));
      else
	{
	  rtx new_mem;
	  rtx scratch_reg_r0 = gen_rtx_REG (SImode, 0);

	  /* We need a scratch register to hold the value of 'address + 4'.
	     We use r0 for this purpose. It is used for example for long
	     jumps and is already marked to not be used by normal register
	     allocation.  */
	  emit_insn (gen_movsi_internal (scratch_reg_r0, addr));
	  emit_insn (gen_addsi_small_int (scratch_reg_r0, scratch_reg_r0,
					  GEN_INT (UNITS_PER_WORD)));
	  new_mem = gen_rtx_MEM (SImode, scratch_reg_r0);
	  MEM_COPY_ATTRIBUTES (new_mem, dest);
	  emit_move_insn (new_mem, src1);
	  emit_insn (gen_blockage ());
	}
    }
  else
    /* This should have been prevented by the constraints on movdi_insn.  */
    gcc_unreachable ();

  val = get_insns ();
  end_sequence ();

  return val;
}
Ejemplo n.º 20
0
rtx
fr30_move_double (rtx * operands)
{
  rtx src  = operands[1];
  rtx dest = operands[0];
  enum rtx_code src_code = GET_CODE (src);
  enum rtx_code dest_code = GET_CODE (dest);
  enum machine_mode mode = GET_MODE (dest);
  rtx val;

  start_sequence ();

  if (dest_code == REG)
    {
      if (src_code == REG)
	{
	  int reverse = (REGNO (dest) == REGNO (src) + 1);
	  
	  /* We normally copy the low-numbered register first.  However, if
	     the first register of operand 0 is the same as the second register
	     of operand 1, we must copy in the opposite order.  */
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, reverse, TRUE, mode),
				  operand_subword (src,  reverse, TRUE, mode)));
	  
	  emit_insn (gen_rtx_SET (VOIDmode,
			      operand_subword (dest, !reverse, TRUE, mode),
			      operand_subword (src,  !reverse, TRUE, mode)));
	}
      else if (src_code == MEM)
	{
	  rtx addr = XEXP (src, 0);
	  int dregno = REGNO (dest);
	  rtx dest0;
	  rtx dest1;
	  rtx new_mem;
	  
	  /* If the high-address word is used in the address, we
	     must load it last.  Otherwise, load it first.  */
	  int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0);

	  gcc_assert (GET_CODE (addr) == REG);
	  
	  dest0 = operand_subword (dest, reverse, TRUE, mode);
	  dest1 = operand_subword (dest, !reverse, TRUE, mode);

	  if (reverse)
	    {
	      emit_insn (gen_rtx_SET (VOIDmode, dest1,
				      adjust_address (src, SImode, 0)));
	      emit_insn (gen_rtx_SET (SImode, dest0,
				      gen_rtx_REG (SImode, REGNO (addr))));
	      emit_insn (gen_rtx_SET (SImode, dest0,
				      plus_constant (dest0, UNITS_PER_WORD)));

	      new_mem = gen_rtx_MEM (SImode, dest0);
	      MEM_COPY_ATTRIBUTES (new_mem, src);
	      
	      emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
	    }
	  else
	    {
	      emit_insn (gen_rtx_SET (VOIDmode, dest0,
				      adjust_address (src, SImode, 0)));
	      emit_insn (gen_rtx_SET (SImode, dest1,
				      gen_rtx_REG (SImode, REGNO (addr))));
	      emit_insn (gen_rtx_SET (SImode, dest1,
				      plus_constant (dest1, UNITS_PER_WORD)));

	      new_mem = gen_rtx_MEM (SImode, dest1);
	      MEM_COPY_ATTRIBUTES (new_mem, src);
	      
	      emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
	    }
	}
      else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
	{
	  rtx words[2];
	  split_double (src, &words[0], &words[1]);
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 0, TRUE, mode),
				  words[0]));
      
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 1, TRUE, mode),
				  words[1]));
	}
    }
  else if (src_code == REG && dest_code == MEM)
    {
      rtx addr = XEXP (dest, 0);
      rtx src0;
      rtx src1;

      gcc_assert (GET_CODE (addr) == REG);
      
      src0 = operand_subword (src, 0, TRUE, mode);
      src1 = operand_subword (src, 1, TRUE, mode);
      
      emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0),
			      src0));

      if (REGNO (addr) == STACK_POINTER_REGNUM
	  || REGNO (addr) == FRAME_POINTER_REGNUM)
	emit_insn (gen_rtx_SET (VOIDmode,
				adjust_address (dest, SImode, UNITS_PER_WORD),
				src1));
      else
	{
	  rtx new_mem;
	  
	  /* We need a scratch register to hold the value of 'address + 4'.
	     We ought to allow gcc to find one for us, but for now, just
	     push one of the source registers.  */
	  emit_insn (gen_movsi_push (src0));
	  emit_insn (gen_movsi_internal (src0, addr));
	  emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD)));
	  
	  new_mem = gen_rtx_MEM (SImode, src0);
	  MEM_COPY_ATTRIBUTES (new_mem, dest);
	  
	  emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
	  emit_insn (gen_movsi_pop (src0));
	}
    }
  else
    /* This should have been prevented by the constraints on movdi_insn.  */
    gcc_unreachable ();
  
  val = get_insns ();
  end_sequence ();

  return val;
}
Ejemplo n.º 21
0
void
init_caller_save ()
{
  char *first_obj = (char *) oballoc (0);
  rtx addr_reg;
  int offset;
  rtx address;
  int i, j;

  /* First find all the registers that we need to deal with and all
     the modes that they can have.  If we can't find a mode to use,
     we can't have the register live over calls.  */

  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    {
      if (call_used_regs[i] && ! call_fixed_regs[i])
	{
	  for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
	    {
	      regno_save_mode[i][j] = choose_hard_reg_mode (i, j);
	      if (regno_save_mode[i][j] == VOIDmode && j == 1)
		{
		  call_fixed_regs[i] = 1;
		  SET_HARD_REG_BIT (call_fixed_reg_set, i);
		}
	    }
	}
      else
	regno_save_mode[i][1] = VOIDmode;
    }

  /* The following code tries to approximate the conditions under which
     we can easily save and restore a register without scratch registers or
     other complexities.  It will usually work, except under conditions where
     the validity of an insn operand is dependent on the address offset.
     No such cases are currently known.

     We first find a typical offset from some BASE_REG_CLASS register.
     This address is chosen by finding the first register in the class
     and by finding the smallest power of two that is a valid offset from
     that register in every mode we will use to save registers.  */

  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    if (TEST_HARD_REG_BIT (reg_class_contents[(int) BASE_REG_CLASS], i))
      break;

  if (i == FIRST_PSEUDO_REGISTER)
    abort ();

  addr_reg = gen_rtx_REG (Pmode, i);

  for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1)
    {
      address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset));

      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
	if (regno_save_mode[i][1] != VOIDmode
	  && ! strict_memory_address_p (regno_save_mode[i][1], address))
	  break;

      if (i == FIRST_PSEUDO_REGISTER)
	break;
    }

  /* If we didn't find a valid address, we must use register indirect.  */
  if (offset == 0)
    address = addr_reg;

  /* Next we try to form an insn to save and restore the register.  We
     see if such an insn is recognized and meets its constraints.  */

  start_sequence ();

  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
      if (regno_save_mode[i][j] != VOIDmode)
        {
	  rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
	  rtx reg = gen_rtx_REG (regno_save_mode[i][j], i);
	  rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
	  rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
	  rtx saveinsn = emit_insn (savepat);
	  rtx restinsn = emit_insn (restpat);
	  int ok;

	  reg_save_code[i][j] = recog_memoized (saveinsn);
	  reg_restore_code[i][j] = recog_memoized (restinsn);

	  /* Now extract both insns and see if we can meet their
             constraints.  */
	  ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1);
	  if (ok)
	    {
	      insn_extract (saveinsn);
	      ok = constrain_operands (reg_save_code[i][j], 1);
	      insn_extract (restinsn);
	      ok &= constrain_operands (reg_restore_code[i][j], 1);
	    }

	  if (! ok)
	    {
	      regno_save_mode[i][j] = VOIDmode;
	      if (j == 1)
		{
		  call_fixed_regs[i] = 1;
		  SET_HARD_REG_BIT (call_fixed_reg_set, i);
		}
	    }
      }

  end_sequence ();

  obfree (first_obj);
}
Ejemplo n.º 22
0
void
expand_builtin_cilk_detach (tree exp)
{
  rtx_insn *insn;
  tree fptr = get_frame_arg (exp);

  if (fptr == NULL_TREE)
    return;

  tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
  tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
  tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);

  rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
  if (GET_CODE (wreg) != REG)
    wreg = copy_to_reg (wreg);
  rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);

  /* TMP <- WORKER.TAIL
    *TMP <- PARENT
     TMP <- TMP + 1
     WORKER.TAIL <- TMP   */

  HOST_WIDE_INT worker_tail_offset =
    tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
    tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
    BITS_PER_UNIT;
  rtx tmem0 = gen_rtx_MEM (Pmode,
			   plus_constant (Pmode, wreg, worker_tail_offset));
  set_mem_attributes (tmem0, tail, 0);
  MEM_NOTRAP_P (tmem0) = 1;
  gcc_assert (MEM_VOLATILE_P (tmem0));
  rtx treg = copy_to_mode_reg (Pmode, tmem0);
  rtx tmem1 = gen_rtx_MEM (Pmode, treg);
  set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
  MEM_NOTRAP_P (tmem1) = 1;
  emit_move_insn (tmem1, preg);
  emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));

  /* There is a release barrier (st8.rel, membar #StoreStore,
     sfence, lwsync, etc.) between the two stores.  On x86
     normal volatile stores have proper semantics; the sfence
     would only be needed for nontemporal stores (which we
     could generate using the storent optab, for no benefit
     in this case).

     The predicate may return false even for a REG if this is
     the limited release operation that only stores 0.  */
  enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode); 
  if (icode != CODE_FOR_nothing
      && insn_data[icode].operand[1].predicate (treg, Pmode)
      && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
    emit_insn (insn);
  else
    emit_move_insn (tmem0, treg);

  /* The memory barrier inserted above should not prevent
     the load of flags from being moved before the stores,
     but in practice it does because it is implemented with
     unspec_volatile.  In-order RISC machines should
     explicitly load flags earlier.  */

  tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
  expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
		       build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
			       build_int_cst (TREE_TYPE (flags),
					      CILK_FRAME_DETACHED))),
	       const0_rtx, VOIDmode, EXPAND_NORMAL);
}
Ejemplo n.º 23
0
/* Functions to expand load_multiple and store_multiple.
   They are auxiliary extern functions to help create rtx template.
   Check nds32-multiple.md file for the patterns.  */
rtx
nds32_expand_load_multiple (int base_regno, int count,
			    rtx base_addr, rtx basemem,
			    bool update_base_reg_p,
			    rtx *update_base_reg)
{
  int par_index;
  int offset;
  int start_idx;
  rtx result;
  rtx new_addr, mem, reg;

  /* Generate a unaligned load to prevent load instruction pull out from
     parallel, and then it will generate lwi, and lose unaligned acces */
  if (count == 1)
    {
      reg = gen_rtx_REG (SImode, base_regno);
      if (update_base_reg_p)
	{
	  *update_base_reg = gen_reg_rtx (SImode);
	  return gen_unaligned_load_update_base_w (*update_base_reg, reg, base_addr);
	}
      else
	return gen_unaligned_load_w (reg, gen_rtx_MEM (SImode, base_addr));
    }

  /* Create the pattern that is presented in nds32-multiple.md.  */
  if (update_base_reg_p)
    {
      result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
      start_idx = 1;
    }
  else
    {
      result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
      start_idx = 0;
    }

  if (update_base_reg_p)
    {
      offset           = count * 4;
      new_addr         = plus_constant (Pmode, base_addr, offset);
      *update_base_reg = gen_reg_rtx (SImode);

      XVECEXP (result, 0, 0) = gen_rtx_SET (*update_base_reg, new_addr);
    }

  for (par_index = 0; par_index < count; par_index++)
    {
      offset   = par_index * 4;
      /* 4-byte for loading data to each register.  */
      new_addr = plus_constant (Pmode, base_addr, offset);
      mem      = adjust_automodify_address_nv (basemem, SImode,
					       new_addr, offset);
      reg      = gen_rtx_REG (SImode, base_regno + par_index);

      XVECEXP (result, 0, (par_index + start_idx)) = gen_rtx_SET (reg, mem);
    }

  return result;
}