Example #1
0
int
aarch_crypto_can_dual_issue (rtx_insn *producer_insn, rtx_insn *consumer_insn)
{
  rtx producer_set, consumer_set;
  rtx producer_src, consumer_src;

  producer_set = single_set (producer_insn);
  consumer_set = single_set (consumer_insn);

  producer_src = producer_set ? SET_SRC (producer_set) : NULL;
  consumer_src = consumer_set ? SET_SRC (consumer_set) : NULL;

  if (producer_src && consumer_src
      && GET_CODE (producer_src) == UNSPEC && GET_CODE (consumer_src) == UNSPEC
      && ((XINT (producer_src, 1) == UNSPEC_AESE
           && XINT (consumer_src, 1) == UNSPEC_AESMC)
          || (XINT (producer_src, 1) == UNSPEC_AESD
              && XINT (consumer_src, 1) == UNSPEC_AESIMC)))
  {
    unsigned int regno = REGNO (SET_DEST (producer_set));

    /* Before reload the registers are virtual, so the destination of
       consumer_set doesn't need to match.  */

    return (REGNO (SET_DEST (consumer_set)) == regno || !reload_completed)
	    && REGNO (XVECEXP (consumer_src, 0, 0)) == regno;
  }

  return 0;
}
Example #2
0
/* Check if all uses in DEF_INSN can be used in TARGET_INSN.  This
   would require full computation of available expressions;
   we check only restricted conditions, see use_killed_between.  */
