This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Enable back ends to override standard constraint definitions


Hi,

the attached patch changes recog and reload in a way that allows the
back end to use the existing constraint definition mechanism to
redefine standard constraints.  The patch just changes the logic in
the loop checking the validity of operands for a certain constraint in
order to prefer the back end defined variants.

I've split the patch into a whitespace diff (which just changes the
indentation of the old loop) and the real changes to allow for easier
reviewing.  I've attached the whitespace diff at the end of "real"
changes although it has to be applied beforehand.

Bootstrapped on s390x, s390 and x86_64.
No testsuite regression occurred.

OK for mainline?

Bye,

-Andreas-


2007-11-07  Andreas Krebbel  <krebbel1@de.ibm.com>

	* genpreds.c (TARGET_DEFINED_CONSTRAINT_P): Generate macro definition.
	* recog.c (preprocess_constraints, constrain_operands): Prefer
	target defined constraints over the standard behaviour.
	* reload.c (find_reloads): Likewise.


Index: gcc/genpreds.c
===================================================================
*** gcc/genpreds.c.orig	2007-11-06 16:11:45.000000000 +0100
--- gcc/genpreds.c	2007-11-06 16:12:28.000000000 +0100
*************** write_tm_preds_h (void)
*** 1261,1267 ****
    if (constraint_max_namelen > 0)
      {
        write_enum_constraint_num ();
!       puts ("extern enum constraint_num lookup_constraint (const char *);\n"
  	    "extern bool constraint_satisfied_p (rtx, enum constraint_num);\n");
  
        if (constraint_max_namelen > 1)
--- 1261,1269 ----
    if (constraint_max_namelen > 0)
      {
        write_enum_constraint_num ();
!       puts ("#define TARGET_DEFINED_CONSTRAINT_P(s_)\\\n"
! 	    "  (lookup_constraint (s_) != CONSTRAINT__UNKNOWN)\n"
! 	    "extern enum constraint_num lookup_constraint (const char *);\n"
  	    "extern bool constraint_satisfied_p (rtx, enum constraint_num);\n");
  
        if (constraint_max_namelen > 1)
Index: gcc/recog.c
===================================================================
*** gcc/recog.c.orig	2007-11-06 16:11:45.000000000 +0100
--- gcc/recog.c	2007-11-06 16:20:53.000000000 +0100
*************** preprocess_constraints (void)
*** 2046,2052 ****
  	      continue;
  	    }
  
! 	  for (;;)
  	    {
  	      char c = *p;
  	      if (c == '#')
--- 2046,2052 ----
  	      continue;
  	    }
  
! 	  for (;; p += CONSTRAINT_LEN (*p, p))
  	    {
  	      char c = *p;
  	      if (c == '#')
*************** preprocess_constraints (void)
*** 2058,2064 ****
  		  p++;
  		  break;
  		}
! 
  		  switch (c)
  		    {
  		    case '=': case '+': case '*': case '%':
--- 2058,2065 ----
  		  p++;
  		  break;
  		}
! 	      if (!TARGET_DEFINED_CONSTRAINT_P (p))
! 		{
  		  switch (c)
  		    {
  		    case '=': case '+': case '*': case '%':
*************** preprocess_constraints (void)
*** 2085,2093 ****
  			char *end;
  			op_alt[j].matches = strtoul (p, &end, 10);
  			recog_op_alt[op_alt[j].matches][j].matched = i;
! 			p = end;
  		      }
! 		      continue;
  
  		    case 'm':
  		      op_alt[j].memory_ok = 1;
--- 2086,2094 ----
  			char *end;
  			op_alt[j].matches = strtoul (p, &end, 10);
  			recog_op_alt[op_alt[j].matches][j].matched = i;
! 			p = end - 1;
  		      }
! 		      break;
  
  		    case 'm':
  		      op_alt[j].memory_ok = 1;
*************** preprocess_constraints (void)
*** 2121,2130 ****
  		      break;
  
  		    default:
  		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
  		    {
  		      op_alt[j].memory_ok = 1;
! 		      break;
  		    }
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    {
--- 2122,2136 ----
  		      break;
  
  		    default:
+ 		      ; /* Unknown constraint letter.  */
+ 		    }
+ 		}
+ 	      else
+ 		{
  		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
  		    {
  		      op_alt[j].memory_ok = 1;
! 		      continue;
  		    }
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    {
*************** preprocess_constraints (void)
*** 2134,2149 ****
  			   [(int) op_alt[j].cl]
  			   [(int) base_reg_class (VOIDmode, ADDRESS,
  						  SCRATCH)]);
! 		      break;
  		    }
  
  		  op_alt[j].cl
  		    = (reg_class_subunion
  		       [(int) op_alt[j].cl]
  		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
- 		  break;
  		}
- 	      p += CONSTRAINT_LEN (c, p);
  	    }
  	}
      }
--- 2140,2153 ----
  			   [(int) op_alt[j].cl]
  			   [(int) base_reg_class (VOIDmode, ADDRESS,
  						  SCRATCH)]);
! 		      continue;
  		    }
  
  		  op_alt[j].cl
  		    = (reg_class_subunion
  		       [(int) op_alt[j].cl]
  		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
  		}
  	    }
  	}
      }
*************** constrain_operands (int strict)
*** 2217,2223 ****
  	  int offset = 0;
  	  int win = 0;
  	  int val;
- 	  int len;
  
  	  earlyclobber[opno] = 0;
  
--- 2221,2226 ----
*************** constrain_operands (int strict)
*** 2242,2257 ****
  	  if (*p == 0 || *p == ',')
  	    win = 1;
  
