pr 4299 fix for mainline

Richard Henderson rth@redhat.com
Sun Dec 23 22:17:00 GMT 2001


I've been somewhat delinquent forward porting this patch
from the 3.0 branch.


r~


        * stmt.c (parse_input_constraint): Break out from ...
        (expand_asm_operands): ... here.  Loop over the operands twice,
        the first time only calling mark_addressable.  Correct and simplify
        the conditions for spilling an output operand to memory.

	* gcc.c-torture/compile/20011205-1.c: New.

Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.238
diff -c -p -d -r1.238 stmt.c
*** stmt.c	2001/12/12 12:44:46	1.238
--- stmt.c	2001/12/24 05:53:47
*************** struct stmt_status
*** 397,402 ****
--- 397,405 ----
  static int using_eh_for_cleanups_p = 0;
  
  static int n_occurrences		PARAMS ((int, const char *));
+ static bool parse_input_constraint	PARAMS ((const char **, int, int, int,
+ 						 int, const char * const *,
+ 						 bool *, bool *));
  static void expand_goto_internal	PARAMS ((tree, rtx, rtx));
  static int expand_fixup			PARAMS ((tree, rtx, rtx));
  static rtx expand_nl_handler_label	PARAMS ((rtx, rtx));
*************** expand_asm (body)
*** 1307,1319 ****
     Returns TRUE if all went well; FALSE if an error occurred.  */
  
  bool
! parse_output_constraint (constraint_p, 
! 			 operand_num,
! 			 ninputs,
! 			 noutputs,
! 			 allows_mem, 
! 			 allows_reg, 
! 			 is_inout)
       const char **constraint_p;
       int operand_num;
       int ninputs;
--- 1310,1317 ----
     Returns TRUE if all went well; FALSE if an error occurred.  */
  
  bool
! parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
! 			 allows_mem, allows_reg, is_inout)
       const char **constraint_p;
       int operand_num;
       int ninputs;
*************** parse_output_constraint (constraint_p, 
*** 1444,1449 ****
--- 1442,1572 ----
    return true;
  }
  
