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]

Re: Named asm operands patch


Sorry it took so long to get to this.

The patch looked reasonable, as far as it went.  The major
thing missing with it is that there was no provision for
how this interacted with matching constraints, which would
still have required the use of operand numbers.

My thought here is to also use "[<name>]" in the constraint
string, which would allow the use of operand names instead
of numbers everywhere.

When thinking of what would have to be changed to make this
work, it also ocurred to me that it's really pointless to 
carry the operand names all the way through to the end of
compilation, and all the changes that required to the 
various hashing routines throughout the compiler.  We can
simply substitute names for numbers immediately after 
parsing the asm statement.

One amusing point is that previous arguments against simply
extending the number of asm operands above 10 is that we
would be changing how "%10" is interpreted.  However, the
fact of the matter is that we have been using atoi to parse
this from the insn template since before gcc 2.7.  So there
is *no* change to how asm templates wrt numerals.

The following has been tested on alphaev6 and i686 linux.

Question for TCL experts:  Why does the attached test case
interpret \1 as an octal character constant instead of a
backward reference?


r~
/* { dg-do compile } */
/* { dg-options "" } */

int main()
{
  int x;

  asm volatile ("test0 X%0Y%[arg]Z" : [arg] "=g" (x));
  asm volatile ("test1 X%[out]Y%[in]Z" : [out] "=g" (x) : [in] "0"(x));
}

/* { dg-final { scan-assembler "test0 X(.*)Y\1Z" } } */
/* { dg-final { scan-assembler "test1 X(.*)Y\1Z" } } */
        * c-parse.in (asm_operand): Allow named operands.
        * genconfig.c (max_recog_operands): Set to 29.
        * local-alloc.c (requires_inout): Skip multiple digits.
        * recog.c (asm_operand_ok): Likewise.
        (preprocess_constraints): Use strtoul for matching constraints.
        (constrain_operands): Likewise.
        * regmove.c (find_matches): Likewise.
        * reload.c (find_reloads): Likewise.
        * stmt.c (parse_output_constraint): Don't reject in-out
        constraint on operands > 9.  Reject '[' in constraint.
        (expand_asm_operands): Handle named operands.  Use strtoul
        for matching constraints.
        (check_operand_nalternatives): Split out from expand_asm_operands.
        (check_unique_operand_names): New.
        (resolve_operand_names, resolve_operand_name_1): New.

        * doc/extend.texi (Extended Asm): Document named operands.
        * doc/md.texi (Simple Constraints): Document matching constraints
        on operands > 9.

        * parse.y (asm_operand): Allow named operands.
        * semantics.c (finish_asm_stmt): Tweek for changed location
        of the operand constrant.

Index: c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.107
diff -c -p -d -r1.107 c-parse.in
*** c-parse.in	2001/10/03 22:05:55	1.107
--- c-parse.in	2001/10/11 06:40:45
*************** nonnull_asm_operands:
*** 2454,2460 ****
  
  asm_operand:
  	  STRING '(' expr ')'
! 		{ $$ = build_tree_list ($1, $3); }
  	;
  
  asm_clobbers:
--- 2454,2462 ----
  
  asm_operand:
  	  STRING '(' expr ')'
