This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] PATCH to gimplification of ASM_EXPR
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 06 Jun 2003 11:57:14 -0400
- Subject: [tree-ssa] PATCH to gimplification of ASM_EXPR
As discussed, this changes gimplification of ASM_EXPRs so that input memory
operands ('m', 'V', 'o') are treated as lvalues. The complexity comes from
having to handle references to output operands. I also changed
resolve_asm_operand_names to avoid doing a strdup of the pattern string if
it isn't necessary.
Currently, passing something which is not an lvalue will cause a
gimplification failure. We ought to give a better diagnostic sooner;
perhaps rth's 3.3.1 patch will do that.
Tested athlon-pc-linux-gnu, applied to tree-ssa.
2003-06-05 Jason Merrill <jason@redhat.com>
* stmt.c (asm_op_is_mem_input): New fn.
(resolve_asm_operand_names): Rename from resolve_operand_names. No longer
static. Avoid needless copying. Don't build array of constraints.
(expand_asm_operands): Build it here.
* tree.h: Declare new fns.
* gimplify.c (simplify_asm_expr): Call resolve_asm_operand_names.
Use is_simple_modify_expr_lhs for mem input ops.
*** tree.h.~1~ 2003-06-03 15:55:46.000000000 -0400
--- tree.h 2003-06-05 18:47:37.000000000 -0400
*************** extern bool parse_output_constraint
*** 3265,3270 ****
--- 3265,3272 ----
extern void expand_asm_operands PARAMS ((tree, tree, tree, tree, int,
const char *, int));
extern void expand_asm_expr PARAMS ((tree));
+ extern bool asm_op_is_mem_input (tree, tree);
+ extern tree resolve_asm_operand_names (tree, tree, tree);
extern int any_pending_cleanups PARAMS ((int));
extern void init_stmt_for_function PARAMS ((void));
extern void expand_start_target_temps PARAMS ((void));
*** stmt.c.~1~ 2003-05-14 15:29:46.000000000 -0400
--- stmt.c 2003-06-05 18:55:44.000000000 -0400
*************** static void fixup_gotos PARAMS ((struc
*** 404,411 ****
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 enum br_predictor return_prediction PARAMS ((rtx));
--- 404,409 ----
*************** parse_input_constraint (constraint_p, in
*** 1447,1452 ****
--- 1445,1477 ----
return true;
}
+ /* INPUT is one of the input operands from EXPR, an ASM_EXPR. Returns true
+ if it is an operand which must be passed in memory (i.e. an "m"
+ constraint), false otherwise. */
+
+ bool
+ asm_op_is_mem_input (tree input, tree expr)
+ {
+ const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (input)));
+ tree outputs = ASM_OUTPUTS (expr);
+ int noutputs = list_length (outputs);
+ const char **constraints
+ = (const char **) alloca ((noutputs) * sizeof (const char *));
+ int i = 0;
+ bool allows_mem, allows_reg;
+ tree t;
+
+ /* Collect output constraints. */
+ for (t = outputs; t ; t = TREE_CHAIN (t), i++)
+ constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+ /* We pass 0 for input_num, ninputs and ninout; they are only used for
+ error checking which will be done at expand time. */
+ parse_input_constraint (&constraint, 0, 0, noutputs, 0, constraints,
+ &allows_mem, &allows_reg);
+ return (!allows_reg && allows_mem);
+ }
+
/* Check for overlap between registers marked in CLOBBERED_REGS and
anything inappropriate in DECL. Emit error and return TRUE for error,
FALSE for ok. */
*************** expand_asm_operands (string, outputs, in
*** 1517,1522 ****
--- 1542,1548 ----
HARD_REG_SET clobbered_regs;
int clobber_conflict_found = 0;
tree tail;
+ tree t;
int i;
/* Vector of RTX's of evaluated output operands. */
rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
*************** expand_asm_operands (string, outputs, in
*** 1538,1544 ****
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.
--- 1564,1577 ----
if (! check_unique_operand_names (outputs, inputs))
return;
! string = resolve_asm_operand_names (string, outputs, inputs);
!
! /* Collect constraints. */
! i = 0;
! for (t = outputs; t ; t = TREE_CHAIN (t), i++)
! constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
! for (t = inputs; t ; t = TREE_CHAIN (t), i++)
! constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
#ifdef MD_ASM_CLOBBERS
/* Sometimes we wish to automatically clobber registers across an asm.
*************** check_unique_operand_names (outputs, inp
*** 2079,2099 ****
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[1] == '[')
--- 2112,2148 ----
in *POUTPUTS and *PINPUTS to numbers, and replace the name expansions in
STRING and in the constraints to those numbers. */
! tree
! resolve_asm_operand_names (tree string, tree outputs, tree inputs)
{
! char *buffer;
char *p;
tree t;
+ /* Substitute [<name>] in input constraint strings. There should be no
+ named operands in output constraints. */
+ for (t = inputs; t ; t = TREE_CHAIN (t))
+ {
+ const char *c = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+ if (strchr (c, '[') != NULL)
+ {
+ p = buffer = xstrdup (c);
+ while ((p = strchr (p, '[')) != NULL)
+ p = resolve_operand_name_1 (p, outputs, inputs);
+ TREE_VALUE (TREE_PURPOSE (t))
+ = build_string (strlen (buffer), buffer);
+ free (buffer);
+ }
+ }
+
+ if (strchr (TREE_STRING_POINTER (string), '[') == NULL)
+ return string;
+
/* 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 = xstrdup (TREE_STRING_POINTER (string));
while ((p = strchr (p, '%')) != NULL)
{
if (p[1] == '[')
*************** resolve_operand_names (string, outputs,
*** 2112,2140 ****
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;
}
--- 2161,2166 ----
*** gimplify.c.~1~ 2003-06-03 16:02:29.000000000 -0400
--- gimplify.c 2003-06-06 11:29:06.000000000 -0400
*************** simplify_asm_expr (expr, pre_p)
*** 2037,2049 ****
{
tree link;
! for (link = ASM_INPUTS (expr); link; link = TREE_CHAIN (link))
! simplify_expr (&TREE_VALUE (link), pre_p, NULL,
! is_simple_val, fb_rvalue);
for (link = ASM_OUTPUTS (expr); link; link = TREE_CHAIN (link))
simplify_expr (&TREE_VALUE (link), pre_p, NULL,
is_simple_modify_expr_lhs, fb_lvalue);
}
/* Apply FN to each statement under *STMT_P, which may be a COMPOUND_EXPR
--- 2047,2071 ----
{
tree link;
! ASM_STRING (expr)
! = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
! ASM_INPUTS (expr));
for (link = ASM_OUTPUTS (expr); link; link = TREE_CHAIN (link))
simplify_expr (&TREE_VALUE (link), pre_p, NULL,
is_simple_modify_expr_lhs, fb_lvalue);
+
+ for (link = ASM_INPUTS (expr); link; link = TREE_CHAIN (link))
+ {
+ /* If the operand is a memory input, it should be an lvalue. */
+ if (asm_op_is_mem_input (link, expr))
+ simplify_expr (&TREE_VALUE (link), pre_p, NULL,
+ is_simple_modify_expr_lhs, fb_lvalue);
+ else
+ simplify_expr (&TREE_VALUE (link), pre_p, NULL,
+ is_simple_val, fb_rvalue);
+ }
+
}
/* Apply FN to each statement under *STMT_P, which may be a COMPOUND_EXPR