Patchwork [lra] patch to solve code size regression on ppc32 SPEC2000

login
register
mail settings
Submitter Vladimir Makarov
Date Sept. 12, 2011, 3:25 p.m.
Message ID <4E6E2460.8040008@redhat.com>
Download mbox | patch
Permalink /patch/114385/
State New
Headers show

Comments

Vladimir Makarov - Sept. 12, 2011, 3:25 p.m.
The following patch fixes ppc32 code size regression on SPEC2000.  I 
already posted an analogous patch

http://gcc.gnu.org/ml/gcc-patches/2011-08/msg02208.html

but it resulted in wrong code generation on x86.  The original patch was 
reworked to fix the x86 code generation.  To do this, classes with 
constraints '*' are made more costly.  This is different from reload 
approach which ignores such constraint.  I believe taking the constraint 
into account will help to make LRA more stable to order of alternatives 
in the insn descriptions making them more descriptive.

The patch was successfully bootstrapped on x86/x86-64 and ppc32.

2011-09-12  Vladimir Makarov <vmakarov@redhat.com>

         * lra-constraints.c (best_reload_nregs): New variable.
         (process_alt_operands): Add heuristics based on number regs
         involved in relaods and based on '*' constraints.  Increase reject
         for all failed non registers.
         (curr_insn_transform, lra_inheritance): Formatting.

         * lra-eliminations.c (mark_not_eliminable): Add check on hard
         register before looping on eliminations.

Patch

Index: lra-constraints.c
===================================================================
--- lra-constraints.c	(revision 178737)
+++ lra-constraints.c	(working copy)
@@ -270,7 +270,8 @@  init_curr_insn_input_reloads (void)
    NEW_CLASS.  Print info about it using TITLE.  Output a new line if
    NL_P.  */
 static void