static bool
all_uses_available_at (rtx_insn *def_insn, rtx_insn *target_insn)
{
  df_ref use;
  struct df_insn_info *insn_info = DF_INSN_INFO_GET (def_insn);
  rtx def_set = single_set (def_insn);
  rtx_insn *next;

  gcc_assert (def_set);

  /* If target_insn comes right after def_insn, which is very common
     for addresses, we can use a quicker test.  Ignore debug insns
     other than target insns for this.  */
  next = NEXT_INSN (def_insn);
  while (next && next != target_insn && DEBUG_INSN_P (next))
    next = NEXT_INSN (next);
  if (next == target_insn && REG_P (SET_DEST (def_set)))
    {
      rtx def_reg = SET_DEST (def_set);

      /* If the insn uses the reg that it defines, the substitution is
         invalid.  */
      FOR_EACH_INSN_INFO_USE (use, insn_info)
	if (rtx_equal_p (DF_REF_REG (use), def_reg))
	  return false;
      FOR_EACH_INSN_INFO_EQ_USE (use, insn_info)
	if (rtx_equal_p (DF_REF_REG (use), def_reg))
	  return false;
    }
Example #3
0
int
aarch_crypto_can_dual_issue (rtx_insn *producer_insn, rtx_insn *consumer_insn)
{
  rtx producer_set, consumer_set;
  rtx producer_src, consumer_src;

  producer_set = single_set (producer_insn);
  consumer_set = single_set (consumer_insn);

  producer_src = producer_set ? SET_SRC (producer_set) : NULL;
  consumer_src = consumer_set ? SET_SRC (consumer_set) : NULL;

  if (producer_src && consumer_src
      && GET_CODE (producer_src) == UNSPEC && GET_CODE (consumer_src) == UNSPEC
      && ((XINT (producer_src, 1) == UNSPEC_AESE
           && XINT (consumer_src, 1) == UNSPEC_AESMC)
          || (XINT (producer_src, 1) == UNSPEC_AESD
              && XINT (consumer_src, 1) == UNSPEC_AESIMC)))
  {
    unsigned int regno = REGNO (SET_DEST (producer_set));

    return REGNO (SET_DEST (consumer_set)) == regno
           && REGNO (XVECEXP (consumer_src, 0, 0)) == regno;
  }

  return 0;
}
Example #4
0
/* See whether a single set SET is a noop.  */
static int
reload_cse_noop_set_p (rtx set)
{
  if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
    return 0;

  return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
}
Example #5
0
/* Function to check whether the OP is a valid load/store operation.
   This is a helper function for the predicates:
   'nds32_load_multiple_operation' and 'nds32_store_multiple_operation'
   in predicates.md file.

   The OP is supposed to be a parallel rtx.
   For each element within this parallel rtx:
     (set (reg) (mem addr)) is the form for load operation.
     (set (mem addr) (reg)) is the form for store operation.
   We have to extract reg and mem of every element and
   check if the information is valid for multiple load/store operation.  */
bool
nds32_valid_multiple_load_store (rtx op, bool load_p)
{
  int count;
  int first_elt_regno;
  rtx elt;

  /* Get the counts of elements in the parallel rtx.  */
  count = XVECLEN (op, 0);
  /* Pick up the first element.  */
  elt = XVECEXP (op, 0, 0);

  /* Perform some quick check for the first element in the parallel rtx.  */
  if (GET_CODE (elt) != SET
      || count <= 1
      || count > 8)
    return false;

  /* Pick up regno of first element for further detail checking.
     Note that the form is different between load and store operation.  */
  if (load_p)
    {
      if (GET_CODE (SET_DEST (elt)) != REG
	  || GET_CODE (SET_SRC (elt)) != MEM)
	return false;

      first_elt_regno = REGNO (SET_DEST (elt));
    }
  else
    {
      if (GET_CODE (SET_SRC (elt)) != REG
	  || GET_CODE (SET_DEST (elt)) != MEM)
	return false;

      first_elt_regno = REGNO (SET_SRC (elt));
    }

  /* Perform detail check for each element.
     Refer to nds32-multiple.md for more information
     about following checking.
     The starting element of parallel rtx is index 0.  */
  if (!nds32_consecutive_registers_load_store_p (op, load_p, 0,
						 first_elt_regno,
						 count))
    return false;

  /* Pass all test, this is a valid rtx.  */
  return true;
}
Example #6
0
/* In case function does not return value,  we get clobber of pseudo followed
   by set to hard return value.  */
static rtx
skip_unreturned_value (rtx orig_insn)
{
  rtx insn = next_nonnote_insn (orig_insn);

  /* Skip possible clobber of pseudo return register.  */
  if (insn
      && GET_CODE (insn) == INSN
      && GET_CODE (PATTERN (insn)) == CLOBBER
      && REG_P (XEXP (PATTERN (insn), 0))
      && (REGNO (XEXP (PATTERN (insn), 0)) >= FIRST_PSEUDO_REGISTER))
    {
      rtx set_insn = next_nonnote_insn (insn);
      rtx set;
      if (!set_insn)
	return insn;
      set = single_set (set_insn);
      if (!set
	  || SET_SRC (set) != XEXP (PATTERN (insn), 0)
	  || SET_DEST (set) != current_function_return_rtx)
	return insn;
      return set_insn;
    }
  return orig_insn;
}
Example #7
0
/* Return true if insn is an instruction that sets a target register.
   if CHECK_CONST is true, only return true if the source is constant.
   If such a set is found and REGNO is nonzero, assign the register number
   of the destination register to *REGNO.  */
static int
insn_sets_btr_p (const_rtx insn, int check_const, int *regno)
{
  rtx set;

  if (NONJUMP_INSN_P (insn)
      && (set = single_set (insn)))
    {
      rtx dest = SET_DEST (set);
      rtx src = SET_SRC (set);

      if (GET_CODE (dest) == SUBREG)
	dest = XEXP (dest, 0);

      if (REG_P (dest)
	  && TEST_HARD_REG_BIT (all_btrs, REGNO (dest)))
	{
	  gcc_assert (!btr_referenced_p (src, NULL));

	  if (!check_const || CONSTANT_P (src))
	    {
	      if (regno)
		*regno = REGNO (dest);
	      return 1;
	    }
	}
    }
  return 0;
}
Example #8
0
/* Return true if is load/store with SYMBOL_REF addressing mode
   and memory mode is SImode.  */
bool
nds32_symbol_load_store_p (rtx_insn *insn)
{
  rtx mem_src = NULL_RTX;

  switch (get_attr_type (insn))
    {
    case TYPE_LOAD:
      mem_src = SET_SRC (PATTERN (insn));
      break;
    case TYPE_STORE:
      mem_src = SET_DEST (PATTERN (insn));
      break;
    default:
      break;
    }

  /* Find load/store insn with addressing mode is SYMBOL_REF.  */
  if (mem_src != NULL_RTX)
    {
      if ((GET_CODE (mem_src) == ZERO_EXTEND)
	  || (GET_CODE (mem_src) == SIGN_EXTEND))
	mem_src = XEXP (mem_src, 0);

      if ((GET_CODE (XEXP (mem_src, 0)) == SYMBOL_REF)
	   || (GET_CODE (XEXP (mem_src, 0)) == LO_SUM))
	return true;
    }

  return false;
}
Example #9
0
static rtx
conforming_compare (rtx_insn *insn)
{
  rtx set, src, dest;

  set = single_set (insn);
  if (set == NULL)
    return NULL;

  src = SET_SRC (set);
  if (GET_CODE (src) != COMPARE)
    return NULL;

  dest = SET_DEST (set);
  if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
    return NULL;

  if (!REG_P (XEXP (src, 0)))
    return NULL;

  if (CONSTANT_P (XEXP (src, 1)) || REG_P (XEXP (src, 1)))
    return src;

  if (GET_CODE (XEXP (src, 1)) == UNSPEC)
    {
      for (int i = 0; i < XVECLEN (XEXP (src, 1), 0); i++)
	if (!REG_P (XVECEXP (XEXP (src, 1), 0, i)))
	  return NULL;
      return src;
    }

  return NULL;
}
Example #10
0
static void
test_uncond_jump ()
{
  rtx_insn *label = gen_label_rtx ();
  rtx jump_pat = gen_rtx_SET (pc_rtx,
			      gen_rtx_LABEL_REF (VOIDmode,
						 label));
  ASSERT_EQ (SET, jump_pat->code);
  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
  ASSERT_EQ (label, label_ref_label (SET_SRC (jump_pat)));
  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);

  verify_print_pattern ("pc=L0", jump_pat);

  ASSERT_RTL_DUMP_EQ ("(set (pc)\n"
		      "    (label_ref 0))",
		      jump_pat);

  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
  ASSERT_FALSE (any_condjump_p (jump_insn));
  ASSERT_TRUE (any_uncondjump_p (jump_insn));
  ASSERT_TRUE (pc_set (jump_insn));
  ASSERT_TRUE (simplejump_p (jump_insn));
  ASSERT_TRUE (onlyjump_p (jump_insn));
  ASSERT_TRUE (control_flow_insn_p (jump_insn));

  ASSERT_RTL_DUMP_EQ ("(cjump_insn 1 (set (pc)\n"
		      "        (label_ref 0)))\n",
		      jump_insn);
}
Example #11
0
static void
adjust_frame_related_expr (rtx last_sp_set, rtx insn,
			   HOST_WIDE_INT this_adjust)
{
  rtx note = find_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, NULL_RTX);
  rtx new_expr = NULL_RTX;

  if (note == NULL_RTX && RTX_FRAME_RELATED_P (insn))
    return;

  if (note
      && GET_CODE (XEXP (note, 0)) == SEQUENCE
      && XVECLEN (XEXP (note, 0), 0) >= 2)
    {
      rtx expr = XEXP (note, 0);
      rtx last = XVECEXP (expr, 0, XVECLEN (expr, 0) - 1);
      int i;

      if (GET_CODE (last) == SET
	  && RTX_FRAME_RELATED_P (last) == RTX_FRAME_RELATED_P (insn)
	  && SET_DEST (last) == stack_pointer_rtx
	  && GET_CODE (SET_SRC (last)) == PLUS
	  && XEXP (SET_SRC (last), 0) == stack_pointer_rtx
	  && CONST_INT_P (XEXP (SET_SRC (last), 1)))
	{
	  XEXP (SET_SRC (last), 1)
	    = GEN_INT (INTVAL (XEXP (SET_SRC (last), 1)) + this_adjust);
	  return;
	}

      new_expr = gen_rtx_SEQUENCE (VOIDmode,
				   rtvec_alloc (XVECLEN (expr, 0) + 1));
      for (i = 0; i < XVECLEN (expr, 0); i++)
	XVECEXP (new_expr, 0, i) = XVECEXP (expr, 0, i);
    }
  else
    {
      new_expr = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
      if (note)
	XVECEXP (new_expr, 0, 0) = XEXP (note, 0);
      else
	{
	  rtx expr = copy_rtx (single_set_for_csa (last_sp_set));

	  XEXP (SET_SRC (expr), 1)
	    = GEN_INT (INTVAL (XEXP (SET_SRC (expr), 1)) - this_adjust);
	  RTX_FRAME_RELATED_P (expr) = 1;
	  XVECEXP (new_expr, 0, 0) = expr;
	}
    }

  XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1)
    = copy_rtx (single_set_for_csa (insn));
  RTX_FRAME_RELATED_P (XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1))
    = RTX_FRAME_RELATED_P (insn);
  if (note)
    XEXP (note, 0) = new_expr;
  else
    add_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, new_expr);
}
void
fma_node::dump_info (ATTRIBUTE_UNUSED fma_forest *forest)
{
  struct du_chain *chain;
  std::list<fma_node *>::iterator fma_child;

  gcc_assert (dump_file);

  if (this->get_children ()->empty ())
    return;

  fprintf (dump_file, "Instruction(s)");
  for (chain = this->m_head->first; chain; chain = chain->next_use)
    {
      if (!is_fmul_fmac_insn (chain->insn, true))
	continue;

      if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
	continue;

      fprintf (dump_file, " %d", INSN_UID (chain->insn));
    }

  fprintf (dump_file, " is(are) accumulator dependency of instructions");
  for (fma_child = this->get_children ()->begin ();
       fma_child != this->get_children ()->end (); fma_child++)
    fprintf (dump_file, " %d", INSN_UID ((*fma_child)->m_insn));
  fprintf (dump_file, "\n");
}
Example #13
0
static rtx
single_set_for_csa (rtx insn)
{
    int i;
    rtx tmp = single_set (insn);
    if (tmp)
        return tmp;

    if (!NONJUMP_INSN_P (insn)
            || GET_CODE (PATTERN (insn)) != PARALLEL)
        return NULL_RTX;

    tmp = PATTERN (insn);
    if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
        return NULL_RTX;

    for (i = 1; i < XVECLEN (tmp, 0); ++i)
    {
        rtx this_rtx = XVECEXP (tmp, 0, i);

        /* The special case is allowing a no-op set.  */
        if (GET_CODE (this_rtx) == SET
                && SET_SRC (this_rtx) == SET_DEST (this_rtx))
            ;
        else if (GET_CODE (this_rtx) != CLOBBER
                 && GET_CODE (this_rtx) != USE)
            return NULL_RTX;
    }

    return XVECEXP (tmp, 0, 0);
}
Example #14
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; 
}
Example #15
0
static bool
arithmetic_flags_clobber_p (rtx_insn *insn)
{
  rtx pat, x;

  if (!NONJUMP_INSN_P (insn))
    return false;
  pat = PATTERN (insn);
  if (extract_asm_operands (pat))
    return false;

  if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
    {
      x = XVECEXP (pat, 0, 0);
      if (GET_CODE (x) != SET)
	return false;
      x = SET_DEST (x);
      if (!REG_P (x))
	return false;

      x = XVECEXP (pat, 0, 1);
      if (GET_CODE (x) == CLOBBER)
	{
	  x = XEXP (x, 0);
	  if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
	    return true;
	}
    }

  return false;
}
Example #16
0
File: rtl.c Project: 0day-ci/gcc
enum rtx_code
classify_insn (rtx x)
{
  if (LABEL_P (x))
    return CODE_LABEL;
  if (GET_CODE (x) == CALL)
    return CALL_INSN;
  if (ANY_RETURN_P (x))
    return JUMP_INSN;
  if (GET_CODE (x) == SET)
    {
      if (GET_CODE (SET_DEST (x)) == PC)
	return JUMP_INSN;
      else if (GET_CODE (SET_SRC (x)) == CALL)
	return CALL_INSN;
      else
	return INSN;
    }
  if (GET_CODE (x) == PARALLEL)
    {
      int j;
      bool has_return_p = false;
      for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
	if (GET_CODE (XVECEXP (x, 0, j)) == CALL)
	  return CALL_INSN;
	else if (ANY_RETURN_P (XVECEXP (x, 0, j)))
	  has_return_p = true;
	else if (GET_CODE (XVECEXP (x, 0, j)) == SET
		 && GET_CODE (SET_DEST (XVECEXP (x, 0, j))) == PC)
	  return JUMP_INSN;
	else if (GET_CODE (XVECEXP (x, 0, j)) == SET
		 && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL)
	  return CALL_INSN;
      if (has_return_p)
	return JUMP_INSN;
    }
#ifdef GENERATOR_FILE
  if (GET_CODE (x) == MATCH_OPERAND
      || GET_CODE (x) == MATCH_OPERATOR
      || GET_CODE (x) == MATCH_PARALLEL
      || GET_CODE (x) == MATCH_OP_DUP
      || GET_CODE (x) == MATCH_DUP
      || GET_CODE (x) == PARALLEL)
    return UNKNOWN;
#endif
  return INSN;
}
void
fma_node::rename (fma_forest *forest)
{
  int cur_parity, target_parity;

  /* This is alternate root of a chain and thus has no children.  It will be
     renamed when processing the canonical root for that chain.  */
  if (!this->m_head)
    return;

  target_parity = forest->get_target_parity ();
  if (this->m_parent)
    target_parity = this->m_parent->get_parity ();
  cur_parity = this->get_parity ();

  /* Rename if parity differs.  */
  if (cur_parity != target_parity)
    {
      rtx_insn *insn = this->m_insn;
      HARD_REG_SET unavailable;
      enum machine_mode mode;
      int reg;

      if (dump_file)
	{
	  unsigned cur_dest_reg = this->m_head->regno;

	  fprintf (dump_file, "FMA or FMUL at insn %d but destination "
		   "register (%s) has different parity from expected to "
		   "maximize FPU pipeline utilization\n", INSN_UID (insn),
		   reg_names[cur_dest_reg]);
	}

      /* Don't clobber traceback for noreturn functions.  */
      CLEAR_HARD_REG_SET (unavailable);
      if (frame_pointer_needed)
	{
	  add_to_hard_reg_set (&unavailable, Pmode, FRAME_POINTER_REGNUM);
	  add_to_hard_reg_set (&unavailable, Pmode, HARD_FRAME_POINTER_REGNUM);
	}

      /* Exclude registers with wrong parity.  */
      mode = GET_MODE (SET_DEST (PATTERN (insn)));
      for (reg = cur_parity; reg < FIRST_PSEUDO_REGISTER; reg += 2)
	add_to_hard_reg_set (&unavailable, mode, reg);

      if (!rename_single_chain (this->m_head, &unavailable))
	{
	  if (dump_file)
	    fprintf (dump_file, "Destination register of insn %d could not be "
		     "renamed. Dependent FMA insns will use this parity from "
		     "there on.\n", INSN_UID (insn));
	}
      else
	cur_parity = target_parity;
    }

  forest->get_globals ()->update_balance (cur_parity);
}
Example #18
0
int
arm_no_early_store_addr_dep (rtx producer, rtx consumer)
{
  rtx value = arm_find_sub_rtx_with_code (producer, SET, false);
  rtx addr = arm_find_sub_rtx_with_code (consumer, SET, false);

  if (value)
    value = SET_DEST (value);

  if (addr)
    addr = SET_DEST (addr);

  if (!value || !addr)
    return 0;

  return !reg_overlap_mentioned_p (value, addr);
}
Example #19
0
/* A subroutine that checks multiple load and store
   using consecutive registers.
     OP is a parallel rtx we would like to check.
     LOAD_P indicates whether we are checking load operation.
     PAR_INDEX is starting element of parallel rtx.
     FIRST_ELT_REGNO is used to tell starting register number.
     COUNT helps us to check consecutive register numbers.  */