! 		{ $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
! 	| '[' identifier ']' STRING '(' expr ')'
! 		{ $$ = build_tree_list (build_tree_list ($2, $4), $6); }
  	;
  
  asm_clobbers:
Index: genconfig.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genconfig.c,v
retrieving revision 1.42
diff -c -p -d -r1.42 genconfig.c
*** genconfig.c	2001/10/11 03:15:42	1.42
--- genconfig.c	2001/10/11 06:40:46
*************** main (argc, argv)
*** 285,292 ****
    puts ("#ifndef GCC_INSN_CONFIG_H");
    puts ("#define GCC_INSN_CONFIG_H\n");
  
!   /* Allow at least 10 operands for the sake of asm constructs.  */
!   max_recog_operands = 9;  /* We will add 1 later.  */
    max_dup_operands = 1;
  
    /* Read the machine description.  */
--- 285,294 ----
    puts ("#ifndef GCC_INSN_CONFIG_H");
    puts ("#define GCC_INSN_CONFIG_H\n");
  
!   /* Allow at least 30 operands for the sake of asm constructs.  */
!   /* ??? We *really* ought to reorganize things such that there
!      is no fixed upper bound.  */
!   max_recog_operands = 29;  /* We will add 1 later.  */
    max_dup_operands = 1;
  
    /* Read the machine description.  */
Index: local-alloc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/local-alloc.c,v
retrieving revision 1.91
diff -c -p -d -r1.91 local-alloc.c
*** local-alloc.c	2001/10/11 03:15:53	1.91
--- local-alloc.c	2001/10/11 06:40:46
*************** block_alloc (b)
*** 1302,1308 ****
  	      for (i = 1; i < recog_data.n_operands; i++)
  		{
  		  const char *p = recog_data.constraints[i];
! 		  int this_match = (requires_inout (p));
  
  		  n_matching_alts += this_match;
  		  if (this_match == recog_data.n_alternatives)
--- 1302,1308 ----
  	      for (i = 1; i < recog_data.n_operands; i++)
  		{
  		  const char *p = recog_data.constraints[i];
! 		  int this_match = requires_inout (p);
  
  		  n_matching_alts += this_match;
  		  if (this_match == recog_data.n_alternatives)
*************** requires_inout (p)
*** 2409,2416 ****
        case '=':  case '+':  case '?':
        case '#':  case '&':  case '!':
        case '*':  case '%':
-       case '1':  case '2':  case '3':  case '4': case '5':
-       case '6':  case '7':  case '8':  case '9':
        case 'm':  case '<':  case '>':  case 'V':  case 'o':
        case 'E':  case 'F':  case 'G':  case 'H':
        case 's':  case 'i':  case 'n':
--- 2409,2414 ----
*************** requires_inout (p)
*** 2429,2434 ****
--- 2427,2439 ----
  
        case '0':
  	found_zero = 1;
+ 	break;
+ 
+       case '1':  case '2':  case '3':  case '4': case '5':
+       case '6':  case '7':  case '8':  case '9':
+ 	/* Skip the balance of the matching constraint.  */
+ 	while (*p >= '0' && *p <= '9')
+ 	  p++;
  	break;
  
        default:
Index: recog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/recog.c,v
retrieving revision 1.126
diff -c -p -d -r1.126 recog.c
*** recog.c	2001/10/11 03:15:56	1.126
--- recog.c	2001/10/11 06:40:46
*************** asm_operand_ok (op, constraint)
*** 1657,1662 ****
--- 1657,1664 ----
  	     proper matching constraint, but we can't actually fail
  	     the check if they didn't.  Indicate that results are
  	     inconclusive.  */
+ 	  while (*constraint >= '0' && *constraint <= '9')
+ 	    constraint++;
  	  result = -1;
  	  break;
  
*************** preprocess_constraints ()
*** 2211,2218 ****
  
  		case '0': case '1': case '2': case '3': case '4':
  		case '5': case '6': case '7': case '8': case '9':
! 		  op_alt[j].matches = c - '0';
! 		  recog_op_alt[op_alt[j].matches][j].matched = i;
  		  break;
  
  		case 'm':
--- 2213,2224 ----
  
  		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 - 1, &end, 10);
! 		    recog_op_alt[op_alt[j].matches][j].matched = i;
! 		    p = end;
! 		  }
  		  break;
  
  		case 'm':
*************** constrain_operands (strict)
*** 2364,2408 ****
  
  	      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.  */
! 		if (strict < 0)
! 		  val = 1;
! 		else
! 		  {
! 		    rtx op1 = recog_data.operand[c - '0'];
! 		    rtx op2 = recog_data.operand[opno];
  
! 	            /* A unary operator may be accepted by the predicate,
! 		       but it is irrelevant for matching constraints.  */
! 	            if (GET_RTX_CLASS (GET_CODE (op1)) == '1')
! 	              op1 = XEXP (op1, 0);
! 	            if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
! 	              op2 = XEXP (op2, 0);
  
! 		    val = operands_match_p (op1, op2);
! 		  }
  
! 		matching_operands[opno] = c - '0';
! 		matching_operands[c - '0'] = 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 = c - '0';
! 		  }
  		break;
  
  	      case 'p':
--- 2370,2423 ----
  
  	      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 - 1, &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 (GET_RTX_CLASS (GET_CODE (op1)) == '1')
! 			op1 = XEXP (op1, 0);
! 		      if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
! 			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;
! 		    }
! 		}
  		break;
  
  	      case 'p':
Index: regmove.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regmove.c,v
retrieving revision 1.116
diff -c -p -d -r1.116 regmove.c
*** regmove.c	2001/10/11 03:15:58	1.116
--- regmove.c	2001/10/11 06:40:47
*************** find_matches (insn, matchp)
*** 1576,1591 ****
  	    matchp->commutative[op_no] = op_no + 1;
  	    matchp->commutative[op_no + 1] = op_no;
  	    break;
  	  case '0': case '1': case '2': case '3': case '4':
  	  case '5': case '6': case '7': case '8': case '9':