-change_class (int regno, enum reg_class new_class, const char *title, bool nl_p)
+change_class (int regno, enum reg_class new_class,
+	      const char *title, bool nl_p)
 {
   int curr_regno;
 
@@ -1143,6 +1144,10 @@  static int best_losers, best_overall;
 /* Number of small register classes used for operands of the best
    alternative.  */
 static int best_small_class_operands_num;
+/* Overall number hard registers used for reloads.  For example, on
+   some targets we need 2 general registers to reload DFmode and only
+   one floating point register.  */
+static int best_reload_nregs;
 /* Overall number reflecting distances of previous reloading the same
    value.  It is used to improve inheritance chances.  */
 static int best_reload_sum;
@@ -1415,7 +1420,9 @@  process_alt_operands (int only_alternati
   rtx no_subreg_operand[MAX_RECOG_OPERANDS], operand_reg[MAX_RECOG_OPERANDS];
   int hard_regno[MAX_RECOG_OPERANDS];
   enum machine_mode biggest_mode[MAX_RECOG_OPERANDS];
-  int reload_sum;
+  int reload_nregs, reload_sum;
+  bool costly_p;
+  enum reg_class cl;
 
   /* Calculate some data common for all alternatives to speed up the
      function.  */
@@ -1460,7 +1467,7 @@  process_alt_operands (int only_alternati
 	  (only_alternative >= 0 && nalt != only_alternative))
 	continue;
 
-      overall = losers = reject = reload_sum = 0;
+      overall = losers = reject = reload_nregs = reload_sum = 0;
       for (nop = 0; nop < n_operands; nop++)
 	reject += (curr_static_id
 		   ->operand_alternative[nalt * n_operands + nop].reject);
@@ -1481,8 +1488,8 @@  process_alt_operands (int only_alternati
 	  /* False if a constant forced into memory would be OK for
 	     this operand.  */
 	  bool constmemok;
-	  enum reg_class this_alternative;
-	  HARD_REG_SET this_alternative_set;
+	  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;
 	  int invalidate_m;
@@ -1510,13 +1517,14 @@  process_alt_operands (int only_alternati
 	  early_clobber_p = false;
 	  p = curr_static_id->operand_alternative[opalt_num].constraint;
       
-	  this_alternative = NO_REGS;
+	  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;
@@ -1534,349 +1542,378 @@  process_alt_operands (int only_alternati
 	     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 '=':  case '+':  case '*': case '?': case '!':
-		break;
-	
-	      case '%':
-		/* We only support one commutative marker, the first
-		   one.  We already set commutative above.  */
-		break;
-	
-	      case '&':
-		early_clobber_p = true;
-		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':
+	    {
+	      switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
 		{
-		  int m_hregno, m_offset;
-		  bool match_p;
-
-		  m = strtoul (p, &end, 10);
-		  p = end;
+		case '\0':
 		  len = 0;
-		  gcc_assert (nop > m);
-	  
-		  this_alternative_matches = m;
-		  lra_get_hard_regno_and_offset (*curr_id->operand_loc[m],
-						 &m_hregno, &m_offset);
-		  m_hregno = get_final_hard_regno (m_hregno, m_offset);
-		  /* 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.)  */
-		  /* If it conflicts with others.  */
-		  match_p = false;
-		  if (operands_match_p (*curr_id->operand_loc[nop],
-					*curr_id->operand_loc[m], m_hregno))
-		    {
-		      int i;
-
-		      for (i = 0; i < early_clobbered_regs_num; i++)
-			if (early_clobbered_nops[i] == m)
-			  break;
-		      /* We should reject matching of an early clobber
-			 operand if the matching operand is not dying
-			 in the insn.  */
-		      if (i >= early_clobbered_regs_num
-			  || operand_reg[nop] == NULL_RTX
-			  || (find_regno_note (curr_insn, REG_DEAD,
-					       REGNO (operand_reg[nop]))
-			      != NULL_RTX))
-			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;
-	      
-		      did_match = curr_alt_win[m];
-		    }
-		  else
-		    {
-		      /* Operands don't match.  */
-		      /* 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++;
-		      invalidate_m = m;
-		      if (curr_alt[m] == NO_REGS)
-			continue;
-	      
-		      /* We prefer no matching alternatives because it
-			 gives more freedom in RA.  */
-		      if (operand_reg[nop] == NULL_RTX
-			  || (find_regno_note (curr_insn, REG_DEAD,
-					       REGNO (operand_reg[nop]))
-			      == NULL_RTX))
-			reject += 2;
-		    }
-		  /* 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]);
-
-		  /* 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.
-		     So reject this alternative.  */
-		  if (! did_match)
-		    for (i = 0; i < nop; i++)
-		      if (curr_alt_matches[i] == this_alternative_matches)
-			badop = true;
-	  
 		  break;
-		}
-	
-	      case 'p':
-		this_alternative
-		  = (reg_class_subunion
-		     [this_alternative]
-		     [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]);
-		IOR_HARD_REG_SET (this_alternative_set,
-				  reg_class_contents
-				  [base_reg_class
-				   (VOIDmode, ADDRESS, SCRATCH)]);
-		win = true;
-		badop = false;
-		break;
-	
-	      case TARGET_MEM_CONSTRAINT:
-		if (MEM_P (op)
-		    || (REG_P (op)
-			&& REGNO (op) >= FIRST_PSEUDO_REGISTER
-			&& in_mem_p (REGNO (op))))
-		  win = true;
-		if (CONST_POOL_OK_P (mode, op))
-		  badop = false;
-		constmemok = true;
-		break;
-	
-	      case '<':
-		if (MEM_P (op)
-		    && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			|| GET_CODE (XEXP (op, 0)) == POST_DEC))
-		  win = true;
-		break;
-	
-	      case '>':
-		if (MEM_P (op)
-		    && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			|| GET_CODE (XEXP (op, 0)) == POST_INC))
-		  win = true;
-		break;
-	
-		/* Memory op whose address is not
-		   offsettable.  */
-	      case 'V':
-		if (MEM_P (op)
-		    && ! offsettable_nonstrict_memref_p (op))
-		  win = true;
-		break;
-	
-		/* Memory operand whose address is offsettable.  */
-	      case 'o':
-		if ((MEM_P (op)
-		     && offsettable_nonstrict_memref_p (op))
-		    || (REG_P (op)
-			&& REGNO (op) >= FIRST_PSEUDO_REGISTER
-			&& in_mem_p (REGNO (op))))
-		  win = true;
-		if (CONST_POOL_OK_P (mode, op) || MEM_P (op))
-		  badop = false;
-		constmemok = true;
-		offmemok = true;
-		break;
-	
-	      case 'E':
-	      case 'F':
-		if (GET_CODE (op) == CONST_DOUBLE
-		    || (GET_CODE (op) == CONST_VECTOR
-			&& (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)))
-		  win = true;
-		break;
-	
-	      case 'G':
-	      case 'H':
-		if (GET_CODE (op) == CONST_DOUBLE
-		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-		  win = true;
-		break;
-	
-	      case 's':
-		if (CONST_INT_P (op)
-		    || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode))
-		  break;
-	      case 'i':
-		if (CONSTANT_P (op)
-		    && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
-		  win = true;
-		break;
-	
-	      case 'n':
-		if (CONST_INT_P (op)
-		    || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode))
-		  win = true;
-		break;
-	
-	      case 'I':
-	      case 'J':
-	      case 'K':
-	      case 'L':
-	      case 'M':
-	      case 'N':
-	      case 'O':
-	      case 'P':
-		if (CONST_INT_P (op)
-		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-		  win = true;
-		break;
-	
-	      case 'X':
-		/* This constraint should be excluded by the fast
-		   track.  */
-		gcc_unreachable ();
-		break;
-	
-	      case 'g':
-		if (/* A PLUS is never a valid operand, but LRA can
-		       make it from a register when eliminating
-		       registers.  */
-		    GET_CODE (op) != PLUS
-		    && (! CONSTANT_P (op) || ! flag_pic
-			|| LEGITIMATE_PIC_OPERAND_P (op))
-		    && (! REG_P (op)
-			|| (REGNO (op) >= FIRST_PSEUDO_REGISTER
-			    && in_mem_p (REGNO (op)))))
-		  win = true;
-		/* Drop through into 'r' case.  */
-	
-	      case 'r':
-		this_alternative
-		  = reg_class_subunion[this_alternative][GENERAL_REGS];
-		IOR_HARD_REG_SET (this_alternative_set,
-				  reg_class_contents[GENERAL_REGS]);
-		goto reg;
+		case ',':
+		  c = '\0';
+		  break;
 	
-	      default:
-		if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+		case '=':  case '+': case '?': case '*': case '!':
+		case ' ': case '\t':
+		  break;
+		  
+		case '%':
+		  /* We only support one commutative marker, the first
+		     one.  We already set commutative above.  */
+		  break;
+		  
+		case '&':
+		  early_clobber_p = true;
+		  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':
 		  {
-#ifdef EXTRA_CONSTRAINT_STR
-		    if (EXTRA_MEMORY_CONSTRAINT (c, p))
+		    int m_hregno, m_offset;
+		    bool match_p;
+		    
+		    m = strtoul (p, &end, 10);
+		    p = end;
+		    len = 0;
+		    gcc_assert (nop > m);
+		    
+		    this_alternative_matches = m;
+		    lra_get_hard_regno_and_offset (*curr_id->operand_loc[m],
+						   &m_hregno, &m_offset);
+		    m_hregno = get_final_hard_regno (m_hregno, m_offset);
+		    /* 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.)  */
+		    /* If it conflicts with others.  */
+		    match_p = false;
+		    if (operands_match_p (*curr_id->operand_loc[nop],
+					  *curr_id->operand_loc[m], m_hregno))
 		      {
-			if (EXTRA_CONSTRAINT_STR (op, c, p))
-			  win = true;
-			/* For regno_equiv_mem_loc we have to
-			   check.  */
-			else if (REG_P (op)
-				 && REGNO (op) >= FIRST_PSEUDO_REGISTER
-				 && in_mem_p (REGNO (op)))
-			  {
-			    /* We could transform spilled memory
-			       finally to indirect memory.  */
-			    if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode),
-						      c, p))
-			      win = true;
-			  }
-		
-			/* If we didn't already win, we can reload
-			   constants via force_const_mem, and other
-			   MEMs by reloading the address like for
-			   'o'.  */
-			if (CONST_POOL_OK_P (mode, op) || MEM_P (op))
-			  badop = false;
-			constmemok = true;
-			offmemok = true;
-			break;
+			int i;
+			
+			for (i = 0; i < early_clobbered_regs_num; i++)
+			  if (early_clobbered_nops[i] == m)
+			    break;
+			/* We should reject matching of an early
+			   clobber operand if the matching operand is
+			   not dying in the insn.  */
+			if (i >= early_clobbered_regs_num
+			    || operand_reg[nop] == NULL_RTX
+			    || (find_regno_note (curr_insn, REG_DEAD,
+						 REGNO (operand_reg[nop]))
+				!= NULL_RTX))
+			  match_p = true;
 		      }
-		    if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+		    if (match_p)
 		      {
-			if (EXTRA_CONSTRAINT_STR (op, c, p))
-			  win = true;
-		
-			/* If we didn't already win, we can reload the
-			   address into a base register.  */
-			this_alternative
-			  = (reg_class_subunion
-			     [this_alternative]
-			     [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]);
-			IOR_HARD_REG_SET
-			  (this_alternative_set,
-			   reg_class_contents[base_reg_class
-					      (VOIDmode, ADDRESS, SCRATCH)]);
-			badop = false;
-			break;
+			/* 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;
+			
+			did_match = curr_alt_win[m];
 		      }
-	    
-		    if (EXTRA_CONSTRAINT_STR (op, c, p))
-		      win = true;
-		    else if (REG_P (op)
-			     && REGNO (op) >= FIRST_PSEUDO_REGISTER
-			     && in_mem_p (REGNO (op)))
+		    else
 		      {
-			/* We could transform spilled memory finally
-			   to indirect memory.  */
-			if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode),
-						  c, p))
-			  win = true;
+			/* Operands don't match.  */
+			/* 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++;
+			    if (curr_alt[m] != NO_REGS)
+			      reload_nregs
+				+= (ira_reg_class_max_nregs[curr_alt[m]]
+				    [GET_MODE (*curr_id->operand_loc[m])]);
+			}
+			invalidate_m = m;
+			if (curr_alt[m] == NO_REGS)
+			  continue;
+			
+			/* We prefer no matching alternatives because
+			   it gives more freedom in RA.  */
+			if (operand_reg[nop] == NULL_RTX
+			    || (find_regno_note (curr_insn, REG_DEAD,
+						 REGNO (operand_reg[nop]))
+				== NULL_RTX))
+			  reject += 2;
 		      }
