Пример #1
0
static void
nds32_emit_mem_move (rtx src, rtx dst,
		     enum machine_mode mode,
		     int addr_offset)
{
  gcc_assert (MEM_P (src) && MEM_P (dst));
  rtx tmp_reg = gen_reg_rtx (mode);
  nds32_emit_load_store (tmp_reg, src, mode,
			 addr_offset, /* load_p */ true);
  nds32_emit_load_store (tmp_reg, dst, mode,
			 addr_offset, /* load_p */ false);
}
Пример #2
0
rtx
gen_lowpart_general (machine_mode mode, rtx x)
{
  rtx result = gen_lowpart_common (mode, x);

  if (result)
    return result;
  /* Handle SUBREGs and hard REGs that were rejected by
     simplify_gen_subreg.  */
  else if (REG_P (x) || GET_CODE (x) == SUBREG)
    {
      result = gen_lowpart_common (mode, copy_to_reg (x));
      gcc_assert (result != 0);
      return result;
    }
  else
    {
      /* The only additional case we can do is MEM.  */
      gcc_assert (MEM_P (x));

      /* The following exposes the use of "x" to CSE.  */
      scalar_int_mode xmode;
      if (is_a <scalar_int_mode> (GET_MODE (x), &xmode)
	  && GET_MODE_SIZE (xmode) <= UNITS_PER_WORD
	  && TRULY_NOOP_TRUNCATION_MODES_P (mode, xmode)
	  && !reload_completed)
	return gen_lowpart_general (mode, force_reg (xmode, x));

      poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x));
      return adjust_address (x, mode, offset);
    }
}
Пример #3
0
rtx
gen_lowpart_if_possible (machine_mode mode, rtx x)
{
  rtx result = gen_lowpart_common (mode, x);

  if (result)
    return result;
  else if (MEM_P (x))
    {
      /* This is the only other case we handle.  */
      poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x));
      rtx new_rtx = adjust_address_nv (x, mode, offset);
      if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0),
					 MEM_ADDR_SPACE (x)))
	return 0;

      return new_rtx;
    }
  else if (mode != GET_MODE (x) && GET_MODE (x) != VOIDmode
	   && validate_subreg (mode, GET_MODE (x), x,
			        subreg_lowpart_offset (mode, GET_MODE (x))))
    return gen_lowpart_SUBREG (mode, x);
  else
    return 0;
}
Пример #4
0
Файл: symtab.c Проект: lv88h/gcc
void
symtab_node::make_decl_local (void)
{
  rtx rtl, symbol;

  /* Avoid clearing comdat_groups on comdat-local decls.  */
  if (TREE_PUBLIC (decl) == 0)
    return;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  DECL_COMDAT (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  DECL_VISIBILITY_SPECIFIED (decl) = 0;
  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
  TREE_PUBLIC (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Пример #5
0
static void
sdbout_toplevel_data (tree decl)
{
  tree type = TREE_TYPE (decl);

  if (DECL_IGNORED_P (decl))
    return;

  gcc_assert (TREE_CODE (decl) == VAR_DECL);
  gcc_assert (MEM_P (DECL_RTL (decl)));
  gcc_assert (DECL_INITIAL (decl));

  PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
  PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
  if (TREE_PUBLIC (decl))
    {
      PUT_SDB_SCL (C_EXT);
    }
  else
    {
      PUT_SDB_SCL (C_STAT);
    }
  PUT_SDB_TYPE (plain_type (type));
  PUT_SDB_ENDEF;
}
Пример #6
0
/* Return true if X contains memory or some UNSPEC.  We can not just
   check insn operands as memory or unspec might be not an operand
   itself but contain an operand.  Insn with memory access is not
   profitable for rematerialization.  Rematerialization of UNSPEC
   might result in wrong code generation as the UNPEC effect is
   unknown (e.g. generating a label).  */
static bool
bad_for_rematerialization_p (rtx x)
{
  int i, j;
  const char *fmt;
  enum rtx_code code;

  if (MEM_P (x) || GET_CODE (x) == UNSPEC || GET_CODE (x) == UNSPEC_VOLATILE)
    return true;
  code = GET_CODE (x);
  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	{
	  if (bad_for_rematerialization_p (XEXP (x, i)))
	    return true;
	}
      else if (fmt[i] == 'E')
	{
	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
	    if (bad_for_rematerialization_p (XVECEXP (x, i, j)))
	      return true;
	}
    }
  return false;
}
Пример #7
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 (MEM_P (operands[i])
               && (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);
        }
    }
}
Пример #8
0
static struct load *
alloc_load (rtx set)
{
  struct load **slot;
  rtx mem, reg;

  mem = SET_DEST (set);
  if (MEM_P (mem))
    reg = SET_SRC (set);
  else
    {
      reg = mem;
      mem = SET_SRC (set);
    }

  slot = (struct load **)
    htab_find_slot_with_hash (htab_load, mem, load_rtx_hash (mem), INSERT);
  if (*slot == NULL)
    {
      *slot = (struct load*) xcalloc (1, sizeof (struct load));
      (*slot)->mem = mem;
    }
  else
    (*slot)->reg_kill = 0;

  (*slot)->reg = reg;

  return *slot; 
}
Пример #9
0
bool
nds32_expand_strlen (rtx result, rtx str,
		     rtx target_char, rtx align ATTRIBUTE_UNUSED)
{
  rtx base_reg, backup_base_reg;
  rtx ffb_result;
  rtx target_char_ptr, length;
  rtx loop_label, tmp;

  if (optimize_size || optimize < 3)
    return false;

  gcc_assert (MEM_P (str));
  gcc_assert (CONST_INT_P (target_char) || REG_P (target_char));

  base_reg = copy_to_mode_reg (SImode, XEXP (str, 0));
  loop_label = gen_label_rtx ();

  ffb_result = gen_reg_rtx (Pmode);
  tmp = gen_reg_rtx (SImode);
  backup_base_reg = gen_reg_rtx (SImode);

  /* Emit loop version of strlen.
       move  $backup_base, $base
     .Lloop:
       lmw.bim $tmp, [$base], $tmp, 0
       ffb   $ffb_result, $tmp, $target_char   ! is there $target_char?
       beqz  $ffb_result, .Lloop
       add   $last_char_ptr, $base, $ffb_result
       sub   $length, $last_char_ptr, $backup_base  */

  /* move  $backup_base, $base  */
  emit_move_insn (backup_base_reg, base_reg);

  /* .Lloop:  */
  emit_label (loop_label);
  /* lmw.bim $tmp, [$base], $tmp, 0  */
  emit_insn (gen_unaligned_load_update_base_w (base_reg, tmp, base_reg));

  /*  ffb   $ffb_result, $tmp, $target_char   ! is there $target_char?  */
  emit_insn (gen_unspec_ffb (ffb_result, tmp, target_char));

  /* beqz  $ffb_result, .Lloop  */
  emit_cmp_and_jump_insns (ffb_result, const0_rtx, EQ, NULL,
			   SImode, 1, loop_label);

  /* add   $target_char_ptr, $base, $ffb_result   */
  target_char_ptr = expand_binop (Pmode, add_optab, base_reg,
				ffb_result, NULL_RTX, 0, OPTAB_WIDEN);

  /* sub   $length, $target_char_ptr, $backup_base  */
  length = expand_binop (Pmode, sub_optab, target_char_ptr,
			 backup_base_reg, NULL_RTX, 0, OPTAB_WIDEN);

  emit_move_insn (result, length);

  return true;
}
Пример #10
0
static bool
varying_mem_p (const_rtx x)
{
  subrtx_iterator::array_type array;
  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
    if (MEM_P (*iter) && !MEM_READONLY_P (*iter))
      return true;
  return false;
}
Пример #11
0
static int
try_apply_stack_adjustment (rtx insn, struct csa_reflist *reflist,
			    HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
{
  struct csa_reflist *ml;
  rtx set;

  set = single_set_for_csa (insn);
  if (MEM_P (SET_DEST (set)))
    validate_change (insn, &SET_DEST (set),
		     replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
		     1);
  else
    validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);

  for (ml = reflist; ml ; ml = ml->next)
    {
      rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
				    ml->sp_offset - delta);
      rtx new_val;

      if (MEM_P (*ml->ref))
	new_val = replace_equiv_address_nv (*ml->ref, new_addr);
      else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
	new_val = new_addr;
      else
	new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
				  GET_MODE (new_addr));
      validate_change (ml->insn, ml->ref, new_val, 1);
    }

  if (apply_change_group ())
    {
      /* Succeeded.  Update our knowledge of the stack references.  */
      for (ml = reflist; ml ; ml = ml->next)
	ml->sp_offset -= delta;

      return 1;
    }
  else
    return 0;
}
Пример #12
0
/* Auxiliary function for mem_read_insn_p.  */
static void
mark_mem_use (rtx *x, void *)
{
  subrtx_iterator::array_type array;
  FOR_EACH_SUBRTX (iter, array, *x, NONCONST)
    if (MEM_P (*iter))
      {
	mem_ref_p = true;
	break;
      }
}
Пример #13
0
static bool
interesting_load (rtx set)
{
  rtx mem, reg;

  if (!set)
    return false;

  /* Handle store just like loads.  */
  mem = SET_DEST (set);
  if (MEM_P (mem))
    reg = SET_SRC (set);
  else
    {
      reg = mem;
      mem = SET_SRC (set);
    }

  return MEM_P (mem) && !MEM_VOLATILE_P (mem) && REG_P (reg);
}
Пример #14
0
static void
sdbout_reg_parms (tree parms)
{
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms))
      {
	const char *name = IDENTIFIER_POINTER (DECL_NAME (parms));

	/* Report parms that live in registers during the function
	   but were passed in memory.  */
	if (REG_P (DECL_RTL (parms))
	    && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER
	    && PARM_PASSED_IN_MEMORY (parms))
	  {
	    if (name == 0 || *name == 0)
	      name = gen_fake_label ();
	    PUT_SDB_DEF (name);
	    PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))));
	    PUT_SDB_SCL (C_REG);
	    PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
	    PUT_SDB_ENDEF;
	  }
	/* Report parms that live in memory but not where they were passed.  */
	else if (MEM_P (DECL_RTL (parms))
		 && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
		 && CONST_INT_P (XEXP (XEXP (DECL_RTL (parms), 0), 1))
		 && PARM_PASSED_IN_MEMORY (parms)
		 && ! rtx_equal_p (DECL_RTL (parms), DECL_INCOMING_RTL (parms)))
	  {
#if 0 /* ??? It is not clear yet what should replace this.  */
	    int offset = DECL_OFFSET (parms) / BITS_PER_UNIT;
	    /* A parm declared char is really passed as an int,
	       so it occupies the least significant bytes.
	       On a big-endian machine those are not the low-numbered ones.  */
	    if (BYTES_BIG_ENDIAN
		&& offset != -1
		&& TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
	      offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
			 - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
	    if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) {...}
#endif
	      {
		if (name == 0 || *name == 0)
		  name = gen_fake_label ();
		PUT_SDB_DEF (name);
		PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET
				 (XEXP (DECL_RTL (parms), 0)));
		PUT_SDB_SCL (C_AUTO);
		PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
		PUT_SDB_ENDEF;
	      }
	  }
      }
