summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog22
-rw-r--r--gcc/c-parse.in4
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/parse.y4
-rw-r--r--gcc/cp/semantics.c2
-rw-r--r--gcc/doc/extend.texi41
-rw-r--r--gcc/doc/md.texi7
-rw-r--r--gcc/genconfig.c6
-rw-r--r--gcc/local-alloc.c11
-rw-r--r--gcc/recog.c83
-rw-r--r--gcc/regmove.c21
-rw-r--r--gcc/reload.c5
-rw-r--r--gcc/stmt.c351
13 files changed, 414 insertions, 149 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5e491e99f68..b322551d11a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,27 @@
2001-10-10 Richard Henderson <rth@redhat.com>
+ * 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.
+
+2001-10-10 Richard Henderson <rth@redhat.com>
+
* combine.c (try_combine): Handle a SEQUENCE of one insn.
* i386.c (test splitter): Narrow tests vs paradoxical subregs.
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
index 28ac2b5a550..8096d1cef27 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -2454,7 +2454,9 @@ nonnull_asm_operands:
asm_operand:
STRING '(' expr ')'
- { $$ = build_tree_list ($1, $3); }
+ { $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
+ | '[' identifier ']' STRING '(' expr ')'
+ { $$ = build_tree_list (build_tree_list ($2, $4), $6); }
;
asm_clobbers:
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 49fdb783d03..8d867bbd579 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2001-10-10 Richard Henderson <rth@redhat.com>
+
+ * parse.y (asm_operand): Allow named operands.
+ * semantics.c (finish_asm_stmt): Tweek for changed location
+ of the operand constrant.
+
2001-10-09 Jason Merrill <jason_merrill@redhat.com>
* call.c (standard_conversion): Add bad conversion between
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index a7651b57468..f3e85ffe849 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -3607,7 +3607,9 @@ nonnull_asm_operands:
asm_operand:
STRING '(' expr ')'
- { $$ = build_tree_list ($$, $3); }
+ { $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
+ | '[' identifier ']' STRING '(' expr ')'
+ { $$ = build_tree_list (build_tree_list ($2, $4), $6); }
;
asm_clobbers:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ec7b968f046..41e3bcf4b46 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -929,7 +929,7 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
const char *constraint;
tree operand;
- constraint = TREE_STRING_POINTER (TREE_PURPOSE (t));
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
operand = TREE_VALUE (output_operands);
if (!parse_output_constraint (&constraint,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 027647d09b2..132ccbad14f 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3382,14 +3382,34 @@ Each operand is described by an operand-constraint string followed by
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.
+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
@@ -3425,10 +3445,10 @@ asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));
@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.
+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 digit in the constraint can guarantee that one operand will be in
+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
@@ -3446,6 +3466,15 @@ 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
the clobbered hard registers (given as strings). Here is a realistic
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 685f5150630..7a62eaf25c0 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -894,6 +894,13 @@ An operand that matches the specified operand number is allowed. If a
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
diff --git a/gcc/genconfig.c b/gcc/genconfig.c
index f9ae6d5e3ce..27000be7d93 100644
--- a/gcc/genconfig.c
+++ b/gcc/genconfig.c
@@ -285,8 +285,10 @@ main (argc, argv)
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. */
+ /* 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. */
diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c
index 2637b7e78a1..22d7d48b528 100644
--- a/gcc/local-alloc.c
+++ b/gcc/local-alloc.c
@@ -1302,7 +1302,7 @@ block_alloc (b)
for (i = 1; i < recog_data.n_operands; i++)
{
const char *p = recog_data.constraints[i];
- int this_match = (requires_inout (p));
+ int this_match = requires_inout (p);
n_matching_alts += this_match;
if (this_match == recog_data.n_alternatives)
@@ -2409,8 +2409,6 @@ requires_inout (p)
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':
@@ -2431,6 +2429,13 @@ requires_inout (p)
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:
if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
break;
diff --git a/gcc/recog.c b/gcc/recog.c
index e240ebbe2cc..15048705763 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1657,6 +1657,8 @@ asm_operand_ok (op, constraint)
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;
@@ -2211,8 +2213,12 @@ preprocess_constraints ()
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;
+ {
+ 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':
@@ -2364,45 +2370,54 @@ constrain_operands (strict)
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.
- /* 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.
- Note that the lower-numbered operand is passed first.
+ If we are not testing strictly, assume that this
+ constraint will be satisfied. */
- 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];
+ char *end;
+ int match;
- /* 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);
+ match = strtoul (p - 1, &end, 10);
+ p = end;
- val = operands_match_p (op1, op2);
- }
+ if (strict < 0)
+ val = 1;
+ else
+ {
+ rtx op1 = recog_data.operand[match];
+ rtx op2 = recog_data.operand[opno];
- matching_operands[opno] = c - '0';
- matching_operands[c - '0'] = 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);
- 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';
- }
+ 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':
diff --git a/gcc/regmove.c b/gcc/regmove.c
index ce62cce72a5..89a55ca44e1 100644
--- a/gcc/regmove.c
+++ b/gcc/regmove.c
@@ -1576,16 +1576,23 @@ find_matches (insn, matchp)
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;
+ {
+ 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':
diff --git a/gcc/reload.c b/gcc/reload.c
index 613d6c7e2c7..8b01ce25403 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -2551,7 +2551,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
else if (c >= '0' && c <= '9')
{
- c -= '0';
+ c = strtoul (p - 1, &p, 10);
+
operands_match[c][i]
= operands_match_p (recog_data.operand[c],
recog_data.operand[i]);
@@ -2939,8 +2940,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
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);
- c -= '0';
this_alternative_matches[i] = c;
/* We are supposed to match a previous operand.
If we do, we win if that one did.
diff --git a/gcc/stmt.c b/gcc/stmt.c
index b7ced6a8eca..1f91823bdc8 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -404,6 +404,11 @@ static void expand_nl_goto_receiver PARAMS ((void));
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));
@@ -1355,14 +1360,6 @@ parse_output_constraint (constraint_p,
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)
{
@@ -1416,6 +1413,7 @@ parse_output_constraint (constraint_p,
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;
@@ -1478,7 +1476,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
const char *filename;
int line;
{
- rtvec argvec, constraints;
+ rtvec argvec, constraintvec;
rtx body;
int ninputs = list_length (inputs);
int noutputs = list_length (outputs);
@@ -1492,8 +1490,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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 *));
+ 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;
@@ -1504,10 +1502,18 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (current_function_check_memory_usage)
{
- error ("`asm' cannot be used with `-fcheck-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 --
@@ -1516,12 +1522,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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;
@@ -1538,43 +1538,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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;
@@ -1588,12 +1555,9 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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],
+ if (!parse_output_constraint (&constraints[i],
i,
ninputs,
noutputs,
@@ -1659,15 +1623,16 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
return;
}
- /* Make vectors for the expression-rtx and constraint strings. */
+ /* Make vectors for the expression-rtx, constraint strings,
+ and named operands. */
argvec = rtvec_alloc (ninputs);
- constraints = 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, constraints,
+ empty_string, 0, argvec, constraintvec,
filename, line);
MEM_VOLATILE_P (body) = vol;
@@ -1675,8 +1640,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* 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))
+ for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
{
int j;
int allows_reg = 0, allows_mem = 0;
@@ -1698,9 +1662,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
return;
}
- constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+ orig_constraint = constraint = constraints[i + noutputs];
c_len = strlen (constraint);
- orig_constraint = constraint;
/* Make sure constraint has neither `=', `+', nor '&'. */
@@ -1744,28 +1707,30 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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);
+ {
+ char *end;
+ unsigned long match;
- constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
- c_len = strlen (constraint);
- j = 0;
- break;
- }
+ 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':
@@ -1814,7 +1779,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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);
+ 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);
@@ -1843,7 +1809,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* ??? 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);
+ warning ("asm operand %d probably doesn't match constraints",
+ i + noutputs);
}
generating_concat_p = old_generating_concat_p;
ASM_OPERANDS_INPUT (body, i) = op;
@@ -1851,7 +1818,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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
@@ -1870,24 +1836,26 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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], digit_string (j));
+ = 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 OUTPUTNUMBER OUTPUTCONSTRAINT
- ARGVEC CONSTRAINTS))
+ (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)
- = output_constraints[0];
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
}
@@ -1916,8 +1884,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
gen_rtx_ASM_OPERANDS
(GET_MODE (output_rtx[i]),
TREE_STRING_POINTER (string),
- output_constraints[i],
- i, argvec, constraints,
+ constraints[i], i, argvec, constraintvec,
filename, line));
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
@@ -1971,6 +1938,206 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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
and remember it in case this is the VALUE in a ({... VALUE; }) constr. */