-#endif
+		    /* 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]);
+		    
+		    /* 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.  So reject this alternative.  */
+		    if (! did_match)
+		      for (i = 0; i < nop; i++)
+			if (curr_alt_matches[i] == this_alternative_matches)
+			  badop = true;
+		    
 		    break;
 		  }
+		  
+		case 'p':
+		  cl = base_reg_class (VOIDmode, ADDRESS, SCRATCH);
+		  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]);
+		    }
+		  win = true;
+		  badop = false;
+		  break;
+		  
+		case TARGET_MEM_CONSTRAINT:
+		  if (MEM_P (op)
+		      || (REG_P (op)
+			  && REGNO (op) >= FIRST_PSEUDO_REGISTER
+			  && in_mem_p (REGNO (op))))
+		    win = true;
+		  if (CONST_POOL_OK_P (mode, op))
+		    badop = false;
+		  constmemok = true;
+		  break;
+		  
+		case '<':
+		  if (MEM_P (op)
+		      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+			  || GET_CODE (XEXP (op, 0)) == POST_DEC))
+		    win = true;
+		  break;
+		  
+		case '>':
+		  if (MEM_P (op)
+		      && (GET_CODE (XEXP (op, 0)) == PRE_INC
+			  || GET_CODE (XEXP (op, 0)) == POST_INC))
+		    win = true;
+		  break;
+		  
+		/* Memory op whose address is not offsettable.  */
+		case 'V':
+		  if (MEM_P (op)
+		      && ! offsettable_nonstrict_memref_p (op))
+		    win = true;
+		  break;
+		  
+		  /* Memory operand whose address is offsettable.  */
+		case 'o':
+		  if ((MEM_P (op)
+		       && offsettable_nonstrict_memref_p (op))
+		      || (REG_P (op)
+			  && REGNO (op) >= FIRST_PSEUDO_REGISTER
+			  && in_mem_p (REGNO (op))))
+		    win = true;
+		  if (CONST_POOL_OK_P (mode, op) || MEM_P (op))
+		    badop = false;
+		  constmemok = true;
+		  offmemok = true;
+		  break;
+		  
+		case 'E':
+		case 'F':
+		  if (GET_CODE (op) == CONST_DOUBLE
+		      || (GET_CODE (op) == CONST_VECTOR
+			  && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)))
+		    win = true;
+		  break;
+		  
+		case 'G':
+		case 'H':
+		  if (GET_CODE (op) == CONST_DOUBLE
+		      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
+		    win = true;
+		  break;
+		  
+		case 's':
+		  if (CONST_INT_P (op)
+		      || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode))
+		    break;
+		case 'i':
+		  if (CONSTANT_P (op)
+		      && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
+		    win = true;
+		  break;
+		  
+		case 'n':
+		  if (CONST_INT_P (op)
+		      || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode))
+		    win = true;
+		  break;
 	