static bool
nds32_consecutive_registers_load_store_p (rtx op,
					  bool load_p,
					  int par_index,
					  int first_elt_regno,
					  int count)
{
  int i;
  int check_regno;
  rtx elt;
  rtx elt_reg;
  rtx elt_mem;

  for (i = 0; i < count; i++)
    {
      /* Pick up each element from parallel rtx.  */
      elt = XVECEXP (op, 0, i + par_index);

      /* If this element is not a 'set' rtx, return false immediately.  */
      if (GET_CODE (elt) != SET)
	return false;

      /* Pick up reg and mem of this element.  */
      elt_reg = load_p ? SET_DEST (elt) : SET_SRC (elt);
      elt_mem = load_p ? SET_SRC (elt) : SET_DEST (elt);

      /* If elt_reg is not a expected reg rtx, return false.  */
      if (GET_CODE (elt_reg) != REG || GET_MODE (elt_reg) != SImode)
	return false;
      /* If elt_mem is not a expected mem rtx, return false.  */
      if (GET_CODE (elt_mem) != MEM || GET_MODE (elt_mem) != SImode)
	return false;

      /* The consecutive registers should be in (Rb,Rb+1...Re) order.  */
      check_regno = first_elt_regno + i;

      /* If the register number is not continuous, return false.  */
      if (REGNO (elt_reg) != (unsigned int) check_regno)
	return false;
    }

  return true;
}
Example #20
0
static unsigned int
postreload_load (void)
{
  basic_block bb;

  init_alias_analysis ();

  FOR_EACH_BB (bb)
    {
      rtx insn;

      htab_load = htab_create (10, load_htab_hash, load_htab_eq, NULL);

      FOR_BB_INSNS (bb, insn)
	{
	  rtx set;
	  struct load **load;

	  /* Set reg_kill, invalidate entries if there is an
	     aliasing store or if the registers making up the address
	     change.  */
	  htab_traverse_noresize
	    (htab_load, find_reg_kill_and_mem_invalidate, insn);	

	  set = single_set (insn);
	  if (interesting_second_load (set, &load, insn))
	    {
	      rtx move;

	      move = gen_move_insn (SET_DEST (set), (*load)->reg);
	      /* Make sure we can generate a move.  */
	      extract_insn (move);
	      if (! constrain_operands (1))
		continue;

	      move = emit_insn_before (move, (*load)->reg_kill);
	      delete_insn (insn);

	      if (dump_file)
		{
		  fputs ("Replaced this load:\n  ", dump_file);
		  print_inline_rtx (dump_file, insn, 2);
		  fputs ("\n  with this move:\n  ", dump_file);
		  print_inline_rtx (dump_file, move, 2);
		  fputs ("\n\n", dump_file);
		}
	    }
	  else if (interesting_load (set))
	    alloc_load (set);
	  else if (CALL_P (insn))
	    htab_empty (htab_load);
	}

      htab_empty (htab_load);
    }
Example #21
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;
}
Example #22
0
/* PRODUCER and CONSUMER are two potentially dependant RTX.  PRODUCER
   (possibly) contains a SET which will provide a result we can access
   using the SET_DEST macro.  We will place the RTX which would be
   written by PRODUCER in SET_SOURCE.
   Similarly, CONSUMER (possibly) contains a SET which has an operand
   we can access using SET_SRC.  We place this operand in
   SET_DESTINATION.

   Return nonzero if we found the SET RTX we expected.  */