+ /* Similar, but for input constraints.  */
+ 
+ static bool
+ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
+ 			constraints, allows_mem, allows_reg)
+      const char **constraint_p;
+      int input_num;
+      int ninputs;
+      int noutputs;
+      int ninout;
+      const char * const * constraints;
+      bool *allows_mem;
+      bool *allows_reg;
+ {
+   const char *constraint = *constraint_p;
+   const char *orig_constraint = constraint;
+   size_t c_len = strlen (constraint);
+   size_t j;
+ 
+   /* Assume the constraint doesn't allow the use of either
+      a register or memory.  */
+   *allows_mem = false;
+   *allows_reg = false;
+ 
+   /* Make sure constraint has neither `=', `+', nor '&'.  */
+ 
+   for (j = 0; j < c_len; j++)
+     switch (constraint[j])
+       {
+       case '+':  case '=':  case '&':
+ 	if (constraint == orig_constraint)
+ 	  {
+ 	    error ("input operand constraint contains `%c'", constraint[j]);
+ 	    return false;
+ 	  }
+ 	break;
+ 
+       case '%':
+ 	if (constraint == orig_constraint
+ 	    && input_num + 1 == ninputs - ninout)
+ 	  {
+ 	    error ("`%%' constraint used with last operand");
+ 	    return false;
+ 	  }
+ 	break;
+ 
+       case 'V':  case 'm':  case 'o':
+ 	*allows_mem = true;
+ 	break;
+ 
+       case '<':  case '>':
+       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':  case ',':
+ 	break;
+ 
+ 	/* Whether or not a numeric constraint allows a register is
+ 	   decided by the matching constraint, and so there is no need
+ 	   to do anything special with them.  We must handle them in
+ 	   the default case, so that we don't unnecessarily force
+ 	   operands to memory.  */
+       case '0':  case '1':  case '2':  case '3':  case '4':
+       case '5':  case '6':  case '7':  case '8':  case '9':
+ 	{
+ 	  char *end;
+ 	  unsigned long match;
+ 
+ 	  match = strtoul (constraint + j, &end, 10);
+ 	  if (match >= (unsigned long) noutputs)
+ 	    {
+ 	      error ("matching constraint references invalid operand number");
+ 	      return false;
+ 	    }
+ 
+ 	  /* Try and find the real constraint for this dup.  Only do this
+ 	     if the matching constraint is the only alternative.  */
+ 	  if (*end == '\0'
+ 	      && (j == 0 || (j == 1 && constraint[0] == '%')))
+ 	    {
+ 	      constraint = constraints[match];
+ 	      *constraint_p = constraint;
+ 	      c_len = strlen (constraint);
+ 	      j = 0;
+ 	      break;
+ 	    }
+ 	  else
+ 	    j = end - constraint;
+ 	}
+ 	/* Fall through.  */
+ 
+       case 'p':  case 'r':
+ 	*allows_reg = true;
+ 	break;
+ 
+       case 'g':  case 'X':
+ 	*allows_reg = true;
+ 	*allows_mem = true;
+ 	break;
+ 
+       default:
+ 	if (! ISALPHA (constraint[j]))
+ 	  {
+ 	    error ("invalid punctuation `%c' in constraint", constraint[j]);
+ 	    return false;
+ 	  }
+ 	if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+ 	  *allows_reg = true;
+ #ifdef EXTRA_CONSTRAINT
+ 	else
+ 	  {
+ 	    /* Otherwise we can't assume anything about the nature of
+ 	       the constraint except that it isn't purely registers.
+ 	       Treat it like "g" and hope for the best.  */
+ 	    *allows_reg = true;
+ 	    *allows_mem = true;
+ 	  }
+ #endif
+ 	break;
+       }
+ 
+   return true;
+ }
+ 
  /* Generate RTL for an asm statement with arguments.
     STRING is the instruction template.
     OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
*************** expand_asm_operands (string, outputs, in
*** 1472,1478 ****
    rtx body;
    int ninputs = list_length (inputs);
    int noutputs = list_length (outputs);
!   int ninout = 0;
    int nclobbers;
    tree tail;
    int i;
--- 1595,1601 ----
    rtx body;
    int ninputs = list_length (inputs);
    int noutputs = list_length (outputs);
!   int ninout;
    int nclobbers;
    tree tail;
    int i;
*************** expand_asm_operands (string, outputs, in
*** 1524,1533 ****
--- 1647,1661 ----
  
    last_expr_type = 0;
  
+   /* First pass over inputs and outputs checks validity and sets
+      mark_addressable if needed.  */
+ 
+   ninout = 0;
    for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
      {
        tree val = TREE_VALUE (tail);
        tree type = TREE_TYPE (val);
+       const char *constraint;
        bool is_inout;
        bool allows_reg;
        bool allows_mem;
*************** expand_asm_operands (string, outputs, in
*** 1536,1557 ****
        if (type == error_mark_node)
  	return;
  
-       /* Make sure constraint has `=' and does not have `+'.  Also, see
- 	 if it allows any register.  Be liberal on the latter test, since
- 	 the worst that happens if we get it wrong is we issue an error
- 	 message.  */
- 
        /* Try to parse the output constraint.  If that fails, there's
  	 no point in going further.  */
!       if (!parse_output_constraint (&constraints[i],
! 				    i,
! 				    ninputs,
! 				    noutputs,
! 				    &allows_mem,
! 				    &allows_reg,
! 				    &is_inout))
  	return;
  
        /* If an output operand is not a decl or indirect ref and our constraint
  	 allows a register, make a temporary to act as an intermediate.
  	 Make the asm insn write into that, then our caller will copy it to
--- 1664,1730 ----
        if (type == error_mark_node)
  	return;
  
        /* Try to parse the output constraint.  If that fails, there's
  	 no point in going further.  */
!       constraint = constraints[i];
!       if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
! 				    &allows_mem, &allows_reg, &is_inout))
! 	return;
! 
!       if (! allows_reg
! 	  && (allows_mem
! 	      || is_inout
! 	      || (DECL_P (val)
! 		  && GET_CODE (DECL_RTL (val)) == REG
! 		  && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
! 	mark_addressable (val);
! 
!       if (is_inout)
! 	ninout++;
!     }
! 
!   ninputs += ninout;
!   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
!     {
!       error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
!       return;
!     }
! 
!   for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
!     {
!       bool allows_reg, allows_mem;
!       const char *constraint;
! 
!       /* If there's an erroneous arg, emit no insn, because the ASM_INPUT
! 	 would get VOIDmode and that could cause a crash in reload.  */
!       if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
! 	return;
! 
!       constraint = constraints[i + noutputs];
!       if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
! 				    constraints, &allows_mem, &allows_reg))
  	return;
  
+       if (! allows_reg && allows_mem)
+ 	mark_addressable (TREE_VALUE (tail));
+     }
+ 
+   /* Second pass evaluates arguments.  */
+ 
+   ninout = 0;
+   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+     {
+       tree val = TREE_VALUE (tail);
+       tree type = TREE_TYPE (val);
+       bool is_inout;
+       bool allows_reg;
+       bool allows_mem;
+ 
+       if (!parse_output_constraint (&constraints[i], i, ninputs,
+ 				    noutputs, &allows_mem, &allows_reg,
+ 				    &is_inout))
+ 	abort ();
+ 
        /* If an output operand is not a decl or indirect ref and our constraint
  	 allows a register, make a temporary to act as an intermediate.
  	 Make the asm insn write into that, then our caller will copy it to
*************** expand_asm_operands (string, outputs, in
*** 1569,1580 ****
  	  || ! allows_reg
  	  || is_inout)
  	{
! 	  if (! allows_reg)
! 	    mark_addressable (TREE_VALUE (tail));
! 
! 	  output_rtx[i]
! 	    = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
! 			   EXPAND_WRITE);
  
  	  if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
  	    error ("output number %d not directly addressable", i);
--- 1742,1748 ----
  	  || ! allows_reg
  	  || is_inout)
  	{
! 	  output_rtx[i] = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
  
  	  if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
  	    error ("output number %d not directly addressable", i);
*************** expand_asm_operands (string, outputs, in
*** 1597,1614 ****
  
        if (is_inout)
  	{
! 	  inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
  	  inout_opnum[ninout++] = i;
  	}
      }
  
-   ninputs += ninout;
-   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
-     {
-       error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
-       return;
-     }
- 
    /* Make vectors for the expression-rtx, constraint strings,
       and named operands.  */
  
--- 1765,1775 ----
  
        if (is_inout)
  	{
! 	  inout_mode[ninout] = TYPE_MODE (type);
  	  inout_opnum[ninout++] = i;
  	}
      }
  
    /* Make vectors for the expression-rtx, constraint strings,
       and named operands.  */
  