-		this_alternative
-		  = (reg_class_subunion
-		     [this_alternative][REG_CLASS_FROM_CONSTRAINT (c, p)]);
-		IOR_HARD_REG_SET
-		  (this_alternative_set,
-		   reg_class_contents[REG_CLASS_FROM_CONSTRAINT (c, p)]);
-	      reg:
-		if (mode == BLKmode)
+		case 'I':
+		case 'J':
+		case 'K':
+		case 'L':
+		case 'M':
+		case 'N':
+		case 'O':
+		case 'P':
+		  if (CONST_INT_P (op)
+		      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
+		    win = true;
 		  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 (REGNO (op),
-					    this_alternative, NULL))
-		      win = true;
-		  }
-		break;
-	      }
+		  
+		case 'X':
+		  /* This constraint should be excluded by the fast
+		     track.  */
+		  gcc_unreachable ();
+		  break;
+		  
+		case 'g':
+		  if (/* A PLUS is never a valid operand, but LRA can
+			 make it from a register when eliminating
+			 registers.  */
+		      GET_CODE (op) != PLUS
+		      && (! CONSTANT_P (op) || ! flag_pic
+			  || LEGITIMATE_PIC_OPERAND_P (op))
+		      && (! REG_P (op)
+			  || (REGNO (op) >= FIRST_PSEUDO_REGISTER
+			      && in_mem_p (REGNO (op)))))
+		    win = true;
+		  /* Drop through into 'r' case.  */
+		  
+		case 'r':
+		  this_alternative
+		    = reg_class_subunion[this_alternative][GENERAL_REGS];
+		  IOR_HARD_REG_SET (this_alternative_set,
+				    reg_class_contents[GENERAL_REGS]);
+		  if (costly_p)
+		    {
+		      this_costly_alternative
+			= reg_class_subunion[this_costly_alternative][GENERAL_REGS];
+		      IOR_HARD_REG_SET (this_costly_alternative_set,
+					reg_class_contents[GENERAL_REGS]);
+		    }
+		  goto reg;
+		  
+		default:
+		  if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+		    {
+#ifdef EXTRA_CONSTRAINT_STR
+		      if (EXTRA_MEMORY_CONSTRAINT (c, p))
+			{
+			  if (EXTRA_CONSTRAINT_STR (op, c, p))
+			    win = true;
+			  /* For regno_equiv_mem_loc we have to
+			     check.  */
+			  else if (REG_P (op)
+				   && REGNO (op) >= FIRST_PSEUDO_REGISTER
+				   && in_mem_p (REGNO (op)))
+			    {
+			      /* We could transform spilled memory
+				 finally to indirect memory.  */
+			      if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode),
+							c, p))
+				win = true;
+			    }
+			  
+			  /* If we didn't already win, we can reload
+			     constants via force_const_mem, and other
+			     MEMs by reloading the address like for
+			     'o'.  */
+			  if (CONST_POOL_OK_P (mode, op) || MEM_P (op))
+			    badop = false;
+			  constmemok = true;
+			  offmemok = true;
+			  break;
+			}
+		      if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+			{
+			  if (EXTRA_CONSTRAINT_STR (op, c, p))
+			    win = true;
+			  
+			  /* If we didn't already win, we can reload
+			     the address into a base register.  */
+			  cl = base_reg_class (VOIDmode, ADDRESS, SCRATCH);
+			  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]);
+			    }
+			  badop = false;
+			  break;
+			}
+		      
+		      if (EXTRA_CONSTRAINT_STR (op, c, p))
+			win = true;
+		      else if (REG_P (op)
+			       && REGNO (op) >= FIRST_PSEUDO_REGISTER
+			       && in_mem_p (REGNO (op)))
+			{
+			  /* We could transform spilled memory finally
+			     to indirect memory.  */
+			  if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode),
+						    c, p))
+			    win = true;
+			}
+#endif
+		      break;
+		    }
+		  
+		  cl = REG_CLASS_FROM_CONSTRAINT (c, p);
+		  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]);
+		    }
+		reg:
+		  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 (REGNO (op),
+					      this_alternative, NULL))
+			win = true;
+		    }
+		  break;
+		}
+	      if (c != ' ' && c != '\t')
+		costly_p = c == '*';
+	    }
 	  while ((p += len), c);
   
 	  /* If this operand could be handled with a reg, and some reg
@@ -1888,10 +1925,24 @@  process_alt_operands (int only_alternati
 	  if (win)
 	    {
 	      this_alternative_win = true;
-	      if (operand_reg[nop] != NULL_RTX && hard_regno[nop] < 0)
-		/* Prefer won reg to spilled pseudo under other equal
-		   conditions.  */
-		reject++;
+	      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]))
+			reject++;
+		    }
+		  else
+		    {
+		      /* Prefer won reg to spilled pseudo under other equal
+			 conditions.  */
+		      reject++;
+		      if (in_class_p (REGNO (operand_reg[nop]),
+				      this_costly_alternative, NULL))
+			reject++;
+		    }
+		}
 	    }
 	  else if (did_match)
 	    this_alternative_match_win = true;