static int
arm_get_set_operands (rtx producer, rtx consumer,
		      rtx *set_source, rtx *set_destination)
{
  rtx set_producer = arm_find_sub_rtx_with_code (producer, SET, false);
  rtx set_consumer = arm_find_sub_rtx_with_code (consumer, SET, false);

  if (set_producer && set_consumer)
    {
      *set_source = SET_DEST (set_producer);
      *set_destination = SET_SRC (set_consumer);
      return 1;
    }
  return 0;
}
Example #23
0
static rtx
skip_pic_restore (rtx orig_insn)
{
  rtx insn, set = NULL_RTX;

  insn = next_nonnote_insn (orig_insn);

  if (insn)
    set = single_set (insn);

  if (insn && set && SET_DEST (set) == pic_offset_table_rtx)
    return insn;

  return orig_insn;
}
Example #24
0
static void
maybe_propagate_label_ref (rtx jump_insn, rtx prev_nonjump_insn)
{
  rtx label_note, pc, pc_src;

  pc = pc_set (jump_insn);
  pc_src = pc != NULL ? SET_SRC (pc) : NULL;
  label_note = find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);

  /* If the previous non-jump insn sets something to a label,
     something that this jump insn uses, make that label the primary
     target of this insn if we don't yet have any.  That previous
     insn must be a single_set and not refer to more than one label.
     The jump insn must not refer to other labels as jump targets
     and must be a plain (set (pc) ...), maybe in a parallel, and
     may refer to the item being set only directly or as one of the
     arms in an IF_THEN_ELSE.  */

  if (label_note != NULL && pc_src != NULL)
    {
      rtx label_set = single_set (prev_nonjump_insn);
      rtx label_dest = label_set != NULL ? SET_DEST (label_set) : NULL;

      if (label_set != NULL
	  /* The source must be the direct LABEL_REF, not a
	     PLUS, UNSPEC, IF_THEN_ELSE etc.  */
	  && GET_CODE (SET_SRC (label_set)) == LABEL_REF
	  && (rtx_equal_p (label_dest, pc_src)
	      || (GET_CODE (pc_src) == IF_THEN_ELSE
		  && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
		      || rtx_equal_p (label_dest, XEXP (pc_src, 2))))))
	{
	  /* The CODE_LABEL referred to in the note must be the
	     CODE_LABEL in the LABEL_REF of the "set".  We can
	     conveniently use it for the marker function, which
	     requires a LABEL_REF wrapping.  */
	  gcc_assert (XEXP (label_note, 0) == XEXP (SET_SRC (label_set), 0));

	  mark_jump_label_1 (label_set, jump_insn, false, true);

	  gcc_assert (JUMP_LABEL (jump_insn) == XEXP (label_note, 0));
	}
    }
}
Example #25
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;
}
Example #26
0
File: ree.c Project: aixoss/gcc
static bool
is_cond_copy_insn (rtx insn, rtx *reg1, rtx *reg2)
{
  rtx expr = single_set (insn);

  if (expr != NULL_RTX
      && GET_CODE (expr) == SET
      && GET_CODE (SET_DEST (expr)) == REG
      && GET_CODE (SET_SRC (expr))  == IF_THEN_ELSE
      && GET_CODE (XEXP (SET_SRC (expr), 1)) == REG
      && GET_CODE (XEXP (SET_SRC (expr), 2)) == REG)
    {
      *reg1 = XEXP (SET_SRC (expr), 1);
      *reg2 = XEXP (SET_SRC (expr), 2);
      return true;
    }

  return false;
}
Example #27
0
File: ree.c Project: aixoss/gcc
static bool
transform_ifelse (ext_cand *cand, rtx def_insn)
{
  rtx set_insn = PATTERN (def_insn);
  rtx srcreg, dstreg, srcreg2;
  rtx map_srcreg, map_dstreg, map_srcreg2;
  rtx ifexpr;
  rtx cond;
  rtx new_set;

  gcc_assert (GET_CODE (set_insn) == SET);

  cond = XEXP (SET_SRC (set_insn), 0);
  dstreg = SET_DEST (set_insn);
  srcreg = XEXP (SET_SRC (set_insn), 1);
  srcreg2 = XEXP (SET_SRC (set_insn), 2);
  /* If the conditional move already has the right or wider mode,
     there is nothing to do.  */
  if (GET_MODE_SIZE (GET_MODE (dstreg)) >= GET_MODE_SIZE (cand->mode))
    return true;

  map_srcreg = gen_rtx_REG (cand->mode, REGNO (srcreg));
  map_srcreg2 = gen_rtx_REG (cand->mode, REGNO (srcreg2));
  map_dstreg = gen_rtx_REG (cand->mode, REGNO (dstreg));
  ifexpr = gen_rtx_IF_THEN_ELSE (cand->mode, cond, map_srcreg, map_srcreg2);
  new_set = gen_rtx_SET (VOIDmode, map_dstreg, ifexpr);

  if (validate_change (def_insn, &PATTERN (def_insn), new_set, true)
      && update_reg_equal_equiv_notes (def_insn, cand->mode, GET_MODE (dstreg),
				       cand->code))
    {
      if (dump_file)
        {
          fprintf (dump_file,
		   "Mode of conditional move instruction extended:\n");
          print_rtl_single (dump_file, def_insn);
        }
      return true;
    }

  return false;
}
Example #28
0
static rtx
skip_stack_adjustment (rtx orig_insn)
{
  rtx insn, set = NULL_RTX;

  insn = next_nonnote_insn (orig_insn);

  if (insn)
    set = single_set (insn);

  if (insn
      && set
      && GET_CODE (SET_SRC (set)) == PLUS
      && XEXP (SET_SRC (set), 0) == stack_pointer_rtx
      && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
      && SET_DEST (set) == stack_pointer_rtx)
    return insn;

  return orig_insn;
}
Example #29
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);
}
Example #30
0
static rtx
conforming_compare (rtx_insn *insn)
{
  rtx set, src, dest;

  set = single_set (insn);
  if (set == NULL)
    return NULL;

  src = SET_SRC (set);
  if (GET_CODE (src) != COMPARE)
    return NULL;

  dest = SET_DEST (set);
  if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
    return NULL;

  if (REG_P (XEXP (src, 0))
      && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
    return src;

  return NULL;
}