*************** expand_asm_operands (string, outputs, in
*** 1628,1781 ****
  
    for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
      {
!       int j;
!       int allows_reg = 0, allows_mem = 0;
!       const char *constraint, *orig_constraint;
!       int c_len;
        rtx op;
- 
-       /* If there's an erroneous arg, emit no insn,
- 	 because the ASM_INPUT would get VOIDmode
- 	 and that could cause a crash in reload.  */
-       if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
- 	return;
- 
-       /* ??? Can this happen, and does the error message make any sense? */
-       if (TREE_PURPOSE (tail) == NULL_TREE)
- 	{
- 	  error ("hard register `%s' listed as input operand to `asm'",
- 		 TREE_STRING_POINTER (TREE_VALUE (tail)) );
- 	  return;
- 	}
- 
-       orig_constraint = constraint = constraints[i + noutputs];
-       c_len = strlen (constraint);
- 
-       /* Make sure constraint has neither `=', `+', nor '&'.  */
- 
-       for (j = 0; j < c_len; j++)
- 	switch (constraint[j])
- 	  {
- 	  case '+':  case '=':  case '&':
- 	    if (constraint == orig_constraint)
- 	      {
- 	        error ("input operand constraint contains `%c'",
- 		       constraint[j]);
- 	        return;
- 	      }
- 	    break;
- 
- 	  case '%':
- 	    if (constraint == orig_constraint
- 		&& i + 1 == ninputs - ninout)
- 	      {
- 		error ("`%%' constraint used with last operand");
- 		return;
- 	      }
- 	    break;
- 
- 	  case 'V':  case 'm':  case 'o':
- 	    allows_mem = 1;
- 	    break;
- 
- 	  case '<':  case '>':
- 	  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':  case ',':
- 	    break;
- 
- 	    /* Whether or not a numeric constraint allows a register is
- 	       decided by the matching constraint, and so there is no need
- 	       to do anything special with them.  We must handle them in
- 	       the default case, so that we don't unnecessarily force
- 	       operands to memory.  */
- 	  case '0':  case '1':  case '2':  case '3':  case '4':
- 	  case '5':  case '6':  case '7':  case '8':  case '9':
- 	    {
- 	      char *end;
- 	      unsigned long match;
- 
- 	      match = strtoul (constraint + j, &end, 10);
- 	      if (match >= (unsigned long) noutputs)
- 		{
- 		  error ("matching constraint references invalid operand number");
- 		  return;
- 		}
- 
- 	      /* Try and find the real constraint for this dup.  Only do
- 	         this if the matching constraint is the only alternative.  */
- 	      if (*end == '\0'
- 		  && (j == 0 || (j == 1 && constraint[0] == '%')))
- 		{
- 		  constraint = constraints[match];
- 		  c_len = strlen (constraint);
- 		  j = 0;
- 	          break;
- 		}
- 	      else
- 		j = end - constraint;
- 	    }
- 	    /* Fall through.  */
  
! 	  case 'p':  case 'r':
! 	    allows_reg = 1;
! 	    break;
! 
! 	  case 'g':  case 'X':
! 	    allows_reg = 1;
! 	    allows_mem = 1;
! 	    break;
! 
! 	  default:
! 	    if (! ISALPHA (constraint[j]))
! 	      {
! 		error ("invalid punctuation `%c' in constraint",
! 		       constraint[j]);
! 		return;
! 	      }
! 	    if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
! 	      allows_reg = 1;
! #ifdef EXTRA_CONSTRAINT
! 	    else
! 	      {
! 		/* Otherwise we can't assume anything about the nature of
! 		   the constraint except that it isn't purely registers.
! 		   Treat it like "g" and hope for the best.  */
! 		allows_reg = 1;
! 		allows_mem = 1;
! 	      }
! #endif
! 	    break;
! 	  }
  
!       if (! allows_reg && allows_mem)
! 	mark_addressable (TREE_VALUE (tail));
  
!       op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
  
        /* Never pass a CONCAT to an ASM.  */
-       generating_concat_p = 0;
        if (GET_CODE (op) == CONCAT)
  	op = force_reg (GET_MODE (op), op);
  
        if (asm_operand_ok (op, constraint) <= 0)
  	{
  	  if (allows_reg)
! 	    op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
  	  else if (!allows_mem)
  	    warning ("asm operand %d probably doesn't match constraints",
  		     i + noutputs);
  	  else if (CONSTANT_P (op))
! 	    op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
! 				  op);
  	  else if (GET_CODE (op) == REG
  		   || GET_CODE (op) == SUBREG
  		   || GET_CODE (op) == ADDRESSOF
  		   || GET_CODE (op) == CONCAT)
  	    {
- 	      tree type = TREE_TYPE (TREE_VALUE (tail));
  	      tree qual_type = build_qualified_type (type,
  						     (TYPE_QUALS (type)
  						      | TYPE_QUAL_CONST));
--- 1789,1828 ----
  
    for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
      {
!       bool allows_reg, allows_mem;
!       const char *constraint;
!       tree val, type;
        rtx op;
  
!       constraint = constraints[i + noutputs];
!       if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
! 				    constraints, &allows_mem, &allows_reg))
! 	abort ();
  
!       generating_concat_p = 0;
  
!       val = TREE_VALUE (tail);
!       type = TREE_TYPE (val);
!       op = expand_expr (val, NULL_RTX, VOIDmode, 0);
  
        /* Never pass a CONCAT to an ASM.  */
        if (GET_CODE (op) == CONCAT)
  	op = force_reg (GET_MODE (op), op);
  
        if (asm_operand_ok (op, constraint) <= 0)
  	{
  	  if (allows_reg)
! 	    op = force_reg (TYPE_MODE (type), op);
  	  else if (!allows_mem)
  	    warning ("asm operand %d probably doesn't match constraints",
  		     i + noutputs);
  	  else if (CONSTANT_P (op))
! 	    op = force_const_mem (TYPE_MODE (type), op);
  	  else if (GET_CODE (op) == REG
  		   || GET_CODE (op) == SUBREG
  		   || GET_CODE (op) == ADDRESSOF
  		   || GET_CODE (op) == CONCAT)
  	    {
  	      tree qual_type = build_qualified_type (type,
  						     (TYPE_QUALS (type)
  						      | TYPE_QUAL_CONST));
*************** expand_asm_operands (string, outputs, in
*** 1786,1794 ****
  	    }
  
  	  else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
! 	    /* We won't recognize volatile memory as available a
! 	       memory_operand at this point.  Ignore it.  */
! 	    ;
  	  else if (queued_subexp_p (op))
  	    ;
  	  else
--- 1833,1842 ----
  	    }
  
  	  else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
! 	    {
! 	      /* We won't recognize volatile memory as available a
! 		 memory_operand at this point.  Ignore it.  */
! 	    }
  	  else if (queued_subexp_p (op))
  	    ;
  	  else
*************** expand_asm_operands (string, outputs, in
*** 1798,1809 ****
  	    warning ("asm operand %d probably doesn't match constraints",
  		     i + noutputs);
  	}
        generating_concat_p = old_generating_concat_p;
        ASM_OPERANDS_INPUT (body, i) = op;
  
        ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
! 	= gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
! 			     orig_constraint);
      }
  
    /* Protect all the operands from the queue now that they have all been
--- 1846,1857 ----
  	    warning ("asm operand %d probably doesn't match constraints",
  		     i + noutputs);
  	}
+ 
        generating_concat_p = old_generating_concat_p;
        ASM_OPERANDS_INPUT (body, i) = op;
  
        ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
! 	= gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
      }
  
    /* Protect all the operands from the queue now that they have all been



More information about the Gcc-patches mailing list