コード例 #1
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return non-zero if the consumer (a multiply-accumulate instruction)
   has an accumulator dependency on the result of the producer (a
   multiplication instruction) and no other dependency on that result.  */
int
arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
{
  rtx mul = PATTERN (producer);
  rtx mac = PATTERN (consumer);
  rtx mul_result;
  rtx mac_op0, mac_op1, mac_acc;

  if (GET_CODE (mul) == COND_EXEC)
    mul = COND_EXEC_CODE (mul);
  if (GET_CODE (mac) == COND_EXEC)
    mac = COND_EXEC_CODE (mac);

  /* Check that mul is of the form (set (...) (mult ...))
     and mla is of the form (set (...) (plus (mult ...) (...))).  */
  if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
      || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
          || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
    return 0;

  mul_result = XEXP (mul, 0);
  mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
  mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
  mac_acc = XEXP (XEXP (mac, 1), 1);

  return (reg_overlap_mentioned_p (mul_result, mac_acc)
          && !reg_overlap_mentioned_p (mul_result, mac_op0)
          && !reg_overlap_mentioned_p (mul_result, mac_op1));
}
コード例 #2
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return non-zero iff the consumer (a multiply-accumulate or a
   multiple-subtract instruction) has an accumulator dependency on the
   result of the producer and no other dependency on that result.  It
   does not check if the producer is multiply-accumulate instruction.  */
int
arm_mac_accumulator_is_result (rtx producer, rtx consumer)
{
  rtx result;
  rtx op0, op1, acc;

  producer = PATTERN (producer);
  consumer = PATTERN (consumer);

  if (GET_CODE (producer) == COND_EXEC)
    producer = COND_EXEC_CODE (producer);
  if (GET_CODE (consumer) == COND_EXEC)
    consumer = COND_EXEC_CODE (consumer);

  if (GET_CODE (producer) != SET)
    return 0;

  result = XEXP (producer, 0);

  if (GET_CODE (consumer) != SET)
    return 0;

  /* Check that the consumer is of the form
     (set (...) (plus (mult ...) (...)))
     or
     (set (...) (minus (...) (mult ...))).  */
  if (GET_CODE (XEXP (consumer, 1)) == PLUS)
    {
      if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT)
        return 0;

      op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0);
      op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1);
      acc = XEXP (XEXP (consumer, 1), 1);
    }
  else if (GET_CODE (XEXP (consumer, 1)) == MINUS)
    {
      if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT)
        return 0;

      op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0);
      op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1);
      acc = XEXP (XEXP (consumer, 1), 0);
    }
  else
    return 0;

  return (reg_overlap_mentioned_p (result, acc)
          && !reg_overlap_mentioned_p (result, op0)
          && !reg_overlap_mentioned_p (result, op1));
}
コード例 #3
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return nonzero if the CONSUMER (a mul or mac op) does not
   have an early register mult dependency on the result of
   PRODUCER.  */
int
arm_no_early_mul_dep (rtx producer, rtx consumer)
{
  rtx value, op;

  if (!arm_get_set_operands (producer, consumer, &value, &op))
    return 0;

  if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
    {
      if (GET_CODE (XEXP (op, 0)) == MULT)
	return !reg_overlap_mentioned_p (value, XEXP (op, 0));
      else
	return !reg_overlap_mentioned_p (value, XEXP (op, 1));
    }

  return 0;
}
コード例 #4
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return nonzero if the CONSUMER instruction (a load) does need
   PRODUCER's value to calculate the address.  */
int
arm_early_load_addr_dep (rtx producer, rtx consumer)
{
  rtx value, addr;

  if (!arm_get_set_operands (producer, consumer, &value, &addr))
    return 0;

  return reg_overlap_mentioned_p (value, addr);
}
コード例 #5
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return nonzero if the CONSUMER instruction (an ALU op) does not
   have an early register shift value dependency on the result of
   PRODUCER.  */
int
arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
{
  rtx value, op;
  rtx early_op;

  if (!arm_get_set_operands (producer, consumer, &value, &op))
    return 0;

  if ((early_op = arm_find_shift_sub_rtx (op)))
    /* We want to check the value being shifted.  */
    if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
      return 1;

  return 0;
}
コード例 #6
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
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);
}
コード例 #7
0
ファイル: aarch-common.c プロジェクト: Nodplus/gcc
/* Return nonzero if the CONSUMER instruction (an ALU op) does not
   have an early register shift value or amount dependency on the
   result of PRODUCER.  */
