https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120400

            Bug ID: 120400
           Summary: C++ FE optimisations reorder && operands.
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: iains at gcc dot gnu.org
                CC: jason at gcc dot gnu.org
  Target Milestone: ---

In the coroutines code we need to guard some accesses to frame data - since
that might become invalidated by completion of a coroutine body.

So we have code-gen like this:

      tree fr_cleanup_if = begin_if_stmt ();
      tree cond = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, iarc_x);
      cond = build2_loc (loc, TRUTH_ANDIF_EXPR, boolean_type_node,
                         coro_before_return, cond);
      finish_if_stmt_cond (cond, fr_cleanup_if);
      finish_expr_stmt (delete_frame_call);
      finish_then_clause (fr_cleanup_if);
      finish_if_stmt (fr_cleanup_if);

The intention is that "coro_before_return" guards the (potentially) unsafe
access of iarc_x.

When we build this with O0 then:

0) coroutine codegen:
        s  if (E |EC|test::_Coro_before_return &&
!test::_Coro_initial_await_resume_called)
          CxE operator delete (E (void*)E cvt[coro::promise_type*,VD
test::_Coro_frameptr], E 40);<<s-cleanup point>>

1) tree-original:

      if (_Coro_before_returnD.9342 &&
!_Coro_initial_await_resume_calledD.9343)
        {

2) gimple:

          if (_Coro_before_returnD.9342 != 0) goto <D.9486>; else goto
<D.9487>;
          <D.9486>:
          _3 = _Coro_frameptrD.9340->_Coro_initial_await_resume_calledD.9326;
          _4 = ~_3;
          if (_4 != 0) goto <D.9488>; else goto <D.9489>;
          <D.9488>:

=== All OK and doing what's expected.

When we build at O1+:

0) coroutine codegen
        s  if (E |EC|test::_Coro_before_return &&
!test::_Coro_initial_await_resume_called)
(same)

1) tree-original:
      if (!_Coro_initial_await_resume_calledD.9346 &&
_Coro_before_returnD.9345)

ouch! .. the operands are reversed - UB can happen

2) tree-gimple:

          _3 = _Coro_frameptrD.9343->_Coro_initial_await_resume_calledD.9329;
          _4 = ~_3;
          _5 = _Coro_before_returnD.9345 & _4;
          if (_5 != 0) goto <D.9490>; else goto <D.9491>;

and this is even worse, it's all unconditional.

========

I guess this is happening in folding or genericization.

Perhaps the argument is that "it's OK to reorder" because if any of the
operations would be UB then we can do what we like... however, that does rather
make defensive programming hard.

I'd categorise it as wrong-code .. but perhaps I'm missing something.

Reply via email to