Пример #15
0
/* Make DECL local.  FIXME: We shouldn't need to mess with rtl this early,
   but other code such as notice_global_symbol generates rtl.  */
void
symtab_make_decl_local (tree decl)
{
  rtx rtl, symbol;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl))
    {
      /* It is possible that we are linking against library defining same COMDAT
	 function.  To avoid conflict we need to rename our local name of the
	 function just in the case WHOPR partitioning decide to make it hidden
	 to avoid cross partition references.  */
      if (flag_wpa)
	{
	  const char *old_name;
          symtab_node node = symtab_get_node (decl);
	  old_name  = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
	  change_decl_assembler_name (decl,
				      clone_function_name (decl, "local"));
	  if (node->symbol.lto_file_data)
	    lto_record_renamed_decl (node->symbol.lto_file_data,
				     old_name,
				     IDENTIFIER_POINTER
				       (DECL_ASSEMBLER_NAME (decl)));
	}
      DECL_SECTION_NAME (decl) = 0;
      DECL_COMDAT (decl) = 0;
    }
  DECL_COMDAT_GROUP (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  TREE_PUBLIC (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Пример #16
0
static int
stack_memref_p (rtx x)
{
    if (!MEM_P (x))
        return 0;
    x = XEXP (x, 0);

    if (x == stack_pointer_rtx)
        return 1;
    if (GET_CODE (x) == PLUS
            && XEXP (x, 0) == stack_pointer_rtx
            && CONST_INT_P (XEXP (x, 1)))
        return 1;

    return 0;
}
Пример #17
0
static bool
interesting_second_load (rtx set, struct load ***load, rtx insn)
{
  rtx mem, reg;

  if (!set)
    return false;

  mem = SET_SRC (set);
  reg = SET_DEST (set);
  if (!MEM_P (mem) || MEM_VOLATILE_P (mem) || !REG_P (reg))
    return false;

  *load = (struct load **)
    htab_find_slot_with_hash (htab_load, mem, load_rtx_hash (mem),
			      NO_INSERT);
  if (!*load)
    return false;

  /* Don't work on cases that never happen: if there is no kill, we
     would have inherited the reload; if the store and load regs are
     the same we would need to find an available register.  If the
     kill insn was already replaced by a move this information is
     stale, disregard it.  */
  if (rtx_equal_p (reg, (**load)->reg)
      || !(**load)->reg_kill
      || INSN_DELETED_P ((**load)->reg_kill)
      || reg_used_between_p (reg, PREV_INSN ((**load)->reg_kill),
			     NEXT_INSN (insn))
      || reg_set_between_p (reg, PREV_INSN ((**load)->reg_kill), insn))
    {
      if (dump_file)
	{
	  fputs ("\nCan't insert the move before the kill for this load:\n  ",
		 dump_file);
	  print_inline_rtx (dump_file, insn, 2);
	  fputs ("\n\n", dump_file);
	}
      return false;
    }

  return true;
}
Пример #18
0
rtx
gen_lowpart_general (enum machine_mode mode, rtx x)
{
  rtx result = gen_lowpart_common (mode, x);

  if (result)
    return result;
  else if (REG_P (x))
    {
      /* Must be a hard reg that's not valid in MODE.  */
      result = gen_lowpart_common (mode, copy_to_reg (x));
      gcc_assert (result != 0);
      return result;
    }
  else
    {
      int offset = 0;

      /* The only additional case we can do is MEM.  */
      gcc_assert (MEM_P (x));

      /* The following exposes the use of "x" to CSE.  */
      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
	  && SCALAR_INT_MODE_P (GET_MODE (x))
	  && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
				    GET_MODE_BITSIZE (GET_MODE (x)))
	  && ! no_new_pseudos)
	return gen_lowpart_general (mode, force_reg (GET_MODE (x), x));

      if (WORDS_BIG_ENDIAN)
	offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
		  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));

      if (BYTES_BIG_ENDIAN)
	/* Adjust the address so that the address-after-the-data
	   is unchanged.  */
	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
		   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));

      return adjust_address (x, mode, offset);
    }
}
Пример #19
0
rtx
gen_lowpart_general (machine_mode mode, rtx x)
{
  rtx result = gen_lowpart_common (mode, x);

  if (result)
    return result;
  /* Handle SUBREGs and hard REGs that were rejected by
     simplify_gen_subreg.  */
  else if (REG_P (x) || GET_CODE (x) == SUBREG)
    {
      result = gen_lowpart_common (mode, copy_to_reg (x));
      gcc_assert (result != 0);
      return result;
    }
  else
    {
      int offset = 0;

      /* The only additional case we can do is MEM.  */
      gcc_assert (MEM_P (x));

      /* The following exposes the use of "x" to CSE.  */
      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
	  && SCALAR_INT_MODE_P (GET_MODE (x))
	  && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x))
	  && !reload_completed)
	return gen_lowpart_general (mode, force_reg (GET_MODE (x), x));

      if (WORDS_BIG_ENDIAN)
	offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
		  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));

      if (BYTES_BIG_ENDIAN)
	/* Adjust the address so that the address-after-the-data
	   is unchanged.  */
	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
		   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));

      return adjust_address (x, mode, offset);
    }
}
Пример #20
0
void
symtab_make_decl_local (tree decl)
{
  rtx rtl, symbol;

  /* Avoid clearing DECL_COMDAT_GROUP on comdat-local decls.  */
  if (TREE_PUBLIC (decl) == 0)
    return;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl))
    {
      DECL_SECTION_NAME (decl) = 0;
      DECL_COMDAT (decl) = 0;
    }
  DECL_COMDAT_GROUP (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  DECL_VISIBILITY_SPECIFIED (decl) = 0;
  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
  TREE_PUBLIC (decl) = 0;
  DECL_DLLIMPORT_P (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Пример #21
0
static void
expand_STORE_LANES (gimple stmt)
{
  struct expand_operand ops[2];
  tree type, lhs, rhs;
  rtx target, reg;

  lhs = gimple_call_lhs (stmt);
  rhs = gimple_call_arg (stmt, 0);
  type = TREE_TYPE (rhs);

  target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  reg = expand_normal (rhs);

  gcc_assert (MEM_P (target));
  PUT_MODE (target, TYPE_MODE (type));

  create_fixed_operand (&ops[0], target);
  create_input_operand (&ops[1], reg, TYPE_MODE (type));
  expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops);
}
Пример #22
0
int
c54x_expand_movqi(rtx ops[])
{
	int done = 0;
	int i;

	fprintf(stderr, "--->>>");
	for(i=0; i < 2; i++) {
		print_rtl(stderr, ops[i]);
	}
	fprintf(stderr, "<<<---\n");

	
	if(ACC_REG_P(ops[0])) {
		ops[0] = copy_rtx(ops[0]);
		PUT_MODE(ops[0], PSImode);
		fprintf(stderr, "+++");
		print_rtl(stderr, ops[0]);
		fprintf(stderr, "+++\n");

		done = 1;

		if(MEM_P(ops[1])) {
			emit_insn(gen_ldm(ops[0], ops[1]));
		} else if(REG_P(ops[1])) {
			emit_insn(gen_ldu(ops[0], ops[1]));
		} else if(CONSTANT_P(ops[1])) {
			emit_insn(gen_ld_const(ops[0], ops[1], gen_reg_rtx(QImode)));
		} else {
			done = 2;
		}

	} else if( (REG_P(ops[0]) && (GET_CODE(ops[1]) == MEM && REG_P(XEXP(ops[1],0))))
			   || (T_REG_P(ops[0]) && ARSP_REG_P(ops[1])) )
	{
		done = 2;
	}
	
	return done;
}
Пример #23
0
static void
expand_MASK_STORE (gimple stmt)
{
  struct expand_operand ops[3];
  tree type, lhs, rhs, maskt;
  rtx mem, reg, mask;

  maskt = gimple_call_arg (stmt, 2);
  rhs = gimple_call_arg (stmt, 3);
  type = TREE_TYPE (rhs);
  lhs = fold_build2 (MEM_REF, type, gimple_call_arg (stmt, 0),
		     gimple_call_arg (stmt, 1));

  mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  gcc_assert (MEM_P (mem));
  mask = expand_normal (maskt);
  reg = expand_normal (rhs);
  create_fixed_operand (&ops[0], mem);
  create_input_operand (&ops[1], reg, TYPE_MODE (type));
  create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
  expand_insn (optab_handler (maskstore_optab, TYPE_MODE (type)), 3, ops);
}
Пример #24
0
static void
expand_MASK_LOAD (gimple stmt)
{
  struct expand_operand ops[3];
  tree type, lhs, rhs, maskt;
  rtx mem, target, mask;

  maskt = gimple_call_arg (stmt, 2);
  lhs = gimple_call_lhs (stmt);
  if (lhs == NULL_TREE)
    return;
  type = TREE_TYPE (lhs);
  rhs = fold_build2 (MEM_REF, type, gimple_call_arg (stmt, 0),
		     gimple_call_arg (stmt, 1));

  mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  gcc_assert (MEM_P (mem));
  mask = expand_normal (maskt);
  target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  create_output_operand (&ops[0], target, TYPE_MODE (type));
  create_fixed_operand (&ops[1], mem);
  create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
  expand_insn (optab_handler (maskload_optab, TYPE_MODE (type)), 3, ops);
}
Пример #25
0
/* Return 1 if x is a valid address not using indexing.
   (This much is the easy part.)  */
static int
nonindexed_address_p (rtx x, int strict)
{
  rtx xfoo0;
  if (REG_P (x))
    {
      extern rtx *reg_equiv_mem;
      if (!reload_in_progress
          || reg_equiv_mem[REGNO (x)] == 0
          || indirectable_address_p (reg_equiv_mem[REGNO (x)], strict))
        return 1;
    }
  if (indirectable_constant_address_p (x))
    return 1;
  if (indirectable_address_p (x, strict))
    return 1;
  xfoo0 = XEXP (x, 0);
  if (MEM_P (x) && indirectable_address_p (xfoo0, strict))
    return 1;
  if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
      && BASE_REGISTER_P (xfoo0, strict))
    return 1;
  return 0;
}
Пример #26
0
static bool
copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
{
  bool anything_changed = false;
  rtx insn;

  for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
    {
      int n_ops, i, alt, predicated;
      bool is_asm, any_replacements;
      rtx set;
      bool replaced[MAX_RECOG_OPERANDS];
      bool changed = false;
      struct kill_set_value_data ksvd;

      if (!NONDEBUG_INSN_P (insn))
	{
	  if (DEBUG_INSN_P (insn))
	    {
	      rtx loc = INSN_VAR_LOCATION_LOC (insn);
	      if (!VAR_LOC_UNKNOWN_P (loc))
		replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn),
					   ALL_REGS, GET_MODE (loc),
					   ADDR_SPACE_GENERIC, insn, vd);
	    }

	  if (insn == BB_END (bb))
	    break;
	  else
	    continue;
	}

      set = single_set (insn);
      extract_insn (insn);
      if (! constrain_operands (1))
	fatal_insn_not_found (insn);
      preprocess_constraints ();
      alt = which_alternative;
      n_ops = recog_data.n_operands;
      is_asm = asm_noperands (PATTERN (insn)) >= 0;

      /* Simplify the code below by rewriting things to reflect
	 matching constraints.  Also promote OP_OUT to OP_INOUT
	 in predicated instructions.  */

      predicated = GET_CODE (PATTERN (insn)) == COND_EXEC;
      for (i = 0; i < n_ops; ++i)
	{
	  int matches = recog_op_alt[i][alt].matches;
	  if (matches >= 0)
	    recog_op_alt[i][alt].cl = recog_op_alt[matches][alt].cl;
	  if (matches >= 0 || recog_op_alt[i][alt].matched >= 0
	      || (predicated && recog_data.operand_type[i] == OP_OUT))
	    recog_data.operand_type[i] = OP_INOUT;
	}

      /* Apply changes to earlier DEBUG_INSNs if possible.  */
      if (vd->n_debug_insn_changes)
	note_uses (&PATTERN (insn), cprop_find_used_regs, vd);

      /* For each earlyclobber operand, zap the value data.  */
      for (i = 0; i < n_ops; i++)
	if (recog_op_alt[i][alt].earlyclobber)
	  kill_value (recog_data.operand[i], vd);

      /* Within asms, a clobber cannot overlap inputs or outputs.
	 I wouldn't think this were true for regular insns, but
	 scan_rtx treats them like that...  */
      note_stores (PATTERN (insn), kill_clobbered_value, vd);

      /* Kill all auto-incremented values.  */
      /* ??? REG_INC is useless, since stack pushes aren't done that way.  */
      for_each_rtx (&PATTERN (insn), kill_autoinc_value, vd);

      /* Kill all early-clobbered operands.  */
      for (i = 0; i < n_ops; i++)
	if (recog_op_alt[i][alt].earlyclobber)
	  kill_value (recog_data.operand[i], vd);

      /* Special-case plain move instructions, since we may well
	 be able to do the move from a different register class.  */
      if (set && REG_P (SET_SRC (set)))
	{
	  rtx src = SET_SRC (set);
	  unsigned int regno = REGNO (src);
	  enum machine_mode mode = GET_MODE (src);
	  unsigned int i;
	  rtx new_rtx;

	  /* If we are accessing SRC in some mode other that what we
	     set it in, make sure that the replacement is valid.  */
	  if (mode != vd->e[regno].mode)
	    {
	      if (hard_regno_nregs[regno][mode]
		  > hard_regno_nregs[regno][vd->e[regno].mode])
		goto no_move_special_case;

	      /* And likewise, if we are narrowing on big endian the transformation
		 is also invalid.  */
	      if (hard_regno_nregs[regno][mode]
		  < hard_regno_nregs[regno][vd->e[regno].mode]
		  && (GET_MODE_SIZE (vd->e[regno].mode) > UNITS_PER_WORD
		      ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
		goto no_move_special_case;
	    }

	  /* If the destination is also a register, try to find a source
	     register in the same class.  */
	  if (REG_P (SET_DEST (set)))
	    {
	      new_rtx = find_oldest_value_reg (REGNO_REG_CLASS (regno), src, vd);
	      if (new_rtx && validate_change (insn, &SET_SRC (set), new_rtx, 0))
		{
		  if (dump_file)
		    fprintf (dump_file,
			     "insn %u: replaced reg %u with %u\n",
			     INSN_UID (insn), regno, REGNO (new_rtx));
		  changed = true;
		  goto did_replacement;
		}
	      /* We need to re-extract as validate_change clobbers
		 recog_data.  */
	      extract_insn (insn);
	      if (! constrain_operands (1))
		fatal_insn_not_found (insn);
	      preprocess_constraints ();
	    }

	  /* Otherwise, try all valid registers and see if its valid.  */
	  for (i = vd->e[regno].oldest_regno; i != regno;
	       i = vd->e[i].next_regno)
	    {
	      new_rtx = maybe_mode_change (vd->e[i].mode, vd->e[regno].mode,
				       mode, i, regno);
	      if (new_rtx != NULL_RTX)
		{
		  if (validate_change (insn, &SET_SRC (set), new_rtx, 0))
		    {
		      ORIGINAL_REGNO (new_rtx) = ORIGINAL_REGNO (src);
		      REG_ATTRS (new_rtx) = REG_ATTRS (src);
		      REG_POINTER (new_rtx) = REG_POINTER (src);
		      if (dump_file)
			fprintf (dump_file,
				 "insn %u: replaced reg %u with %u\n",
				 INSN_UID (insn), regno, REGNO (new_rtx));
		      changed = true;
		      goto did_replacement;
		    }
		  /* We need to re-extract as validate_change clobbers
		     recog_data.  */
		  extract_insn (insn);
		  if (! constrain_operands (1))
		    fatal_insn_not_found (insn);
		  preprocess_constraints ();
		}
	    }
	}
      no_move_special_case:

      any_replacements = false;

      /* For each input operand, replace a hard register with the
	 eldest live copy that's in an appropriate register class.  */
      for (i = 0; i < n_ops; i++)
	{
	  replaced[i] = false;

	  /* Don't scan match_operand here, since we've no reg class
	     information to pass down.  Any operands that we could
	     substitute in will be represented elsewhere.  */
	  if (recog_data.constraints[i][0] == '\0')
	    continue;

	  /* Don't replace in asms intentionally referencing hard regs.  */
	  if (is_asm && REG_P (recog_data.operand[i])
	      && (REGNO (recog_data.operand[i])
		  == ORIGINAL_REGNO (recog_data.operand[i])))
	    continue;

	  if (recog_data.operand_type[i] == OP_IN)
	    {
	      if (recog_op_alt[i][alt].is_address)
		replaced[i]
		  = replace_oldest_value_addr (recog_data.operand_loc[i],
					       recog_op_alt[i][alt].cl,
					       VOIDmode, ADDR_SPACE_GENERIC,
					       insn, vd);
	      else if (REG_P (recog_data.operand[i]))
		replaced[i]
		  = replace_oldest_value_reg (recog_data.operand_loc[i],
					      recog_op_alt[i][alt].cl,
					      insn, vd);
	      else if (MEM_P (recog_data.operand[i]))
		replaced[i] = replace_oldest_value_mem (recog_data.operand[i],
							insn, vd);
	    }
	  else if (MEM_P (recog_data.operand[i]))
	    replaced[i] = replace_oldest_value_mem (recog_data.operand[i],
						    insn, vd);

	  /* If we performed any replacement, update match_dups.  */
	  if (replaced[i])
	    {
	      int j;
	      rtx new_rtx;

	      new_rtx = *recog_data.operand_loc[i];
	      recog_data.operand[i] = new_rtx;
	      for (j = 0; j < recog_data.n_dups; j++)
		if (recog_data.dup_num[j] == i)
		  validate_unshare_change (insn, recog_data.dup_loc[j], new_rtx, 1);

	      any_replacements = true;
	    }
	}

      if (any_replacements)
	{
	  if (! apply_change_group ())
	    {
	      for (i = 0; i < n_ops; i++)
		if (replaced[i])
		  {
		    rtx old = *recog_data.operand_loc[i];
		    recog_data.operand[i] = old;
		  }

	      if (dump_file)
		fprintf (dump_file,
			 "insn %u: reg replacements not verified\n",
			 INSN_UID (insn));
	    }
	  else
	    changed = true;
	}

    did_replacement:
      if (changed)
	{
	  anything_changed = true;

	  /* If something changed, perhaps further changes to earlier
	     DEBUG_INSNs can be applied.  */
	  if (vd->n_debug_insn_changes)
	    note_uses (&PATTERN (insn), cprop_find_used_regs, vd);
	}

      ksvd.vd = vd;
      ksvd.ignore_set_reg = NULL_RTX;

      /* Clobber call-clobbered registers.  */
      if (CALL_P (insn))
	{
	  unsigned int set_regno = INVALID_REGNUM;
	  unsigned int set_nregs = 0;
	  unsigned int regno;
	  rtx exp;
	  hard_reg_set_iterator hrsi;

	  for (exp = CALL_INSN_FUNCTION_USAGE (insn); exp; exp = XEXP (exp, 1))
	    {
	      rtx x = XEXP (exp, 0);
	      if (GET_CODE (x) == SET)
		{
		  rtx dest = SET_DEST (x);
		  kill_value (dest, vd);
		  set_value_regno (REGNO (dest), GET_MODE (dest), vd);
		  copy_value (dest, SET_SRC (x), vd);
		  ksvd.ignore_set_reg = dest;
		  set_regno = REGNO (dest);
		  set_nregs
		    = hard_regno_nregs[set_regno][GET_MODE (dest)];
		  break;
		}
	    }

	  EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
	    if (regno < set_regno || regno >= set_regno + set_nregs)
	      kill_value_regno (regno, 1, vd);

	  /* If SET was seen in CALL_INSN_FUNCTION_USAGE, and SET_SRC
	     of the SET isn't in regs_invalidated_by_call hard reg set,
	     but instead among CLOBBERs on the CALL_INSN, we could wrongly
	     assume the value in it is still live.  */
	  if (ksvd.ignore_set_reg)
	    note_stores (PATTERN (insn), kill_clobbered_value, vd);
	}

      /* Notice stores.  */
      note_stores (PATTERN (insn), kill_set_value, &ksvd);

      /* Notice copies.  */
      if (set && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set)))
	copy_value (SET_DEST (set), SET_SRC (set), vd);

      if (insn == BB_END (bb))
	break;
    }

  return anything_changed;
}
Пример #27
0
Файл: dce.c Проект: AHelper/gcc
static bool
find_call_stack_args (rtx_call_insn *call_insn, bool do_mark, bool fast,
		      bitmap arg_stores)
{
  rtx p;
  rtx_insn *insn, *prev_insn;
  bool ret;
  HOST_WIDE_INT min_sp_off, max_sp_off;
  bitmap sp_bytes;

  gcc_assert (CALL_P (call_insn));
  if (!ACCUMULATE_OUTGOING_ARGS)
    return true;

  if (!do_mark)
    {
      gcc_assert (arg_stores);
      bitmap_clear (arg_stores);
    }

  min_sp_off = INTTYPE_MAXIMUM (HOST_WIDE_INT);
  max_sp_off = 0;

  /* First determine the minimum and maximum offset from sp for
     stored arguments.  */
  for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
    if (GET_CODE (XEXP (p, 0)) == USE
	&& MEM_P (XEXP (XEXP (p, 0), 0)))
      {
	rtx mem = XEXP (XEXP (p, 0), 0), addr;
	HOST_WIDE_INT off = 0, size;
	if (!MEM_SIZE_KNOWN_P (mem))
	  return false;
	size = MEM_SIZE (mem);
	addr = XEXP (mem, 0);
	if (GET_CODE (addr) == PLUS
	    && REG_P (XEXP (addr, 0))
	    && CONST_INT_P (XEXP (addr, 1)))
	  {
	    off = INTVAL (XEXP (addr, 1));
	    addr = XEXP (addr, 0);
	  }
	if (addr != stack_pointer_rtx)
	  {
	    if (!REG_P (addr))
	      return false;
	    /* If not fast, use chains to see if addr wasn't set to
	       sp + offset.  */
	    if (!fast)
	      {
		df_ref use;
		struct df_link *defs;
		rtx set;

		FOR_EACH_INSN_USE (use, call_insn)
		  if (rtx_equal_p (addr, DF_REF_REG (use)))
		    break;

		if (use == NULL)
		  return false;

		for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
		  if (! DF_REF_IS_ARTIFICIAL (defs->ref))
		    break;

		if (defs == NULL)
		  return false;

		set = single_set (DF_REF_INSN (defs->ref));
		if (!set)
		  return false;

		if (GET_CODE (SET_SRC (set)) != PLUS
		    || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
		    || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
		  return false;

		off += INTVAL (XEXP (SET_SRC (set), 1));
	      }
	    else
	      return false;
Пример #28
0
static bool
propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags)
{
  rtx x = *px, tem = NULL_RTX, op0, op1, op2;
  enum rtx_code code = GET_CODE (x);
  machine_mode mode = GET_MODE (x);
  machine_mode op_mode;
  bool can_appear = (flags & PR_CAN_APPEAR) != 0;
  bool valid_ops = true;

  if (!(flags & PR_HANDLE_MEM) && MEM_P (x) && !MEM_READONLY_P (x))
    {
      /* If unsafe, change MEMs to CLOBBERs or SCRATCHes (to preserve whether
	 they have side effects or not).  */
      *px = (side_effects_p (x)
	     ? gen_rtx_CLOBBER (GET_MODE (x), const0_rtx)
	     : gen_rtx_SCRATCH (GET_MODE (x)));
      return false;
    }

  /* If X is OLD_RTX, return NEW_RTX.  But not if replacing only within an
     address, and we are *not* inside one.  */
  if (x == old_rtx)
    {
      *px = new_rtx;
      return can_appear;
    }

  /* If this is an expression, try recursive substitution.  */
  switch (GET_RTX_CLASS (code))
    {
    case RTX_UNARY:
      op0 = XEXP (x, 0);
      op_mode = GET_MODE (op0);
      valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
      if (op0 == XEXP (x, 0))
	return true;
      tem = simplify_gen_unary (code, mode, op0, op_mode);
      break;

    case RTX_BIN_ARITH:
    case RTX_COMM_ARITH:
      op0 = XEXP (x, 0);
      op1 = XEXP (x, 1);
      valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
      valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
	return true;
      tem = simplify_gen_binary (code, mode, op0, op1);
      break;

    case RTX_COMPARE:
    case RTX_COMM_COMPARE:
      op0 = XEXP (x, 0);
      op1 = XEXP (x, 1);
      op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
      valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
      valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
	return true;
      tem = simplify_gen_relational (code, mode, op_mode, op0, op1);
      break;

    case RTX_TERNARY:
    case RTX_BITFIELD_OPS:
      op0 = XEXP (x, 0);
      op1 = XEXP (x, 1);
      op2 = XEXP (x, 2);
      op_mode = GET_MODE (op0);
      valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
      valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
      valid_ops &= propagate_rtx_1 (&op2, old_rtx, new_rtx, flags);
      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2))
	return true;
      if (op_mode == VOIDmode)
	op_mode = GET_MODE (op0);
      tem = simplify_gen_ternary (code, mode, op_mode, op0, op1, op2);
      break;

    case RTX_EXTRA:
      /* The only case we try to handle is a SUBREG.  */
      if (code == SUBREG)
	{
          op0 = XEXP (x, 0);
	  valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
          if (op0 == XEXP (x, 0))
	    return true;
	  tem = simplify_gen_subreg (mode, op0, GET_MODE (SUBREG_REG (x)),
				     SUBREG_BYTE (x));
	}
      break;

    case RTX_OBJ:
      if (code == MEM && x != new_rtx)
	{
	  rtx new_op0;
	  op0 = XEXP (x, 0);

	  /* There are some addresses that we cannot work on.  */
	  if (!can_simplify_addr (op0))
	    return true;

	  op0 = new_op0 = targetm.delegitimize_address (op0);
	  valid_ops &= propagate_rtx_1 (&new_op0, old_rtx, new_rtx,
					flags | PR_CAN_APPEAR);

	  /* Dismiss transformation that we do not want to carry on.  */
	  if (!valid_ops
	      || new_op0 == op0
	      || !(GET_MODE (new_op0) == GET_MODE (op0)
		   || GET_MODE (new_op0) == VOIDmode))
	    return true;

	  canonicalize_address (new_op0);

	  /* Copy propagations are always ok.  Otherwise check the costs.  */
	  if (!(REG_P (old_rtx) && REG_P (new_rtx))
	      && !should_replace_address (op0, new_op0, GET_MODE (x),
					  MEM_ADDR_SPACE (x),
	      			 	  flags & PR_OPTIMIZE_FOR_SPEED))
	    return true;

	  tem = replace_equiv_address_nv (x, new_op0);
	}

      else if (code == LO_SUM)
	{
          op0 = XEXP (x, 0);
          op1 = XEXP (x, 1);

	  /* The only simplification we do attempts to remove references to op0
	     or make it constant -- in both cases, op0's invalidity will not
	     make the result invalid.  */
	  propagate_rtx_1 (&op0, old_rtx, new_rtx, flags | PR_CAN_APPEAR);
	  valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
          if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
	    return true;

	  /* (lo_sum (high x) x) -> x  */
	  if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
	    tem = op1;
	  else
	    tem = gen_rtx_LO_SUM (mode, op0, op1);

	  /* OP1 is likely not a legitimate address, otherwise there would have
	     been no LO_SUM.  We want it to disappear if it is invalid, return
	     false in that case.  */
	  return memory_address_p (mode, tem);
	}

      else if (code == REG)
	{
	  if (rtx_equal_p (x, old_rtx))
	    {
              *px = new_rtx;
              return can_appear;
	    }
	}
      break;

    default:
      break;
    }

  /* No change, no trouble.  */
  if (tem == NULL_RTX)
    return true;

  *px = tem;

  /* Allow replacements that simplify operations on a vector or complex
     value to a component.  The most prominent case is
     (subreg ([vec_]concat ...)).   */
  if (REG_P (tem) && !HARD_REGISTER_P (tem)
      && (VECTOR_MODE_P (GET_MODE (new_rtx))
	  || COMPLEX_MODE_P (GET_MODE (new_rtx)))
      && GET_MODE (tem) == GET_MODE_INNER (GET_MODE (new_rtx)))
    return true;

  /* The replacement we made so far is valid, if all of the recursive
     replacements were valid, or we could simplify everything to
     a constant.  */
  return valid_ops || can_appear || CONSTANT_P (tem);
}
Пример #29
0
static void
combine_stack_adjustments_for_block (basic_block bb)
{
    HOST_WIDE_INT last_sp_adjust = 0;
    rtx last_sp_set = NULL_RTX;
    rtx last2_sp_set = NULL_RTX;
    struct csa_reflist *reflist = NULL;
    rtx insn, next, set;
    struct record_stack_refs_data data;
    bool end_of_block = false;

    for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
    {
        end_of_block = insn == BB_END (bb);
        next = NEXT_INSN (insn);

        if (! INSN_P (insn))
            continue;

        set = single_set_for_csa (insn);
        if (set)
        {
            rtx dest = SET_DEST (set);
            rtx src = SET_SRC (set);

            /* Find constant additions to the stack pointer.  */
            if (dest == stack_pointer_rtx
                    && GET_CODE (src) == PLUS
                    && XEXP (src, 0) == stack_pointer_rtx
                    && CONST_INT_P (XEXP (src, 1)))
            {
                HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));

                /* If we've not seen an adjustment previously, record
                it now and continue.  */
                if (! last_sp_set)
                {
                    last_sp_set = insn;
                    last_sp_adjust = this_adjust;
                    continue;
                }

                /* If not all recorded refs can be adjusted, or the
                adjustment is now too large for a constant addition,
                 we cannot merge the two stack adjustments.

                 Also we need to be careful to not move stack pointer
                 such that we create stack accesses outside the allocated
                 area.  We can combine an allocation into the first insn,
                 or a deallocation into the second insn.  We can not
                 combine an allocation followed by a deallocation.

                 The only somewhat frequent occurrence of the later is when
                 a function allocates a stack frame but does not use it.
                 For this case, we would need to analyze rtl stream to be
                 sure that allocated area is really unused.  This means not
                 only checking the memory references, but also all registers
                 or global memory references possibly containing a stack
                 frame address.

                 Perhaps the best way to address this problem is to teach
                 gcc not to allocate stack for objects never used.  */

                /* Combine an allocation into the first instruction.  */
                if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
                {
                    if (try_apply_stack_adjustment (last_sp_set, reflist,
                                                    last_sp_adjust + this_adjust,
                                                    this_adjust))
                    {
                        /* It worked!  */
                        maybe_move_args_size_note (last_sp_set, insn, false);
                        delete_insn (insn);
                        last_sp_adjust += this_adjust;
                        continue;
                    }
                }

                /* Otherwise we have a deallocation.  Do not combine with
                a previous allocation.  Combine into the second insn.  */
                else if (STACK_GROWS_DOWNWARD
                         ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
                {
                    if (try_apply_stack_adjustment (insn, reflist,
                                                    last_sp_adjust + this_adjust,
                                                    -last_sp_adjust))
                    {
                        /* It worked!  */
                        maybe_move_args_size_note (insn, last_sp_set, true);
                        delete_insn (last_sp_set);
                        last_sp_set = insn;
                        last_sp_adjust += this_adjust;
                        free_csa_reflist (reflist);
                        reflist = NULL;
                        continue;
                    }
                }

                /* Combination failed.  Restart processing from here.  If
                deallocation+allocation conspired to cancel, we can
                 delete the old deallocation insn.  */
                if (last_sp_set)
                {
                    if (last_sp_adjust == 0)
                    {
                        maybe_move_args_size_note (insn, last_sp_set, true);
                        delete_insn (last_sp_set);
                    }
                    else
                        last2_sp_set = last_sp_set;
                }
                free_csa_reflist (reflist);
                reflist = NULL;
                last_sp_set = insn;
                last_sp_adjust = this_adjust;
                continue;
            }

            /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
               the previous adjustment and turn it into a simple store.  This
               is equivalent to anticipating the stack adjustment so this must
               be an allocation.  */
            if (MEM_P (dest)
                    && ((STACK_GROWS_DOWNWARD
                         ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
                            && last_sp_adjust
                            == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
                         : (GET_CODE (XEXP (dest, 0)) == PRE_INC
                            && last_sp_adjust
                            == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
                        || ((STACK_GROWS_DOWNWARD
                             ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
                            && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
                            && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
                            && XEXP (XEXP (XEXP (dest, 0), 1), 0)
                            == stack_pointer_rtx
                            && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
                            == CONST_INT
                            && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
                            == -last_sp_adjust))
                    && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
                    && !reg_mentioned_p (stack_pointer_rtx, src)
                    && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
                    && try_apply_stack_adjustment (insn, reflist, 0,
                                                   -last_sp_adjust))
            {
                if (last2_sp_set)
                    maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
                else
                    maybe_move_args_size_note (insn, last_sp_set, true);
                delete_insn (last_sp_set);
                free_csa_reflist (reflist);
                reflist = NULL;
                last_sp_set = NULL_RTX;
                last_sp_adjust = 0;
                continue;
            }
        }

        data.insn = insn;
        data.reflist = reflist;
        if (!CALL_P (insn) && last_sp_set
                && !for_each_rtx (&PATTERN (insn), record_stack_refs, &data))
        {
            reflist = data.reflist;
            continue;
        }
        reflist = data.reflist;

        /* Otherwise, we were not able to process the instruction.
        Do not continue collecting data across such a one.  */
        if (last_sp_set
                && (CALL_P (insn)
                    || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
        {
            if (last_sp_set && last_sp_adjust == 0)
            {
                force_move_args_size_note (bb, last2_sp_set, last_sp_set);
                delete_insn (last_sp_set);
            }
            free_csa_reflist (reflist);
            reflist = NULL;
            last2_sp_set = NULL_RTX;
            last_sp_set = NULL_RTX;
            last_sp_adjust = 0;
        }
    }

    if (last_sp_set && last_sp_adjust == 0)
    {
        force_move_args_size_note (bb, last2_sp_set, last_sp_set);
        delete_insn (last_sp_set);
    }

    if (reflist)
        free_csa_reflist (reflist);
}
Пример #30
0
void
sdbout_symbol (tree decl, int local)
{
  tree type = TREE_TYPE (decl);
  tree context = NULL_TREE;
  rtx value;
  int regno = -1;
  const char *name;

  /* If we are called before sdbout_init is run, just save the symbol
     for later.  */
  if (!sdbout_initialized)
    {
      preinit_symbols = tree_cons (0, decl, preinit_symbols);
      return;
    }

  sdbout_one_type (type);

  switch (TREE_CODE (decl))
    {
    case CONST_DECL:
      /* Enum values are defined by defining the enum type.  */
      return;

    case FUNCTION_DECL:
      /* Don't mention a nested function under its parent.  */
      context = decl_function_context (decl);
      if (context == current_function_decl)
	return;
      /* Check DECL_INITIAL to distinguish declarations from definitions.
	 Don't output debug info here for declarations; they will have
	 a DECL_INITIAL value of 0.  */
      if (! DECL_INITIAL (decl))
	return;
      if (!MEM_P (DECL_RTL (decl))
	  || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
	return;
      PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
      PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
      PUT_SDB_SCL (TREE_PUBLIC (decl) ? C_EXT : C_STAT);
      break;

    case TYPE_DECL:
      /* Done with tagged types.  */
      if (DECL_NAME (decl) == 0)
	return;
      if (DECL_IGNORED_P (decl))
	return;
      /* Don't output intrinsic types.  GAS chokes on SDB .def
	 statements that contain identifiers with embedded spaces
	 (eg "unsigned long").  */
      if (DECL_IS_BUILTIN (decl))
	return;

      /* Output typedef name.  */
      if (template_name_p (DECL_NAME (decl)))
	PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
      else
	PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl)));
      PUT_SDB_SCL (C_TPDEF);
      break;

    case PARM_DECL:
      /* Parm decls go in their own separate chains
	 and are output by sdbout_reg_parms and sdbout_parms.  */
      gcc_unreachable ();

    case VAR_DECL:
      /* Don't mention a variable that is external.
	 Let the file that defines it describe it.  */
      if (DECL_EXTERNAL (decl))
	return;

      /* Ignore __FUNCTION__, etc.  */
      if (DECL_IGNORED_P (decl))
	return;

      /* If there was an error in the declaration, don't dump core
	 if there is no RTL associated with the variable doesn't
	 exist.  */
      if (!DECL_RTL_SET_P (decl))
	return;

      SET_DECL_RTL (decl,
		    eliminate_regs (DECL_RTL (decl), VOIDmode, NULL_RTX));
#ifdef LEAF_REG_REMAP
      if (crtl->uses_only_leaf_regs)
	leaf_renumber_regs_insn (DECL_RTL (decl));
#endif
      value = DECL_RTL (decl);

      /* Don't mention a variable at all
	 if it was completely optimized into nothingness.

	 If DECL was from an inline function, then its rtl
	 is not identically the rtl that was used in this
	 particular compilation.  */
      if (REG_P (value))
	{
	  regno = REGNO (value);
	  if (regno >= FIRST_PSEUDO_REGISTER)
	    return;
	}
      else if (GET_CODE (value) == SUBREG)
	{
	  while (GET_CODE (value) == SUBREG)
	    value = SUBREG_REG (value);
	  if (REG_P (value))
	    {
	      if (REGNO (value) >= FIRST_PSEUDO_REGISTER)
		return;
	    }
	  regno = REGNO (alter_subreg (&value));
	  SET_DECL_RTL (decl, value);
	}
      /* Don't output anything if an auto variable
	 gets RTL that is static.
	 GAS version 2.2 can't handle such output.  */
      else if (MEM_P (value) && CONSTANT_P (XEXP (value, 0))
	       && ! TREE_STATIC (decl))
	return;

      /* Emit any structure, union, or enum type that has not been output.
	 This occurs for tag-less structs (et al) used to declare variables
	 within functions.  */
      if (TREE_CODE (type) == ENUMERAL_TYPE
	  || TREE_CODE (type) == RECORD_TYPE
	  || TREE_CODE (type) == UNION_TYPE
	  || TREE_CODE (type) == QUAL_UNION_TYPE)
	{
	  if (COMPLETE_TYPE_P (type)		/* not a forward reference */
	      && KNOWN_TYPE_TAG (type) == 0)	/* not yet declared */
	    sdbout_one_type (type);
	}

      /* Defer SDB information for top-level initialized variables! */
      if (! local
	  && MEM_P (value)
	  && DECL_INITIAL (decl))
	return;

      /* C++ in 2.3 makes nameless symbols.  That will be fixed later.
	 For now, avoid crashing.  */
      if (DECL_NAME (decl) == NULL_TREE)
	return;

      /* Record the name for, starting a symtab entry.  */
      if (local)
	name = IDENTIFIER_POINTER (DECL_NAME (decl));
      else
	name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));

      if (MEM_P (value)
	  && GET_CODE (XEXP (value, 0)) == SYMBOL_REF)
	{
	  PUT_SDB_DEF (name);
	  if (TREE_PUBLIC (decl))
	    {
	      PUT_SDB_VAL (XEXP (value, 0));
	      PUT_SDB_SCL (C_EXT);
	    }
	  else
	    {
	      PUT_SDB_VAL (XEXP (value, 0));
	      PUT_SDB_SCL (C_STAT);
	    }
	}
      else if (regno >= 0)
	{
	  PUT_SDB_DEF (name);
	  PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (regno));
	  PUT_SDB_SCL (C_REG);
	}
      else if (MEM_P (value)
	       && (MEM_P (XEXP (value, 0))
		   || (REG_P (XEXP (value, 0))
		       && REGNO (XEXP (value, 0)) != HARD_FRAME_POINTER_REGNUM
		       && REGNO (XEXP (value, 0)) != STACK_POINTER_REGNUM)))
	/* If the value is indirect by memory or by a register
	   that isn't the frame pointer
	   then it means the object is variable-sized and address through
	   that register or stack slot.  COFF has no way to represent this
	   so all we can do is output the variable as a pointer.  */
	{
	  PUT_SDB_DEF (name);
	  if (REG_P (XEXP (value, 0)))
	    {
	      PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (XEXP (value, 0))));
	      PUT_SDB_SCL (C_REG);
	    }
	  else
	    {
	      /* DECL_RTL looks like (MEM (MEM (PLUS (REG...)
		 (CONST_INT...)))).
		 We want the value of that CONST_INT.  */
	      /* Encore compiler hates a newline in a macro arg, it seems.  */
	      PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET
			       (XEXP (XEXP (value, 0), 0)));
	      PUT_SDB_SCL (C_AUTO);
	    }

	  /* Effectively do build_pointer_type, but don't cache this type,
	     since it might be temporary whereas the type it points to
	     might have been saved for inlining.  */
	  /* Don't use REFERENCE_TYPE because dbx can't handle that.  */
	  type = make_node (POINTER_TYPE);
	  TREE_TYPE (type) = TREE_TYPE (decl);
	}
      else if (MEM_P (value)
	       && ((GET_CODE (XEXP (value, 0)) == PLUS
		    && REG_P (XEXP (XEXP (value, 0), 0))
		    && CONST_INT_P (XEXP (XEXP (value, 0), 1)))
		   /* This is for variables which are at offset zero from
		      the frame pointer.  This happens on the Alpha.
		      Non-frame pointer registers are excluded above.  */
		   || (REG_P (XEXP (value, 0)))))
	{
	  /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...)))
	     or (MEM (REG...)).  We want the value of that CONST_INT
	     or zero.  */
	  PUT_SDB_DEF (name);
	  PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET (XEXP (value, 0)));
	  PUT_SDB_SCL (C_AUTO);
	}
      else
	{
	  /* It is something we don't know how to represent for SDB.  */
	  return;
	}
      break;

    default:
      break;
    }
  PUT_SDB_TYPE (plain_type (type));
  PUT_SDB_ENDEF;
}