*参照元 [#xae243ce]
#backlinks

*説明 [#fa4689f3]
-パス: [[gcc-8.3/gcc/lra-constraints.c]]

-FIXME: これは何?
--説明


**引数 [#q6a4166f]
-int only_alternative
--


**返り値 [#h33e0fe0]
-bool
--


**参考 [#sd3ab371]


*実装 [#q662f0d2]
 /* 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;
 }


*コメント [#a8273e31]


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS