参照元

説明

  • パス: gcc-8.3/gcc/lra-constraints.c?
  • FIXME: これは何?
    • 説明

引数

  • int only_alternative

返り値

  • bool

参考

実装

/* Major function to choose the current insn alternative and what
   operands should be reloaded and how.	 If ONLY_ALTERNATIVE is not
   negative we should consider only this alternative.  Return false if
   we can not choose the alternative or find how to reload the
   operands.  */
static bool
process_alt_operands (int only_alternative)
{
  bool ok_p = false;
  int nop, overall, nalt;
  int n_alternatives = curr_static_id->n_alternatives;
  int n_operands = curr_static_id->n_operands;
  /* LOSERS counts the operands that don't fit this alternative and
     would require loading.  */
  int losers;
  int addr_losers;
  /* REJECT is a count of how undesirable this alternative says it is
     if any reloading is required.  If the alternative matches exactly
     then REJECT is ignored, but otherwise it gets this much counted
     against it in addition to the reloading needed.  */
  int reject;
  /* This is defined by '!' or '?' alternative constraint and added to
     reject.  But in some cases it can be ignored.  */
  int static_reject;
  int op_reject;
  /* The number of elements in the following array.  */
  int early_clobbered_regs_num;
  /* Numbers of operands which are early clobber registers.  */
  int early_clobbered_nops[MAX_RECOG_OPERANDS];
  enum reg_class curr_alt[MAX_RECOG_OPERANDS];
  HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS];
  bool curr_alt_match_win[MAX_RECOG_OPERANDS];
  bool curr_alt_win[MAX_RECOG_OPERANDS];
  bool curr_alt_offmemok[MAX_RECOG_OPERANDS];
  int curr_alt_matches[MAX_RECOG_OPERANDS];
  /* The number of elements in the following array.  */
  int curr_alt_dont_inherit_ops_num;
  /* Numbers of operands whose reload pseudos should not be inherited.	*/
  int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
  rtx op;
  /* The register when the operand is a subreg of register, otherwise the
     operand itself.  */
  rtx no_subreg_reg_operand[MAX_RECOG_OPERANDS];
  /* The register if the operand is a register or subreg of register,
     otherwise NULL.  */
  rtx operand_reg[MAX_RECOG_OPERANDS];
  int hard_regno[MAX_RECOG_OPERANDS];
  machine_mode biggest_mode[MAX_RECOG_OPERANDS];
  int reload_nregs, reload_sum;
  bool costly_p;
  enum reg_class cl;

  /* Calculate some data common for all alternatives to speed up the
     function.	*/
  for (nop = 0; nop < n_operands; nop++)
    {
      rtx reg;

      op = no_subreg_reg_operand[nop] = *curr_id->operand_loc[nop];
      /* The real hard regno of the operand after the allocation.  */
      hard_regno[nop] = get_hard_regno (op, true);

      operand_reg[nop] = reg = op;
      biggest_mode[nop] = GET_MODE (op);
      if (GET_CODE (op) == SUBREG)
	{
	  biggest_mode[nop] = wider_subreg_mode (op);
	  operand_reg[nop] = reg = SUBREG_REG (op);
	}
      if (! REG_P (reg))
	operand_reg[nop] = NULL_RTX;
      else if (REGNO (reg) >= FIRST_PSEUDO_REGISTER
	       || ((int) REGNO (reg)
		   == lra_get_elimination_hard_regno (REGNO (reg))))
	no_subreg_reg_operand[nop] = reg;
      else
	operand_reg[nop] = no_subreg_reg_operand[nop]
	  /* Just use natural mode for elimination result.  It should
	     be enough for extra constraints hooks.  */
	  = regno_reg_rtx[hard_regno[nop]];
    }

  /* The constraints are made of several alternatives.	Each operand's
     constraint looks like foo,bar,... with commas separating the
     alternatives.  The first alternatives for all operands go
     together, the second alternatives go together, etc.

     First loop over alternatives.  */
  alternative_mask preferred = curr_id->preferred_alternatives;
  if (only_alternative >= 0)
    preferred &= ALTERNATIVE_BIT (only_alternative);

  for (nalt = 0; nalt < n_alternatives; nalt++)
    {
      /* Loop over operands for one constraint alternative.  */
      if (!TEST_BIT (preferred, nalt))
	continue;

      curr_small_class_check++;
      overall = losers = addr_losers = 0;
      static_reject = reject = reload_nregs = reload_sum = 0;
      for (nop = 0; nop < n_operands; nop++)
	{
	  int inc = (curr_static_id
		     ->operand_alternative[nalt * n_operands + nop].reject);
	  if (lra_dump_file != NULL && inc != 0)
	    fprintf (lra_dump_file,
		     "            Staticly defined alt reject+=%d\n", inc);
	  static_reject += inc;
	}
      reject += static_reject;
      early_clobbered_regs_num = 0;

      for (nop = 0; nop < n_operands; nop++)
	{
	  const char *p;
	  char *end;
	  int len, c, m, i, opalt_num, this_alternative_matches;
	  bool win, did_match, offmemok, early_clobber_p;
	  /* false => this operand can be reloaded somehow for this
	     alternative.  */
	  bool badop;
	  /* true => this operand can be reloaded if the alternative
	     allows regs.  */
	  bool winreg;
	  /* True if a constant forced into memory would be OK for
	     this operand.  */
	  bool constmemok;
	  enum reg_class this_alternative, this_costly_alternative;
	  HARD_REG_SET this_alternative_set, this_costly_alternative_set;
	  bool this_alternative_match_win, this_alternative_win;
	  bool this_alternative_offmemok;
	  bool scratch_p;
	  machine_mode mode;
	  enum constraint_num cn;

	  opalt_num = nalt * n_operands + nop;
	  if (curr_static_id->operand_alternative[opalt_num].anything_ok)
	    {
	      /* Fast track for no constraints at all.	*/
	      curr_alt[nop] = NO_REGS;
	      CLEAR_HARD_REG_SET (curr_alt_set[nop]);
	      curr_alt_win[nop] = true;
	      curr_alt_match_win[nop] = false;
	      curr_alt_offmemok[nop] = false;
	      curr_alt_matches[nop] = -1;
	      continue;
	    }

	  op = no_subreg_reg_operand[nop];
	  mode = curr_operand_mode[nop];

	  win = did_match = winreg = offmemok = constmemok = false;
	  badop = true;

	  early_clobber_p = false;
	  p = curr_static_id->operand_alternative[opalt_num].constraint;

	  this_costly_alternative = this_alternative = NO_REGS;
	  /* We update set of possible hard regs besides its class
	     because reg class might be inaccurate.  For example,
	     union of LO_REGS (l), HI_REGS(h), and STACK_REG(k) in ARM
	     is translated in HI_REGS because classes are merged by
	     pairs and there is no accurate intermediate class.	 */
	  CLEAR_HARD_REG_SET (this_alternative_set);
	  CLEAR_HARD_REG_SET (this_costly_alternative_set);
	  this_alternative_win = false;
	  this_alternative_match_win = false;
	  this_alternative_offmemok = false;
	  this_alternative_matches = -1;

	  /* An empty constraint should be excluded by the fast
	     track.  */
	  lra_assert (*p != 0 && *p != ',');

	  op_reject = 0;
	  /* Scan this alternative's specs for this operand; set WIN
	     if the operand fits any letter in this alternative.
	     Otherwise, clear BADOP if this operand could fit some
	     letter after reloads, or set WINREG if this operand could
	     fit after reloads provided the constraint allows some
	     registers.	 */
	  costly_p = false;
	  do
	    {
	      switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
		{
		case '\0':
		  len = 0;
		  break;
		case ',':
		  c = '\0';
		  break;

		case '&':
		  early_clobber_p = true;
		  break;

		case '$':
		  op_reject += LRA_MAX_REJECT;
		  break;
		case '^':
		  op_reject += LRA_LOSER_COST_FACTOR;
		  break;

		case '#':
		  /* Ignore rest of this alternative.  */
		  c = '\0';
		  break;

		case '0':  case '1':  case '2':	 case '3':  case '4':
		case '5':  case '6':  case '7':	 case '8':  case '9':
		  {
		    int m_hregno;
		    bool match_p;

		    m = strtoul (p, &end, 10);
		    p = end;
		    len = 0;
		    lra_assert (nop > m);

		    /* Reject matches if we don't know which operand is
		       bigger.  This situation would arguably be a bug in
		       an .md pattern, but could also occur in a user asm.  */
		    if (!ordered_p (GET_MODE_SIZE (biggest_mode[m]),
				    GET_MODE_SIZE (biggest_mode[nop])))
		      break;

		    /* Don't match wrong asm insn operands for proper
		       diagnostic later.  */
		    if (INSN_CODE (curr_insn) < 0
			&& (curr_operand_mode[m] == BLKmode
			    || curr_operand_mode[nop] == BLKmode)
			&& curr_operand_mode[m] != curr_operand_mode[nop])
		      break;
		    
		    m_hregno = get_hard_regno (*curr_id->operand_loc[m], false);
		    /* We are supposed to match a previous operand.
		       If we do, we win if that one did.  If we do
		       not, count both of the operands as losers.
		       (This is too conservative, since most of the
		       time only a single reload insn will be needed
		       to make the two operands win.  As a result,
		       this alternative may be rejected when it is
		       actually desirable.)  */
		    match_p = false;
		    if (operands_match_p (*curr_id->operand_loc[nop],
					  *curr_id->operand_loc[m], m_hregno))
		      {
			/* We should reject matching of an early
			   clobber operand if the matching operand is
			   not dying in the insn.  */
			if (! curr_static_id->operand[m].early_clobber
			    || operand_reg[nop] == NULL_RTX
			    || (find_regno_note (curr_insn, REG_DEAD,
						 REGNO (op))
				|| REGNO (op) == REGNO (operand_reg[m])))
			  match_p = true;
		      }
		    if (match_p)
		      {
			/* If we are matching a non-offsettable
			   address where an offsettable address was
			   expected, then we must reject this
			   combination, because we can't reload
			   it.	*/
			if (curr_alt_offmemok[m]
			    && MEM_P (*curr_id->operand_loc[m])
			    && curr_alt[m] == NO_REGS && ! curr_alt_win[m])
			  continue;
		      }
		    else
		      {
			/* Operands don't match.  Both operands must
			   allow a reload register, otherwise we
			   cannot make them match.  */
			if (curr_alt[m] == NO_REGS)
			  break;
			/* Retroactively mark the operand we had to
			   match as a loser, if it wasn't already and
			   it wasn't matched to a register constraint
			   (e.g it might be matched by memory). */
			if (curr_alt_win[m]
			    && (operand_reg[m] == NULL_RTX
				|| hard_regno[m] < 0))
			  {
			    losers++;
			    reload_nregs
			      += (ira_reg_class_max_nregs[curr_alt[m]]
				  [GET_MODE (*curr_id->operand_loc[m])]);
			  }

			/* Prefer matching earlyclobber alternative as
			   it results in less hard regs required for
			   the insn than a non-matching earlyclobber
			   alternative.  */
			if (curr_static_id->operand[m].early_clobber)
			  {
			    if (lra_dump_file != NULL)
			      fprintf
				(lra_dump_file,
				 "            %d Matching earlyclobber alt:"
				 " reject--\n",
				 nop);
			    reject--;
			  }
			/* Otherwise we prefer no matching
			   alternatives because it gives more freedom
			   in RA.  */
			else if (operand_reg[nop] == NULL_RTX
				 || (find_regno_note (curr_insn, REG_DEAD,
						      REGNO (operand_reg[nop]))
				     == NULL_RTX))
			  {
			    if (lra_dump_file != NULL)
			      fprintf
				(lra_dump_file,
				 "            %d Matching alt: reject+=2\n",
				 nop);
			    reject += 2;
			  }
		      }
		    /* If we have to reload this operand and some
		       previous operand also had to match the same
		       thing as this operand, we don't know how to do
		       that.  */
		    if (!match_p || !curr_alt_win[m])
		      {
			for (i = 0; i < nop; i++)
			  if (curr_alt_matches[i] == m)
			    break;
			if (i < nop)
			  break;
		      }
		    else
		      did_match = true;

		    this_alternative_matches = m;
		    /* This can be fixed with reloads if the operand
		       we are supposed to match can be fixed with
		       reloads. */
		    badop = false;
		    this_alternative = curr_alt[m];
		    COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]);
		    winreg = this_alternative != NO_REGS;
		    break;
		  }

		case 'g':
		  if (MEM_P (op)
		      || general_constant_p (op)
		      || spilled_pseudo_p (op))
		    win = true;
		  cl = GENERAL_REGS;
		  goto reg;

		default:
		  cn = lookup_constraint (p);
		  switch (get_constraint_type (cn))
		    {
		    case CT_REGISTER:
		      cl = reg_class_for_constraint (cn);
		      if (cl != NO_REGS)
			goto reg;
		      break;

		    case CT_CONST_INT:
		      if (CONST_INT_P (op)
			  && insn_const_int_ok_for_constraint (INTVAL (op), cn))
			win = true;
		      break;

		    case CT_MEMORY:
		      if (MEM_P (op)
			  && satisfies_memory_constraint_p (op, cn))
			win = true;
		      else if (spilled_pseudo_p (op))
			win = true;

		      /* If we didn't already win, we can reload constants
			 via force_const_mem or put the pseudo value into
			 memory, or make other memory by reloading the
			 address like for 'o'.  */
		      if (CONST_POOL_OK_P (mode, op)
			  || MEM_P (op) || REG_P (op)
			  /* We can restore the equiv insn by a
			     reload.  */
			  || equiv_substition_p[nop])
			badop = false;
		      constmemok = true;
		      offmemok = true;
		      break;

		    case CT_ADDRESS:
		      /* An asm operand with an address constraint
			 that doesn't satisfy address_operand has
			 is_address cleared, so that we don't try to
			 make a non-address fit.  */
		      if (!curr_static_id->operand[nop].is_address)
			break;
		      /* If we didn't already win, we can reload the address
			 into a base register.  */
		      if (satisfies_address_constraint_p (op, cn))
			win = true;
		      cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
					   ADDRESS, SCRATCH);
		      badop = false;
		      goto reg;

		    case CT_FIXED_FORM:
		      if (constraint_satisfied_p (op, cn))
			win = true;
		      break;

		    case CT_SPECIAL_MEMORY:
		      if (MEM_P (op)
			  && satisfies_memory_constraint_p (op, cn))
			win = true;
		      else if (spilled_pseudo_p (op))
			win = true;
		      break;
		    }
		  break;

		reg:
		  this_alternative = reg_class_subunion[this_alternative][cl];
		  IOR_HARD_REG_SET (this_alternative_set,
				    reg_class_contents[cl]);
		  if (costly_p)
		    {
		      this_costly_alternative
			= reg_class_subunion[this_costly_alternative][cl];
		      IOR_HARD_REG_SET (this_costly_alternative_set,
					reg_class_contents[cl]);
		    }
		  if (mode == BLKmode)
		    break;
		  winreg = true;
		  if (REG_P (op))
		    {
		      if (hard_regno[nop] >= 0
			  && in_hard_reg_set_p (this_alternative_set,
						mode, hard_regno[nop]))
			win = true;
		      else if (hard_regno[nop] < 0
			       && in_class_p (op, this_alternative, NULL))
			win = true;
		    }
		  break;
		}
	      if (c != ' ' && c != '\t')
		costly_p = c == '*';
	    }
	  while ((p += len), c);

	  scratch_p = (operand_reg[nop] != NULL_RTX
		       && lra_former_scratch_p (REGNO (operand_reg[nop])));
	  /* Record which operands fit this alternative.  */
	  if (win)
	    {
	      this_alternative_win = true;
	      if (operand_reg[nop] != NULL_RTX)
		{
		  if (hard_regno[nop] >= 0)
		    {
		      if (in_hard_reg_set_p (this_costly_alternative_set,
					     mode, hard_regno[nop]))
			{
			  if (lra_dump_file != NULL)
			    fprintf (lra_dump_file,
				     "            %d Costly set: reject++\n",
				     nop);
			  reject++;
			}
		    }
		  else
		    {
		      /* Prefer won reg to spilled pseudo under other
			 equal conditions for possibe inheritance.  */
		      if (! scratch_p)
			{
			  if (lra_dump_file != NULL)
			    fprintf
			      (lra_dump_file,
			       "            %d Non pseudo reload: reject++\n",
			       nop);
			  reject++;
			}
		      if (in_class_p (operand_reg[nop],
				      this_costly_alternative, NULL))
			{
			  if (lra_dump_file != NULL)
			    fprintf
			      (lra_dump_file,
			       "            %d Non pseudo costly reload:"
			       " reject++\n",
			       nop);
			  reject++;
			}
		    }
		  /* We simulate the behavior of old reload here.
		     Although scratches need hard registers and it
		     might result in spilling other pseudos, no reload
		     insns are generated for the scratches.  So it
		     might cost something but probably less than old
		     reload pass believes.  */
		  if (scratch_p)
		    {
		      if (lra_dump_file != NULL)
			fprintf (lra_dump_file,
				 "            %d Scratch win: reject+=2\n",
				 nop);
		      reject += 2;
		    }
		}
	    }
	  else if (did_match)
	    this_alternative_match_win = true;
	  else
	    {
	      int const_to_mem = 0;
	      bool no_regs_p;

	      reject += op_reject;
	      /* Never do output reload of stack pointer.  It makes
		 impossible to do elimination when SP is changed in
		 RTL.  */
	      if (op == stack_pointer_rtx && ! frame_pointer_needed
		  && curr_static_id->operand[nop].type != OP_IN)
		goto fail;

	      /* If this alternative asks for a specific reg class, see if there
		 is at least one allocatable register in that class.  */
	      no_regs_p
		= (this_alternative == NO_REGS
		   || (hard_reg_set_subset_p
		       (reg_class_contents[this_alternative],
			lra_no_alloc_regs)));

	      /* For asms, verify that the class for this alternative is possible
		 for the mode that is specified.  */
	      if (!no_regs_p && INSN_CODE (curr_insn) < 0)
		{
		  int i;
		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
		    if (targetm.hard_regno_mode_ok (i, mode)
			&& in_hard_reg_set_p (reg_class_contents[this_alternative],
					      mode, i))
		      break;
		  if (i == FIRST_PSEUDO_REGISTER)
		    winreg = false;
		}

	      /* If this operand accepts a register, and if the
		 register class has at least one allocatable register,
		 then this operand can be reloaded.  */
	      if (winreg && !no_regs_p)
		badop = false;

	      if (badop)
		{
		  if (lra_dump_file != NULL)
		    fprintf (lra_dump_file,
			     "            alt=%d: Bad operand -- refuse\n",
			     nalt);
		  goto fail;
		}

	      if (this_alternative != NO_REGS)
		{
		  HARD_REG_SET available_regs;
		  
		  COPY_HARD_REG_SET (available_regs,
				     reg_class_contents[this_alternative]);
		  AND_COMPL_HARD_REG_SET
		    (available_regs,
		     ira_prohibited_class_mode_regs[this_alternative][mode]);
		  AND_COMPL_HARD_REG_SET (available_regs, lra_no_alloc_regs);
		  if (hard_reg_set_empty_p (available_regs))
		    {
		      /* There are no hard regs holding a value of given
			 mode.  */
		      if (offmemok)
			{
			  this_alternative = NO_REGS;
			  if (lra_dump_file != NULL)
			    fprintf (lra_dump_file,
				     "            %d Using memory because of"
				     " a bad mode: reject+=2\n",
				     nop);
			  reject += 2;
			}
		      else
			{
			  if (lra_dump_file != NULL)
			    fprintf (lra_dump_file,
				     "            alt=%d: Wrong mode -- refuse\n",
				     nalt);
			  goto fail;
			}
		    }
		}

	      /* If not assigned pseudo has a class which a subset of
		 required reg class, it is a less costly alternative
		 as the pseudo still can get a hard reg of necessary
		 class.  */
	      if (! no_regs_p && REG_P (op) && hard_regno[nop] < 0
		  && (cl = get_reg_class (REGNO (op))) != NO_REGS
		  && ira_class_subset_p[this_alternative][cl])
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            %d Super set class reg: reject-=3\n", nop);
		  reject -= 3;
		}

	      this_alternative_offmemok = offmemok;
	      if (this_costly_alternative != NO_REGS)
		{
		  if (lra_dump_file != NULL)
		    fprintf (lra_dump_file,
			     "            %d Costly loser: reject++\n", nop);
		  reject++;
		}
	      /* If the operand is dying, has a matching constraint,
		 and satisfies constraints of the matched operand
		 which failed to satisfy the own constraints, most probably
		 the reload for this operand will be gone.  */
	      if (this_alternative_matches >= 0
		  && !curr_alt_win[this_alternative_matches]
		  && REG_P (op)
		  && find_regno_note (curr_insn, REG_DEAD, REGNO (op))
		  && (hard_regno[nop] >= 0
		      ? in_hard_reg_set_p (this_alternative_set,
					   mode, hard_regno[nop])
		      : in_class_p (op, this_alternative, NULL)))
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            %d Dying matched operand reload: reject++\n",
		       nop);
		  reject++;
		}
	      else
		{
		  /* Strict_low_part requires to reload the register
		     not the sub-register.  In this case we should
		     check that a final reload hard reg can hold the
		     value mode.  */
		  if (curr_static_id->operand[nop].strict_low
		      && REG_P (op)
		      && hard_regno[nop] < 0
		      && GET_CODE (*curr_id->operand_loc[nop]) == SUBREG
		      && ira_class_hard_regs_num[this_alternative] > 0
		      && (!targetm.hard_regno_mode_ok
			  (ira_class_hard_regs[this_alternative][0],
			   GET_MODE (*curr_id->operand_loc[nop]))))
		    {
		      if (lra_dump_file != NULL)
			fprintf
			  (lra_dump_file,
			   "            alt=%d: Strict low subreg reload -- refuse\n",
			   nalt);
		      goto fail;
		    }
		  losers++;
		}
	      if (operand_reg[nop] != NULL_RTX
		  /* Output operands and matched input operands are
		     not inherited.  The following conditions do not
		     exactly describe the previous statement but they
		     are pretty close.  */
		  && curr_static_id->operand[nop].type != OP_OUT
		  && (this_alternative_matches < 0
		      || curr_static_id->operand[nop].type != OP_IN))
		{
		  int last_reload = (lra_reg_info[ORIGINAL_REGNO
						  (operand_reg[nop])]
				     .last_reload);

		  /* The value of reload_sum has sense only if we
		     process insns in their order.  It happens only on
		     the first constraints sub-pass when we do most of
		     reload work.  */
		  if (lra_constraint_iter == 1 && last_reload > bb_reload_num)
		    reload_sum += last_reload - bb_reload_num;
		}
	      /* If this is a constant that is reloaded into the
		 desired class by copying it to memory first, count
		 that as another reload.  This is consistent with
		 other code and is required to avoid choosing another
		 alternative when the constant is moved into memory.
		 Note that the test here is precisely the same as in
		 the code below that calls force_const_mem.  */
	      if (CONST_POOL_OK_P (mode, op)
		  && ((targetm.preferred_reload_class
		       (op, this_alternative) == NO_REGS)
		      || no_input_reloads_p))
		{
		  const_to_mem = 1;
		  if (! no_regs_p)
		    losers++;
		}

	      /* Alternative loses if it requires a type of reload not
		 permitted for this insn.  We can always reload
		 objects with a REG_UNUSED note.  */
	      if ((curr_static_id->operand[nop].type != OP_IN
		   && no_output_reloads_p
		   && ! find_reg_note (curr_insn, REG_UNUSED, op))
		  || (curr_static_id->operand[nop].type != OP_OUT
		      && no_input_reloads_p && ! const_to_mem)
		  || (this_alternative_matches >= 0
		      && (no_input_reloads_p
			  || (no_output_reloads_p
			      && (curr_static_id->operand
				  [this_alternative_matches].type != OP_IN)
			      && ! find_reg_note (curr_insn, REG_UNUSED,
						  no_subreg_reg_operand
						  [this_alternative_matches])))))
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            alt=%d: No input/otput reload -- refuse\n",
		       nalt);
		  goto fail;
		}

	      /* Alternative loses if it required class pseudo can not
		 hold value of required mode.  Such insns can be
		 described by insn definitions with mode iterators.  */
	      if (GET_MODE (*curr_id->operand_loc[nop]) != VOIDmode
		  && ! hard_reg_set_empty_p (this_alternative_set)
		  /* It is common practice for constraints to use a
		     class which does not have actually enough regs to
		     hold the value (e.g. x86 AREG for mode requiring
		     more one general reg).  Therefore we have 2
		     conditions to check that the reload pseudo can
		     not hold the mode value.  */
		  && (!targetm.hard_regno_mode_ok
		      (ira_class_hard_regs[this_alternative][0],
		       GET_MODE (*curr_id->operand_loc[nop])))
		  /* The above condition is not enough as the first
		     reg in ira_class_hard_regs can be not aligned for
		     multi-words mode values.  */
		  && (prohibited_class_reg_set_mode_p
		      (this_alternative, this_alternative_set,
		       GET_MODE (*curr_id->operand_loc[nop]))))
		{
		  if (lra_dump_file != NULL)
		    fprintf (lra_dump_file,
			     "            alt=%d: reload pseudo for op %d "
			     " can not hold the mode value -- refuse\n",
			     nalt, nop);
		  goto fail;
		}

	      /* Check strong discouragement of reload of non-constant
		 into class THIS_ALTERNATIVE.  */
	      if (! CONSTANT_P (op) && ! no_regs_p
		  && (targetm.preferred_reload_class
		      (op, this_alternative) == NO_REGS
		      || (curr_static_id->operand[nop].type == OP_OUT
			  && (targetm.preferred_output_reload_class
			      (op, this_alternative) == NO_REGS))))
		{
		  if (lra_dump_file != NULL)
		    fprintf (lra_dump_file,
			     "            %d Non-prefered reload: reject+=%d\n",
			     nop, LRA_MAX_REJECT);
		  reject += LRA_MAX_REJECT;
		}

	      if (! (MEM_P (op) && offmemok)
		  && ! (const_to_mem && constmemok))
		{
		  /* We prefer to reload pseudos over reloading other
		     things, since such reloads may be able to be
		     eliminated later.  So bump REJECT in other cases.
		     Don't do this in the case where we are forcing a
		     constant into memory and it will then win since
		     we don't want to have a different alternative
		     match then.  */
		  if (! (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER))
		    {
		      if (lra_dump_file != NULL)
			fprintf
			  (lra_dump_file,
			   "            %d Non-pseudo reload: reject+=2\n",
			   nop);
		      reject += 2;
		    }

		  if (! no_regs_p)
		    reload_nregs
		      += ira_reg_class_max_nregs[this_alternative][mode];

		  if (SMALL_REGISTER_CLASS_P (this_alternative))
		    {
		      if (lra_dump_file != NULL)
			fprintf
			  (lra_dump_file,
			   "            %d Small class reload: reject+=%d\n",
			   nop, LRA_LOSER_COST_FACTOR / 2);
		      reject += LRA_LOSER_COST_FACTOR / 2;
		    }
		}

	      /* We are trying to spill pseudo into memory.  It is
		 usually more costly than moving to a hard register
		 although it might takes the same number of
		 reloads.

		 Non-pseudo spill may happen also.  Suppose a target allows both
		 register and memory in the operand constraint alternatives,
		 then it's typical that an eliminable register has a substition
		 of "base + offset" which can either be reloaded by a simple
		 "new_reg <= base + offset" which will match the register
		 constraint, or a similar reg addition followed by further spill
		 to and reload from memory which will match the memory
		 constraint, but this memory spill will be much more costly
		 usually.

		 Code below increases the reject for both pseudo and non-pseudo
		 spill.  */
	      if (no_regs_p
		  && !(MEM_P (op) && offmemok)
		  && !(REG_P (op) && hard_regno[nop] < 0))
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            %d Spill %spseudo into memory: reject+=3\n",
		       nop, REG_P (op) ? "" : "Non-");
		  reject += 3;
		  if (VECTOR_MODE_P (mode))
		    {
		      /* Spilling vectors into memory is usually more
			 costly as they contain big values.  */
		      if (lra_dump_file != NULL)
			fprintf
			  (lra_dump_file,
			   "            %d Spill vector pseudo: reject+=2\n",
			   nop);
		      reject += 2;
		    }
		}

	      /* When we use an operand requiring memory in given
		 alternative, the insn should write *and* read the
		 value to/from memory it is costly in comparison with
		 an insn alternative which does not use memory
		 (e.g. register or immediate operand).  We exclude
		 memory operand for such case as we can satisfy the
		 memory constraints by reloading address.  */
	      if (no_regs_p && offmemok && !MEM_P (op))
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            Using memory insn operand %d: reject+=3\n",
		       nop);
		  reject += 3;
		}
	      
	      /* If reload requires moving value through secondary
		 memory, it will need one more insn at least.  */
	      if (this_alternative != NO_REGS 
		  && REG_P (op) && (cl = get_reg_class (REGNO (op))) != NO_REGS
		  && ((curr_static_id->operand[nop].type != OP_OUT
		       && targetm.secondary_memory_needed (GET_MODE (op), cl,
							   this_alternative))
		      || (curr_static_id->operand[nop].type != OP_IN
			  && (targetm.secondary_memory_needed
			      (GET_MODE (op), this_alternative, cl)))))
		losers++;

	      /* Input reloads can be inherited more often than output
		 reloads can be removed, so penalize output
		 reloads.  */
	      if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN)
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            %d Non input pseudo reload: reject++\n",
		       nop);
		  reject++;
		}

	      if (MEM_P (op) && offmemok)
		addr_losers++;
	      else if (curr_static_id->operand[nop].type == OP_INOUT)
		{
		  if (lra_dump_file != NULL)
		    fprintf
		      (lra_dump_file,
		       "            %d Input/Output reload: reject+=%d\n",
		       nop, LRA_LOSER_COST_FACTOR);
		  reject += LRA_LOSER_COST_FACTOR;
		}
	    }

	  if (early_clobber_p && ! scratch_p)
	    {
	      if (lra_dump_file != NULL)
		fprintf (lra_dump_file,
			 "            %d Early clobber: reject++\n", nop);
	      reject++;
	    }
	  /* ??? We check early clobbers after processing all operands
	     (see loop below) and there we update the costs more.
	     Should we update the cost (may be approximately) here
	     because of early clobber register reloads or it is a rare
	     or non-important thing to be worth to do it.  */
	  overall = (losers * LRA_LOSER_COST_FACTOR + reject
		     - (addr_losers == losers ? static_reject : 0));
	  if ((best_losers == 0 || losers != 0) && best_overall < overall)
            {
              if (lra_dump_file != NULL)
		fprintf (lra_dump_file,
			 "            alt=%d,overall=%d,losers=%d -- refuse\n",
			 nalt, overall, losers);
              goto fail;
            }

	  if (update_and_check_small_class_inputs (nop, this_alternative))
	    {
	      if (lra_dump_file != NULL)
		fprintf (lra_dump_file,
			 "            alt=%d, not enough small class regs -- refuse\n",
			 nalt);
	      goto fail;
	    }
	  curr_alt[nop] = this_alternative;
	  COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_set);
	  curr_alt_win[nop] = this_alternative_win;
	  curr_alt_match_win[nop] = this_alternative_match_win;
	  curr_alt_offmemok[nop] = this_alternative_offmemok;
	  curr_alt_matches[nop] = this_alternative_matches;

	  if (this_alternative_matches >= 0
	      && !did_match && !this_alternative_win)
	    curr_alt_win[this_alternative_matches] = false;

	  if (early_clobber_p && operand_reg[nop] != NULL_RTX)
	    early_clobbered_nops[early_clobbered_regs_num++] = nop;
	}

      if (curr_insn_set != NULL_RTX && n_operands == 2
	  /* Prevent processing non-move insns.  */
	  && (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG
	      || SET_SRC (curr_insn_set) == no_subreg_reg_operand[1])
	  && ((! curr_alt_win[0] && ! curr_alt_win[1]
	       && REG_P (no_subreg_reg_operand[0])
	       && REG_P (no_subreg_reg_operand[1])
	       && (reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1])
		   || reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0])))
	      || (! curr_alt_win[0] && curr_alt_win[1]
		  && REG_P (no_subreg_reg_operand[1])
		  /* Check that we reload memory not the memory
		     address.  */
		  && ! (curr_alt_offmemok[0]
			&& MEM_P (no_subreg_reg_operand[0]))
		  && reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0]))
	      || (curr_alt_win[0] && ! curr_alt_win[1]
		  && REG_P (no_subreg_reg_operand[0])
		  /* Check that we reload memory not the memory
		     address.  */
		  && ! (curr_alt_offmemok[1]
			&& MEM_P (no_subreg_reg_operand[1]))
		  && reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1])
		  && (! CONST_POOL_OK_P (curr_operand_mode[1],
					 no_subreg_reg_operand[1])
		      || (targetm.preferred_reload_class
			  (no_subreg_reg_operand[1],
			   (enum reg_class) curr_alt[1]) != NO_REGS))
		  /* If it is a result of recent elimination in move
		     insn we can transform it into an add still by
		     using this alternative.  */
		  && GET_CODE (no_subreg_reg_operand[1]) != PLUS
		  /* Likewise if the source has been replaced with an
		     equivalent value.  This only happens once -- the reload
		     will use the equivalent value instead of the register it
		     replaces -- so there should be no danger of cycling.  */
		  && !equiv_substition_p[1])))
	{
	  /* We have a move insn and a new reload insn will be similar
	     to the current insn.  We should avoid such situation as
	     it results in LRA cycling.  */
	  if (lra_dump_file != NULL)
	    fprintf (lra_dump_file,
		     "            Cycle danger: overall += LRA_MAX_REJECT\n");
	  overall += LRA_MAX_REJECT;
	}
      ok_p = true;
      curr_alt_dont_inherit_ops_num = 0;
      for (nop = 0; nop < early_clobbered_regs_num; nop++)
	{
	  int i, j, clobbered_hard_regno, first_conflict_j, last_conflict_j;
	  HARD_REG_SET temp_set;

	  i = early_clobbered_nops[nop];
	  if ((! curr_alt_win[i] && ! curr_alt_match_win[i])
	      || hard_regno[i] < 0)
	    continue;
	  lra_assert (operand_reg[i] != NULL_RTX);
	  clobbered_hard_regno = hard_regno[i];
	  CLEAR_HARD_REG_SET (temp_set);
	  add_to_hard_reg_set (&temp_set, biggest_mode[i], clobbered_hard_regno);
	  first_conflict_j = last_conflict_j = -1;
	  for (j = 0; j < n_operands; j++)
	    if (j == i
		/* We don't want process insides of match_operator and
		   match_parallel because otherwise we would process
		   their operands once again generating a wrong
		   code.  */
		|| curr_static_id->operand[j].is_operator)
	      continue;
	    else if ((curr_alt_matches[j] == i && curr_alt_match_win[j])
		     || (curr_alt_matches[i] == j && curr_alt_match_win[i]))
	      continue;
	    /* If we don't reload j-th operand, check conflicts.  */
	    else if ((curr_alt_win[j] || curr_alt_match_win[j])
		     && uses_hard_regs_p (*curr_id->operand_loc[j], temp_set))
	      {
		if (first_conflict_j < 0)
		  first_conflict_j = j;
		last_conflict_j = j;
	      }
	  if (last_conflict_j < 0)
	    continue;
	  /* If earlyclobber operand conflicts with another
	     non-matching operand which is actually the same register
	     as the earlyclobber operand, it is better to reload the
	     another operand as an operand matching the earlyclobber
	     operand can be also the same.  */
	  if (first_conflict_j == last_conflict_j
	      && operand_reg[last_conflict_j] != NULL_RTX
	      && ! curr_alt_match_win[last_conflict_j]
	      && REGNO (operand_reg[i]) == REGNO (operand_reg[last_conflict_j]))
	    {
	      curr_alt_win[last_conflict_j] = false;
	      curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]
		= last_conflict_j;
	      losers++;
	      /* Early clobber was already reflected in REJECT. */
	      lra_assert (reject > 0);
	      if (lra_dump_file != NULL)
		fprintf
		  (lra_dump_file,
		   "            %d Conflict early clobber reload: reject--\n",
		   i);
	      reject--;
	      overall += LRA_LOSER_COST_FACTOR - 1;
	    }
	  else
	    {
	      /* We need to reload early clobbered register and the
		 matched registers.  */
	      for (j = 0; j < n_operands; j++)
		if (curr_alt_matches[j] == i)
		  {
		    curr_alt_match_win[j] = false;
		    losers++;
		    overall += LRA_LOSER_COST_FACTOR;
		  }
	      if (! curr_alt_match_win[i])
		curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i;
	      else
		{
		  /* Remember pseudos used for match reloads are never
		     inherited.  */
		  lra_assert (curr_alt_matches[i] >= 0);
		  curr_alt_win[curr_alt_matches[i]] = false;
		}
	      curr_alt_win[i] = curr_alt_match_win[i] = false;
	      losers++;
	      /* Early clobber was already reflected in REJECT. */
	      lra_assert (reject > 0);
	      if (lra_dump_file != NULL)
		fprintf
		  (lra_dump_file,
		   "            %d Matched conflict early clobber reloads: "
		   "reject--\n",
		   i);
	      reject--;
	      overall += LRA_LOSER_COST_FACTOR - 1;
	    }
	}
      if (lra_dump_file != NULL)
	fprintf (lra_dump_file, "          alt=%d,overall=%d,losers=%d,rld_nregs=%d\n",
		 nalt, overall, losers, reload_nregs);

      /* If this alternative can be made to work by reloading, and it
	 needs less reloading than the others checked so far, record
	 it as the chosen goal for reloading.  */
      if ((best_losers != 0 && losers == 0)
	  || (((best_losers == 0 && losers == 0)
	       || (best_losers != 0 && losers != 0))
	      && (best_overall > overall
		  || (best_overall == overall
		      /* If the cost of the reloads is the same,
			 prefer alternative which requires minimal
			 number of reload regs.  */
		      && (reload_nregs < best_reload_nregs
			  || (reload_nregs == best_reload_nregs
			      && (best_reload_sum < reload_sum
				  || (best_reload_sum == reload_sum
				      && nalt < goal_alt_number))))))))
	{
	  for (nop = 0; nop < n_operands; nop++)
	    {
	      goal_alt_win[nop] = curr_alt_win[nop];
	      goal_alt_match_win[nop] = curr_alt_match_win[nop];
	      goal_alt_matches[nop] = curr_alt_matches[nop];
	      goal_alt[nop] = curr_alt[nop];
	      goal_alt_offmemok[nop] = curr_alt_offmemok[nop];
	    }
	  goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num;
	  for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++)
	    goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop];
	  goal_alt_swapped = curr_swapped;
	  best_overall = overall;
	  best_losers = losers;
	  best_reload_nregs = reload_nregs;
	  best_reload_sum = reload_sum;
	  goal_alt_number = nalt;
	}
      if (losers == 0)
	/* Everything is satisfied.  Do not process alternatives
	   anymore.  */
	break;
    fail:
      ;
    }
  return ok_p;
}

コメント


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-03-17 (火) 19:21:54 (111d)