! 	    c -= '0';
! 	    if (c < op_no && likely_spilled[(unsigned char) c])
! 	      break;
! 	    matchp->with[op_no] = c;
! 	    any_matches = 1;
! 	    if (matchp->commutative[op_no] >= 0)
! 	      matchp->with[matchp->commutative[op_no]] = c;
  	    break;
  	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
  	  case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
  	  case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
--- 1576,1598 ----
  	    matchp->commutative[op_no] = op_no + 1;
  	    matchp->commutative[op_no + 1] = op_no;
  	    break;
+ 
  	  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 = strtoul (p - 1, &end, 10);
! 	      p = end;
! 
! 	      if (match < op_no && likely_spilled[match])
! 		break;
! 	      matchp->with[op_no] = match;
! 	      any_matches = 1;
! 	      if (matchp->commutative[op_no] >= 0)
! 		matchp->with[matchp->commutative[op_no]] = match;
! 	    }
  	    break;
+ 
  	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
  	  case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
  	  case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.166
diff -c -p -d -r1.166 reload.c
*** reload.c	2001/10/11 03:15:58	1.166
--- reload.c	2001/10/11 06:40:48
*************** find_reloads (insn, replace, ind_levels,
*** 2551,2557 ****
  	    }
  	  else if (c >= '0' && c <= '9')
  	    {
! 	      c -= '0';
  	      operands_match[c][i]
  		= operands_match_p (recog_data.operand[c],
  				    recog_data.operand[i]);
--- 2551,2558 ----
  	    }
  	  else if (c >= '0' && c <= '9')
  	    {
! 	      c = strtoul (p - 1, &p, 10);
! 
  	      operands_match[c][i]
  		= operands_match_p (recog_data.operand[c],
  				    recog_data.operand[i]);
*************** find_reloads (insn, replace, ind_levels,
*** 2939,2946 ****
  
  	      case '0':  case '1':  case '2':  case '3':  case '4':
  	      case '5':  case '6':  case '7':  case '8':  case '9':
  
- 		c -= '0';
  		this_alternative_matches[i] = c;
  		/* We are supposed to match a previous operand.
  		   If we do, we win if that one did.
--- 2940,2947 ----
  
  	      case '0':  case '1':  case '2':  case '3':  case '4':
  	      case '5':  case '6':  case '7':  case '8':  case '9':
+ 		c = strtoul (p - 1, &p, 10);
  
  		this_alternative_matches[i] = c;
  		/* We are supposed to match a previous operand.
  		   If we do, we win if that one did.
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.218
diff -c -p -d -r1.218 stmt.c
*** stmt.c	2001/10/11 03:16:10	1.218
--- stmt.c	2001/10/11 06:40:48
*************** static void expand_nl_goto_receiver	PARA
*** 404,409 ****
--- 404,414 ----
  static void expand_nl_goto_receivers	PARAMS ((struct nesting *));
  static void fixup_gotos			PARAMS ((struct nesting *, rtx, tree,
  					       rtx, int));
+ static bool check_operand_nalternatives	PARAMS ((tree, tree));
+ static bool check_unique_operand_names	PARAMS ((tree, tree));
+ static tree resolve_operand_names	PARAMS ((tree, tree, tree,
+ 						 const char **));
+ static char *resolve_operand_name_1	PARAMS ((char *, tree, tree));
  static void expand_null_return_1	PARAMS ((rtx));
  static void expand_value_return		PARAMS ((rtx));
  static int tail_recursion_args		PARAMS ((tree, tree));
*************** parse_output_constraint (constraint_p, 
*** 1355,1368 ****
       from and written to.  */
    *is_inout = (*p == '+');
  
-   /* Make sure we can specify the matching operand.  */
-   if (*is_inout && operand_num > 9)
-     {
-       error ("output operand constraint %d contains `+'", 
- 	     operand_num);
-       return false;
-     }
- 
    /* Canonicalize the output constraint so that it begins with `='.  */
    if (p != constraint || is_inout)
      {
--- 1360,1365 ----
*************** parse_output_constraint (constraint_p, 
*** 1416,1421 ****
--- 1413,1419 ----
  
        case '0':  case '1':  case '2':  case '3':  case '4':
        case '5':  case '6':  case '7':  case '8':  case '9':
+       case '[':
  	error ("matching constraint not valid in output operand");
  	return false;
  
*************** expand_asm_operands (string, outputs, in
*** 1478,1484 ****
       const char *filename;
       int line;
  {
!   rtvec argvec, constraints;
    rtx body;
    int ninputs = list_length (inputs);
    int noutputs = list_length (outputs);
--- 1476,1482 ----
       const char *filename;
       int line;
  {
!   rtvec argvec, constraintvec;
    rtx body;
    int ninputs = list_length (inputs);
    int noutputs = list_length (outputs);
*************** expand_asm_operands (string, outputs, in
*** 1492,1499 ****
    rtx *real_output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
    enum machine_mode *inout_mode
      = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
!   const char **output_constraints
!     = alloca (noutputs * sizeof (const char *));
    /* The insn we have emitted.  */
    rtx insn;
    int old_generating_concat_p = generating_concat_p;
--- 1490,1497 ----
    rtx *real_output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
    enum machine_mode *inout_mode
      = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
!   const char **constraints
!     = (const char **) alloca ((noutputs + ninputs) * sizeof (const char *));
    /* The insn we have emitted.  */
    rtx insn;
    int old_generating_concat_p = generating_concat_p;
*************** expand_asm_operands (string, outputs, in
*** 1504,1513 ****
  
    if (current_function_check_memory_usage)
      {
!       error ("`asm' cannot be used with `-fcheck-memory-usage'");
        return;
      }
  
  #ifdef MD_ASM_CLOBBERS
    /* Sometimes we wish to automatically clobber registers across an asm.
       Case in point is when the i386 backend moved from cc0 to a hard reg --
--- 1502,1519 ----
  
    if (current_function_check_memory_usage)
      {
!       error ("`asm' cannot be used in function where memory usage is checked");
        return;
      }
  
+   if (! check_operand_nalternatives (outputs, inputs))
+     return;
+ 
+   if (! check_unique_operand_names (outputs, inputs))
+     return;
+ 
+   string = resolve_operand_names (string, outputs, inputs, constraints);
+ 
  #ifdef MD_ASM_CLOBBERS
    /* Sometimes we wish to automatically clobber registers across an asm.
       Case in point is when the i386 backend moved from cc0 to a hard reg --
*************** expand_asm_operands (string, outputs, in
*** 1516,1527 ****
    MD_ASM_CLOBBERS (clobbers);
  #endif
  
-   if (current_function_check_memory_usage)
-     {
-       error ("`asm' cannot be used in function where memory usage is checked");
-       return;
-     }
- 
    /* Count the number of meaningful clobbered registers, ignoring what
       we would ignore later.  */
    nclobbers = 0;
--- 1522,1527 ----
*************** expand_asm_operands (string, outputs, in
*** 1538,1580 ****
  
    last_expr_type = 0;
  
-   /* Check that the number of alternatives is constant across all
-      operands.  */
-   if (outputs || inputs)
-     {
-       tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
-       int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
-       tree next = inputs;
- 
-       if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
- 	{
- 	  error ("too many alternatives in `asm'");
- 	  return;
- 	}
- 
-       tmp = outputs;
-       while (tmp)
- 	{
- 	  const char *constraint = TREE_STRING_POINTER (TREE_PURPOSE (tmp));
- 
- 	  if (n_occurrences (',', constraint) != nalternatives)
- 	    {
- 	      error ("operand constraints for `asm' differ in number of alternatives");
- 	      return;
- 	    }
- 
- 	  if (TREE_CHAIN (tmp))
- 	    tmp = TREE_CHAIN (tmp);
- 	  else
- 	    tmp = next, next = 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;
--- 1538,1547 ----
*************** expand_asm_operands (string, outputs, in
*** 1588,1599 ****
  	 the worst that happens if we get it wrong is we issue an error
  	 message.  */
  
-       constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
-       output_constraints[i] = constraint;
- 
        /* Try to parse the output constraint.  If that fails, there's
  	 no point in going further.  */
!       if (!parse_output_constraint (&output_constraints[i],
  				    i,
  				    ninputs,
  				    noutputs,
--- 1555,1563 ----
  	 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,
*************** expand_asm_operands (string, outputs, in
*** 1659,1673 ****
        return;
      }
  
!   /* Make vectors for the expression-rtx and constraint strings.  */
  
    argvec = rtvec_alloc (ninputs);
!   constraints = rtvec_alloc (ninputs);
  
    body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
  				: GET_MODE (output_rtx[0])),
  			       TREE_STRING_POINTER (string), 
! 			       empty_string, 0, argvec, constraints,
  			       filename, line);
  
    MEM_VOLATILE_P (body) = vol;
--- 1623,1638 ----
        return;
      }
  
!   /* Make vectors for the expression-rtx, constraint strings,
!      and named operands.  */
  
    argvec = rtvec_alloc (ninputs);
!   constraintvec = rtvec_alloc (ninputs);
  
    body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
  				: GET_MODE (output_rtx[0])),
  			       TREE_STRING_POINTER (string), 
! 			       empty_string, 0, argvec, constraintvec,
  			       filename, line);
  
    MEM_VOLATILE_P (body) = vol;
*************** expand_asm_operands (string, outputs, in
*** 1675,1682 ****
    /* Eval the inputs and put them into ARGVEC.
       Put their constraints into ASM_INPUTs and store in CONSTRAINTS.  */
  
!   i = 0;
!   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
      {
        int j;
        int allows_reg = 0, allows_mem = 0;
--- 1640,1646 ----
    /* Eval the inputs and put them into ARGVEC.
       Put their constraints into ASM_INPUTs and store in CONSTRAINTS.  */
  
!   for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
      {
        int j;
        int allows_reg = 0, allows_mem = 0;
*************** expand_asm_operands (string, outputs, in
*** 1698,1706 ****
  	  return;
  	}
  
!       constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
        c_len = strlen (constraint);
-       orig_constraint = constraint;
  
        /* Make sure constraint has neither `=', `+', nor '&'.  */
  
--- 1662,1669 ----
  	  return;
  	}
  
!       orig_constraint = constraint = constraints[i + noutputs];
        c_len = strlen (constraint);
  
        /* Make sure constraint has neither `=', `+', nor '&'.  */
  
*************** expand_asm_operands (string, outputs, in
*** 1744,1771 ****
  	       operands to memory.  */
  	  case '0':  case '1':  case '2':  case '3':  case '4':
  	  case '5':  case '6':  case '7':  case '8':  case '9':
! 	    if (constraint[j] >= '0' + noutputs)
! 	      {
! 		error
! 		  ("matching constraint references invalid operand number");
! 		return;
! 	      }
! 
! 	    /* Try and find the real constraint for this dup.  */
! 	    if ((j == 0 && c_len == 1)
! 		|| (j == 1 && c_len == 2 && constraint[0] == '%'))
! 	      {
! 		tree o = outputs;
! 
! 		for (j = constraint[j] - '0'; j > 0; --j)
! 		  o = TREE_CHAIN (o);
  
! 		constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
! 		c_len = strlen (constraint);
! 		j = 0;
! 		break;
! 	      }
  
  	    /* Fall through.  */
  
  	  case 'p':  case 'r':
--- 1707,1736 ----
  	       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':
*************** expand_asm_operands (string, outputs, in
*** 1814,1820 ****
  	  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);
  	  else if (CONSTANT_P (op))
  	    op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
  				  op);
--- 1779,1786 ----
  	  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);
*************** expand_asm_operands (string, outputs, in
*** 1843,1849 ****
  	    /* ??? Leave this only until we have experience with what
  	       happens in combine and elsewhere when constraints are
  	       not satisfied.  */
! 	    warning ("asm operand %d probably doesn't match constraints", i);
  	}
        generating_concat_p = old_generating_concat_p;
        ASM_OPERANDS_INPUT (body, i) = op;
--- 1809,1816 ----
  	    /* ??? Leave this only until we have experience with what
  	       happens in combine and elsewhere when constraints are
  	       not satisfied.  */
! 	    warning ("asm operand %d probably doesn't match constraints",
! 		     i + noutputs);
  	}
        generating_concat_p = old_generating_concat_p;
        ASM_OPERANDS_INPUT (body, i) = op;
*************** expand_asm_operands (string, outputs, in
*** 1851,1857 ****
        ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
  	= gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
  			     orig_constraint);
-       i++;
      }
  
    /* Protect all the operands from the queue now that they have all been
--- 1818,1823 ----
*************** expand_asm_operands (string, outputs, in
*** 1870,1893 ****
    for (i = 0; i < ninout; i++)
      {
        int j = inout_opnum[i];
  
        ASM_OPERANDS_INPUT (body, ninputs - ninout + i)
  	= output_rtx[j];
        ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i)
! 	= gen_rtx_ASM_INPUT (inout_mode[i], digit_string (j));
      }
  
    generating_concat_p = old_generating_concat_p;
  
    /* Now, for each output, construct an rtx
!      (set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT
! 			       ARGVEC CONSTRAINTS))
       If there is more than one, put them inside a PARALLEL.  */
  
    if (noutputs == 1 && nclobbers == 0)
      {
!       ASM_OPERANDS_OUTPUT_CONSTRAINT (body)
! 	= output_constraints[0];
        insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
      }
  
--- 1836,1861 ----
    for (i = 0; i < ninout; i++)
      {
        int j = inout_opnum[i];
+       char buffer[16];
  
        ASM_OPERANDS_INPUT (body, ninputs - ninout + i)
  	= output_rtx[j];
+ 
+       sprintf (buffer, "%d", j);
        ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i)
! 	= gen_rtx_ASM_INPUT (inout_mode[i], ggc_alloc_string (buffer, -1));
      }
  
    generating_concat_p = old_generating_concat_p;
  
    /* Now, for each output, construct an rtx
!      (set OUTPUT (asm_operands INSN OUTPUTCONSTRAINT OUTPUTNUMBER
! 			       ARGVEC CONSTRAINTS OPNAMES))
       If there is more than one, put them inside a PARALLEL.  */
  
    if (noutputs == 1 && nclobbers == 0)
      {
!       ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
        insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
      }
  
*************** expand_asm_operands (string, outputs, in
*** 1916,1923 ****
  			   gen_rtx_ASM_OPERANDS
  			   (GET_MODE (output_rtx[i]),
  			    TREE_STRING_POINTER (string),
! 			    output_constraints[i],
! 			    i, argvec, constraints,
  			    filename, line));
  
  	  MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
--- 1884,1890 ----
  			   gen_rtx_ASM_OPERANDS
  			   (GET_MODE (output_rtx[i]),
  			    TREE_STRING_POINTER (string),
! 			    constraints[i], i, argvec, constraintvec,
  			    filename, line));
  
  	  MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
*************** expand_asm_operands (string, outputs, in
*** 1970,1975 ****
--- 1937,2142 ----
        emit_move_insn (real_output_rtx[i], output_rtx[i]);
  
    free_temp_slots ();
+ }
+ 
+ /* A subroutine of expand_asm_operands.  Check that all operands have
+    the same number of alternatives.  Return true if so.  */
+ 
+ static bool
+ check_operand_nalternatives (outputs, inputs)
+      tree outputs, inputs;
+ {
+   if (outputs || inputs)
+     {
+       tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
+       int nalternatives
+ 	= n_occurrences (',', TREE_STRING_POINTER (TREE_VALUE (tmp)));
+       tree next = inputs;
+ 
+       if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
+ 	{
+ 	  error ("too many alternatives in `asm'");
+ 	  return false;
+ 	}
+ 
+       tmp = outputs;
+       while (tmp)
+ 	{
+ 	  const char *constraint
+ 	    = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tmp)));
+ 
+ 	  if (n_occurrences (',', constraint) != nalternatives)
+ 	    {
+ 	      error ("operand constraints for `asm' differ in number of alternatives");
+ 	      return false;
+ 	    }
+ 
+ 	  if (TREE_CHAIN (tmp))
+ 	    tmp = TREE_CHAIN (tmp);
+ 	  else
+ 	    tmp = next, next = 0;
+ 	}
+     }
+ 
+   return true;
+ }
+ 
+ /* A subroutine of expand_asm_operands.  Check that all operand names
+    are unique.  Return true if so.  We rely on the fact that these names
+    are identifiers, and so have been canonicalized by get_identifier,
+    so all we need are pointer comparisons.  */
+ 
+ static bool
+ check_unique_operand_names (outputs, inputs)
+      tree outputs, inputs;
+ {
+   tree i, j;
+ 
+   for (i = outputs; i ; i = TREE_CHAIN (i))
+     {
+       tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
+       if (! i_name)
+ 	continue;
+ 
+       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
+ 	if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ 	  goto failure;
+     }
+ 
+   for (i = inputs; i ; i = TREE_CHAIN (i))
+     {
+       tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
+       if (! i_name)
+ 	continue;
+ 
+       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
+ 	if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ 	  goto failure;
+       for (j = outputs; j ; j = TREE_CHAIN (j))
+ 	if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ 	  goto failure;
+     }
+ 
+   return true;
+ 
+  failure:
+   error ("duplicate asm operand name '%s'",
+ 	 IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
+   return false;
+ }
+ 
+ /* A subroutine of expand_asm_operands.  Resolve the names of the operands
+    in *POUTPUTS and *PINPUTS to numbers, and replace the name expansions in
+    STRING and in the constraints to those numbers.  */
+ 
+ static tree
+ resolve_operand_names (string, outputs, inputs, pconstraints)
+      tree string;
+      tree outputs, inputs;
+      const char **pconstraints;
+ {
+   char *buffer = xstrdup (TREE_STRING_POINTER (string));
+   char *p;
+   tree t;
+ 
+   /* Assume that we will not need extra space to perform the substitution.
+      This because we get to remove '[' and ']', which means we cannot have
+      a problem until we have more than 999 operands.  */
+ 
+   p = buffer;
+   while ((p = strchr (p, '%')) != NULL)
+     {
+       if (*++p != '[')
+ 	continue;
+       p = resolve_operand_name_1 (p, outputs, inputs);
+     }
+ 
+   string = build_string (strlen (buffer), buffer);
+   free (buffer);
+ 
+   /* Collect output constraints here because it's convenient.
+      There should be no named operands here; this is verified
+      in expand_asm_operand.  */
+   for (t = outputs; t ; t = TREE_CHAIN (t), pconstraints++)
+     *pconstraints = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+ 
+   /* Substitute [<name>] in input constraint strings.  */
+   for (t = inputs; t ; t = TREE_CHAIN (t), pconstraints++)
+     {
+       const char *c = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+       if (strchr (c, '[') == NULL)
+ 	*pconstraints = c;
+       else
+ 	{
+ 	  p = buffer = xstrdup (c);
+ 	  while ((p = strchr (p, '[')) != NULL)
+ 	    p = resolve_operand_name_1 (p, outputs, inputs);
+ 
+ 	  *pconstraints = ggc_alloc_string (buffer, -1);
+ 	  free (buffer);
+ 	}
+     }
+ 
+   return string;
+ }
+ 
+ /* A subroutine of resolve_operand_names.  P points to the '[' for a
+    potential named operand of the form [<name>].  In place, replace
+    the name and brackets with a number.  Return a pointer to the 
+    balance of the string after substitution.  */
+ 
+ static char *
+ resolve_operand_name_1 (p, outputs, inputs)
+      char *p;
+      tree outputs, inputs;
+ {
+   char *q;
+   int op;
+   tree t;
+   size_t len;
+ 
+   /* Collect the operand name.  */
+   q = strchr (p, ']');
+   if (!q)
+     {
+       error ("missing close brace for named operand");
+       return strchr (p, '\0');
+     }
+   len = q - p - 1;
+ 
+   /* Resolve the name to a number.  */
+   for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
+     {
+       const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
+       if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+ 	goto found;
+     }
+   for (t = inputs; t ; t = TREE_CHAIN (t), op++)
+     {
+       const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
+       if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+ 	goto found;
+     }
+ 
+   *q = '\0';
+   error ("undefined named operand '%s'", p + 1);
+   op = 0;
+  found:
+ 
+   /* Replace the name with the number.  Unfortunately, not all libraries
+      get the return value of sprintf correct, so search for the end of the
+      generated string by hand.  */
+   sprintf (p, "%d", op);
+   p = strchr (p, '\0');
+ 
+   /* Verify the no extra buffer space assumption.  */
+   if (p > q)
+     abort ();
+ 
+   /* Shift the rest of the buffer down to fill the gap.  */
+   memmove (p, q + 1, strlen (q + 1) + 1);
+ 
+   return p;
  }
  
  /* Generate RTL to evaluate the expression EXP
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.227
diff -c -p -d -r1.227 parse.y
*** parse.y	2001/10/02 15:43:43	1.227
--- parse.y	2001/10/11 06:40:49
*************** nonnull_asm_operands:
*** 3607,3613 ****
  
  asm_operand:
  	  STRING '(' expr ')'
! 		{ $$ = build_tree_list ($$, $3); }
  	;
  
  asm_clobbers:
--- 3607,3615 ----
  
  asm_operand:
  	  STRING '(' expr ')'
! 		{ $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
! 	| '[' identifier ']' STRING '(' expr ')'
! 		{ $$ = build_tree_list (build_tree_list ($2, $4), $6); }
  	;
  
  asm_clobbers:
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.225
diff -c -p -d -r1.225 semantics.c
*** semantics.c	2001/10/05 02:48:47	1.225
--- semantics.c	2001/10/11 06:40:50
*************** finish_asm_stmt (cv_qualifier, string, o
*** 929,935 ****
  	  const char *constraint;
  	  tree operand;
  
! 	  constraint = TREE_STRING_POINTER (TREE_PURPOSE (t));
  	  operand = TREE_VALUE (output_operands);
  
  	  if (!parse_output_constraint (&constraint,
--- 929,935 ----
  	  const char *constraint;
  	  tree operand;
  
! 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
  	  operand = TREE_VALUE (output_operands);
  
  	  if (!parse_output_constraint (&constraint,
Index: doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.30
diff -c -p -d -r1.30 extend.texi
*** extend.texi	2001/10/09 23:11:55	1.30
--- extend.texi	2001/10/11 06:40:50
*************** Each operand is described by an operand-
*** 3382,3395 ****
  the C expression in parentheses.  A colon separates the assembler
  template from the first output operand and another separates the last
  output operand from the first input, if any.  Commas separate the
! operands within each group.  The total number of operands is limited to
! ten or to the maximum number of operands in any instruction pattern in
! the machine description, whichever is greater.
  
  If there are no output operands but there are input operands, you must
  place two consecutive colons surrounding the place where the output
  operands would go.
  
  Output operand expressions must be lvalues; the compiler can check this.
  The input operands need not be lvalues.  The compiler cannot check
  whether the operands have data types that are reasonable for the
--- 3382,3415 ----
  the C expression in parentheses.  A colon separates the assembler
  template from the first output operand and another separates the last
  output operand from the first input, if any.  Commas separate the
! operands within each group.  The total number of operands is currently
! limited to 30; this limitation may be lifted in some future version of
! GCC.
  
  If there are no output operands but there are input operands, you must
  place two consecutive colons surrounding the place where the output
  operands would go.
  
+ As of GCC version 3.1, it is also possible to specify input and output
+ operands using symbolic names which can be referenced within the
+ assembler code.  These names are specified inside square brackets
+ preceding the constraint string, and can be referenced inside the
+ assembler code using @code{%[@var{name}]} instead of a percentage sign
+ followed by the operand number.  Using named operands the above example
+ could look like:
+ 
+ @example
+ asm ("fsinx %[angle],%[output]"
+      : [output] "=f" (result)
+      : [angle] "f" (angle));
+ @end example
+ 
+ @noindent
+ Note that the symbolic operand names have no relation whatsoever to
+ other C identifiers.  You may use any name you like, even those of
+ existing C symbols, but must ensure that no two operands within the same
+ assembler construct use the same symbolic name.
+ 
  Output operand expressions must be lvalues; the compiler can check this.
  The input operands need not be lvalues.  The compiler cannot check
  whether the operands have data types that are reasonable for the
*************** asm ("combine %2,%0" : "=r" (foo) : "0" 
*** 3425,3434 ****
  
  @noindent
  The constraint @samp{"0"} for operand 1 says that it must occupy the
! same location as operand 0.  A digit in constraint is allowed only in an
! input operand and it must refer to an output operand.
  
! Only a digit in the constraint can guarantee that one operand will be in
  the same place as another.  The mere fact that @code{foo} is the value
  of both operands is not enough to guarantee that they will be in the
  same place in the generated assembler code.  The following would not
--- 3445,3454 ----
  
  @noindent
  The constraint @samp{"0"} for operand 1 says that it must occupy the
! same location as operand 0.  A number in constraint is allowed only in
! an input operand and it must refer to an output operand.
  
! Only a number in the constraint can guarantee that one operand will be in
  the same place as another.  The mere fact that @code{foo} is the value
  of both operands is not enough to guarantee that they will be in the
  same place in the generated assembler code.  The following would not
*************** use it for operand 1, but generate the o
*** 3445,3450 ****
--- 3465,3479 ----
  register (copying it afterward to @code{foo}'s own address).  Of course,
  since the register for operand 1 is not even mentioned in the assembler
  code, the result will not work, but GCC can't tell that.
+ 
+ As of GCC version 3.1, one may write @code{[@var{name}]} instead of
+ the operand number for a matching constraint.  For example:
+ 
+ @example
+ asm ("cmoveq %1,%2,%[result]"
+      : [result] "=r"(result)
+      : "r" (test), "r"(new), "[result]"(old));
+ @end example
  
  Some instructions clobber specific hard registers.  To describe this,
  write a third colon after the input operands, followed by the names of
Index: doc/md.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/md.texi,v
retrieving revision 1.24
diff -c -p -d -r1.24 md.texi
*** md.texi	2001/10/09 23:11:55	1.24
--- md.texi	2001/10/11 06:40:50
*************** An operand that matches the specified op
*** 894,899 ****
--- 894,906 ----
  digit is used together with letters within the same alternative, the
  digit should come last.
  
+ This number is allowed to be more than a single digit.  If multiple
+ digits are encountered consecutavely, they are interpreted as a single
+ decimal integer.  There is scant chance for ambiguity, since to-date
+ it has never been desirable that @samp{10} be interpreted as matching
+ either operand 1 @emph{or} operand 0.  Should this be desired, one
+ can use multiple alternatives instead.
+ 
  @cindex matching constraint
  @cindex constraint, matching
  This is called a @dfn{matching constraint} and what it really means is

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