int
arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
{
  rtx value, op;
  rtx early_op;

  if (!arm_get_set_operands (producer, consumer, &value, &op))
    return 0;

  if ((early_op = arm_find_shift_sub_rtx (op)))
    {
      if (REG_P (early_op))
	early_op = op;

      return !reg_overlap_mentioned_p (value, early_op);
    }

  return 0;
}
コード例 #8
0
ファイル: auto-inc-dec.c プロジェクト: nevinhappy/gcc
static bool
find_inc (bool first_try)
{
  rtx insn;
  basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
  rtx other_insn;
  df_ref *def_rec;

  /* Make sure this reg appears only once in this insn.  */
  if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1)
    {
      if (dump_file)
	fprintf (dump_file, "mem count failure\n");
      return false;
    }

  if (dump_file)
    dump_mem_insn (dump_file);

  /* Find the next use that is an inc.  */
  insn = get_next_ref (REGNO (mem_insn.reg0),
		       BLOCK_FOR_INSN (mem_insn.insn),
		       reg_next_inc_use);
  if (!insn)
    return false;

  /* Even though we know the next use is an add or inc because it came
     from the reg_next_inc_use, we must still reparse.  */
  if (!parse_add_or_inc (insn, false))
    {
      /* Next use was not an add.  Look for one extra case. It could be
	 that we have:

	 *(a + b)
	 ...= a;
	 ...= b + a

	 if we reverse the operands in the mem ref we would
	 find this.  Only try it once though.  */
      if (first_try && !mem_insn.reg1_is_const)
	{
	  reverse_mem ();
	  return find_inc (false);
	}
      else
	return false;
    }

  /* Need to assure that none of the operands of the inc instruction are
     assigned to by the mem insn.  */
  for (def_rec = DF_INSN_DEFS (mem_insn.insn); *def_rec; def_rec++)
    {
      df_ref def = *def_rec;
      unsigned int regno = DF_REF_REGNO (def);
      if ((regno == REGNO (inc_insn.reg0))
	  || (regno == REGNO (inc_insn.reg_res)))
	{
	  if (dump_file)
	    fprintf (dump_file, "inc conflicts with store failure.\n");
	  return false;
	}
      if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1)))
	{
	  if (dump_file)
	    fprintf (dump_file, "inc conflicts with store failure.\n");
	  return false;
	}
    }

  if (dump_file)
    dump_inc_insn (dump_file);

  if (inc_insn.form == FORM_POST_ADD)
    {
      /* Make sure that there is no insn that assigns to inc_insn.res
	 between the mem_insn and the inc_insn.  */
      rtx other_insn = get_next_ref (REGNO (inc_insn.reg_res),
				     BLOCK_FOR_INSN (mem_insn.insn),
				     reg_next_def);
      if (other_insn != inc_insn.insn)
	{
	  if (dump_file)
	    fprintf (dump_file,
		     "result of add is assigned to between mem and inc insns.\n");
	  return false;
	}

      other_insn = get_next_ref (REGNO (inc_insn.reg_res),
				 BLOCK_FOR_INSN (mem_insn.insn),
				 reg_next_use);
      if (other_insn
	  && (other_insn != inc_insn.insn)
	  && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn)))
	{
	  if (dump_file)
	    fprintf (dump_file,
		     "result of add is used between mem and inc insns.\n");
	  return false;
	}

      /* For the post_add to work, the result_reg of the inc must not be
	 used in the mem insn since this will become the new index
	 register.  */
      if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn)))
	{
	  if (dump_file)
	    fprintf (dump_file, "base reg replacement failure.\n");
	  return false;
	}
    }

  if (mem_insn.reg1_is_const)
    {
      if (mem_insn.reg1_val == 0)
	{
	  if (!inc_insn.reg1_is_const)
	    {
	      /* The mem looks like *r0 and the rhs of the add has two
		 registers.  */
	      int luid = DF_INSN_LUID (inc_insn.insn);
	      if (inc_insn.form == FORM_POST_ADD)
		{
		  /* The trick is that we are not going to increment r0,
		     we are going to increment the result of the add insn.
		     For this trick to be correct, the result reg of
		     the inc must be a valid addressing reg.  */
		  addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
		  if (GET_MODE (inc_insn.reg_res)
		      != targetm.addr_space.address_mode (as))
		    {
		      if (dump_file)
			fprintf (dump_file, "base reg mode failure.\n");
		      return false;
		    }

		  /* We also need to make sure that the next use of
		     inc result is after the inc.  */
		  other_insn
		    = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
		  if (other_insn && luid > DF_INSN_LUID (other_insn))
		    return false;

		  if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
		    reverse_inc ();
		}

	      other_insn
		= get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
	      if (other_insn && luid > DF_INSN_LUID (other_insn))
		return false;
	    }
	}
      /* Both the inc/add and the mem have a constant.  Need to check
	 that the constants are ok. */
      else if ((mem_insn.reg1_val != inc_insn.reg1_val)
	       && (mem_insn.reg1_val != -inc_insn.reg1_val))
	return false;
    }
  else
    {
      /* The mem insn is of the form *(a + b) where a and b are both
	 regs.  It may be that in order to match the add or inc we
	 need to treat it as if it was *(b + a).  It may also be that
	 the add is of the form a + c where c does not match b and
	 then we just abandon this.  */

      int luid = DF_INSN_LUID (inc_insn.insn);
      rtx other_insn;

      /* Make sure this reg appears only once in this insn.  */
      if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1)
	return false;

      if (inc_insn.form == FORM_POST_ADD)
	{
	  /* For this trick to be correct, the result reg of the inc
	     must be a valid addressing reg.  */
	  addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
	  if (GET_MODE (inc_insn.reg_res)
	      != targetm.addr_space.address_mode (as))
	    {
	      if (dump_file)
		fprintf (dump_file, "base reg mode failure.\n");
	      return false;
	    }

	  if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
	    {
	      if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
		{
		  /* See comment above on find_inc (false) call.  */
		  if (first_try)
		    {
		      reverse_mem ();
		      return find_inc (false);
		    }
		  else
		    return false;
		}

	      /* Need to check that there are no assignments to b
		 before the add insn.  */
	      other_insn
		= get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
	      if (other_insn && luid > DF_INSN_LUID (other_insn))
		return false;
	      /* All ok for the next step.  */
	    }
	  else
	    {
	      /* We know that mem_insn.reg0 must equal inc_insn.reg1
		 or else we would not have found the inc insn.  */
	      reverse_mem ();
	      if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
		{
		  /* See comment above on find_inc (false) call.  */
		  if (first_try)
		    return find_inc (false);
		  else
		    return false;
		}
	      /* To have gotten here know that.
	       *(b + a)

	       ... = (b + a)

	       We also know that the lhs of the inc is not b or a.  We
	       need to make sure that there are no assignments to b
	       between the mem ref and the inc.  */

	      other_insn
		= get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def);
	      if (other_insn && luid > DF_INSN_LUID (other_insn))
		return false;
	    }

	  /* Need to check that the next use of the add result is later than
	     add insn since this will be the reg incremented.  */
	  other_insn
	    = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use);
	  if (other_insn && luid > DF_INSN_LUID (other_insn))
	    return false;
	}
      else /* FORM_POST_INC.  There is less to check here because we
	      know that operands must line up.  */
	{
	  if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
	    /* See comment above on find_inc (false) call.  */
	    {
	      if (first_try)
		{
		  reverse_mem ();
		  return find_inc (false);
		}
	      else
		return false;
	    }

	  /* To have gotten here know that.
	   *(a + b)

	   ... = (a + b)

	   We also know that the lhs of the inc is not b.  We need to make
	   sure that there are no assignments to b between the mem ref and
	   the inc.  */
	  other_insn
	    = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
	  if (other_insn && luid > DF_INSN_LUID (other_insn))
	    return false;
	}
    }

  if (inc_insn.form == FORM_POST_INC)
    {
      other_insn
	= get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use);
      /* When we found inc_insn, we were looking for the
	 next add or inc, not the next insn that used the
	 reg.  Because we are going to increment the reg
	 in this form, we need to make sure that there
	 were no intervening uses of reg.  */
      if (inc_insn.insn != other_insn)
	return false;
    }

  return try_merge ();
}
コード例 #9
0
ファイル: regcprop.c プロジェクト: AlissonLinhares/NativeKit
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;
      rtx link;
      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);

      /* If we have dead sets in the insn, then we need to note these as we
	 would clobbers.  */
      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
	{
	  if (REG_NOTE_KIND (link) == REG_UNUSED)
	    {
	      kill_value (XEXP (link, 0), vd);
	      /* Furthermore, if the insn looked like a single-set,
		 but the dead store kills the source value of that
		 set, then we can no-longer use the plain move
		 special case below.  */
	      if (set
		  && reg_overlap_mentioned_p (XEXP (link, 0), SET_SRC (set)))
		set = NULL;
	    }
	}

      /* 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;
}
コード例 #10
0
void
vax_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
{
  if (GET_CODE (exp) == SET)
    {
      if (GET_CODE (SET_SRC (exp)) == CALL)
	CC_STATUS_INIT;
      else if (GET_CODE (SET_DEST (exp)) != ZERO_EXTRACT
	       && GET_CODE (SET_DEST (exp)) != PC)
	{
	  cc_status.flags = 0;
	  /* The integer operations below don't set carry or
	     set it in an incompatible way.  That's ok though
	     as the Z bit is all we need when doing unsigned
	     comparisons on the result of these insns (since
	     they're always with 0).  Set CC_NO_OVERFLOW to
	     generate the correct unsigned branches.  */
	  switch (GET_CODE (SET_SRC (exp)))
	    {
	    case NEG:
	      if (GET_MODE_CLASS (GET_MODE (exp)) == MODE_FLOAT)
		break;
	    case AND:
	    case IOR:
	    case XOR:
	    case NOT:
	    case MEM:
	    case REG:
	      cc_status.flags = CC_NO_OVERFLOW;
	      break;
	    default:
	      break;
	    }
	  cc_status.value1 = SET_DEST (exp);
	  cc_status.value2 = SET_SRC (exp);
	}
    }
  else if (GET_CODE (exp) == PARALLEL
	   && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
    {
      if (GET_CODE (SET_SRC (XVECEXP (exp, 0, 0))) == CALL)
	CC_STATUS_INIT;
      else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) != PC)
	{
	  cc_status.flags = 0;
	  cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
	  cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
	}
      else
	/* PARALLELs whose first element sets the PC are aob,
	   sob insns.  They do change the cc's.  */
	CC_STATUS_INIT;
    }
  else
    CC_STATUS_INIT;
  if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
      && cc_status.value2
      && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
    cc_status.value2 = 0;
  if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
      && cc_status.value2
      && GET_CODE (cc_status.value2) == MEM)
    cc_status.value2 = 0;
  /* Actual condition, one line up, should be that value2's address
     depends on value1, but that is too much of a pain.  */
}
コード例 #11
0
ファイル: struct-equiv.c プロジェクト: 0mp/freebsd
/* Check if *XP is equivalent to Y.  Until an an unreconcilable difference is
   found, use in-group changes with validate_change on *XP to make register
   assignments agree.  It is the (not necessarily direct) callers
   responsibility to verify / confirm / cancel these changes, as appropriate.
   RVALUE indicates if the processed piece of rtl is used as a destination, in
   which case we can't have different registers being an input.  Returns
   nonzero if the two blocks have been identified as equivalent, zero otherwise.
   RVALUE == 0: destination
   RVALUE == 1: source
   RVALUE == -1: source, ignore SET_DEST of SET / clobber.  */
