This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [C++ PATCH] Fix ICE with inline asm and MODIFY_EXPR/preinc/predec in output operand (PR c++/84961, take 2)
- From: Jason Merrill <jason at redhat dot com>
- To: Jakub Jelinek <jakub at redhat dot com>
- Cc: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 21 Mar 2018 13:51:40 -0400
- Subject: Re: [C++ PATCH] Fix ICE with inline asm and MODIFY_EXPR/preinc/predec in output operand (PR c++/84961, take 2)
- References: <20180320210452.GF8577@tucnak> <CADzB+2=NTxq8r5E4eK2G2Dng+Mb1a0AWzfhaCakNv+UfrSJpFg@mail.gmail.com> <20180321102606.GI8577@tucnak> <CADzB+2nFCJ22kAYGSTB1ZimqaN92D9CaBd+qP0sOKc6n1J=ybA@mail.gmail.com> <20180321174716.GM8577@tucnak>
OK.
On Wed, Mar 21, 2018 at 1:47 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Mar 21, 2018 at 01:01:38PM -0400, Jason Merrill wrote:
>> >> Hmm, it would be nice to share this with the similar patterns in
>> >> unary_complex_lvalue and cp_build_modify_expr.
>>
>> > You mean just outline the
>> > if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
>> > lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
>> > cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
>> > TREE_OPERAND (lhs, 1));
>> > lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
>> > into lhs = some_function (lhs); and use that in finish_asm_stmt,
>> > unary_complex_lvalue and cp_build_modify_expr in these spots?
>>
>> > I really have no idea how to commonize anything else, e.g. the COMPOUND_EXPR
>> > handling is substantially different between the 3 functions.
>>
>> > Any suggestion for the some_function name if you want that?
>>
>> Sure, that's something. How about genericize_compound_lvalue?
>
> So like this (if it passes bootstrap/regtest)?
>
> 2018-03-21 Jakub Jelinek <jakub@redhat.com>
>
> PR c++/84961
> * cp-tree.h (genericize_compound_lvalue): Declare.
> * typeck.c (genericize_compound_lvalue): New function.
> (unary_complex_lvalue, cp_build_modify_expr): Use it.
> * 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/cp-tree.h.jj 2018-03-20 22:05:57.053431471 +0100
> +++ gcc/cp/cp-tree.h 2018-03-21 18:41:42.301838677 +0100
> @@ -7145,6 +7145,7 @@ extern tree cp_build_addressof (locati
> extern tree cp_build_addr_expr (tree, tsubst_flags_t);
> extern tree cp_build_unary_op (enum tree_code, tree, bool,
> tsubst_flags_t);
> +extern tree genericize_compound_lvalue (tree);
> extern tree unary_complex_lvalue (enum tree_code, tree);
> extern tree build_x_conditional_expr (location_t, tree, tree, tree,
> tsubst_flags_t);
> --- gcc/cp/typeck.c.jj 2018-03-06 08:01:37.827883402 +0100
> +++ gcc/cp/typeck.c 2018-03-21 18:40:23.350862956 +0100
> @@ -6357,6 +6357,25 @@ build_unary_op (location_t /*location*/,
> return cp_build_unary_op (code, xarg, noconvert, tf_warning_or_error);
> }
>
> +/* Adjust LVALUE, an MODIFY_EXPR, PREINCREMENT_EXPR or PREDECREMENT_EXPR,
> + so that it is a valid lvalue even for GENERIC by replacing
> + (lhs = rhs) with ((lhs = rhs), lhs)
> + (--lhs) with ((--lhs), lhs)
> + (++lhs) with ((++lhs), lhs)
> + and if lhs has side-effects, calling cp_stabilize_reference on it, so
> + that it can be evaluated multiple times. */
> +
> +tree
> +genericize_compound_lvalue (tree lvalue)
> +{
> + if (TREE_SIDE_EFFECTS (TREE_OPERAND (lvalue, 0)))
> + lvalue = build2 (TREE_CODE (lvalue), TREE_TYPE (lvalue),
> + cp_stabilize_reference (TREE_OPERAND (lvalue, 0)),
> + TREE_OPERAND (lvalue, 1));
> + return build2 (COMPOUND_EXPR, TREE_TYPE (TREE_OPERAND (lvalue, 0)),
> + lvalue, TREE_OPERAND (lvalue, 0));
> +}
> +
> /* Apply unary lvalue-demanding operator CODE to the expression ARG
> for certain kinds of expressions which are not really lvalues
> but which we can accept as lvalues.
> @@ -6391,17 +6410,7 @@ unary_complex_lvalue (enum tree_code cod
> if (TREE_CODE (arg) == MODIFY_EXPR
> || TREE_CODE (arg) == PREINCREMENT_EXPR
> || TREE_CODE (arg) == PREDECREMENT_EXPR)
> - {
> - tree lvalue = TREE_OPERAND (arg, 0);
> - if (TREE_SIDE_EFFECTS (lvalue))
> - {
> - lvalue = cp_stabilize_reference (lvalue);
> - arg = build2 (TREE_CODE (arg), TREE_TYPE (arg),
> - lvalue, TREE_OPERAND (arg, 1));
> - }
> - return unary_complex_lvalue
> - (code, build2 (COMPOUND_EXPR, TREE_TYPE (lvalue), arg, lvalue));
> - }
> + return unary_complex_lvalue (code, genericize_compound_lvalue (arg));
>
> if (code != ADDR_EXPR)
> return NULL_TREE;
> @@ -7887,11 +7896,7 @@ cp_build_modify_expr (location_t loc, tr
> case PREINCREMENT_EXPR:
> if (compound_side_effects_p)
> newrhs = rhs = stabilize_expr (rhs, &preeval);
> - if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
> - lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
> - cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
> - TREE_OPERAND (lhs, 1));
> - lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
> + lhs = genericize_compound_lvalue (lhs);
> maybe_add_compound:
> /* If we had (bar, --foo) = 5; or (bar, (baz, --foo)) = 5;
> and looked through the COMPOUND_EXPRs, readd them now around
> @@ -7914,11 +7919,7 @@ cp_build_modify_expr (location_t loc, tr
> case MODIFY_EXPR:
> if (compound_side_effects_p)
> newrhs = rhs = stabilize_expr (rhs, &preeval);
> - if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
> - lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
> - cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
> - TREE_OPERAND (lhs, 1));
> - lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
> + lhs = genericize_compound_lvalue (lhs);
> goto maybe_add_compound;
>
> case MIN_EXPR:
> --- gcc/cp/semantics.c.jj 2018-03-20 22:05:54.385430766 +0100
> +++ gcc/cp/semantics.c 2018-03-21 18:42:50.084817830 +0100
> @@ -1512,6 +1512,21 @@ 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:
> + *op = genericize_compound_lvalue (*op);
> + op = &TREE_OPERAND (*op, 1);
> + break;
> + default:
> + break;
> + }
> +
> constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
> oconstraints[i] = constraint;
>
> @@ -1520,7 +1535,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 +1577,23 @@ 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:
> + *op = genericize_compound_lvalue (*op);
> + 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 2018-03-20 22:05:54.237430727 +0100
> +++ gcc/testsuite/c-c++-common/pr43690.c 2018-03-21 18:26:40.348908281 +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-21 18:26:40.349908281 +0100
> +++ gcc/testsuite/g++.dg/torture/pr84961-1.C 2018-03-21 18:26:40.349908281 +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-21 18:26:40.349908281 +0100
> +++ gcc/testsuite/g++.dg/torture/pr84961-2.C 2018-03-21 18:26:40.349908281 +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