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]
Other format: [Raw text]

[C++ PATCH] Fix ICE with inline asm and MODIFY_EXPR/preinc/predec in output operand (PR c++/84961)


Hi!

While in C, x = 10 or ++x or --x aren't lvalues and so we reject such
expressions in inline asm output operands (and inputs that only allow
memory, not registers), in C++ they apparently are lvalues; for output
operands we ICE in the gimplifier on this, because in the generic code
MODIFY_EXPR or PREINCREMENT_EXPR or PREDECREMENT_EXPR aren't considered
to be lvalues, and for "m" inputs we just reject them, but when those
expressions are allowed on lhs of a store, they should be IMHO allowed
as "m" inputs too.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

2018-03-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/84961
	* semantics.c (finish_asm_stmt): Replace MODIFY_EXPR, PREINCREMENT_EXPR
	and PREDECREMENT_EXPR in output and "m" constrained input operands with
	COMPOUND_EXPR.  Call cxx_mark_addressable on the rightmost
	COMPOUND_EXPR operand.

	* c-c++-common/pr43690.c: Don't expect errors on "m" (--x) and
	"m" (++x) in C++.
	* g++.dg/torture/pr84961-1.C: New test.
	* g++.dg/torture/pr84961-2.C: New test.

--- gcc/cp/semantics.c.jj	2018-03-20 11:58:17.069356145 +0100
+++ gcc/cp/semantics.c	2018-03-20 21:56:43.745292245 +0100
@@ -1512,6 +1512,26 @@ finish_asm_stmt (int volatile_p, tree st
 		      && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
 	    cxx_readonly_error (operand, lv_asm);
 
+	  tree *op = &operand;
+	  while (TREE_CODE (*op) == COMPOUND_EXPR)
+	    op = &TREE_OPERAND (*op, 1);
+	  switch (TREE_CODE (*op))
+	    {
+	    case PREINCREMENT_EXPR:
+	    case PREDECREMENT_EXPR:
+	    case MODIFY_EXPR:
+	      if (TREE_SIDE_EFFECTS (TREE_OPERAND (*op, 0)))
+		*op = build2 (TREE_CODE (*op), TREE_TYPE (*op),
+			      cp_stabilize_reference (TREE_OPERAND (*op, 0)),
+			      TREE_OPERAND (*op, 1));
+	      *op = build2 (COMPOUND_EXPR, TREE_TYPE (*op), *op,
+			    TREE_OPERAND (*op, 0));
+	      op = &TREE_OPERAND (*op, 1);
+	      break;
+	    default:
+	      break;
+	    }
+
 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
 	  oconstraints[i] = constraint;
 
@@ -1520,7 +1540,7 @@ finish_asm_stmt (int volatile_p, tree st
 	    {
 	      /* If the operand is going to end up in memory,
 		 mark it addressable.  */
-	      if (!allows_reg && !cxx_mark_addressable (operand))
+	      if (!allows_reg && !cxx_mark_addressable (*op))
 		operand = error_mark_node;
 	    }
 	  else
@@ -1562,7 +1582,30 @@ finish_asm_stmt (int volatile_p, tree st
 		  /* Strip the nops as we allow this case.  FIXME, this really
 		     should be rejected or made deprecated.  */
 		  STRIP_NOPS (operand);
-		  if (!cxx_mark_addressable (operand))
+
+		  tree *op = &operand;
+		  while (TREE_CODE (*op) == COMPOUND_EXPR)
+		    op = &TREE_OPERAND (*op, 1);
+		  switch (TREE_CODE (*op))
+		    {
+		    case PREINCREMENT_EXPR:
+		    case PREDECREMENT_EXPR:
+		    case MODIFY_EXPR:
+		      if (TREE_SIDE_EFFECTS (TREE_OPERAND (*op, 0)))
+			*op
+			  = build2 (TREE_CODE (*op), TREE_TYPE (*op),
+				    cp_stabilize_reference (TREE_OPERAND (*op,
+							    0)),
+				    TREE_OPERAND (*op, 1));
+		      *op = build2 (COMPOUND_EXPR, TREE_TYPE (*op), *op,
+				    TREE_OPERAND (*op, 0));
+		      op = &TREE_OPERAND (*op, 1);
+		      break;
+		    default:
+		      break;
+		    }
+
+		  if (!cxx_mark_addressable (*op))
 		    operand = error_mark_node;
 		}
 	      else if (!allows_reg && !allows_mem)
--- gcc/testsuite/c-c++-common/pr43690.c.jj	2010-11-09 13:58:21.000000000 +0100
+++ gcc/testsuite/c-c++-common/pr43690.c	2018-03-20 21:58:43.077317034 +0100
@@ -6,8 +6,8 @@ void
 foo (char *x)
 {
   asm ("" : : "m" (x++));	/* { dg-error "is not directly addressable" } */
-  asm ("" : : "m" (++x));	/* { dg-error "is not directly addressable" } */
+  asm ("" : : "m" (++x));	/* { dg-error "is not directly addressable" "" { target c } } */
   asm ("" : : "m" (x--));	/* { dg-error "is not directly addressable" } */
-  asm ("" : : "m" (--x));	/* { dg-error "is not directly addressable" } */
+  asm ("" : : "m" (--x));	/* { dg-error "is not directly addressable" "" { target c } } */
   asm ("" : : "m" (x + 1));	/* { dg-error "is not directly addressable" } */
 }
--- gcc/testsuite/g++.dg/torture/pr84961-1.C.jj	2018-03-20 21:51:17.231238830 +0100
+++ gcc/testsuite/g++.dg/torture/pr84961-1.C	2018-03-20 21:51:17.231238830 +0100
@@ -0,0 +1,24 @@
+// PR c++/84961
+// { dg-do compile }
+
+short a;
+volatile int b;
+int c, d;
+
+void
+foo ()
+{
+  asm volatile ("" : "=r" (b = a));
+}
+
+void
+bar ()
+{
+  asm volatile ("" : "=r" (++c, ++d, b = a));
+}
+
+void
+baz ()
+{
+  asm volatile ("" : "=r" (--b));
+}
--- gcc/testsuite/g++.dg/torture/pr84961-2.C.jj	2018-03-20 21:51:17.231238830 +0100
+++ gcc/testsuite/g++.dg/torture/pr84961-2.C	2018-03-20 21:51:17.231238830 +0100
@@ -0,0 +1,24 @@
+// PR c++/84961
+// { dg-do compile }
+
+short a;
+volatile int b;
+int c, d;
+
+void
+foo ()
+{
+  asm volatile ("" : : "m" (b = a));
+}
+
+void
+bar ()
+{
+  asm volatile ("" : : "m" (++c, ++d, b = a));
+}
+
+void
+baz ()
+{
+  asm volatile ("" : : "m" (--b));
+}

	Jakub


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