@@ -1906,6 +1957,8 @@  process_alt_operands (int only_alternati
 		       (reg_class_contents[this_alternative],
 			lra_no_alloc_regs)));
 	      this_alternative_offmemok = offmemok;
+	      if (this_costly_alternative != NO_REGS)
+		reject++;
 	      /* If the operand is dying, has a matching constraint,
 		 and satisfies constraints of the matched operand
 		 which failed to satisfy the own constraints, we do
@@ -2003,7 +2056,7 @@  process_alt_operands (int only_alternati
 	      /* Input reloads can be inherited more often than output
 		 reloads can be removed, so penalize output
 		 reloads.  */
-	      if (curr_static_id->operand[nop].type != OP_IN)
+	      if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN)
 		reject++;
 	      /* SUBREGS ??? */
 	      if (this_alternative_matches >= 0)
@@ -2012,6 +2065,9 @@  process_alt_operands (int only_alternati
 		}
 	      else if (no_regs_p && ! this_alternative_offmemok && ! constmemok)
 		goto fail;
+
+	      if (! no_regs_p)
+		reload_nregs += ira_reg_class_max_nregs[this_alternative][mode];
 	    }
   
 	  if (early_clobber_p)
@@ -2128,7 +2184,9 @@  process_alt_operands (int only_alternati
 			  < best_small_class_operands_num
 			  || (small_class_operands_num
 			      == best_small_class_operands_num
-			      && best_reload_sum < reload_sum))))))
+			      && (reload_nregs < best_reload_nregs
+				  || (reload_nregs == best_reload_nregs
+				      && best_reload_sum < reload_sum))))))))
 	{
 	  for (nop = 0; nop < n_operands; nop++)
 	    {
@@ -2145,6 +2203,7 @@  process_alt_operands (int only_alternati
 	  best_overall = overall;
 	  best_losers = losers;
 	  best_small_class_operands_num = small_class_operands_num;
+	  best_reload_nregs = reload_nregs;
 	  best_reload_sum = reload_sum;
 	  goal_alt_number = nalt;
 	}
@@ -3045,7 +3104,8 @@  curr_insn_transform (void)
 	  return false;
 	}
     }
