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

--- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
To sum up IRC discussion with richi, he doesn't want this to be in the
gimplifier, as it is one FE specific, which means cp-gimplify.c is where this
needs to be done.
Furthermore, if we there have a predicate which for flag_strong_eval_order == 2
will fail for user decls (note, I still don't know how to safely recognize the
"safe" gimple temporaries), we could force stuff into temporaries too often,
e.g. for this case, we only need to do it if the other operand that is to be
sequenced after has side-effects.
So, I thought something along the lines of:
--- gcc/cp/cp-gimplify.c.jj     2019-10-04 08:53:01.737740712 +0200
+++ gcc/cp/cp-gimplify.c        2019-10-04 10:15:07.629709617 +0200
@@ -884,6 +884,29 @@ cp_gimplify_expr (tree *expr_p, gimple_s
        }
       break;

+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      /* If the second operand has side-effects, ensure the first operand
+        is evaluated first and is not a decl that the side-effects of the
+        second operand could modify.  */
+      if (flag_strong_eval_order == 2
+         && TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1)))
+       {
+         enum gimplify_status t
+           = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                            is_gimple_val, fb_rvalue);
+         if (t == GS_ERROR)
+           break;
+         else if (is_gimple_variable (TREE_OPERAND (*expr_p, 0))
+                  && TREE_CODE (TREE_OPERAND (*expr_p, 0)) != SSA_NAME)
+           TREE_OPERAND (*expr_p, 0)
+             = get_initialized_tmp_var (TREE_OPERAND (*expr_p, 0), pre_p,
+                                        NULL);
+       }
+      goto do_default;      
+
     case RETURN_EXPR:
       if (TREE_OPERAND (*expr_p, 0)
          && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR
@@ -897,6 +920,7 @@ cp_gimplify_expr (tree *expr_p, gimple_s
        }
       /* Fall through.  */

+    do_default:
     default:
       ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
       break;

and similarly for the other occurrences of E? is sequenced before E? in the
standard.
Unfortunately, on the above testcase this doesn't work, because it is already
broken earlier, fold_binary_loc (invoked during cp_fold) has:
  if (TREE_CODE_CLASS (code) == tcc_binary
      || TREE_CODE_CLASS (code) == tcc_comparison)
    {
      if (TREE_CODE (arg0) == COMPOUND_EXPR)
        {
          tem = fold_build2_loc (loc, code, type,
                             fold_convert_loc (loc, TREE_TYPE (op0),
                                               TREE_OPERAND (arg0, 1)), op1);
          return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
                             tem);
        }
      if (TREE_CODE (arg1) == COMPOUND_EXPR)
        {
          tem = fold_build2_loc (loc, code, type, op0,
                             fold_convert_loc (loc, TREE_TYPE (op1),
                                               TREE_OPERAND (arg1, 1)));
          return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
                             tem);
        }
where the last if is invalid for the shifts (and rotates?) in
flag_strict_eval_order == 2 (at least if TREE_SIDE_EFFECTS (TREE_OPERAND (arg1,
1)), but for a COMPOUND_EXPR it would likely be optimized into just the last
operand if the first one doesn't have side-effects).

Reply via email to