! 	  do
! 		  switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
! 		    {
! 		    case '\0':
! 		      len = 0;
! 		      break;
! 		    case ',':
! 		      c = '\0';
! 		      break;
  
  		    case '?':  case '!': case '*':  case '%':
  		    case '=':  case '+':
  		      break;
--- 2245,2266 ----
  	  if (*p == 0 || *p == ',')
  	    win = 1;
  
! 	  for (; *p != '\0'; p += CONSTRAINT_LEN (*p, p))
! 	    {
! 	      c = *p;
! 
! 	      if (c == ',')
! 		{
! 		  p++;
! 		  break;
! 		}
  
+ 	      /* Check if the back end wants to override a standard
+ 		 constraint.  */
+ 	      if (!TARGET_DEFINED_CONSTRAINT_P (p))
+ 		{
+ 		  switch (c)
+ 		    {
  		    case '?':  case '!': case '*':  case '%':
  		    case '=':  case '+':
  		      break;
*************** constrain_operands (int strict)
*** 2262,2268 ****
  		      do
  			p++;
  		      while (*p && *p != ',');
! 		      len = 0;
  		      break;
  
  		    case '&':
--- 2271,2277 ----
  		      do
  			p++;
  		      while (*p && *p != ',');
! 		      p--;
  		      break;
  
  		    case '&':
*************** constrain_operands (int strict)
*** 2287,2293 ****
  			int match;
  
  			match = strtoul (p, &end, 10);
! 			p = end;
  
  			if (strict < 0)
  			  val = 1;
--- 2296,2302 ----
  			int match;
  
  			match = strtoul (p, &end, 10);
! 			p = end - 1;
  
  			if (strict < 0)
  			  val = 1;
*************** constrain_operands (int strict)
*** 2321,2327 ****
  			    funny_match[funny_match_index++].other = match;
  			  }
  		      }
- 		      len = 0;
  		      break;
  
  		    case 'p':
--- 2330,2335 ----
*************** constrain_operands (int strict)
*** 2467,2478 ****
  			win = 1;
  		      break;
  
  		    default:
  		{
  		  enum reg_class cl;
  
! 		  cl = (c == 'r'
! 			   ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
  		  if (cl != NO_REGS)
  		    {
  		      if (strict < 0
--- 2475,2501 ----
  			win = 1;
  		      break;
  
+ 		    case 'r':
+ 		      if (strict < 0
+ 			  || (strict == 0
+ 			      && REG_P (op)
+ 			      && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ 			  || (strict == 0 && GET_CODE (op) == SCRATCH)
+ 			  || (REG_P (op)
+ 			      && reg_fits_class_p (op, GENERAL_REGS, offset, mode)))
+ 			win = 1;
+ 		      break;
  		    default:
+ 		      ; /* Unknown constraint letter.  */
+ 		    }
+ 		}
+ 	      else /* Target specific constraint letter or
+ 		      standard constraint overridden by the back
+ 		      end.  */
  		{
  		  enum reg_class cl;
  
! 		  cl = REG_CLASS_FROM_CONSTRAINT (c, p);
  		  if (cl != NO_REGS)
  		    {
  		      if (strict < 0
*************** constrain_operands (int strict)
*** 2503,2512 ****
  			   && strict < 0)
  		    win = 1;
  #endif
- 		  break;
  		}
! 	      }
! 	  while (p += len, c);
  
  	  constraints[opno] = p;
  	  /* If this operand did not win somehow,
--- 2526,2533 ----
  			   && strict < 0)
  		    win = 1;
  #endif
  		}
! 	    }
  
  	  constraints[opno] = p;
  	  /* If this operand did not win somehow,
Index: gcc/reload.c
===================================================================
*** gcc/reload.c.orig	2007-11-06 16:11:45.000000000 +0100
--- gcc/reload.c	2007-11-06 16:14:22.000000000 +0100
*************** find_reloads (rtx insn, int replace, int
*** 2735,2741 ****
        if (*constraints[i] == 0)
  	/* Ignore things like match_operator operands.  */
  	;
!       else if (constraints[i][0] == 'p'
  	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
  	{
  	  address_operand_reloaded[i]
--- 2735,2741 ----
        if (*constraints[i] == 0)
  	/* Ignore things like match_operator operands.  */
  	;
!       else if ((!TARGET_DEFINED_CONSTRAINT_P ("p") && constraints[i][0] == 'p')
  	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
  	{
  	  address_operand_reloaded[i]
*************** find_reloads (rtx insn, int replace, int
*** 2908,2914 ****
  	{
  	  char *p = constraints[i];
  	  char *end;
- 	  int len;
  	  int win = 0;
  	  int did_match = 0;
  	  /* 0 => this operand can be reloaded somehow for this alternative.  */
--- 2908,2913 ----
*************** find_reloads (rtx insn, int replace, int
*** 3031,3046 ****
  	     or set WINREG if this operand could fit after reloads
  	     provided the constraint allows some registers.  */
  
! 	  do
! 		  switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
! 		    {
! 		    case '\0':
! 		      len = 0;
! 		      break;
! 		    case ',':
! 		      c = '\0';
! 		      break;
  
  		    case '=':  case '+':  case '*':
  		      break;
  
--- 3030,3049 ----
  	     or set WINREG if this operand could fit after reloads
  	     provided the constraint allows some registers.  */
  
! 	  for (; *p != '\0'; p += CONSTRAINT_LEN (*p, p))
! 	    {
! 	      c = *p;
! 
! 	      if (c == ',')
! 		{
! 		  p++;
! 		  break;
! 		}
  
+ 	      if (!TARGET_DEFINED_CONSTRAINT_P (p))
+ 		{
+ 		  switch (c)
+ 		    {
  		    case '=':  case '+':  case '*':
  		      break;
  
*************** find_reloads (rtx insn, int replace, int
*** 3063,3077 ****
  		      do
  			p++;
  		      while (*p && *p != ',');
! 		      len = 0;
  		      break;
  
  		    case '0':  case '1':  case '2':  case '3':  case '4':
  		    case '5':  case '6':  case '7':  case '8':  case '9':
  		      m = strtoul (p, &end, 10);
! 		      p = end;
! 		      len = 0;
! 
  		      this_alternative_matches[i] = m;
  		      /* We are supposed to match a previous operand.
  			 If we do, we win if that one did.
--- 3066,3078 ----
  		      do
  			p++;
  		      while (*p && *p != ',');
! 		      p--;
  		      break;
  
  		    case '0':  case '1':  case '2':  case '3':  case '4':
  		    case '5':  case '6':  case '7':  case '8':  case '9':
  		      m = strtoul (p, &end, 10);
! 		      p = end - 1;
  		      this_alternative_matches[i] = m;
  		      /* We are supposed to match a previous operand.
  			 If we do, we win if that one did.
*************** find_reloads (rtx insn, int replace, int
*** 3325,3340 ****
  		    case 'r':
  		      this_alternative[i]
  			= (int) reg_class_subunion[this_alternative[i]][(int) 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 (force_reload)
! 			break;
  		      if (EXTRA_CONSTRAINT_STR (operand, c, p))
  			win = 1;
  		      /* If the address was already reloaded,
--- 3326,3353 ----
  		    case 'r':
  		      this_alternative[i]
  			= (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
! 		      if (GET_MODE (operand) == BLKmode)
! 			break;
! 		      winreg = 1;
! 		      if (REG_P (operand)
! 			  && reg_fits_class_p (operand, this_alternative[i],
! 					       offset, GET_MODE (recog_data.operand[i])))
! 			win = 1;
! 		      break;
  		    default:
+ 		      ; /* Unknown constraint letter.  */
+ 		  }
+ 		}
+ 
+ 	      /* Handle target specific constraints as well as
+ 		 overridden standard constraints.  */
  	      if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
  		{
  #ifdef EXTRA_CONSTRAINT_STR
  		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
  		    {
  		      if (force_reload)
! 			continue;
  		      if (EXTRA_CONSTRAINT_STR (operand, c, p))
  			win = 1;
  		      /* If the address was already reloaded,
*************** find_reloads (rtx insn, int replace, int
*** 3361,3367 ****
  			badop = 0;
  		      constmemok = 1;
  		      offmemok = 1;
! 		      break;
  		    }
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    {
--- 3374,3380 ----
  			badop = 0;
  		      constmemok = 1;
  		      offmemok = 1;
! 		      continue;
  		    }
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    {
*************** find_reloads (rtx insn, int replace, int
*** 3373,3402 ****
  		      this_alternative[i]
  			= (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
  		      badop = 0;
! 		      break;
  		    }
  
  		  if (EXTRA_CONSTRAINT_STR (operand, c, p))
  		    win = 1;
  #endif
- 		  break;
  		}
! 
! 		this_alternative[i]
! 		  = (int) (reg_class_subunion
! 			   [this_alternative[i]]
! 			   [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
! 	      reg:
! 		if (GET_MODE (operand) == BLKmode)
! 		  break;
! 		winreg = 1;
! 		if (REG_P (operand)
! 		    && reg_fits_class_p (operand, this_alternative[i],
! 					 offset, GET_MODE (recog_data.operand[i])))
! 		  win = 1;
! 		break;
! 	      }
! 	  while ((p += len), c);
  
  	  constraints[i] = p;
  
--- 3386,3413 ----
  		      this_alternative[i]
  			= (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
  		      badop = 0;
! 		      continue;
  		    }
  
  		  if (EXTRA_CONSTRAINT_STR (operand, c, p))
  		    win = 1;
  #endif
  		}
! 	      else /* Register constraint.  */
! 		{
! 		  this_alternative[i]
! 		    = (int) (reg_class_subunion
! 			     [this_alternative[i]]
! 			     [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
! 		  if (GET_MODE (operand) == BLKmode)
! 		    continue;
! 		  winreg = 1;
! 		  if (REG_P (operand)
! 		      && reg_fits_class_p (operand, this_alternative[i],
! 					   offset, GET_MODE (recog_data.operand[i])))
! 		    win = 1;
! 		}
! 	    }
  
  	  constraints[i] = p;
  




here the whitespace changes to be applied beforehand:


Index: gcc/reload.c
===================================================================
*** gcc/reload.c.orig	2007-11-06 15:41:18.000000000 +0100
--- gcc/reload.c	2007-11-06 15:55:06.000000000 +0100
*************** find_reloads (rtx insn, int replace, int
*** 3032,3386 ****
  	     provided the constraint allows some registers.  */
  
  	  do
! 	    switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
! 	      {
! 	      case '\0':
! 		len = 0;
! 		break;
! 	      case ',':
! 		c = '\0';
! 		break;
! 
! 	      case '=':  case '+':  case '*':
! 		break;
! 
! 	      case '%':
! 		/* We only support one commutative marker, the first
! 		   one.  We already set commutative above.  */
! 		break;
! 
! 	      case '?':
! 		reject += 6;
! 		break;
! 
! 	      case '!':
! 		reject = 600;
! 		break;
! 
! 	      case '#':
! 		/* Ignore rest of this alternative as far as
! 		   reloading is concerned.  */
! 		do
! 		  p++;
! 		while (*p && *p != ',');
! 		len = 0;
! 		break;
! 
! 	      case '0':  case '1':  case '2':  case '3':  case '4':
! 	      case '5':  case '6':  case '7':  case '8':  case '9':
! 		m = strtoul (p, &end, 10);
! 		p = end;
! 		len = 0;
! 
! 		this_alternative_matches[i] = m;
! 		/* 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 ((swapped && (m != commutative || i != commutative + 1))
! 		    /* If we are matching as if two operands were swapped,
! 		       also pretend that operands_match had been computed
! 		       with swapped.
! 		       But if I is the second of those and C is the first,
! 		       don't exchange them, because operands_match is valid
! 		       only on one side of its diagonal.  */
! 		    ? (operands_match
! 		       [(m == commutative || m == commutative + 1)
! 		       ? 2 * commutative + 1 - m : m]
! 		       [(i == commutative || i == commutative + 1)
! 		       ? 2 * commutative + 1 - i : i])
! 		    : operands_match[m][i])
! 		  {
! 		    /* 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 (this_alternative_offmemok[m]
! 			&& MEM_P (recog_data.operand[m])
! 			&& this_alternative[m] == (int) NO_REGS
! 			&& ! this_alternative_win[m])
! 		      bad = 1;
! 
! 		    did_match = this_alternative_win[m];
! 		  }
! 		else
! 		  {
! 		    /* Operands don't match.  */
! 		    rtx value;
! 		    int loc1, loc2;
! 		    /* Retroactively mark the operand we had to match
! 		       as a loser, if it wasn't already.  */
! 		    if (this_alternative_win[m])
! 		      losers++;
! 		    this_alternative_win[m] = 0;
! 		    if (this_alternative[m] == (int) NO_REGS)
! 		      bad = 1;
! 		    /* But count the pair only once in the total badness of
! 		       this alternative, if the pair can be a dummy reload.
! 		       The pointers in operand_loc are not swapped; swap
! 		       them by hand if necessary.  */
! 		    if (swapped && i == commutative)
! 		      loc1 = commutative + 1;
! 		    else if (swapped && i == commutative + 1)
! 		      loc1 = commutative;
! 		    else
! 		      loc1 = i;
! 		    if (swapped && m == commutative)
! 		      loc2 = commutative + 1;
! 		    else if (swapped && m == commutative + 1)
! 		      loc2 = commutative;
! 		    else
! 		      loc2 = m;
! 		    value
! 		      = find_dummy_reload (recog_data.operand[i],
! 					   recog_data.operand[m],
! 					   recog_data.operand_loc[loc1],
! 					   recog_data.operand_loc[loc2],
! 					   operand_mode[i], operand_mode[m],
! 					   this_alternative[m], -1,
! 					   this_alternative_earlyclobber[m]);
! 
! 		    if (value != 0)
! 		      losers--;
! 		  }
! 		/* This can be fixed with reloads if the operand
! 		   we are supposed to match can be fixed with reloads.  */
! 		badop = 0;
! 		this_alternative[i] = this_alternative[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 || force_reload)
! 		  for (j = 0; j < i; j++)
! 		    if (this_alternative_matches[j]
! 			== this_alternative_matches[i])
! 		      badop = 1;
! 		break;
! 
! 	      case 'p':
! 		/* All necessary reloads for an address_operand
! 		   were handled in find_reloads_address.  */
! 		this_alternative[i]
! 		  = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
! 		win = 1;
! 		badop = 0;
! 		break;
! 
! 	      case 'm':
! 		if (force_reload)
! 		  break;
! 		if (MEM_P (operand)
! 		    || (REG_P (operand)
! 			&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			&& reg_renumber[REGNO (operand)] < 0))
! 		  win = 1;
! 		if (CONST_POOL_OK_P (operand))
! 		  badop = 0;
! 		constmemok = 1;
! 		break;
! 
! 	      case '<':
! 		if (MEM_P (operand)
! 		    && ! address_reloaded[i]
! 		    && (GET_CODE (XEXP (operand, 0)) == PRE_DEC
! 			|| GET_CODE (XEXP (operand, 0)) == POST_DEC))
! 		  win = 1;
! 		break;
! 
! 	      case '>':
! 		if (MEM_P (operand)
! 		    && ! address_reloaded[i]
! 		    && (GET_CODE (XEXP (operand, 0)) == PRE_INC
! 			|| GET_CODE (XEXP (operand, 0)) == POST_INC))
! 		  win = 1;
! 		break;
! 
! 		/* Memory operand whose address is not offsettable.  */
! 	      case 'V':
! 		if (force_reload)
! 		  break;
! 		if (MEM_P (operand)
! 		    && ! (ind_levels ? offsettable_memref_p (operand)
! 			  : offsettable_nonstrict_memref_p (operand))
! 		    /* Certain mem addresses will become offsettable
! 		       after they themselves are reloaded.  This is important;
! 		       we don't want our own handling of unoffsettables
! 		       to override the handling of reg_equiv_address.  */
! 		    && !(REG_P (XEXP (operand, 0))
! 			 && (ind_levels == 0
! 			     || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0)))
! 		  win = 1;
! 		break;
! 
! 		/* Memory operand whose address is offsettable.  */
! 	      case 'o':
! 		if (force_reload)
! 		  break;
! 		if ((MEM_P (operand)
! 		     /* If IND_LEVELS, find_reloads_address won't reload a
! 			pseudo that didn't get a hard reg, so we have to
! 			reject that case.  */
! 		     && ((ind_levels ? offsettable_memref_p (operand)
! 			  : offsettable_nonstrict_memref_p (operand))
! 			 /* A reloaded address is offsettable because it is now
! 			    just a simple register indirect.  */
! 			 || address_reloaded[i] == 1))
! 		    || (REG_P (operand)
! 			&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			&& reg_renumber[REGNO (operand)] < 0
! 			/* If reg_equiv_address is nonzero, we will be
! 			   loading it into a register; hence it will be
! 			   offsettable, but we cannot say that reg_equiv_mem
! 			   is offsettable without checking.  */
! 			&& ((reg_equiv_mem[REGNO (operand)] != 0
! 			     && offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
! 			    || (reg_equiv_address[REGNO (operand)] != 0))))
! 		  win = 1;
! 		if (CONST_POOL_OK_P (operand)
! 		    || MEM_P (operand))
! 		  badop = 0;
! 		constmemok = 1;
! 		offmemok = 1;
! 		break;
! 
! 	      case '&':
! 		/* Output operand that is stored before the need for the
! 		   input operands (and their index registers) is over.  */
! 		earlyclobber = 1, this_earlyclobber = 1;
! 		break;
! 
! 	      case 'E':
! 	      case 'F':
! 		if (GET_CODE (operand) == CONST_DOUBLE
! 		    || (GET_CODE (operand) == CONST_VECTOR
! 			&& (GET_MODE_CLASS (GET_MODE (operand))
! 			    == MODE_VECTOR_FLOAT)))
! 		  win = 1;
! 		break;
! 
! 	      case 'G':
! 	      case 'H':
! 		if (GET_CODE (operand) == CONST_DOUBLE
! 		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
! 		  win = 1;
! 		break;
  
! 	      case 's':
! 		if (GET_CODE (operand) == CONST_INT
! 		    || (GET_CODE (operand) == CONST_DOUBLE
! 			&& GET_MODE (operand) == VOIDmode))
! 		  break;
! 	      case 'i':
! 		if (CONSTANT_P (operand)
! 		    && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
! 		  win = 1;
! 		break;
  
! 	      case 'n':
! 		if (GET_CODE (operand) == CONST_INT
! 		    || (GET_CODE (operand) == CONST_DOUBLE
! 			&& GET_MODE (operand) == VOIDmode))
! 		  win = 1;
! 		break;
  
! 	      case 'I':
! 	      case 'J':
! 	      case 'K':
! 	      case 'L':
! 	      case 'M':
! 	      case 'N':
! 	      case 'O':
! 	      case 'P':
! 		if (GET_CODE (operand) == CONST_INT
! 		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
! 		  win = 1;
! 		break;
  
! 	      case 'X':
! 		force_reload = 0;
! 		win = 1;
! 		break;
  
! 	      case 'g':
! 		if (! force_reload
! 		    /* A PLUS is never a valid operand, but reload can make
! 		       it from a register when eliminating registers.  */
! 		    && GET_CODE (operand) != PLUS
! 		    /* A SCRATCH is not a valid operand.  */
! 		    && GET_CODE (operand) != SCRATCH
! 		    && (! CONSTANT_P (operand)
! 			|| ! flag_pic
! 			|| LEGITIMATE_PIC_OPERAND_P (operand))
! 		    && (GENERAL_REGS == ALL_REGS
! 			|| !REG_P (operand)
! 			|| (REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			    && reg_renumber[REGNO (operand)] < 0)))
! 		  win = 1;
! 		/* Drop through into 'r' case.  */
  
! 	      case 'r':
! 		this_alternative[i]
! 		  = (int) reg_class_subunion[this_alternative[i]][(int) 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 (force_reload)
! 			  break;
! 		        if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 		          win = 1;
! 			/* If the address was already reloaded,
! 			   we win as well.  */
! 			else if (MEM_P (operand)
! 				 && address_reloaded[i] == 1)
! 			  win = 1;
! 			/* Likewise if the address will be reloaded because
! 			   reg_equiv_address is nonzero.  For reg_equiv_mem
! 			   we have to check.  */
! 		        else if (REG_P (operand)
! 				 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 				 && reg_renumber[REGNO (operand)] < 0
! 				 && ((reg_equiv_mem[REGNO (operand)] != 0
! 				      && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p))
! 				     || (reg_equiv_address[REGNO (operand)] != 0)))
! 			  win = 1;
! 
! 			/* 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 (operand)
! 			    || MEM_P (operand))
! 			  badop = 0;
! 			constmemok = 1;
! 			offmemok = 1;
  			break;
! 		      }
! 		    if (EXTRA_ADDRESS_CONSTRAINT (c, p))
! 		      {
! 		        if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 		          win = 1;
! 
! 			/* If we didn't already win, we can reload
! 			   the address into a base register.  */
! 			this_alternative[i]
! 			  = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
  			badop = 0;
! 			break;
! 		      }
  
! 		    if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 		      win = 1;
  #endif
! 		    break;
! 		  }
  
  		this_alternative[i]
  		  = (int) (reg_class_subunion
--- 3032,3386 ----
  	     provided the constraint allows some registers.  */
  
  	  do
! 		  switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
! 		    {
! 		    case '\0':
! 		      len = 0;
! 		      break;
! 		    case ',':
! 		      c = '\0';
! 		      break;
! 
! 		    case '=':  case '+':  case '*':
! 		      break;
! 
! 		    case '%':
! 		      /* We only support one commutative marker, the first
! 			 one.  We already set commutative above.  */
! 		      break;
! 
! 		    case '?':
! 		      reject += 6;
! 		      break;
! 
! 		    case '!':
! 		      reject = 600;
! 		      break;
! 
! 		    case '#':
! 		      /* Ignore rest of this alternative as far as
! 			 reloading is concerned.  */
! 		      do
! 			p++;
! 		      while (*p && *p != ',');
! 		      len = 0;
! 		      break;
! 
! 		    case '0':  case '1':  case '2':  case '3':  case '4':
! 		    case '5':  case '6':  case '7':  case '8':  case '9':
! 		      m = strtoul (p, &end, 10);
! 		      p = end;
! 		      len = 0;
! 
! 		      this_alternative_matches[i] = m;
! 		      /* 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 ((swapped && (m != commutative || i != commutative + 1))
! 			  /* If we are matching as if two operands were swapped,
! 			     also pretend that operands_match had been computed
! 			     with swapped.
! 			     But if I is the second of those and C is the first,
! 			     don't exchange them, because operands_match is valid
! 			     only on one side of its diagonal.  */
! 			  ? (operands_match
! 			     [(m == commutative || m == commutative + 1)
! 			      ? 2 * commutative + 1 - m : m]
! 			     [(i == commutative || i == commutative + 1)
! 			      ? 2 * commutative + 1 - i : i])
! 			  : operands_match[m][i])
! 			{
! 			  /* 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 (this_alternative_offmemok[m]
! 			      && MEM_P (recog_data.operand[m])
! 			      && this_alternative[m] == (int) NO_REGS
! 			      && ! this_alternative_win[m])
! 			    bad = 1;
  
! 			  did_match = this_alternative_win[m];
! 			}
! 		      else
! 			{
! 			  /* Operands don't match.  */
! 			  rtx value;
! 			  int loc1, loc2;
! 			  /* Retroactively mark the operand we had to match
! 			     as a loser, if it wasn't already.  */
! 			  if (this_alternative_win[m])
! 			    losers++;
! 			  this_alternative_win[m] = 0;
! 			  if (this_alternative[m] == (int) NO_REGS)
! 			    bad = 1;
! 			  /* But count the pair only once in the total badness of
! 			     this alternative, if the pair can be a dummy reload.
! 			     The pointers in operand_loc are not swapped; swap
! 			     them by hand if necessary.  */
! 			  if (swapped && i == commutative)
! 			    loc1 = commutative + 1;
! 			  else if (swapped && i == commutative + 1)
! 			    loc1 = commutative;
! 			  else
! 			    loc1 = i;
! 			  if (swapped && m == commutative)
! 			    loc2 = commutative + 1;
! 			  else if (swapped && m == commutative + 1)
! 			    loc2 = commutative;
! 			  else
! 			    loc2 = m;
! 			  value
! 			    = find_dummy_reload (recog_data.operand[i],
! 						 recog_data.operand[m],
! 						 recog_data.operand_loc[loc1],
! 						 recog_data.operand_loc[loc2],
! 						 operand_mode[i], operand_mode[m],
! 						 this_alternative[m], -1,
! 						 this_alternative_earlyclobber[m]);
  
! 			  if (value != 0)
! 			    losers--;
! 			}
! 		      /* This can be fixed with reloads if the operand
! 			 we are supposed to match can be fixed with reloads.  */
! 		      badop = 0;
! 		      this_alternative[i] = this_alternative[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 || force_reload)
! 			for (j = 0; j < i; j++)
! 			  if (this_alternative_matches[j]
! 			      == this_alternative_matches[i])
! 			    badop = 1;
! 		      break;
! 
! 		    case 'p':
! 		      /* All necessary reloads for an address_operand
! 			 were handled in find_reloads_address.  */
! 		      this_alternative[i]
! 			= (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
! 		      win = 1;
! 		      badop = 0;
! 		      break;
  
! 		    case 'm':
! 		      if (force_reload)
! 			break;
! 		      if (MEM_P (operand)
! 			  || (REG_P (operand)
! 			      && REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			      && reg_renumber[REGNO (operand)] < 0))
! 			win = 1;
! 		      if (CONST_POOL_OK_P (operand))
! 			badop = 0;
! 		      constmemok = 1;
! 		      break;
  
! 		    case '<':
! 		      if (MEM_P (operand)
! 			  && ! address_reloaded[i]
! 			  && (GET_CODE (XEXP (operand, 0)) == PRE_DEC
! 			      || GET_CODE (XEXP (operand, 0)) == POST_DEC))
! 			win = 1;
! 		      break;
! 
! 		    case '>':
! 		      if (MEM_P (operand)
! 			  && ! address_reloaded[i]
! 			  && (GET_CODE (XEXP (operand, 0)) == PRE_INC
! 			      || GET_CODE (XEXP (operand, 0)) == POST_INC))
! 			win = 1;
! 		      break;
! 
! 		      /* Memory operand whose address is not offsettable.  */
! 		    case 'V':
! 		      if (force_reload)
! 			break;
! 		      if (MEM_P (operand)
! 			  && ! (ind_levels ? offsettable_memref_p (operand)
! 				: offsettable_nonstrict_memref_p (operand))
! 			  /* Certain mem addresses will become offsettable
! 			     after they themselves are reloaded.  This is important;
! 			     we don't want our own handling of unoffsettables
! 			     to override the handling of reg_equiv_address.  */
! 			  && !(REG_P (XEXP (operand, 0))
! 			       && (ind_levels == 0
! 				   || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0)))
! 			win = 1;
! 		      break;
! 
! 		      /* Memory operand whose address is offsettable.  */
! 		    case 'o':
! 		      if (force_reload)
! 			break;
! 		      if ((MEM_P (operand)
! 			   /* If IND_LEVELS, find_reloads_address won't reload a
! 			      pseudo that didn't get a hard reg, so we have to
! 			      reject that case.  */
! 			   && ((ind_levels ? offsettable_memref_p (operand)
! 				: offsettable_nonstrict_memref_p (operand))
! 			       /* A reloaded address is offsettable because it is now
! 				  just a simple register indirect.  */
! 			       || address_reloaded[i] == 1))
! 			  || (REG_P (operand)
! 			      && REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			      && reg_renumber[REGNO (operand)] < 0
! 			      /* If reg_equiv_address is nonzero, we will be
! 				 loading it into a register; hence it will be
! 				 offsettable, but we cannot say that reg_equiv_mem
! 				 is offsettable without checking.  */
! 			      && ((reg_equiv_mem[REGNO (operand)] != 0
! 				   && offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
! 				  || (reg_equiv_address[REGNO (operand)] != 0))))
! 			win = 1;
! 		      if (CONST_POOL_OK_P (operand)
! 			  || MEM_P (operand))
! 			badop = 0;
! 		      constmemok = 1;
! 		      offmemok = 1;
! 		      break;
! 
! 		    case '&':
! 		      /* Output operand that is stored before the need for the
! 			 input operands (and their index registers) is over.  */
! 		      earlyclobber = 1, this_earlyclobber = 1;
! 		      break;
! 
! 		    case 'E':
! 		    case 'F':
! 		      if (GET_CODE (operand) == CONST_DOUBLE
! 			  || (GET_CODE (operand) == CONST_VECTOR
! 			      && (GET_MODE_CLASS (GET_MODE (operand))
! 				  == MODE_VECTOR_FLOAT)))
! 			win = 1;
! 		      break;
! 
! 		    case 'G':
! 		    case 'H':
! 		      if (GET_CODE (operand) == CONST_DOUBLE
! 			  && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
! 			win = 1;
! 		      break;
! 
! 		    case 's':
! 		      if (GET_CODE (operand) == CONST_INT
! 			  || (GET_CODE (operand) == CONST_DOUBLE
! 			      && GET_MODE (operand) == VOIDmode))
! 			break;
! 		    case 'i':
! 		      if (CONSTANT_P (operand)
! 			  && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
! 			win = 1;
! 		      break;
! 
! 		    case 'n':
! 		      if (GET_CODE (operand) == CONST_INT
! 			  || (GET_CODE (operand) == CONST_DOUBLE
! 			      && GET_MODE (operand) == VOIDmode))
! 			win = 1;
! 		      break;
! 
! 		    case 'I':
! 		    case 'J':
! 		    case 'K':
! 		    case 'L':
! 		    case 'M':
! 		    case 'N':
! 		    case 'O':
! 		    case 'P':
! 		      if (GET_CODE (operand) == CONST_INT
! 			  && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
! 			win = 1;
! 		      break;
  
! 		    case 'X':
! 		      force_reload = 0;
! 		      win = 1;
! 		      break;
  
! 		    case 'g':
! 		      if (! force_reload
! 			  /* A PLUS is never a valid operand, but reload can make
! 			     it from a register when eliminating registers.  */
! 			  && GET_CODE (operand) != PLUS
! 			  /* A SCRATCH is not a valid operand.  */
! 			  && GET_CODE (operand) != SCRATCH
! 			  && (! CONSTANT_P (operand)
! 			      || ! flag_pic
! 			      || LEGITIMATE_PIC_OPERAND_P (operand))
! 			  && (GENERAL_REGS == ALL_REGS
! 			      || !REG_P (operand)
! 			      || (REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 				  && reg_renumber[REGNO (operand)] < 0)))
! 			win = 1;
! 		      /* Drop through into 'r' case.  */
! 
! 		    case 'r':
! 		      this_alternative[i]
! 			= (int) reg_class_subunion[this_alternative[i]][(int) 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 (force_reload)
  			break;
! 		      if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 			win = 1;
! 		      /* If the address was already reloaded,
! 			 we win as well.  */
! 		      else if (MEM_P (operand)
! 			       && address_reloaded[i] == 1)
! 			win = 1;
! 		      /* Likewise if the address will be reloaded because
! 			 reg_equiv_address is nonzero.  For reg_equiv_mem
! 			 we have to check.  */
! 		      else if (REG_P (operand)
! 			       && REGNO (operand) >= FIRST_PSEUDO_REGISTER
! 			       && reg_renumber[REGNO (operand)] < 0
! 			       && ((reg_equiv_mem[REGNO (operand)] != 0
! 				    && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p))
! 				   || (reg_equiv_address[REGNO (operand)] != 0)))
! 			win = 1;
! 
! 		      /* 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 (operand)
! 			  || MEM_P (operand))
  			badop = 0;
! 		      constmemok = 1;
! 		      offmemok = 1;
! 		      break;
! 		    }
! 		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
! 		    {
! 		      if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 			win = 1;
  
! 		      /* If we didn't already win, we can reload
! 			 the address into a base register.  */
! 		      this_alternative[i]
! 			= (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
! 		      badop = 0;
! 		      break;
! 		    }
! 
! 		  if (EXTRA_CONSTRAINT_STR (operand, c, p))
! 		    win = 1;
  #endif
! 		  break;
! 		}
  
  		this_alternative[i]
  		  = (int) (reg_class_subunion
Index: gcc/recog.c
===================================================================
*** gcc/recog.c.orig	2007-11-06 15:41:18.000000000 +0100
--- gcc/recog.c	2007-11-06 15:59:32.000000000 +0100
*************** preprocess_constraints (void)
*** 2059,2126 ****
  		  break;
  		}
  
! 	      switch (c)
! 		{
! 		case '=': case '+': case '*': case '%':
! 		case 'E': case 'F': case 'G': case 'H':
! 		case 's': case 'i': case 'n':
! 		case 'I': case 'J': case 'K': case 'L':
! 		case 'M': case 'N': case 'O': case 'P':
! 		  /* These don't say anything we care about.  */
! 		  break;
  
! 		case '?':
! 		  op_alt[j].reject += 6;
! 		  break;
! 		case '!':
! 		  op_alt[j].reject += 600;
! 		  break;
! 		case '&':
! 		  op_alt[j].earlyclobber = 1;
! 		  break;
  
! 		case '0': case '1': case '2': case '3': case '4':
! 		case '5': case '6': case '7': case '8': case '9':
! 		  {
! 		    char *end;
! 		    op_alt[j].matches = strtoul (p, &end, 10);
! 		    recog_op_alt[op_alt[j].matches][j].matched = i;
! 		    p = end;
! 		  }
! 		  continue;
  
! 		case 'm':
! 		  op_alt[j].memory_ok = 1;
! 		  break;
! 		case '<':
! 		  op_alt[j].decmem_ok = 1;
! 		  break;
! 		case '>':
! 		  op_alt[j].incmem_ok = 1;
! 		  break;
! 		case 'V':
! 		  op_alt[j].nonoffmem_ok = 1;
! 		  break;
! 		case 'o':
! 		  op_alt[j].offmem_ok = 1;
! 		  break;
! 		case 'X':
! 		  op_alt[j].anything_ok = 1;
! 		  break;
  
! 		case 'p':
! 		  op_alt[j].is_address = 1;
! 		  op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
! 		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
! 		  break;
  
! 		case 'g':
! 		case 'r':
! 		  op_alt[j].cl =
! 		   reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS];
! 		  break;
  
! 		default:
  		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
  		    {
  		      op_alt[j].memory_ok = 1;
--- 2059,2126 ----
  		  break;
  		}
  
! 		  switch (c)
! 		    {
! 		    case '=': case '+': case '*': case '%':
! 		    case 'E': case 'F': case 'G': case 'H':
! 		    case 's': case 'i': case 'n':
! 		    case 'I': case 'J': case 'K': case 'L':
! 		    case 'M': case 'N': case 'O': case 'P':
! 		      /* These don't say anything we care about.  */
! 		      break;
  
! 		    case '?':
! 		      op_alt[j].reject += 6;
! 		      break;
! 		    case '!':
! 		      op_alt[j].reject += 600;
! 		      break;
! 		    case '&':
! 		      op_alt[j].earlyclobber = 1;
! 		      break;
  
! 		    case '0': case '1': case '2': case '3': case '4':
! 		    case '5': case '6': case '7': case '8': case '9':
! 		      {
! 			char *end;
! 			op_alt[j].matches = strtoul (p, &end, 10);
! 			recog_op_alt[op_alt[j].matches][j].matched = i;
! 			p = end;
! 		      }
! 		      continue;
  
! 		    case 'm':
! 		      op_alt[j].memory_ok = 1;
! 		      break;
! 		    case '<':
! 		      op_alt[j].decmem_ok = 1;
! 		      break;
! 		    case '>':
! 		      op_alt[j].incmem_ok = 1;
! 		      break;
! 		    case 'V':
! 		      op_alt[j].nonoffmem_ok = 1;
! 		      break;
! 		    case 'o':
! 		      op_alt[j].offmem_ok = 1;
! 		      break;
! 		    case 'X':
! 		      op_alt[j].anything_ok = 1;
! 		      break;
  
! 		    case 'p':
! 		      op_alt[j].is_address = 1;
! 		      op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
! 			[(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
! 		      break;
  
! 		    case 'g':
! 		    case 'r':
! 		      op_alt[j].cl =
! 			reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS];
! 		      break;
  
! 		    default:
  		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
  		    {
  		      op_alt[j].memory_ok = 1;
*************** constrain_operands (int strict)
*** 2243,2473 ****
  	    win = 1;
  
  	  do
! 	    switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
! 	      {
! 	      case '\0':
! 		len = 0;
! 		break;
! 	      case ',':
! 		c = '\0';
! 		break;
! 
! 	      case '?':  case '!': case '*':  case '%':
! 	      case '=':  case '+':
! 		break;
! 
! 	      case '#':
! 		/* Ignore rest of this alternative as far as
! 		   constraint checking is concerned.  */
! 		do
! 		  p++;
! 		while (*p && *p != ',');
! 		len = 0;
! 		break;
! 
! 	      case '&':
! 		earlyclobber[opno] = 1;
! 		if (seen_earlyclobber_at < 0)
! 		  seen_earlyclobber_at = opno;
! 		break;
  
! 	      case '0':  case '1':  case '2':  case '3':  case '4':
! 	      case '5':  case '6':  case '7':  case '8':  case '9':
! 		{
! 		  /* This operand must be the same as a previous one.
! 		     This kind of constraint is used for instructions such
! 		     as add when they take only two operands.
  
! 		     Note that the lower-numbered operand is passed first.
  
! 		     If we are not testing strictly, assume that this
! 		     constraint will be satisfied.  */
  
! 		  char *end;
! 		  int match;
  
! 		  match = strtoul (p, &end, 10);
! 		  p = end;
  
! 		  if (strict < 0)
! 		    val = 1;
! 		  else
! 		    {
! 		      rtx op1 = recog_data.operand[match];
! 		      rtx op2 = recog_data.operand[opno];
  
! 		      /* A unary operator may be accepted by the predicate,
! 			 but it is irrelevant for matching constraints.  */
! 		      if (UNARY_P (op1))
! 			op1 = XEXP (op1, 0);
! 		      if (UNARY_P (op2))
! 			op2 = XEXP (op2, 0);
  
! 		      val = operands_match_p (op1, op2);
! 		    }
  
! 		  matching_operands[opno] = match;
! 		  matching_operands[match] = opno;
  
! 		  if (val != 0)
! 		    win = 1;
  
! 		  /* If output is *x and input is *--x, arrange later
! 		     to change the output to *--x as well, since the
! 		     output op is the one that will be printed.  */
! 		  if (val == 2 && strict > 0)
! 		    {
! 		      funny_match[funny_match_index].this = opno;
! 		      funny_match[funny_match_index++].other = match;
! 		    }
! 		}
! 		len = 0;
! 		break;
  
! 	      case 'p':
! 		/* p is used for address_operands.  When we are called by
! 		   gen_reload, no one will have checked that the address is
! 		   strictly valid, i.e., that all pseudos requiring hard regs
! 		   have gotten them.  */
! 		if (strict <= 0
! 		    || (strict_memory_address_p (recog_data.operand_mode[opno],
! 						 op)))
! 		  win = 1;
! 		break;
! 
! 		/* No need to check general_operand again;
! 		   it was done in insn-recog.c.  Well, except that reload
! 		   doesn't check the validity of its replacements, but
! 		   that should only matter when there's a bug.  */
! 	      case 'g':
! 		/* Anything goes unless it is a REG and really has a hard reg
! 		   but the hard reg is not in the class GENERAL_REGS.  */
! 		if (REG_P (op))
! 		  {
! 		    if (strict < 0
! 			|| GENERAL_REGS == ALL_REGS
! 			|| (reload_in_progress
! 			    && REGNO (op) >= FIRST_PSEUDO_REGISTER)
! 			|| reg_fits_class_p (op, GENERAL_REGS, offset, mode))
  		      win = 1;
- 		  }
- 		else if (strict < 0 || general_operand (op, mode))
- 		  win = 1;
- 		break;
- 
- 	      case 'X':
- 		/* This is used for a MATCH_SCRATCH in the cases when
- 		   we don't actually need anything.  So anything goes
- 		   any time.  */
- 		win = 1;
- 		break;
- 
- 	      case 'm':
- 		/* Memory operands must be valid, to the extent
- 		   required by STRICT.  */
- 		if (MEM_P (op))
- 		  {
- 		    if (strict > 0
- 			&& !strict_memory_address_p (GET_MODE (op),
- 						     XEXP (op, 0)))
  		      break;
! 		    if (strict == 0
! 			&& !memory_address_p (GET_MODE (op), XEXP (op, 0)))
  		      break;
- 		    win = 1;
- 		  }
- 		/* Before reload, accept what reload can turn into mem.  */
- 		else if (strict < 0 && CONSTANT_P (op))
- 		  win = 1;
- 		/* During reload, accept a pseudo  */
- 		else if (reload_in_progress && REG_P (op)
- 			 && REGNO (op) >= FIRST_PSEUDO_REGISTER)
- 		  win = 1;
- 		break;
- 
- 	      case '<':
- 		if (MEM_P (op)
- 		    && (GET_CODE (XEXP (op, 0)) == PRE_DEC
- 			|| GET_CODE (XEXP (op, 0)) == POST_DEC))
- 		  win = 1;
- 		break;
- 
- 	      case '>':
- 		if (MEM_P (op)
- 		    && (GET_CODE (XEXP (op, 0)) == PRE_INC
- 			|| GET_CODE (XEXP (op, 0)) == POST_INC))
- 		  win = 1;
- 		break;
- 
- 	      case 'E':
- 	      case 'F':
- 		if (GET_CODE (op) == CONST_DOUBLE
- 		    || (GET_CODE (op) == CONST_VECTOR
- 			&& GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
- 		  win = 1;
- 		break;
- 
- 	      case 'G':
- 	      case 'H':
- 		if (GET_CODE (op) == CONST_DOUBLE
- 		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
- 		  win = 1;
- 		break;
- 
- 	      case 's':
- 		if (GET_CODE (op) == CONST_INT
- 		    || (GET_CODE (op) == CONST_DOUBLE
- 			&& GET_MODE (op) == VOIDmode))
- 		  break;
- 	      case 'i':
- 		if (CONSTANT_P (op))
- 		  win = 1;
- 		break;
- 
- 	      case 'n':
- 		if (GET_CODE (op) == CONST_INT
- 		    || (GET_CODE (op) == CONST_DOUBLE
- 			&& GET_MODE (op) == VOIDmode))
- 		  win = 1;
- 		break;
- 
- 	      case 'I':
- 	      case 'J':
- 	      case 'K':
- 	      case 'L':
- 	      case 'M':
- 	      case 'N':
- 	      case 'O':
- 	      case 'P':
- 		if (GET_CODE (op) == CONST_INT
- 		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
- 		  win = 1;
- 		break;
- 
- 	      case 'V':
- 		if (MEM_P (op)
- 		    && ((strict > 0 && ! offsettable_memref_p (op))
- 			|| (strict < 0
- 			    && !(CONSTANT_P (op) || MEM_P (op)))
- 			|| (reload_in_progress
- 			    && !(REG_P (op)
- 				 && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
- 		  win = 1;
- 		break;
- 
- 	      case 'o':
- 		if ((strict > 0 && offsettable_memref_p (op))
- 		    || (strict == 0 && offsettable_nonstrict_memref_p (op))
- 		    /* Before reload, accept what reload can handle.  */
- 		    || (strict < 0
- 			&& (CONSTANT_P (op) || MEM_P (op)))
- 		    /* During reload, accept a pseudo  */
- 		    || (reload_in_progress && REG_P (op)
- 			&& REGNO (op) >= FIRST_PSEUDO_REGISTER))
- 		  win = 1;
- 		break;
  
! 	      default:
  		{
  		  enum reg_class cl;
  
--- 2243,2473 ----
  	    win = 1;
  
  	  do
! 		  switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
! 		    {
! 		    case '\0':
! 		      len = 0;
! 		      break;
! 		    case ',':
! 		      c = '\0';
! 		      break;
  
! 		    case '?':  case '!': case '*':  case '%':
! 		    case '=':  case '+':
! 		      break;
  
! 		    case '#':
! 		      /* Ignore rest of this alternative as far as
! 			 constraint checking is concerned.  */
! 		      do
! 			p++;
! 		      while (*p && *p != ',');
! 		      len = 0;
! 		      break;
  
! 		    case '&':
! 		      earlyclobber[opno] = 1;
! 		      if (seen_earlyclobber_at < 0)
! 			seen_earlyclobber_at = opno;
! 		      break;
  
! 		    case '0':  case '1':  case '2':  case '3':  case '4':
! 		    case '5':  case '6':  case '7':  case '8':  case '9':
! 		      {
! 			/* This operand must be the same as a previous one.
! 			   This kind of constraint is used for instructions such
! 			   as add when they take only two operands.
  
! 			   Note that the lower-numbered operand is passed first.
  
! 			   If we are not testing strictly, assume that this
! 			   constraint will be satisfied.  */
  
! 			char *end;
! 			int match;
  
! 			match = strtoul (p, &end, 10);
! 			p = end;
  
! 			if (strict < 0)
! 			  val = 1;
! 			else
! 			  {
! 			    rtx op1 = recog_data.operand[match];
! 			    rtx op2 = recog_data.operand[opno];
  
! 			    /* A unary operator may be accepted by the predicate,
! 			       but it is irrelevant for matching constraints.  */
! 			    if (UNARY_P (op1))
! 			      op1 = XEXP (op1, 0);
! 			    if (UNARY_P (op2))
! 			      op2 = XEXP (op2, 0);
  
! 			    val = operands_match_p (op1, op2);
! 			  }
  
! 			matching_operands[opno] = match;
! 			matching_operands[match] = opno;
! 
! 			if (val != 0)
! 			  win = 1;
! 
! 			/* If output is *x and input is *--x, arrange later
! 			   to change the output to *--x as well, since the
! 			   output op is the one that will be printed.  */
! 			if (val == 2 && strict > 0)
! 			  {
! 			    funny_match[funny_match_index].this = opno;
! 			    funny_match[funny_match_index++].other = match;
! 			  }
! 		      }
! 		      len = 0;
! 		      break;
! 
! 		    case 'p':
! 		      /* p is used for address_operands.  When we are called by
! 			 gen_reload, no one will have checked that the address is
! 			 strictly valid, i.e., that all pseudos requiring hard regs
! 			 have gotten them.  */
! 		      if (strict <= 0
! 			  || (strict_memory_address_p (recog_data.operand_mode[opno],
! 						       op)))
! 			win = 1;
! 		      break;
! 
! 		      /* No need to check general_operand again;
! 			 it was done in insn-recog.c.  Well, except that reload
! 			 doesn't check the validity of its replacements, but
! 			 that should only matter when there's a bug.  */
! 		    case 'g':
! 		      /* Anything goes unless it is a REG and really has a hard reg
! 			 but the hard reg is not in the class GENERAL_REGS.  */
! 		      if (REG_P (op))
! 			{
! 			  if (strict < 0
! 			      || GENERAL_REGS == ALL_REGS
! 			      || (reload_in_progress
! 				  && REGNO (op) >= FIRST_PSEUDO_REGISTER)
! 			      || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
! 			    win = 1;
! 			}
! 		      else if (strict < 0 || general_operand (op, mode))
! 			win = 1;
! 		      break;
! 
! 		    case 'X':
! 		      /* This is used for a MATCH_SCRATCH in the cases when
! 			 we don't actually need anything.  So anything goes
! 			 any time.  */
  		      win = 1;
  		      break;
! 
! 		    case 'm':
! 		      /* Memory operands must be valid, to the extent
! 			 required by STRICT.  */
! 		      if (MEM_P (op))
! 			{
! 			  if (strict > 0
! 			      && !strict_memory_address_p (GET_MODE (op),
! 							   XEXP (op, 0)))
! 			    break;
! 			  if (strict == 0
! 			      && !memory_address_p (GET_MODE (op), XEXP (op, 0)))
! 			    break;
! 			  win = 1;
! 			}
! 		      /* Before reload, accept what reload can turn into mem.  */
! 		      else if (strict < 0 && CONSTANT_P (op))
! 			win = 1;
! 		      /* During reload, accept a pseudo  */
! 		      else if (reload_in_progress && REG_P (op)
! 			       && REGNO (op) >= FIRST_PSEUDO_REGISTER)
! 			win = 1;
! 		      break;
! 
! 		    case '<':
! 		      if (MEM_P (op)
! 			  && (GET_CODE (XEXP (op, 0)) == PRE_DEC
! 			      || GET_CODE (XEXP (op, 0)) == POST_DEC))
! 			win = 1;
! 		      break;
! 
! 		    case '>':
! 		      if (MEM_P (op)
! 			  && (GET_CODE (XEXP (op, 0)) == PRE_INC
! 			      || GET_CODE (XEXP (op, 0)) == POST_INC))
! 			win = 1;
! 		      break;
! 
! 		    case 'E':
! 		    case 'F':
! 		      if (GET_CODE (op) == CONST_DOUBLE
! 			  || (GET_CODE (op) == CONST_VECTOR
! 			      && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
! 			win = 1;
! 		      break;
! 
! 		    case 'G':
! 		    case 'H':
! 		      if (GET_CODE (op) == CONST_DOUBLE
! 			  && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
! 			win = 1;
! 		      break;
! 
! 		    case 's':
! 		      if (GET_CODE (op) == CONST_INT
! 			  || (GET_CODE (op) == CONST_DOUBLE
! 			      && GET_MODE (op) == VOIDmode))
! 			break;
! 		    case 'i':
! 		      if (CONSTANT_P (op))
! 			win = 1;
! 		      break;
! 
! 		    case 'n':
! 		      if (GET_CODE (op) == CONST_INT
! 			  || (GET_CODE (op) == CONST_DOUBLE
! 			      && GET_MODE (op) == VOIDmode))
! 			win = 1;
! 		      break;
! 
! 		    case 'I':
! 		    case 'J':
! 		    case 'K':
! 		    case 'L':
! 		    case 'M':
! 		    case 'N':
! 		    case 'O':
! 		    case 'P':
! 		      if (GET_CODE (op) == CONST_INT
! 			  && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
! 			win = 1;
! 		      break;
! 
! 		    case 'V':
! 		      if (MEM_P (op)
! 			  && ((strict > 0 && ! offsettable_memref_p (op))
! 			      || (strict < 0
! 				  && !(CONSTANT_P (op) || MEM_P (op)))
! 			      || (reload_in_progress
! 				  && !(REG_P (op)
! 				       && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
! 			win = 1;
! 		      break;
! 
! 		    case 'o':
! 		      if ((strict > 0 && offsettable_memref_p (op))
! 			  || (strict == 0 && offsettable_nonstrict_memref_p (op))
! 			  /* Before reload, accept what reload can handle.  */
! 			  || (strict < 0
! 			      && (CONSTANT_P (op) || MEM_P (op)))
! 			  /* During reload, accept a pseudo  */
! 			  || (reload_in_progress && REG_P (op)
! 			      && REGNO (op) >= FIRST_PSEUDO_REGISTER))
! 			win = 1;
  		      break;
  
! 		    default:
  		{
  		  enum reg_class cl;
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]