-  if (before != NULL_RTX || after != NULL_RTX || max_regno_before != max_reg_num ())
+  if (before != NULL_RTX || after != NULL_RTX
+      || max_regno_before != max_reg_num ())
     change_p = true;
   if (change_p)
     {
@@ -3504,7 +3564,8 @@  lra_inheritance (void)
 				       * lra_constraint_new_regno_start);
   memset (reload_insn_check, 0,
 	  sizeof (int) * lra_constraint_new_regno_start);
-  reload_insn = (rtx *) xmalloc (sizeof (rtx) * lra_constraint_new_regno_start);
+  reload_insn
+    = (rtx *) xmalloc (sizeof (rtx) * lra_constraint_new_regno_start);
   FOR_EACH_BB (bb)
     {
       head = BB_HEAD (bb);
Index: lra-eliminations.c
===================================================================
--- lra-eliminations.c	(revision 178734)
+++ lra-eliminations.c	(working copy)
@@ -671,49 +671,46 @@  mark_not_eliminable (rtx x)
     case POST_DEC:
     case POST_MODIFY:
     case PRE_MODIFY:
-      /* If we modify the source of an elimination rule, disable it.  */
-      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
-	if (ep->from_rtx == XEXP (x, 0)
-	    || (ep->to_rtx == XEXP (x, 0)
-		&& ep->to_rtx != hard_frame_pointer_rtx))
-	  setup_can_eliminate (ep, false);
-
-      /* These two aren't unary operators.  */
-      if (code == POST_MODIFY || code == PRE_MODIFY)
-	break;
-
-      mark_not_eliminable (XEXP (x, 0));
-      return;
-
-    case SUBREG:
-      mark_not_eliminable (SUBREG_REG (x));
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+	/* If we modify the source of an elimination rule, disable it.  */
+	for (ep = reg_eliminate;
+	     ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+	       ep++)
+	  if (ep->from_rtx == XEXP (x, 0)
+	      || (ep->to_rtx == XEXP (x, 0)
+		  && ep->to_rtx != hard_frame_pointer_rtx))
+	    setup_can_eliminate (ep, false);
       return;
 
     case USE:
-      /* If using a register that is the source of an eliminate we still
-	 think can be performed, note it cannot be performed since we don't
-	 know how this register is used.  */
-      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
-	if (ep->from_rtx == XEXP (x, 0) && ep->to_rtx != hard_frame_pointer_rtx)
-	  setup_can_eliminate (ep, false);
-
-      mark_not_eliminable (XEXP (x, 0));
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+	/* If using a register that is the source of an eliminate we
+	   still think can be performed, note it cannot be performed
+	   since we don't know how this register is used.  */
+	for (ep = reg_eliminate;
+	     ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+	     ep++)
+	  if (ep->from_rtx == XEXP (x, 0)
+	      && ep->to_rtx != hard_frame_pointer_rtx)
+	    setup_can_eliminate (ep, false);
       return;
 
     case CLOBBER:
-      /* If clobbering a register that is the replacement register for an
-	 elimination we still think can be performed, note that it cannot
-	 be performed.  Otherwise, we need not be concerned about it.  */
-      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
-	if (ep->to_rtx == XEXP (x, 0) && ep->to_rtx != hard_frame_pointer_rtx)
-	  setup_can_eliminate (ep, false);
-
-      mark_not_eliminable (XEXP (x, 0));
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+	/* If clobbering a register that is the replacement register for an
+	   elimination we still think can be performed, note that it cannot
+	   be performed.  Otherwise, we need not be concerned about it.  */
+	for (ep = reg_eliminate;
+	     ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+	     ep++)
+	  if (ep->to_rtx == XEXP (x, 0)
+	      && ep->to_rtx != hard_frame_pointer_rtx)
+	    setup_can_eliminate (ep, false);
       return;
 
     case SET:
       /* Check for setting a register that we know about.  */
-      if (REG_P (SET_DEST (x)))
+      if (REG_P (SET_DEST (x)) && REGNO (SET_DEST (x)) < FIRST_PSEUDO_REGISTER)
 	{
 	  /* See if this is setting the replacement register for an
 	     elimination.