This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix ASM_EXPR handling in tree-nested.c and omp-low.c (PRs middle-end/30262, middle-end/30263)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Diego Novillo <dnovillo at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Wed, 20 Dec 2006 11:22:05 -0500
- Subject: [PATCH] Fix ASM_EXPR handling in tree-nested.c and omp-low.c (PRs middle-end/30262, middle-end/30263)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following testcases ICE (or some subset of them is just rejected valid
code). The problem is that walk_stmts (which is used by both tree-nested.c
changes as well as omp lowering) isn't ASM_EXPR aware. Even when output
operands of ASM_EXPR aren't LHS of a GIMPLE_MODIFY_STMT, they are lvalues
the ASM_EXPR modifies, also for constraints which don't allow a reg and
allow a mem we can't allow setting a temporary variable and later copying
that value to its final location, as ASM_EXPR implicitly takes address
of the "m" operand. Similarly, input "m" operands, eventhough they aren't
really written into, need to be lvalues and ASM_EXPR is taking their
address. The following patch fixes this.
Ok for trunk/4.2?
2006-12-20 Jakub Jelinek <jakub@redhat.com>
PR middle-end/30262
PR middle-end/30263
* tree-nested.c (walk_asm_expr): New function.
(walk_stmts): Use it for ASM_EXPR.
* gcc.c-torture/execute/20061220-1.c: New test.
* gcc.dg/gomp/asm-1.c: New test.
--- gcc/tree-nested.c.jj 2006-12-08 15:58:09.000000000 +0100
+++ gcc/tree-nested.c 2006-12-20 16:28:35.000000000 +0100
@@ -546,6 +546,47 @@ get_nl_goto_field (struct nesting_info *
return field;
}
+/* Helper function for walk_stmts. Walk output operands of an ASM_EXPR. */
+
+static void
+walk_asm_expr (struct walk_stmt_info *wi, tree stmt)
+{
+ int noutputs = list_length (ASM_OUTPUTS (stmt));
+ const char **oconstraints
+ = (const char **) alloca ((noutputs) * sizeof (const char *));
+ int i;
+ tree link;
+ const char *constraint;
+ bool allows_mem, allows_reg, is_inout;
+
+ wi->is_lhs = true;
+ for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
+ {
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ oconstraints[i] = constraint;
+ parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+ &allows_reg, &is_inout);
+
+ wi->val_only = (allows_reg || !allows_mem);
+ walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+ }
+
+ for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+ {
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg);
+
+ wi->val_only = (allows_reg || !allows_mem);
+ /* Although input "m" is not really a LHS, we need a lvalue. */
+ wi->is_lhs = !wi->val_only;
+ walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+ }
+
+ wi->is_lhs = false;
+ wi->val_only = true;
+}
+
/* Iterate over all sub-statements of *TP calling walk_tree with
WI->CALLBACK for every sub-expression in each statement found. */
@@ -628,6 +669,10 @@ walk_stmts (struct walk_stmt_info *wi, t
wi->is_lhs = false;
break;
+ case ASM_EXPR:
+ walk_asm_expr (wi, *tp);
+ break;
+
default:
wi->val_only = true;
walk_tree (tp, wi->callback, wi, NULL);
--- gcc/testsuite/gcc.c-torture/execute/20061220-1.c.jj 2006-12-20 15:40:09.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20061220-1.c 2006-12-20 15:39:33.000000000 +0100
@@ -0,0 +1,72 @@
+/* PR middle-end/30262 */
+extern void abort (void);
+
+int
+foo (void)
+{
+ unsigned int x = 0;
+
+ void nested (void)
+ {
+ x = 254;
+ }
+
+ nested ();
+ asm volatile ("" :: "r" (x));
+ asm volatile ("" :: "m" (x));
+ asm volatile ("" :: "mr" (x));
+ asm volatile ("" : "=r" (x) : "0" (x));
+ asm volatile ("" : "=m" (x) : "m" (x));
+ return x;
+}
+
+int
+bar (void)
+{
+ unsigned int x = 0;
+
+ void nested (void)
+ {
+ asm volatile ("" :: "r" (x));
+ asm volatile ("" :: "m" (x));
+ asm volatile ("" :: "mr" (x));
+ x += 4;
+ asm volatile ("" : "=r" (x) : "0" (x));
+ asm volatile ("" : "=m" (x) : "m" (x));
+ }
+
+ nested ();
+ return x;
+}
+
+int
+baz (void)
+{
+ unsigned int x = 0;
+
+ void nested (void)
+ {
+ void nested2 (void)
+ {
+ asm volatile ("" :: "r" (x));
+ asm volatile ("" :: "m" (x));
+ asm volatile ("" :: "mr" (x));
+ x += 4;
+ asm volatile ("" : "=r" (x) : "0" (x));
+ asm volatile ("" : "=m" (x) : "m" (x));
+ }
+ nested2 ();
+ nested2 ();
+ }
+
+ nested ();
+ return x;
+}
+
+int
+main (void)
+{
+ if (foo () != 254 || bar () != 4 || baz () != 8)
+ abort ();
+ return 0;
+}
--- gcc/testsuite/gcc.dg/gomp/asm-1.c.jj 2006-12-20 16:35:57.000000000 +0100
+++ gcc/testsuite/gcc.dg/gomp/asm-1.c 2006-12-20 16:36:41.000000000 +0100
@@ -0,0 +1,19 @@
+/* PR middle-end/30263 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fopenmp" } */
+
+void
+foo (void)
+{
+ int s0, s1 = 5, s2 = 6;
+ int p0, p1, p2;
+ int f0 = 4, f1 = 5, f2 = 6;
+#pragma omp parallel shared (s0, s1, s2) private (p0, p1, p2) \
+ firstprivate (f0, f1, f2)
+ {
+ asm ("" : "=m" (p0) : "m" (p1), "mr" (p2));
+ if (omp_get_thread_num () == 0)
+ asm ("" : "=m" (s0) : "m" (s1), "mr" (s2));
+ asm ("" : "=m" (f0) : "m" (f1), "mr" (f2));
+ }
+}
Jakub