bool
rtx_equiv_p (rtx *xp, rtx y, int rvalue, struct equiv_info *info)
{
  rtx x = *xp;
  enum rtx_code code;
  int length;
  const char *format;
  int i;

  if (!y || !x)
    return x == y;
  code = GET_CODE (y);
  if (code != REG && x == y)
    return true;
  if (GET_CODE (x) != code
      || GET_MODE (x) != GET_MODE (y))
    return false;

  /* ??? could extend to allow CONST_INT inputs.  */
  switch (code)
    {
    case REG:
      {
	unsigned x_regno = REGNO (x);
	unsigned y_regno = REGNO (y);
	int x_common_live, y_common_live;

	if (reload_completed
	    && (x_regno >= FIRST_PSEUDO_REGISTER
		|| y_regno >= FIRST_PSEUDO_REGISTER))
	  {
	    /* We should only see this in REG_NOTEs.  */
	    gcc_assert (!info->live_update);
	    /* Returning false will cause us to remove the notes.  */
	    return false;
	  }
#ifdef STACK_REGS
	/* After reg-stack, can only accept literal matches of stack regs.  */
	if (info->mode & CLEANUP_POST_REGSTACK
	    && (IN_RANGE (x_regno, FIRST_STACK_REG, LAST_STACK_REG)
		|| IN_RANGE (y_regno, FIRST_STACK_REG, LAST_STACK_REG)))
	  return x_regno == y_regno;
#endif

	/* If the register is a locally live one in one block, the
	   corresponding one must be locally live in the other, too, and
	   match of identical regnos doesn't apply.  */
	if (REGNO_REG_SET_P (info->x_local_live, x_regno))
	  {
	    if (!REGNO_REG_SET_P (info->y_local_live, y_regno))
	      return false;
	  }
	else if (REGNO_REG_SET_P (info->y_local_live, y_regno))
	  return false;
	else if (x_regno == y_regno)
	  {
	    if (!rvalue && info->cur.input_valid
		&& (reg_overlap_mentioned_p (x, info->x_input)
		    || reg_overlap_mentioned_p (x, info->y_input)))
	      return false;

	    /* Update liveness information.  */
	    if (info->live_update
		&& assign_reg_reg_set (info->common_live, x, rvalue))
	      info->cur.version++;

	    return true;
	  }

	x_common_live = REGNO_REG_SET_P (info->common_live, x_regno);
	y_common_live = REGNO_REG_SET_P (info->common_live, y_regno);
	if (x_common_live != y_common_live)
	  return false;
	else if (x_common_live)
	  {
	    if (! rvalue || info->input_cost < 0 || no_new_pseudos)
	      return false;
	    /* If info->live_update is not set, we are processing notes.
	       We then allow a match with x_input / y_input found in a
	       previous pass.  */
	    if (info->live_update && !info->cur.input_valid)
	      {
		info->cur.input_valid = true;
		info->x_input = x;
		info->y_input = y;
		info->cur.input_count += optimize_size ? 2 : 1;
		if (info->input_reg
		    && GET_MODE (info->input_reg) != GET_MODE (info->x_input))
		  info->input_reg = NULL_RTX;
		if (!info->input_reg)
		  info->input_reg = gen_reg_rtx (GET_MODE (info->x_input));
	      }
	    else if ((info->live_update
		      ? ! info->cur.input_valid : ! info->x_input)
		     || ! rtx_equal_p (x, info->x_input)
		     || ! rtx_equal_p (y, info->y_input))
	      return false;
	    validate_change (info->cur.x_start, xp, info->input_reg, 1);
	  }
	else
	  {
	    int x_nregs = (x_regno >= FIRST_PSEUDO_REGISTER
			   ? 1 : hard_regno_nregs[x_regno][GET_MODE (x)]);
	    int y_nregs = (y_regno >= FIRST_PSEUDO_REGISTER
			   ? 1 : hard_regno_nregs[y_regno][GET_MODE (y)]);
	    int size = GET_MODE_SIZE (GET_MODE (x));
	    enum machine_mode x_mode = GET_MODE (x);
	    unsigned x_regno_i, y_regno_i;
	    int x_nregs_i, y_nregs_i, size_i;
	    int local_count = info->cur.local_count;

	    /* This might be a register local to each block.  See if we have
	       it already registered.  */
	    for (i = local_count - 1; i >= 0; i--)
	      {
		x_regno_i = REGNO (info->x_local[i]);
		x_nregs_i = (x_regno_i >= FIRST_PSEUDO_REGISTER
			     ? 1 : hard_regno_nregs[x_regno_i][GET_MODE (x)]);
		y_regno_i = REGNO (info->y_local[i]);
		y_nregs_i = (y_regno_i >= FIRST_PSEUDO_REGISTER
			     ? 1 : hard_regno_nregs[y_regno_i][GET_MODE (y)]);
		size_i = GET_MODE_SIZE (GET_MODE (info->x_local[i]));

		/* If we have a new pair of registers that is wider than an
		   old pair and enclosing it with matching offsets,
		   remove the old pair.  If we find a matching, wider, old
		   pair, use the old one.  If the width is the same, use the
		   old one if the modes match, but the new if they don't.
		   We don't want to get too fancy with subreg_regno_offset
		   here, so we just test two straightforward cases each.  */
		if (info->live_update
		    && (x_mode != GET_MODE (info->x_local[i])
			? size >= size_i : size > size_i))
		  {
		    /* If the new pair is fully enclosing a matching
		       existing pair, remove the old one.  N.B. because
		       we are removing one entry here, the check below
		       if we have space for a new entry will succeed.  */
		    if ((x_regno <= x_regno_i
			 && x_regno + x_nregs >= x_regno_i + x_nregs_i
			 && x_nregs == y_nregs && x_nregs_i == y_nregs_i
			 && x_regno - x_regno_i == y_regno - y_regno_i)
			|| (x_regno == x_regno_i && y_regno == y_regno_i
			    && x_nregs >= x_nregs_i && y_nregs >= y_nregs_i))
		      {
			info->cur.local_count = --local_count;
			info->x_local[i] = info->x_local[local_count];
			info->y_local[i] = info->y_local[local_count];
			continue;
		      }
		  }
		else
		  {

		    /* If the new pair is fully enclosed within a matching
		       existing pair, succeed.  */
		    if (x_regno >= x_regno_i
			&& x_regno + x_nregs <= x_regno_i + x_nregs_i
			&& x_nregs == y_nregs && x_nregs_i == y_nregs_i
			&& x_regno - x_regno_i == y_regno - y_regno_i)
		      break;
		    if (x_regno == x_regno_i && y_regno == y_regno_i
			&& x_nregs <= x_nregs_i && y_nregs <= y_nregs_i)
		      break;
		}

		/* Any other overlap causes a match failure.  */
		if (x_regno + x_nregs > x_regno_i
		    && x_regno_i + x_nregs_i > x_regno)
		  return false;
		if (y_regno + y_nregs > y_regno_i
		    && y_regno_i + y_nregs_i > y_regno)
		  return false;
	      }
	    if (i < 0)
	      {
		/* Not found.  Create a new entry if possible.  */
		if (!info->live_update
		    || info->cur.local_count >= STRUCT_EQUIV_MAX_LOCAL)
		  return false;
		info->x_local[info->cur.local_count] = x;
		info->y_local[info->cur.local_count] = y;
		info->cur.local_count++;
		info->cur.version++;
	      }
	    note_local_live (info, x, y, rvalue);
	  }
	return true;
      }
    case SET:
      gcc_assert (rvalue < 0);
      /* Ignore the destinations role as a destination.  Still, we have
	 to consider input registers embedded in the addresses of a MEM.
	 N.B., we process the rvalue aspect of STRICT_LOW_PART /
	 ZERO_EXTEND / SIGN_EXTEND along with their lvalue aspect.  */
      if(!set_dest_addr_equiv_p (SET_DEST (x), SET_DEST (y), info))
	return false;
      /* Process source.  */
      return rtx_equiv_p (&SET_SRC (x), SET_SRC (y), 1, info);
    case PRE_MODIFY:
      /* Process destination.  */
      if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info))
	return false;
      /* Process source.  */
      return rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), 1, info);
    case POST_MODIFY:
      {
	rtx x_dest0, x_dest1;

	/* Process destination.  */
	x_dest0 = XEXP (x, 0);
	gcc_assert (REG_P (x_dest0));
	if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info))
	  return false;
	x_dest1 = XEXP (x, 0);
	/* validate_change might have changed the destination.  Put it back
	   so that we can do a proper match for its role a an input.  */
	XEXP (x, 0) = x_dest0;
	if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 1, info))
	  return false;
	gcc_assert (x_dest1 == XEXP (x, 0));
	/* Process source.  */
	return rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), 1, info);
      }
    case CLOBBER:
      gcc_assert (rvalue < 0);
      return true;
    /* Some special forms are also rvalues when they appear in lvalue
       positions.  However, we must ont try to match a register after we
       have already altered it with validate_change, consider the rvalue
       aspect while we process the lvalue.  */
    case STRICT_LOW_PART:
    case ZERO_EXTEND:
    case SIGN_EXTEND:
      {
	rtx x_inner, y_inner;
	enum rtx_code code;
	int change;

	if (rvalue)
	  break;
	x_inner = XEXP (x, 0);
	y_inner = XEXP (y, 0);
	if (GET_MODE (x_inner) != GET_MODE (y_inner))
	  return false;
	code = GET_CODE (x_inner);
	if (code != GET_CODE (y_inner))
	  return false;
	/* The address of a MEM is an input that will be processed during
	   rvalue == -1 processing.  */
	if (code == SUBREG)
	  {
	    if (SUBREG_BYTE (x_inner) != SUBREG_BYTE (y_inner))
	      return false;
	    x = x_inner;
	    x_inner = SUBREG_REG (x_inner);
	    y_inner = SUBREG_REG (y_inner);
	    if (GET_MODE (x_inner) != GET_MODE (y_inner))
	      return false;
	    code = GET_CODE (x_inner);
	    if (code != GET_CODE (y_inner))
	      return false;
	  }
	if (code == MEM)
	  return true;
	gcc_assert (code == REG);
	if (! rtx_equiv_p (&XEXP (x, 0), y_inner, rvalue, info))
	  return false;
	if (REGNO (x_inner) == REGNO (y_inner))
	  {
	    change = assign_reg_reg_set (info->common_live, x_inner, 1);
	    info->cur.version++;
	  }
	else
	  change = note_local_live (info, x_inner, y_inner, 1);
	gcc_assert (change);
	return true;
      }
    /* The AUTO_INC / POST_MODIFY / PRE_MODIFY sets are modelled to take
       place during input processing, however, that is benign, since they
       are paired with reads.  */
    case MEM:
      return !rvalue || rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), rvalue, info);
    case POST_INC: case POST_DEC: case PRE_INC: case PRE_DEC:
      return (rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info)
	      && rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 1, info));
    case PARALLEL:
      /* If this is a top-level PATTERN PARALLEL, we expect the caller to 
	 have handled the SET_DESTs.  A complex or vector PARALLEL can be
	 identified by having a mode.  */
      gcc_assert (rvalue < 0 || GET_MODE (x) != VOIDmode);
      break;
    case LABEL_REF:
      /* Check special tablejump match case.  */
      if (XEXP (y, 0) == info->y_label)
	return (XEXP (x, 0) == info->x_label);
      /* We can't assume nonlocal labels have their following insns yet.  */
      if (LABEL_REF_NONLOCAL_P (x) || LABEL_REF_NONLOCAL_P (y))
	return XEXP (x, 0) == XEXP (y, 0);

      /* Two label-refs are equivalent if they point at labels
	 in the same position in the instruction stream.  */
      return (next_real_insn (XEXP (x, 0))
	      == next_real_insn (XEXP (y, 0)));
    case SYMBOL_REF:
      return XSTR (x, 0) == XSTR (y, 0);
    /* Some rtl is guaranteed to be shared, or unique;  If we didn't match
       EQ equality above, they aren't the same.  */
    case CONST_INT:
    case CODE_LABEL:
      return false;
    default:
      break;
    }

  /* For commutative operations, the RTX match if the operands match in any
     order.  */
  if (targetm.commutative_p (x, UNKNOWN))
    return ((rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), rvalue, info)
	     && rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), rvalue, info))
	    || (rtx_equiv_p (&XEXP (x, 0), XEXP (y, 1), rvalue, info)
		&& rtx_equiv_p (&XEXP (x, 1), XEXP (y, 0), rvalue, info)));

  /* Process subexpressions - this is similar to rtx_equal_p.  */
  length = GET_RTX_LENGTH (code);
  format = GET_RTX_FORMAT (code);

  for (i = 0; i < length; ++i)
    {
      switch (format[i])
	{
	case 'w':
	  if (XWINT (x, i) != XWINT (y, i))
	    return false;
	  break;
	case 'n':
	case 'i':
	  if (XINT (x, i) != XINT (y, i))
	    return false;
	  break;
	case 'V':
	case 'E':
	  if (XVECLEN (x, i) != XVECLEN (y, i))
	    return false;
	  if (XVEC (x, i) != 0)
	    {
	      int j;
	      for (j = 0; j < XVECLEN (x, i); ++j)
		{
		  if (! rtx_equiv_p (&XVECEXP (x, i, j), XVECEXP (y, i, j),
				     rvalue, info))
		    return false;
		}
	    }
	  break;
	case 'e':
	  if (! rtx_equiv_p (&XEXP (x, i), XEXP (y, i), rvalue, info))
	    return false;
	  break;
	case 'S':
	case 's':
	  if ((XSTR (x, i) || XSTR (y, i))
	      && (! XSTR (x, i) || ! XSTR (y, i)
		  || strcmp (XSTR (x, i), XSTR (y, i))))
	    return false;
	  break;
	case 'u':
	  /* These are just backpointers, so they don't matter.  */
	  break;
	case '0':
	case 't':
	  break;
	  /* It is believed that rtx's at this level will never
	     contain anything but integers and other rtx's,
	     except for within LABEL_REFs and SYMBOL_REFs.  */
	default:
	  gcc_unreachable ();
	}
    }
  return true;
}