public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ delayed folding branch review
@ 2015-06-12  5:41 Jason Merrill
  2015-06-12 16:17 ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-06-12  5:41 UTC (permalink / raw)
  To: Kai Tietz; +Cc: gcc-patches List

Generally, it seems like most of my comments from April haven't been 
addressed yet.

> @@ -3023,13 +3023,14 @@ conversion_warning (location_t loc, tree type, tree expr

Instead of adding folds here, let's make sure that the argument we pass 
(e.g. from cp_convert_and_check to warnings_for_convert_and_check) is 
fully folded.

> @@ -589,9 +589,9 @@ null_member_pointer_value_p (tree t)
>      return false;
>    else if (TYPE_PTRMEMFUNC_P (type))
>      return (TREE_CODE (t) == CONSTRUCTOR
> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>    else if (TYPE_PTRDATAMEM_P (type))
> -    return integer_all_onesp (t);
> +    return integer_all_onesp (fold (t));

Again, calling fold here is wrong; it doesn't handle constexpr, and we 
should have folded before we got here.

> @@ -5090,9 +5090,9 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
>
>   valid_operands:
>    result = build3 (COND_EXPR, result_type, arg1, arg2, arg3);
> -  if (!cp_unevaluated_operand)
> +  if (!cp_unevaluated_operand && !processing_template_decl)
>      /* Avoid folding within decltype (c++/42013) and noexcept.  */
> -    result = fold_if_not_in_template (result);
> +    result = fold (result);

This seems related to your status report note:

> Additionally addressed issue about cond_expr, as we want to fold cases with a constant-condition.  Here we need to use "fold_to_constant" so that we just fold things to constant-value, if possible and otherwise don't modify anything.

But why do you say we want to fold cases with a constant condition?  We 
certainly want to avoid warning about the dead branch in that case, but 
it would be better if we can do that folding only in the warning code.

> @@ -5628,8 +5628,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int f
> lags, tree arg1,
>                  decaying an enumerator to its value.  */
>               if (complain & tf_warning)
>                 warn_logical_operator (loc, code, boolean_type_node,
> -                                      code_orig_arg1, arg1,
> -                                      code_orig_arg2, arg2);
> +                                      code_orig_arg1, fold (arg1),
> +                                      code_orig_arg2, fold (arg2));
>
>               arg2 = convert_like (conv, arg2, complain);
>             }
> @@ -5666,7 +5666,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int f
> lags, tree arg1,
>      case TRUTH_AND_EXPR:
>      case TRUTH_OR_EXPR:
>        warn_logical_operator (loc, code, boolean_type_node,
> -                            code_orig_arg1, arg1, code_orig_arg2, arg2);
> +                            code_orig_arg1, fold (arg1),
> +                            code_orig_arg2, fold (arg2));
>        /* Fall through.  */
>      case GT_EXPR:
>      case LT_EXPR:
> @@ -5676,7 +5677,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int f
> lags, tree arg1,
>      case NE_EXPR:
>        if ((code_orig_arg1 == BOOLEAN_TYPE)
>           ^ (code_orig_arg2 == BOOLEAN_TYPE))
> -       maybe_warn_bool_compare (loc, code, arg1, arg2);
> +       maybe_warn_bool_compare (loc, code, fold (arg1), fold (arg2));
>        /* Fall through.  */
>      case PLUS_EXPR:
>      case MINUS_EXPR:

I still think these fold calls should be cp_fully_fold.

> @@ -7382,8 +7383,13 @@ build_over_call (struct z_candidate *cand, int flags, tsu
> bst_flags_t complain)
>
>    gcc_assert (j <= nargs);
>    nargs = j;
> +  {
> +    tree *fargs = (!nargs ? argarray : (tree *) alloca (nargs * sizeof (tree)))
> ;
> +    for (j = 0; j < nargs; j++)
> +      fargs[j] = fold_non_dependent_expr (argarray[j]);

No change needed here, but I notice that fold_non_dependent_expr is 
still using maybe_constant_value; it should probably use cp_fully_fold 
instead.

> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>  {
>    if (TREE_TYPE (temp) == type)
>      return temp;
> +  STRIP_NOPS (temp);
> +  if (TREE_TYPE (temp) == type)
> +    return temp;
> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>  bool
>  reduced_constant_expression_p (tree t)
>  {
> +  /* Make sure we remove useless initial NOP_EXPRs.  */
> +  STRIP_NOPS (t);

Within the constexpr code we should be folding away NOPs as they are 
generated, they shouldn't live this long.

> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
>           && is_dummy_object (x))
>         {
>           x = ctx->object;
> -         x = cp_build_addr_expr (x, tf_warning_or_error);
> +         if (x)
> +           x = cp_build_addr_expr (x, tf_warning_or_error);
> +         else
> +           x = get_nth_callarg (t, i);

This still should not be necessary.

> @@ -1576,13 +1586,15 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tre
> e t,
>    enum tree_code code = TREE_CODE (t);
>    tree type = TREE_TYPE (t);
>    r = fold_unary_loc (loc, code, type, arg);
> -  if (r == NULL_TREE)
> +  if (r == NULL_TREE || !CONSTANT_CLASS_P (r))
>      {
>        if (arg == orig_arg)
>         r = t;
>        else
>         r = build1_loc (loc, code, type, arg);
>      }
> +  else
> +    r = unify_constant (ctx, r, overflow_p);

This still should not be necessary.

> @@ -1780,7 +1792,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>        if (field == part)
>         {
>           if (value)
> -           return value;
> +           return cxx_eval_constant_expression (ctx, value, lval,
> +                                                non_constant_p, overflow_p);
>           else
>             /* We're in the middle of initializing it.  */
>             break;
> @@ -1864,7 +1877,8 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
>      {
>        tree bitpos = bit_position (field);
>        if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
> -       return value;
> +       return cxx_eval_constant_expression (ctx, value, lval,
> +                                             non_constant_p, overflow_p);
>        if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
>           && TREE_CODE (value) == INTEGER_CST
>           && tree_fits_shwi_p (bitpos)

Again, this shouldn't be necessary, either; the elements of the 
CONSTRUCTOR should be fully evaluated already.

> @@ -2987,19 +3017,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>    constexpr_ctx new_ctx;
>    tree r = t;
>
> -  if (t == error_mark_node)
> +  if (!t || t == error_mark_node)
>      {
>        *non_constant_p = true;
> -      return t;
> +      return error_mark_node;
>      }
> @@ -3761,6 +3819,8 @@ fold_non_dependent_expr (tree t)
>  tree
>  maybe_constant_init (tree t, tree decl)
>  {
> +  if (!t)
> +    return t;

You were going to test whether the null check was necessary.  What was 
the result?

>      case SIZEOF_EXPR:
> +      if (processing_template_decl
> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
> +       return t;

Why is this necessary?

> @@ -3368,6 +3399,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>         /* Don't re-process a constant CONSTRUCTOR, but do fold it to
>            VECTOR_CST if applicable.  */
>         return fold (t);
> +      /* See this can happen for case like g++.dg/init/static2.C testcase.  */
> +      if (!ctx || !ctx->ctor || (lval && !ctx->object)
> +         || !same_type_ignoring_top_level_qualifiers_p
> +              (TREE_TYPE (t), TREE_TYPE (ctx->ctor))
> +         || CONSTRUCTOR_NELTS (ctx->ctor) != 0)
> +       {
> +         *non_constant_p = true;
> +         break;
> +       }

Why does this happen for static2.C when it doesn't happen on the trunk? 
  I think the bug is somewhere else.

> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>      case CONVERT_EXPR:
>      case VIEW_CONVERT_EXPR:
>      case NOP_EXPR:
> +    case UNARY_PLUS_EXPR:
>        {
> +       enum tree_code tcode = TREE_CODE (t);
>         tree oldop = TREE_OPERAND (t, 0);
> +
> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) && TREE_OVERFLOW_P (oldop))
> +         {
> +           if (!ctx->quiet)
> +             permerror (input_location, "overflow in constant expression");
> +           /* If we're being permissive (and are in an enforcing
> +               context), ignore the overflow.  */
> +           if (!flag_permissive)
> +             *overflow_p = true;
> +           *non_constant_p = true;
> +
> +           return t;
> +         }
>         tree op = cxx_eval_constant_expression (ctx, oldop,

Why doesn't the call to cxx_eval_constant_expression at the bottom here 
handle oldop having TREE_OVERFLOW set?

> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
>
>    switch (code)
>      {
> +    case SIZEOF_EXPR:
> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (*expr_p,
> +                                                                      0)),
> +                                             SIZEOF_EXPR, false);
> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p, 0),
> +                                             SIZEOF_EXPR, false);
> +      else
> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p, 0),
> +                                             SIZEOF_EXPR, false);
> +      if (*expr_p == error_mark_node)
> +       *expr_p = size_one_node;
> +
> +      *expr_p = maybe_constant_value (*expr_p);
> +      ret = GS_OK;
> +      break;

Why are these surviving until gimplification time?

> +static tree
> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)

Looks like cp_fold still doesn't call maybe_constant_value.

> +  case CALL_EXPR:
> +    r = fold (x);
> +    if (TREE_CODE (r) != CALL_EXPR)
> +      {
> +       x = cp_fold (r, fold_hash);
> +       break;
> +      }
> +    {
> +      int i, m = call_expr_nargs (x);
> +      for (i = 0; i < m; i++)
> +        {
> +         CALL_EXPR_ARG (x, i) = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
> +       }
> +    }
> +    r = fold (x);
> +    if (TREE_CODE (r) != CALL_EXPR)
> +      {
> +       x = cp_fold (r, fold_hash);
> +       break;
> +      }
> +    return org_x;

Why return org_x here?  Don't we still want to add this to the hash table?

I'm also nervous about clobbering the args in the original CALL_EXPR. 
In most of cp_fold you build a new expression rather than change the 
operands of the original one.

> @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
>      }
>    else
>      {
> -      conv = fold_convert (type, expr);
> +      if (TREE_CODE (expr) == INTEGER_CST)
> +        conv = fold_convert (type, expr);
> +      else
> +        conv = convert (type, expr);

I still think that cp_fold_convert should always call fold_convert, and 
callers that we don't want to fold should call convert instead, or 
another function that folds only conversion of constants.  We had talked 
about the name "fold_cst", but I think that name isn't very clear; would 
it make sense to just have convert always fold conversions of constants?

> @@ -632,12 +636,12 @@ cp_convert (tree type, tree expr, tsubst_flags_t complain)
>  tree
>  cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>  {
> -  tree result;
> +  tree result, ret;
>
>    if (TREE_TYPE (expr) == type)
>      return expr;
>
> -  result = cp_convert (type, expr, complain);
> +  result = ret = cp_convert (type, expr, complain);
>
>    if ((complain & tf_warning)
>        && c_inhibit_evaluation_warnings == 0)
> @@ -646,6 +650,7 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>        tree stripped = folded;
>        tree folded_result
>         = folded != expr ? cp_convert (type, folded, complain) : result;
> +      folded_result = fold (folded_result);
>
>        /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
>          NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
> @@ -657,7 +662,7 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>                                         folded_result);
>      }
>
> -  return result;
> +  return ret;
>  }

Again, there seems to be no reason to introduce the new "ret" variable.

> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
>    tree basetype = TREE_TYPE (expr);
>    tree conv = NULL_TREE;
>    tree winner = NULL_TREE;
> +  /* Want to see if EXPR is a constant.  See below checks for null_node.  */
> +  tree expr_folded = cp_try_fold_to_constant (expr);
>
> -  if (expr == null_node
> +  STRIP_NOPS (expr_folded);
> +  if (expr_folded == null_node

Again, we shouldn't need to fold to check for null_node, it only occurs 
when explicitly written.  Folding should never produce null_node unless 
the argument was already null_node.

> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
>      switch (TREE_CODE (basetype))
>        {
>        case INTEGER_TYPE:
> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))

Again, we don't want to fold before calling null_ptr_cst_p, since in 
C++11 only a literal 0 is a null pointer constant.  For C++98 we already 
fold in null_ptr_cst_p.

> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>        SET_TYPE_STRUCTURAL_EQUALITY (itype);
>        return itype;
>      }
> -
> +
> +  /* We need to do fully folding to determine if we have VLA, or not.  */
> +  tree size_constant = cp_try_fold_to_constant (size);

Again, we already called maybe_constant_value.

> @@ -8736,7 +8697,10 @@ create_array_type_for_decl (tree name, tree type, tree size)
>
>    /* Figure out the index type for the array.  */
>    if (size)
> -    itype = compute_array_index_type (name, size, tf_warning_or_error);
> +    {
> +      size = cp_try_fold_to_constant (size);
> +      itype = compute_array_index_type (name, size, tf_warning_or_error);
> +    }

There's no need to fold here and inside compute_array_index_type.

> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree enumtype, tree attributes,
>    if (value)
>      STRIP_TYPE_NOPS (value);
>
> +  if (value)
> +    value = cp_try_fold_to_constant (value);

Again, this is unnecessary because we call cxx_constant_value below.

> @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree enumtype, tree attributes,
>           if (value != NULL_TREE)
>             {
>               value = cxx_constant_value (value);
> +             STRIP_NOPS (value);

Again, the only time a constant result should have a NOP_EXPR around it 
is if it isn't really constant.  Why do you want to strip that?

> @@ -779,7 +779,8 @@ perform_member_init (tree member, tree init)
>            in that case.  */
>         init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
>                                                 tf_warning_or_error);
> -
> +      if (init)
> +       init = fold (init);

Again, why fold here, rather than later when something really wants a 
constant?  If that ever actually occurs?

> @@ -417,7 +417,9 @@ strip_using_decl (tree decl)
>    if (decl == NULL_TREE)
>      return NULL_TREE;
>
> -  while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
> +  while (TREE_CODE (decl) == USING_DECL
> +        && !DECL_DEPENDENT_P (decl)
> +        && !uses_template_parms (USING_DECL_SCOPE (decl)))

This seems unrelated to delayed folding.

> @@ -6136,6 +6139,10 @@ push_to_top_level (void)
>    else
>      need_pop = false;
>
> +  if (scope_chain)
> +    fm = scope_chain->fold_map;
> +  else
> +    fm = NULL;
>    if (scope_chain && previous_class_level)
>      store_class_bindings (previous_class_level->class_shadowed,
>                           &s->old_bindings);
> @@ -6167,6 +6174,9 @@ push_to_top_level (void)
>    FOR_EACH_VEC_SAFE_ELT (s->old_bindings, i, sb)
>      IDENTIFIER_MARKED (sb->identifier) = 0;
>
> +  if (!fm)
> +    fm = new hash_map<tree, tree>;

Why are these hunks so far apart?  I would expect them to be all together.

> @@ -6473,7 +6473,8 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
>          2. ARRAY [ EXP : EXP ]
>          3. ARRAY [ EXP : EXP : EXP ]  */
>
> -      *init_index = cp_parser_expression (parser);
> +      *init_index = cp_parser_expression (parser);
> +      *init_index = cp_try_fold_to_constant (*init_index);
>        if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
>         {
>           /* This indicates that we have a normal array expression.  */
> @@ -6484,10 +6485,12 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
>        /* Consume the ':'.  */
>        cp_lexer_consume_token (parser->lexer);
>        length_index = cp_parser_expression (parser);
> +      length_index = cp_try_fold_to_constant (length_index);
>        if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
>         {
>           cp_lexer_consume_token (parser->lexer);
>           stride = cp_parser_expression (parser);
> +         stride = cp_try_fold_to_constant (stride);

Again, why fold here, rather than later when something really wants a 
constant?  If that ever actually occurs?

> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
>         index = cp_parser_expression (parser);
>      }
>
> +  /* For offsetof and declaration of types we need
> +     constant integeral values.
> +     Also we meed to fold for negative constants so that diagnostic in
> +     c-family/c-common.c doesn't fail for array-bounds.  */
> +  if (for_offsetof || decltype_p
> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND (index, 0)) == INTEGER_CST))
> +    index = cp_try_fold_to_constant (index);

Similarly, for offsetof the folding should happen closer to where it is 
needed.

Why is it needed for decltype, which is querying the type of an expression?

For NEGATE_EXPR, we had talked about always folding a NEGATE of a 
constant; this isn't the right place to do it.

> @@ -8031,7 +8041,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
>                 return error_mark_node;
>
>               /* Perform the cast.  */
> -             expr = build_c_cast (input_location, type, expr);
> +             /* We don't want to resolve cast too early.  Therefore we don't
> +                be able to use build_c_cast.  */
> +             expr = cp_build_c_cast (type, expr, tf_warning_or_error);

Huh?  build_c_cast just calls cp_build_c_cast.

> @@ -9869,6 +9881,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
>         cp_lexer_consume_token (parser->lexer);
>         /* Parse the constant-expression.  */
>         expr = cp_parser_constant_expression (parser);
> +       expr = cp_try_fold_to_constant (expr);
>         if (check_for_bare_parameter_packs (expr))
>           expr = error_mark_node;
>
> @@ -9878,6 +9891,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
>             /* Consume the `...' token.  */
>             cp_lexer_consume_token (parser->lexer);
>             expr_hi = cp_parser_constant_expression (parser);
> +           expr_hi = cp_try_fold_to_constant (expr_hi);

Again, this seems redundant with the call to cxx_constant_value in 
case_conversion.

> @@ -12210,6 +12224,10 @@ cp_parser_static_assert(cp_parser *parser, bool member_p)
>                                     /*allow_non_constant_p=*/true,
>                                     /*non_constant_p=*/&dummy);
>
> +  /* Make sure we folded it completely before doing trying to get
> +     constant value.  */
> +  condition = fold_non_dependent_expr (condition);

Again, this is redundant with the code in finish_static_assert.

> @@ -16115,6 +16133,7 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
>        cp_lexer_consume_token (parser->lexer);
>        /* Parse the value.  */
>        value = cp_parser_constant_expression (parser);
> +      value = cp_try_fold_to_constant (value);

Again, this is redundant with the code in build_enumerator.

> @@ -17702,7 +17721,8 @@ cp_parser_direct_declarator (cp_parser* parser,
>              constant-expression.  */
>           if (token->type != CPP_CLOSE_SQUARE)
>             {
> -             bool non_constant_p;
> +             bool non_constant_p = false;

This is unnecessary, as cp_parser_constant_expression will set 
non_constant_p.

> @@ -19354,12 +19374,10 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
>    /* If it is not a `{', then we are looking at an
>       assignment-expression.  */
>    if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
> -    {
> -      initializer
> -       = cp_parser_constant_expression (parser,
> -                                       /*allow_non_constant_p=*/true,
> -                                       non_constant_p);
> -    }
> +    initializer
> +      = cp_parser_constant_expression (parser,
> +                                     /*allow_non_constant_p=*/true,
> +                                     non_constant_p);

Let's not reformat unrelated code in a big project like this.

> @@ -20955,9 +20973,11 @@ cp_parser_member_declaration (cp_parser* parser)
>
>               /* Consume the `:' token.  */
>               cp_lexer_consume_token (parser->lexer);
> +
>               /* Get the width of the bitfield.  */
>               width
>                 = cp_parser_constant_expression (parser);
> +             width = maybe_constant_value (width);

Again, this seems redundant with the call to cxx_constant_value in 
check_bitfield_decl.

Again, it seems like you added maybe_constant_value or 
cp_try_fold_to_constant after every occurrence of 
cp_parser_constant_expression, and I suspect that few are actually 
needed, and the ones that are should go closer to the code that really 
needs a constant.  I'd prefer to avoid calling it at all in parser.c.

>  finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
>                       tsubst_flags_t complain)
>  {
> +  tree expr_ovl = expr;
>    tree result = build_x_unary_op (loc, code, expr, complain);
> +  tree result_ovl = result;
> +
> +  STRIP_NOPS (expr_ovl);
> +  switch (code)
> +    {
> +    case ABS_EXPR:
> +    case NEGATE_EXPR:
> +      if (TREE_CODE (expr) == INTEGER_CST
> +         || TREE_CODE (expr) == REAL_CST
> +         || TREE_CODE (expr) == VECTOR_CST
> +         || TREE_CODE (expr) == FIXED_CST
> +         || TREE_CODE (expr) == COMPLEX_CST)
> +      result_ovl = fold (result);
> +      break;
> +    default:
> +      break;
> +    }

Not cp_fully_fold?

> @@ -6301,8 +6321,9 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv,
>                                     tf_warning_or_error);
>        if (error_operand_p (iter_incr))
>         return true;
> -      else if (TREE_CODE (incr) == PREINCREMENT_EXPR
> -              || TREE_CODE (incr) == POSTINCREMENT_EXPR)
> +      iter_incr = fold (iter_incr);
> +      if (TREE_CODE (incr) == PREINCREMENT_EXPR
> +         || TREE_CODE (incr) == POSTINCREMENT_EXPR)
> @@ -6357,6 +6376,7 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv,
>                                                  tf_warning_or_error);
>                   if (error_operand_p (iter_incr))
>                     return true;
> +                 iter_incr = fold (iter_incr);
>                   iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs),
>                                                    iter, NOP_EXPR,
>                                                    iter_incr,
> @@ -6364,6 +6384,7 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv,
>                   if (error_operand_p (iter_incr))
>                     return true;
>                   incr = TREE_OPERAND (rhs, 0);
> +                 incr = fold (incr);

Why are these folds needed?

> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>    else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>      fn = AGGR_INIT_EXPR_FN (init);
>    else
> -    return convert (type, init);
> +    return fold (convert (type, init));

Why fold here?

> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
>           && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>         val = TREE_OPERAND (val, 0);
>
> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
> +      if (fndecl && DECL_BUILT_IN (fndecl)
> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> +       val = fold (val);

Why?

> @@ -4941,7 +4938,7 @@ cp_build_binary_op (location_t location,
>              from being kept in a register.
>              Instead, make copies of the our local variables and
>              pass the copies by reference, then copy them back afterward.  */
> -         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
> +         tree xop0 = fold (op0), xop1 = fold (op1), xresult_type = result_type;

Again, this seems wrong.  In fact, the whole short_compare business 
seems like the sort of early folding we want to do away with.

> @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
>      }
>
>    result = build2 (resultcode, build_type, op0, op1);
> -  result = fold_if_not_in_template (result);
>    if (final_type != 0)
>      result = cp_convert (final_type, result, complain);
> -
> -  if (TREE_OVERFLOW_P (result)
> +  op0 = fold_non_dependent_expr (op0);
> +  op1 = fold_non_dependent_expr (op1);
> +  STRIP_NOPS (op0);
> +  STRIP_NOPS (op1);
> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
> +  if (TREE_OVERFLOW_P (result_ovl)
>        && !TREE_OVERFLOW_P (op0)
>        && !TREE_OVERFLOW_P (op1))
> -    overflow_warning (location, result);
> +    overflow_warning (location, result_ovl);

Don't you want to use cp_fully_fold here?

> @@ -7989,7 +7984,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
>        tree binfo = binfo_or_else (orig_class, fn_class);
>        *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
>                        *delta, BINFO_OFFSET (binfo));
> -      *delta = fold_if_not_in_template (*delta);
>
>        /* We set PFN to the vtable offset at which the function can be
>          found, plus one (unless ptrmemfunc_vbit_in_delta, in which
> @@ -7997,23 +7991,19 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
>        *pfn = DECL_VINDEX (fn);
>        *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
>                      TYPE_SIZE_UNIT (vtable_entry_type));
> -      *pfn = fold_if_not_in_template (*pfn);
>
>        switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
>         {
>         case ptrmemfunc_vbit_in_pfn:
>           *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
>                          integer_one_node);
> -         *pfn = fold_if_not_in_template (*pfn);
>           break;
>
>         case ptrmemfunc_vbit_in_delta:
>           *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
>                            *delta, integer_one_node);
> -         *delta = fold_if_not_in_template (*delta);
>           *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
>                            *delta, integer_one_node);
> -         *delta = fold_if_not_in_template (*delta);
>           break;
>
>         default:
> @@ -8021,7 +8011,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
>         }
>
>        *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
> -      *pfn = fold_if_not_in_template (*pfn);

Again, I think all the calls to fold_if_not_in_template in 
expand_ptrmemfunc_cst should become regular folds.  Or rather, change 
the build2 to fold_build2.  This is very much compiler internals, and we 
should only get here when folding anyway.

> @@ -1866,7 +1866,8 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
>           }
>           break;
>         case dw_val_class_addr:
> -         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
> +         gcc_assert (val1->v.val_unsigned
> +                     == (unsigned HOST_WIDE_INT) DWARF2_ADDR_SIZE);

Again, we need to fix this warning so this change is unnecessary.

> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>        /* Handle OMP_FOR_COND.  */
>        t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>        gcc_assert (COMPARISON_CLASS_P (t));
> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) == decl);

Why didn't delayed folding canonicalize this so that the decl is in op0?

> @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
>           gcc_assert (gimple_omp_for_kind (for_stmt)
>                       == GF_OMP_FOR_KIND_CILKSIMD
>                       || (gimple_omp_for_kind (for_stmt)
> -                         == GF_OMP_FOR_KIND_CILKFOR));
> +                         == GF_OMP_FOR_KIND_CILKFOR)
> +                     || (gimple_omp_for_kind (for_stmt)
> +                         == GF_OMP_FOR_KIND_FOR));

This still seems like a red flag; how is delayed folding changing the 
OMP for kind?

> @@ -1796,6 +1796,9 @@ evaluate_stmt (gimple stmt)
>        && (likelyvalue == CONSTANT || is_gimple_call (stmt)
>           || (gimple_assign_single_p (stmt)
>               && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
> +      && (likelyvalue == CONSTANT || is_gimple_call (stmt)
> +         || (gimple_assign_single_p (stmt)
> +             && gimple_assign_rhs_code (stmt) == ADDR_EXPR))

You were going to revert this merge error?

> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>  {
>    tree t = make_node (COMPLEX_CST);
>
> +  real = fold (real);
> +  imag = fold (imag);

I still think this is wrong.  The arguments should be sufficiently folded.

> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset)
>    while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>          || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>      local->val = TREE_OPERAND (local->val, 0);
> +  local->val = fold (local->val);

Likewise.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-06-12  5:41 C++ delayed folding branch review Jason Merrill
@ 2015-06-12 16:17 ` Kai Tietz
  2015-06-13  7:58   ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-06-12 16:17 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

Hello Jason,

Thanks for the review.  I addressed a lot of your comments directly on svn-branch.  See revision r224439.

----- Ursprüngliche Mail -----
> Generally, it seems like most of my comments from April haven't been
> addressed yet.

Yes, most of them.
 
> > @@ -3023,13 +3023,14 @@ conversion_warning (location_t loc, tree type, tree
> > expr
> 
> Instead of adding folds here, let's make sure that the argument we pass
> (e.g. from cp_convert_and_check to warnings_for_convert_and_check) is
> fully folded.

I looked for dependencies, and address this.
 
> > @@ -589,9 +589,9 @@ null_member_pointer_value_p (tree t)
> >      return false;
> >    else if (TYPE_PTRMEMFUNC_P (type))
> >      return (TREE_CODE (t) == CONSTRUCTOR
> > -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
> > +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
> >    else if (TYPE_PTRDATAMEM_P (type))
> > -    return integer_all_onesp (t);
> > +    return integer_all_onesp (fold (t));
> 
> Again, calling fold here is wrong; it doesn't handle constexpr, and we
> should have folded before we got here.

Agreed.  I will commit change for this.

Nevertheless CONSTRUCTOR_ELT's value might still be prefixed by nops due possible overflows, or by negative sign/invert/etc.  This is caused by non-constant-folding of values.  I removed for now those folds, as I agree we should address this at place of value-assignment.  Nevertheless we still have this issue
 
> > @@ -5090,9 +5090,9 @@ build_conditional_expr_1 (location_t loc, tree arg1,
> > tree arg2, tree arg3,
> >
> >   valid_operands:
> >    result = build3 (COND_EXPR, result_type, arg1, arg2, arg3);
> > -  if (!cp_unevaluated_operand)
> > +  if (!cp_unevaluated_operand && !processing_template_decl)
> >      /* Avoid folding within decltype (c++/42013) and noexcept.  */
> > -    result = fold_if_not_in_template (result);
> > +    result = fold (result);
> 
> This seems related to your status report note:
> 
> > Additionally addressed issue about cond_expr, as we want to fold cases with
> > a constant-condition.  Here we need to use "fold_to_constant" so that we
> > just fold things to constant-value, if possible and otherwise don't modify
> > anything.
> 
> But why do you say we want to fold cases with a constant condition?  We
> certainly want to avoid warning about the dead branch in that case, but
> it would be better if we can do that folding only in the warning code.

Issue is that we otherwise detect in conditions that expressions aren't constant due never-executed-code-path.  The diagnostics we can deal differently, but this was actually the reason for doing this.  I can remove this here, but we still need a place to avoid ill detection of constexpr (or invalid code) on dead code-branch.  Eg.  (1 ? 0/0 : 1) etc
 
> > @@ -5628,8 +5628,8 @@ build_new_op_1 (location_t loc, enum tree_code code,
> > int f
> > lags, tree arg1,
> >                  decaying an enumerator to its value.  */
> >               if (complain & tf_warning)
> >                 warn_logical_operator (loc, code, boolean_type_node,
> > -                                      code_orig_arg1, arg1,
> > -                                      code_orig_arg2, arg2);
> > +                                      code_orig_arg1, fold (arg1),
> > +                                      code_orig_arg2, fold (arg2));
> >
> >               arg2 = convert_like (conv, arg2, complain);
> >             }
> > @@ -5666,7 +5666,8 @@ build_new_op_1 (location_t loc, enum tree_code code,
> > int f
> > lags, tree arg1,
> >      case TRUTH_AND_EXPR:
> >      case TRUTH_OR_EXPR:
> >        warn_logical_operator (loc, code, boolean_type_node,
> > -                            code_orig_arg1, arg1, code_orig_arg2, arg2);
> > +                            code_orig_arg1, fold (arg1),
> > +                            code_orig_arg2, fold (arg2));
> >        /* Fall through.  */
> >      case GT_EXPR:
> >      case LT_EXPR:
> > @@ -5676,7 +5677,7 @@ build_new_op_1 (location_t loc, enum tree_code code,
> > int f
> > lags, tree arg1,
> >      case NE_EXPR:
> >        if ((code_orig_arg1 == BOOLEAN_TYPE)
> >           ^ (code_orig_arg2 == BOOLEAN_TYPE))
> > -       maybe_warn_bool_compare (loc, code, arg1, arg2);
> > +       maybe_warn_bool_compare (loc, code, fold (arg1), fold (arg2));
> >        /* Fall through.  */
> >      case PLUS_EXPR:
> >      case MINUS_EXPR:
> 
> I still think these fold calls should be cp_fully_fold.

Ok, modified here use of fold to cp_fully_fold.

> 
> > @@ -7382,8 +7383,13 @@ build_over_call (struct z_candidate *cand, int
> > flags, tsu
> > bst_flags_t complain)
> >
> >    gcc_assert (j <= nargs);
> >    nargs = j;
> > +  {
> > +    tree *fargs = (!nargs ? argarray : (tree *) alloca (nargs * sizeof
> > (tree)))
> > ;
> > +    for (j = 0; j < nargs; j++)
> > +      fargs[j] = fold_non_dependent_expr (argarray[j]);
> 
> No change needed here, but I notice that fold_non_dependent_expr is
> still using maybe_constant_value; it should probably use cp_fully_fold
> instead.

Hmm, maybe we should limit this folding on constants.  So cp_fold_to_constant ()?
 
> > @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
> >  {
> >    if (TREE_TYPE (temp) == type)
> >      return temp;
> > +  STRIP_NOPS (temp);
> > +  if (TREE_TYPE (temp) == type)
> > +    return temp;
> > @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
> > tree t,
> >  bool
> >  reduced_constant_expression_p (tree t)
> >  {
> > +  /* Make sure we remove useless initial NOP_EXPRs.  */
> > +  STRIP_NOPS (t);
> 
> Within the constexpr code we should be folding away NOPs as they are
> generated, they shouldn't live this long.

Well, we might see them on overflows ...
 
> > @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
> > *ctx, tree t,
> >           && is_dummy_object (x))
> >         {
> >           x = ctx->object;
> > -         x = cp_build_addr_expr (x, tf_warning_or_error);
> > +         if (x)
> > +           x = cp_build_addr_expr (x, tf_warning_or_error);
> > +         else
> > +           x = get_nth_callarg (t, i);
> 
> This still should not be necessary.

Yeah, most likely.  But I got initially here some issues, so I don't see that this code would worsen things.
 
> > @@ -1576,13 +1586,15 @@ cxx_eval_unary_expression (const constexpr_ctx
> > *ctx, tre
> > e t,
> >    enum tree_code code = TREE_CODE (t);
> >    tree type = TREE_TYPE (t);
> >    r = fold_unary_loc (loc, code, type, arg);
> > -  if (r == NULL_TREE)
> > +  if (r == NULL_TREE || !CONSTANT_CLASS_P (r))
> >      {
> >        if (arg == orig_arg)
> >         r = t;
> >        else
> >         r = build1_loc (loc, code, type, arg);
> >      }
> > +  else
> > +    r = unify_constant (ctx, r, overflow_p);
> 
> This still should not be necessary.

Well, I just wanted to make sure that if arg is a PTRMEM_CST (or something like this) that we still try to resolve its constant.  But yes, you are right that arg is anyway resolved already, and so this might not happen.  Nevertheless we might need to handle here OVERFLOW?

 
> > @@ -1780,7 +1792,8 @@ cxx_eval_component_reference (const constexpr_ctx
> > *ctx, tree t,
> >        if (field == part)
> >         {
> >           if (value)
> > -           return value;
> > +           return cxx_eval_constant_expression (ctx, value, lval,
> > +                                                non_constant_p,
> > overflow_p);
> >           else
> >             /* We're in the middle of initializing it.  */
> >             break;
> > @@ -1864,7 +1877,8 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx,
> > tree t,
> >      {
> >        tree bitpos = bit_position (field);
> >        if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
> > -       return value;
> > +       return cxx_eval_constant_expression (ctx, value, lval,
> > +                                             non_constant_p, overflow_p);
> >        if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
> >           && TREE_CODE (value) == INTEGER_CST
> >           && tree_fits_shwi_p (bitpos)
> 
> Again, this shouldn't be necessary, either; the elements of the
> CONSTRUCTOR should be fully evaluated already.

Evaluated yes, but not necessarily folded to constant.  Maybe cp_fold_to_constant could be better choice here?
 
> > @@ -2987,19 +3017,15 @@ cxx_eval_constant_expression (const constexpr_ctx
> > *ctx, tree t,
> >    constexpr_ctx new_ctx;
> >    tree r = t;
> >
> > -  if (t == error_mark_node)
> > +  if (!t || t == error_mark_node)
> >      {
> >        *non_constant_p = true;
> > -      return t;
> > +      return error_mark_node;
> >      }
> > @@ -3761,6 +3819,8 @@ fold_non_dependent_expr (tree t)
> >  tree
> >  maybe_constant_init (tree t, tree decl)
> >  {
> > +  if (!t)
> > +    return t;
> 
> You were going to test whether the null check was necessary.  What was
> the result?

I will need to redo this test if the boostrap-issue about real.h is resolved.  But I agree that this check could be superflous.
 
> >      case SIZEOF_EXPR:
> > +      if (processing_template_decl
> > +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
> > +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
> > +       return t;
> 
> Why is this necessary?

We don't want to resolve SIZEOF_EXPR within template-declarations for incomplete types, of if its size isn't fixed.  Issue is that we otherwise get issues about expressions without existing type (as usual within template-declarations for some expressions).
 
> > @@ -3368,6 +3399,15 @@ cxx_eval_constant_expression (const constexpr_ctx
> > *ctx, tree t,
> >         /* Don't re-process a constant CONSTRUCTOR, but do fold it to
> >            VECTOR_CST if applicable.  */
> >         return fold (t);
> > +      /* See this can happen for case like g++.dg/init/static2.C testcase.
> > */
> > +      if (!ctx || !ctx->ctor || (lval && !ctx->object)
> > +         || !same_type_ignoring_top_level_qualifiers_p
> > +              (TREE_TYPE (t), TREE_TYPE (ctx->ctor))
> > +         || CONSTRUCTOR_NELTS (ctx->ctor) != 0)
> > +       {
> > +         *non_constant_p = true;
> > +         break;
> > +       }
> 
> Why does this happen for static2.C when it doesn't happen on the trunk?
>   I think the bug is somewhere else.

I will try to investigate in more detail, when bootstrap is working again.
 
> > @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const constexpr_ctx
> > *ctx, tree t,
> >      case CONVERT_EXPR:
> >      case VIEW_CONVERT_EXPR:
> >      case NOP_EXPR:
> > +    case UNARY_PLUS_EXPR:
> >        {
> > +       enum tree_code tcode = TREE_CODE (t);
> >         tree oldop = TREE_OPERAND (t, 0);
> > +
> > +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
> > TREE_OVERFLOW_P (oldop))
> > +         {
> > +           if (!ctx->quiet)
> > +             permerror (input_location, "overflow in constant
> > expression");
> > +           /* If we're being permissive (and are in an enforcing
> > +               context), ignore the overflow.  */
> > +           if (!flag_permissive)
> > +             *overflow_p = true;
> > +           *non_constant_p = true;
> > +
> > +           return t;
> > +         }
> >         tree op = cxx_eval_constant_expression (ctx, oldop,
> 
> Why doesn't the call to cxx_eval_constant_expression at the bottom here
> handle oldop having TREE_OVERFLOW set?

I just handled the case that we see here a wrapping NOP_EXPR around an overflow.  As this isn't handled by cxx_eval_constant_expression.

 
> > @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
> > gimple_seq *post_p)
> >
> >    switch (code)
> >      {
> > +    case SIZEOF_EXPR:
> > +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
> > +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
> > (*expr_p,
> > +                                                                      0)),
> > +                                             SIZEOF_EXPR, false);
> > +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
> > +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p, 0),
> > +                                             SIZEOF_EXPR, false);
> > +      else
> > +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p, 0),
> > +                                             SIZEOF_EXPR, false);
> > +      if (*expr_p == error_mark_node)
> > +       *expr_p = size_one_node;
> > +
> > +      *expr_p = maybe_constant_value (*expr_p);
> > +      ret = GS_OK;
> > +      break;
> 
> Why are these surviving until gimplification time?

This might be still necessary. I will retest, when bootstrap works.  As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all expressions a sizeof can occure, this shouldn't be necessary anymore.  AFAIR I saw here some issues about initialzation for global-variables, which weren't caught.
 
> > +static tree
> > +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
> 
> Looks like cp_fold still doesn't call maybe_constant_value.

Yes, it should do this just in case of seen PTRMEM_CST.  Or shall we try to invoke it on each iteration within cp_fold.  Later might be a bit costy, isn't it?
 
> > +  case CALL_EXPR:
> > +    r = fold (x);
> > +    if (TREE_CODE (r) != CALL_EXPR)
> > +      {
> > +       x = cp_fold (r, fold_hash);
> > +       break;
> > +      }
> > +    {
> > +      int i, m = call_expr_nargs (x);
> > +      for (i = 0; i < m; i++)
> > +        {
> > +         CALL_EXPR_ARG (x, i) = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
> > +       }
> > +    }
> > +    r = fold (x);
> > +    if (TREE_CODE (r) != CALL_EXPR)
> > +      {
> > +       x = cp_fold (r, fold_hash);
> > +       break;
> > +      }
> > +    return org_x;
> 
> Why return org_x here?  Don't we still want to add this to the hash table?

No, as we just tried here to fold expression-arguments, so that later fold might be able to optimize.  So x is intermediate, and we don't want to cache it.

But well, we might want to hash here org_x itself ...
 
> I'm also nervous about clobbering the args in the original CALL_EXPR.
> In most of cp_fold you build a new expression rather than change the
> operands of the original one.

Well, this shouldn't be problematic IMP.  I just wanted to avoid to make use of a node-copy, which might be for a call-expression expensive.  But well, as we now have cp_try_fold_to_constant, this could lead indeed to folded call-expressions too early.  Before cp_fold was just used in the final folding before gimplification, where these modifications weren't problematic at all.
So we might want to avoid such argument-conversion in context of cp_try_fold_to_constant at all?

 
> > @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
> >      }
> >    else
> >      {
> > -      conv = fold_convert (type, expr);
> > +      if (TREE_CODE (expr) == INTEGER_CST)
> > +        conv = fold_convert (type, expr);
> > +      else
> > +        conv = convert (type, expr);
> 
> I still think that cp_fold_convert should always call fold_convert, and
> callers that we don't want to fold should call convert instead, or
> another function that folds only conversion of constants.  We had talked
> about the name "fold_cst", but I think that name isn't very clear; would
> it make sense to just have convert always fold conversions of constants?

We could introduce that, but we still have the issues about some unary-operations on constants, too.  So we could do for any conversion afterwards a call to cp_try_fold_to_constant, which should reflect that pretty well, beside within template-declarations ...

 
> > @@ -632,12 +636,12 @@ cp_convert (tree type, tree expr, tsubst_flags_t
> > complain)
> >  tree
> >  cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
> >  {
> > -  tree result;
> > +  tree result, ret;
> >
> >    if (TREE_TYPE (expr) == type)
> >      return expr;
> >
> > -  result = cp_convert (type, expr, complain);
> > +  result = ret = cp_convert (type, expr, complain);
> >
> >    if ((complain & tf_warning)
> >        && c_inhibit_evaluation_warnings == 0)
> > @@ -646,6 +650,7 @@ cp_convert_and_check (tree type, tree expr,
> > tsubst_flags_t complain)
> >        tree stripped = folded;
> >        tree folded_result
> >         = folded != expr ? cp_convert (type, folded, complain) : result;
> > +      folded_result = fold (folded_result);
> >
> >        /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
> >          NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
> > @@ -657,7 +662,7 @@ cp_convert_and_check (tree type, tree expr,
> > tsubst_flags_t complain)
> >                                         folded_result);
> >      }
> >
> > -  return result;
> > +  return ret;
> >  }
> 
> Again, there seems to be no reason to introduce the new "ret" variable.


Yes, removed it.
I am trying right now a version using here cp_fully_fold instead of fold.
 
> > @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree expr,
> > bool complain)
> >    tree basetype = TREE_TYPE (expr);
> >    tree conv = NULL_TREE;
> >    tree winner = NULL_TREE;
> > +  /* Want to see if EXPR is a constant.  See below checks for null_node.
> > */
> > +  tree expr_folded = cp_try_fold_to_constant (expr);
> >
> > -  if (expr == null_node
> > +  STRIP_NOPS (expr_folded);
> > +  if (expr_folded == null_node
> 
> Again, we shouldn't need to fold to check for null_node, it only occurs
> when explicitly written.  Folding should never produce null_node unless
> the argument was already null_node.

6Well, we need to do this for diagnostic messages AFAIR.  We want to see if expression folded gets a constant, so that diagnostics getting displayed right.
 
> > @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree expr,
> > bool complain)
> >      switch (TREE_CODE (basetype))
> >        {
> >        case INTEGER_TYPE:
> > -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
> > +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
> 
> Again, we don't want to fold before calling null_ptr_cst_p, since in
> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
> fold in null_ptr_cst_p.

We need to avoid useless conversion, so we should reduce to simple constant-value ...
 
> > @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
> > tsubst_flags_t complain)
> >        SET_TYPE_STRUCTURAL_EQUALITY (itype);
> >        return itype;
> >      }
> > -
> > +
> > +  /* We need to do fully folding to determine if we have VLA, or not.  */
> > +  tree size_constant = cp_try_fold_to_constant (size);
> 
> Again, we already called maybe_constant_value.

Sure, but maybe_constant_value still produces nops ...
 
> > @@ -8736,7 +8697,10 @@ create_array_type_for_decl (tree name, tree type,
> > tree size)
> >
> >    /* Figure out the index type for the array.  */
> >    if (size)
> > -    itype = compute_array_index_type (name, size, tf_warning_or_error);
> > +    {
> > +      size = cp_try_fold_to_constant (size);
> > +      itype = compute_array_index_type (name, size, tf_warning_or_error);
> > +    }
> 
> There's no need to fold here and inside compute_array_index_type.

Yeahm within compute_array_index_type should be enough.
 
> > @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
> > enumtype, tree attributes,
> >    if (value)
> >      STRIP_TYPE_NOPS (value);
> >
> > +  if (value)
> > +    value = cp_try_fold_to_constant (value);
> 
> Again, this is unnecessary because we call cxx_constant_value below.

See nops, and other unary-operations we want to reduce here to real constant value ...
 
> > @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree
> > enumtype, tree attributes,
> >           if (value != NULL_TREE)
> >             {
> >               value = cxx_constant_value (value);
> > +             STRIP_NOPS (value);
> 
> Again, the only time a constant result should have a NOP_EXPR around it
> is if it isn't really constant.  Why do you want to strip that?

As for an enumerator-value we might have overflows, which are silently ignored.  I will recheck this what example we have for this when bootstrap is working again.

 
> > @@ -779,7 +779,8 @@ perform_member_init (tree member, tree init)
> >            in that case.  */
> >         init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
> >                                                 tf_warning_or_error);
> > -
> > +      if (init)
> > +       init = fold (init);
> 
> Again, why fold here, rather than later when something really wants a
> constant?  If that ever actually occurs?

Hmm, this had to do with some weak code-generation AFAIR.  Need to recheck.  Could be also a relict about unary-operations on constants, which we want to elliminate for initializers soon.
 
> > @@ -417,7 +417,9 @@ strip_using_decl (tree decl)
> >    if (decl == NULL_TREE)
> >      return NULL_TREE;
> >
> > -  while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
> > +  while (TREE_CODE (decl) == USING_DECL
> > +        && !DECL_DEPENDENT_P (decl)
> > +        && !uses_template_parms (USING_DECL_SCOPE (decl)))
> 
> This seems unrelated to delayed folding.

Yeah,  I will remove from branch.  Should be nevertheless something pretty opaque ...
 
> > @@ -6136,6 +6139,10 @@ push_to_top_level (void)
> >    else
> >      need_pop = false;
> >
> > +  if (scope_chain)
> > +    fm = scope_chain->fold_map;
> > +  else
> > +    fm = NULL;
> >    if (scope_chain && previous_class_level)
> >      store_class_bindings (previous_class_level->class_shadowed,
> >                           &s->old_bindings);
> > @@ -6167,6 +6174,9 @@ push_to_top_level (void)
> >    FOR_EACH_VEC_SAFE_ELT (s->old_bindings, i, sb)
> >      IDENTIFIER_MARKED (sb->identifier) = 0;
> >
> > +  if (!fm)
> > +    fm = new hash_map<tree, tree>;
> 
> Why are these hunks so far apart?  I would expect them to be all together.

Oh, nothing special.  I just wanted to have base initialization together with the other if initializes, and doing then later near assignment the optional allocation.
I can change this, if you prefer.
 
> > @@ -6473,7 +6473,8 @@ cp_parser_array_notation (location_t loc, cp_parser
> > *parser, tree *init_index,
> >          2. ARRAY [ EXP : EXP ]
> >          3. ARRAY [ EXP : EXP : EXP ]  */
> >
> > -      *init_index = cp_parser_expression (parser);
> > +      *init_index = cp_parser_expression (parser);
> > +      *init_index = cp_try_fold_to_constant (*init_index);
> >        if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
> >         {
> >           /* This indicates that we have a normal array expression.  */
> > @@ -6484,10 +6485,12 @@ cp_parser_array_notation (location_t loc, cp_parser
> > *parser, tree *init_index,
> >        /* Consume the ':'.  */
> >        cp_lexer_consume_token (parser->lexer);
> >        length_index = cp_parser_expression (parser);
> > +      length_index = cp_try_fold_to_constant (length_index);
> >        if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
> >         {
> >           cp_lexer_consume_token (parser->lexer);
> >           stride = cp_parser_expression (parser);
> > +         stride = cp_try_fold_to_constant (stride);
> 
> Again, why fold here, rather than later when something really wants a
> constant?  If that ever actually occurs?

This code for cilk expects that these statements are folded to constants.  It doesn't make much difference to move those folders to later locations, as we have to fold them early anyway.

> > @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression (cp_parser
> > *parser,
> >         index = cp_parser_expression (parser);
> >      }
> >
> > +  /* For offsetof and declaration of types we need
> > +     constant integeral values.
> > +     Also we meed to fold for negative constants so that diagnostic in
> > +     c-family/c-common.c doesn't fail for array-bounds.  */
> > +  if (for_offsetof || decltype_p
> > +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
> > (index, 0)) == INTEGER_CST))
> > +    index = cp_try_fold_to_constant (index);
> 
> Similarly, for offsetof the folding should happen closer to where it is
> needed.
> 
> Why is it needed for decltype, which is querying the type of an expression?
> 
> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
> constant; this isn't the right place to do it.

Same as above, we need in those cases (and for -1 too) the constant values early anyway.  So I saw it as more logical to have done this conversion as soon as possible after initialization.

> > @@ -8031,7 +8041,9 @@ cp_parser_cast_expression (cp_parser *parser, bool
> > address_p, bool cast_p,
> >                 return error_mark_node;
> >
> >               /* Perform the cast.  */
> > -             expr = build_c_cast (input_location, type, expr);
> > +             /* We don't want to resolve cast too early.  Therefore we
> > don't
> > +                be able to use build_c_cast.  */
> > +             expr = cp_build_c_cast (type, expr, tf_warning_or_error);
> 
> Huh?  build_c_cast just calls cp_build_c_cast.

Yes, as we don't want to do cast-folding too early.
 
> > @@ -9869,6 +9881,7 @@ cp_parser_label_for_labeled_statement (cp_parser*
> > parser, tree attributes)
> >         cp_lexer_consume_token (parser->lexer);
> >         /* Parse the constant-expression.  */
> >         expr = cp_parser_constant_expression (parser);
> > +       expr = cp_try_fold_to_constant (expr);
> >         if (check_for_bare_parameter_packs (expr))
> >           expr = error_mark_node;
> >
> > @@ -9878,6 +9891,7 @@ cp_parser_label_for_labeled_statement (cp_parser*
> > parser, tree attributes)
> >             /* Consume the `...' token.  */
> >             cp_lexer_consume_token (parser->lexer);
> >             expr_hi = cp_parser_constant_expression (parser);
> > +           expr_hi = cp_try_fold_to_constant (expr_hi);
> 
> Again, this seems redundant with the call to cxx_constant_value in
> case_conversion.

Well, but we want to do here check_for_bare_parameter_packs directly after that, and so we need folded value early.
 
> > @@ -12210,6 +12224,10 @@ cp_parser_static_assert(cp_parser *parser, bool
> > member_p)
> >                                     /*allow_non_constant_p=*/true,
> >                                     /*non_constant_p=*/&dummy);
> >
> > +  /* Make sure we folded it completely before doing trying to get
> > +     constant value.  */
> > +  condition = fold_non_dependent_expr (condition);
> 
> Again, this is redundant with the code in finish_static_assert.

Hmm, yes.  We check that.
 
> > @@ -16115,6 +16133,7 @@ cp_parser_enumerator_definition (cp_parser* parser,
> > tree type)
> >        cp_lexer_consume_token (parser->lexer);
> >        /* Parse the value.  */
> >        value = cp_parser_constant_expression (parser);
> > +      value = cp_try_fold_to_constant (value);
> 
> Again, this is redundant with the code in build_enumerator.

Hmm, don't see here redundancy.  I just see that we need folded-value for leter call of check_for_bare_parameter_packs.  But might not see the obvious

 
> > @@ -17702,7 +17721,8 @@ cp_parser_direct_declarator (cp_parser* parser,
> >              constant-expression.  */
> >           if (token->type != CPP_CLOSE_SQUARE)
> >             {
> > -             bool non_constant_p;
> > +             bool non_constant_p = false;
> 
> This is unnecessary, as cp_parser_constant_expression will set
> non_constant_p.

Ok.
 
> > @@ -19354,12 +19374,10 @@ cp_parser_initializer_clause (cp_parser* parser,
> > bool* non_constant_p)
> >    /* If it is not a `{', then we are looking at an
> >       assignment-expression.  */
> >    if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
> > -    {
> > -      initializer
> > -       = cp_parser_constant_expression (parser,
> > -                                       /*allow_non_constant_p=*/true,
> > -                                       non_constant_p);
> > -    }
> > +    initializer
> > +      = cp_parser_constant_expression (parser,
> > +                                     /*allow_non_constant_p=*/true,
> > +                                     non_constant_p);
> 
> Let's not reformat unrelated code in a big project like this.

Well, but it violates coding-rules.  anyway agreed ;)
 
> > @@ -20955,9 +20973,11 @@ cp_parser_member_declaration (cp_parser* parser)
> >
> >               /* Consume the `:' token.  */
> >               cp_lexer_consume_token (parser->lexer);
> > +
> >               /* Get the width of the bitfield.  */
> >               width
> >                 = cp_parser_constant_expression (parser);
> > +             width = maybe_constant_value (width);
> 
> Again, this seems redundant with the call to cxx_constant_value in
> check_bitfield_decl.

Ah, this escaped.  This should be a cp_try_fold_to_constant.
 
> Again, it seems like you added maybe_constant_value or
> cp_try_fold_to_constant after every occurrence of
> cp_parser_constant_expression, and I suspect that few are actually
> needed, and the ones that are should go closer to the code that really
> needs a constant.  I'd prefer to avoid calling it at all in parser.c.

Actually it should be cp_try_fold_to_constant, as at those places we need to deal anyway with constant-values.  At some please we use those values already for some diagnostics, so I thoght it is more consistent to do this folding to constant directly after parsing it.  To delay that into builder-routines is IMO just less clear, and could lead to double-doing foldings.  Additionally the chance to conflict here with shared parts with C is much less.

Anyway, if you prefer, we can do this in builder-routines, and remove at places constants aren't needed directly after parsing it those calls.

 
> >  finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
> >                       tsubst_flags_t complain)
> >  {
> > +  tree expr_ovl = expr;
> >    tree result = build_x_unary_op (loc, code, expr, complain);
> > +  tree result_ovl = result;
> > +
> > +  STRIP_NOPS (expr_ovl);
> > +  switch (code)
> > +    {
> > +    case ABS_EXPR:
> > +    case NEGATE_EXPR:
> > +      if (TREE_CODE (expr) == INTEGER_CST
> > +         || TREE_CODE (expr) == REAL_CST
> > +         || TREE_CODE (expr) == VECTOR_CST
> > +         || TREE_CODE (expr) == FIXED_CST
> > +         || TREE_CODE (expr) == COMPLEX_CST)
> > +      result_ovl = fold (result);
> > +      break;
> > +    default:
> > +      break;
> > +    }
> 
> Not cp_fully_fold?

Hmm, yeah,  I changed the switch to a call to cp_try_fold_to_constant, which should be pretty exactly what we are looking here for diagnostics.
 
> > @@ -6301,8 +6321,9 @@ handle_omp_for_class_iterator (int i, location_t
> > locus, tree declv, tree initv,
> >                                     tf_warning_or_error);
> >        if (error_operand_p (iter_incr))
> >         return true;
> > -      else if (TREE_CODE (incr) == PREINCREMENT_EXPR
> > -              || TREE_CODE (incr) == POSTINCREMENT_EXPR)
> > +      iter_incr = fold (iter_incr);
> > +      if (TREE_CODE (incr) == PREINCREMENT_EXPR
> > +         || TREE_CODE (incr) == POSTINCREMENT_EXPR)
> > @@ -6357,6 +6376,7 @@ handle_omp_for_class_iterator (int i, location_t
> > locus, tree declv, tree initv,
> >                                                  tf_warning_or_error);
> >                   if (error_operand_p (iter_incr))
> >                     return true;
> > +                 iter_incr = fold (iter_incr);
> >                   iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs),
> >                                                    iter, NOP_EXPR,
> >                                                    iter_incr,
> > @@ -6364,6 +6384,7 @@ handle_omp_for_class_iterator (int i, location_t
> > locus, tree declv, tree initv,
> >                   if (error_operand_p (iter_incr))
> >                     return true;
> >                   incr = TREE_OPERAND (rhs, 0);
> > +                 incr = fold (incr);
> 
> Why are these folds needed?
> 
> > @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
> >    else if (TREE_CODE (init) == AGGR_INIT_EXPR)
> >      fn = AGGR_INIT_EXPR_FN (init);
> >    else
> > -    return convert (type, init);
> > +    return fold (convert (type, init));
> 
> Why fold here?

We had this already in prior thread.  fold (convert ()) != fold_convert () for C++.  The fold is just there to make sure we fold away useless casts.
 
> > @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree, va_gc>
> > **values, tree fndecl,
> >           && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
> >         val = TREE_OPERAND (val, 0);
> >
> > +      /* For BUILT_IN_NORMAL we want to fold constants.  */
> > +      if (fndecl && DECL_BUILT_IN (fndecl)
> > +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> > +       val = fold (val);
> 
> Why?

As builtin-handlers are expecting to see constant values.  Otherwise the produce either ICE, or other funny things.  We could call here instead also the cp_try_fold... function.
Btw some lines above there is a comment about NOP_EXPR being extended to indicate that a value isn't lvalue.  Not sure if this NOP_EXPR strip is still necessary, as we don't call anymore directly into build_c_cast ().  I need to check if cp-version does the same.
 
> > @@ -4941,7 +4938,7 @@ cp_build_binary_op (location_t location,
> >              from being kept in a register.
> >              Instead, make copies of the our local variables and
> >              pass the copies by reference, then copy them back afterward.
> >              */
> > -         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
> > +         tree xop0 = fold (op0), xop1 = fold (op1), xresult_type =
> > result_type;
> 
> Again, this seems wrong.  In fact, the whole short_compare business
> seems like the sort of early folding we want to do away with.
> 
> > @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
> >      }
> >
> >    result = build2 (resultcode, build_type, op0, op1);
> > -  result = fold_if_not_in_template (result);
> >    if (final_type != 0)
> >      result = cp_convert (final_type, result, complain);
> > -
> > -  if (TREE_OVERFLOW_P (result)
> > +  op0 = fold_non_dependent_expr (op0);
> > +  op1 = fold_non_dependent_expr (op1);
> > +  STRIP_NOPS (op0);
> > +  STRIP_NOPS (op1);
> > +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
> > +  if (TREE_OVERFLOW_P (result_ovl)
> >        && !TREE_OVERFLOW_P (op0)
> >        && !TREE_OVERFLOW_P (op1))
> > -    overflow_warning (location, result);
> > +    overflow_warning (location, result_ovl);
> 
> Don't you want to use cp_fully_fold here?
> 
> > @@ -7989,7 +7984,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree
> > *pfn)
> >        tree binfo = binfo_or_else (orig_class, fn_class);
> >        *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
> >                        *delta, BINFO_OFFSET (binfo));
> > -      *delta = fold_if_not_in_template (*delta);
> >
> >        /* We set PFN to the vtable offset at which the function can be
> >          found, plus one (unless ptrmemfunc_vbit_in_delta, in which
> > @@ -7997,23 +7991,19 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree
> > *pfn)
> >        *pfn = DECL_VINDEX (fn);
> >        *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
> >                      TYPE_SIZE_UNIT (vtable_entry_type));
> > -      *pfn = fold_if_not_in_template (*pfn);
> >
> >        switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
> >         {
> >         case ptrmemfunc_vbit_in_pfn:
> >           *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
> >                          integer_one_node);
> > -         *pfn = fold_if_not_in_template (*pfn);
> >           break;
> >
> >         case ptrmemfunc_vbit_in_delta:
> >           *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
> >                            *delta, integer_one_node);
> > -         *delta = fold_if_not_in_template (*delta);
> >           *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
> >                            *delta, integer_one_node);
> > -         *delta = fold_if_not_in_template (*delta);
> >           break;
> >
> >         default:
> > @@ -8021,7 +8011,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree
> > *pfn)
> >         }
> >
> >        *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
> > -      *pfn = fold_if_not_in_template (*pfn);
> 
> Again, I think all the calls to fold_if_not_in_template in
> expand_ptrmemfunc_cst should become regular folds.  Or rather, change
> the build2 to fold_build2.  This is very much compiler internals, and we
> should only get here when folding anyway.

Ok, I will check if *delta always has a valid type.  As otherwise fold_build2 will crash.
 
> > @@ -1866,7 +1866,8 @@ output_loc_operands (dw_loc_descr_ref loc, int
> > for_eh_or_skip)
> >           }
> >           break;
> >         case dw_val_class_addr:
> > -         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
> > +         gcc_assert (val1->v.val_unsigned
> > +                     == (unsigned HOST_WIDE_INT) DWARF2_ADDR_SIZE);
> 
> Again, we need to fix this warning so this change is unnecessary.

Yeah, just something intermediate.  It is on my list.
 
> > @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
> >        /* Handle OMP_FOR_COND.  */
> >        t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
> >        gcc_assert (COMPARISON_CLASS_P (t));
> > -      gcc_assert (TREE_OPERAND (t, 0) == decl);
> > +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) ==
> > decl);
> 
> Why didn't delayed folding canonicalize this so that the decl is in op0?

Delay folding doesn't canonicalize this.  Actually we don't want to touch here anything in parsered tree.  We could do this in generalization-pass before gimplification.  Seems to be something we don't catch for now, which makes me wonder a bit.
 
> > @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct
> > omp_for_data *fd,
> >           gcc_assert (gimple_omp_for_kind (for_stmt)
> >                       == GF_OMP_FOR_KIND_CILKSIMD
> >                       || (gimple_omp_for_kind (for_stmt)
> > -                         == GF_OMP_FOR_KIND_CILKFOR));
> > +                         == GF_OMP_FOR_KIND_CILKFOR)
> > +                     || (gimple_omp_for_kind (for_stmt)
> > +                         == GF_OMP_FOR_KIND_FOR));
> 
> This still seems like a red flag; how is delayed folding changing the
> OMP for kind?

It doesn't.  The issue is that some canonical operations of fold aren't happening anymore on which omp depends.
 
> > @@ -1796,6 +1796,9 @@ evaluate_stmt (gimple stmt)
> >        && (likelyvalue == CONSTANT || is_gimple_call (stmt)
> >           || (gimple_assign_single_p (stmt)
> >               && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
> > +      && (likelyvalue == CONSTANT || is_gimple_call (stmt)
> > +         || (gimple_assign_single_p (stmt)
> > +             && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
> 
> You were going to revert this merge error?

Sure.
 
> > @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
> >  {
> >    tree t = make_node (COMPLEX_CST);
> >
> > +  real = fold (real);
> > +  imag = fold (imag);
> 
> I still think this is wrong.  The arguments should be sufficiently folded.

As we don't fold unary-operators on constants, we need to fold it at some place.  AFAICS is the C++ FE not calling directly build_complex.  So this place was the easiest way to avoid issues with things like '-' '1' etc.
 
> > @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state *local,
> > unsigned int bit_offset)
> >    while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
> >          || TREE_CODE (local->val) == NON_LVALUE_EXPR)
> >      local->val = TREE_OPERAND (local->val, 0);
> > +  local->val = fold (local->val);
> 
> Likewise.

As soon as we can be sure that values getting fully_folded, or at least folded for constants, we should be able to remove this.

 
> Jason
> 

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-06-12 16:17 ` Kai Tietz
@ 2015-06-13  7:58   ` Jason Merrill
  2015-07-27 19:01     ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-06-13  7:58 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>> @@ -589,9 +589,9 @@ null_member_pointer_value_p (tree t)
>>>       return false;
>>>     else if (TYPE_PTRMEMFUNC_P (type))
>>>       return (TREE_CODE (t) == CONSTRUCTOR
>>> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
>>> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>>>     else if (TYPE_PTRDATAMEM_P (type))
>>> -    return integer_all_onesp (t);
>>> +    return integer_all_onesp (fold (t));
>>
>> Again, calling fold here is wrong; it doesn't handle constexpr, and we
>> should have folded before we got here.
>
> Agreed.  I will commit change for this.
>
> Nevertheless CONSTRUCTOR_ELT's value might still be prefixed by nops due possible overflows, or by negative sign/invert/etc.

It shouldn't in any calls to this function; the argument to this 
function should have already been folded.

>>> @@ -5090,9 +5090,9 @@ build_conditional_expr_1 (location_t loc, tree arg1,
>>> tree arg2, tree arg3,
>>>
>>>    valid_operands:
>>>     result = build3 (COND_EXPR, result_type, arg1, arg2, arg3);
>>> -  if (!cp_unevaluated_operand)
>>> +  if (!cp_unevaluated_operand && !processing_template_decl)
>>>       /* Avoid folding within decltype (c++/42013) and noexcept.  */
>>> -    result = fold_if_not_in_template (result);
>>> +    result = fold (result);
>>
>> This seems related to your status report note:
>>
>>> Additionally addressed issue about cond_expr, as we want to fold cases with
>>> a constant-condition.  Here we need to use "fold_to_constant" so that we
>>> just fold things to constant-value, if possible and otherwise don't modify
>>> anything.
>>
>> But why do you say we want to fold cases with a constant condition?  We
>> certainly want to avoid warning about the dead branch in that case, but
>> it would be better if we can do that folding only in the warning code.
>
> Issue is that we otherwise detect in conditions that expressions aren't constant due never-executed-code-path.

How so?  The code for determining whether an expression is constant 
should do the folding.

I think the way to avoid warnings about dead code paths is to do the 
folding in cp_parser_question_colon_clause and in tsubst_copy_and_build, 
case COND_EXPR.

> The diagnostics we can deal differently, but this was actually the reason for doing this.  I can remove this here, but we still need a place to avoid ill detection of constexpr (or invalid code) on dead code-branch.  Eg.  (1 ? 0/0 : 1) etc

>>> @@ -7382,8 +7383,13 @@ build_over_call (struct z_candidate *cand, int
>>> flags, tsu
>>> bst_flags_t complain)
>>>
>>>     gcc_assert (j <= nargs);
>>>     nargs = j;
>>> +  {
>>> +    tree *fargs = (!nargs ? argarray : (tree *) alloca (nargs * sizeof
>>> (tree)))
>>> ;
>>> +    for (j = 0; j < nargs; j++)
>>> +      fargs[j] = fold_non_dependent_expr (argarray[j]);
>>
>> No change needed here, but I notice that fold_non_dependent_expr is
>> still using maybe_constant_value; it should probably use cp_fully_fold
>> instead.
>
> Hmm, maybe we should limit this folding on constants.  So cp_fold_to_constant ()?

This folding is just for diagnostics, so I think cp_fully_fold is the 
right choice.

>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>   {
>>>     if (TREE_TYPE (temp) == type)
>>>       return temp;
>>> +  STRIP_NOPS (temp);
>>> +  if (TREE_TYPE (temp) == type)
>>> +    return temp;
>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
>>> tree t,
>>>   bool
>>>   reduced_constant_expression_p (tree t)
>>>   {
>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>> +  STRIP_NOPS (t);
>>
>> Within the constexpr code we should be folding away NOPs as they are
>> generated, they shouldn't live this long.
>
> Well, we might see them on overflows ...

We shouldn't within the constexpr code.  NOPs for expressions that are 
non-constant due to overflow are added in 
cxx_eval_outermost_constant_expr, so we shouldn't see them in the middle 
of constexpr evaluation.

>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>>> *ctx, tree t,
>>>            && is_dummy_object (x))
>>>          {
>>>            x = ctx->object;
>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>> +         if (x)
>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>> +         else
>>> +           x = get_nth_callarg (t, i);
>>
>> This still should not be necessary.
>
> Yeah, most likely.  But I got initially here some issues, so I don't see that this code would worsen things.

If this code path is hit, that means something has broken my design, and 
I don't want to just paper over that.  Please revert this change.

>>> @@ -1576,13 +1586,15 @@ cxx_eval_unary_expression (const constexpr_ctx
>>> *ctx, tre
>>> e t,
>>>     enum tree_code code = TREE_CODE (t);
>>>     tree type = TREE_TYPE (t);
>>>     r = fold_unary_loc (loc, code, type, arg);
>>> -  if (r == NULL_TREE)
>>> +  if (r == NULL_TREE || !CONSTANT_CLASS_P (r))
>>>       {
>>>         if (arg == orig_arg)
>>>          r = t;
>>>         else
>>>          r = build1_loc (loc, code, type, arg);
>>>       }
>>> +  else
>>> +    r = unify_constant (ctx, r, overflow_p);
>>
>> This still should not be necessary.
>
> Well, I just wanted to make sure that if arg is a PTRMEM_CST (or something like this) that we still try to resolve its constant.  But yes, you are right that arg is anyway resolved already, and so this might not happen.  Nevertheless we might need to handle here OVERFLOW?

We shouldn't, as above.

>>> @@ -1780,7 +1792,8 @@ cxx_eval_component_reference (const constexpr_ctx
>>> *ctx, tree t,
>>>         if (field == part)
>>>          {
>>>            if (value)
>>> -           return value;
>>> +           return cxx_eval_constant_expression (ctx, value, lval,
>>> +                                                non_constant_p,
>>> overflow_p);
>>>            else
>>>              /* We're in the middle of initializing it.  */
>>>              break;
>>> @@ -1864,7 +1877,8 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx,
>>> tree t,
>>>       {
>>>         tree bitpos = bit_position (field);
>>>         if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
>>> -       return value;
>>> +       return cxx_eval_constant_expression (ctx, value, lval,
>>> +                                             non_constant_p, overflow_p);
>>>         if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
>>>            && TREE_CODE (value) == INTEGER_CST
>>>            && tree_fits_shwi_p (bitpos)
>>
>> Again, this shouldn't be necessary, either; the elements of the
>> CONSTRUCTOR should be fully evaluated already.
>
> Evaluated yes, but not necessarily folded to constant.  Maybe cp_fold_to_constant could be better choice here?

By evaluated I mean folded to constant.  We already called 
cxx_eval_constant_expression on all of the elements of the CONSTRUCTOR 
in cxx_eval_bare_aggregate.  If calling it again here does anything at 
all, something is broken.

>>>       case SIZEOF_EXPR:
>>> +      if (processing_template_decl
>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>> +       return t;
>>
>> Why is this necessary?
>
> We don't want to resolve SIZEOF_EXPR within template-declarations for incomplete types, of if its size isn't fixed.  Issue is that we otherwise get issues about expressions without existing type (as usual within template-declarations for some expressions).

Yes, but we shouldn't have gotten this far with a dependent sizeof; 
maybe_constant_value just returns if 
instantiation_dependent_expression_p is true.

>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const constexpr_ctx
>>> *ctx, tree t,
>>>       case CONVERT_EXPR:
>>>       case VIEW_CONVERT_EXPR:
>>>       case NOP_EXPR:
>>> +    case UNARY_PLUS_EXPR:
>>>         {
>>> +       enum tree_code tcode = TREE_CODE (t);
>>>          tree oldop = TREE_OPERAND (t, 0);
>>> +
>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
>>> TREE_OVERFLOW_P (oldop))
>>> +         {
>>> +           if (!ctx->quiet)
>>> +             permerror (input_location, "overflow in constant
>>> expression");
>>> +           /* If we're being permissive (and are in an enforcing
>>> +               context), ignore the overflow.  */
>>> +           if (!flag_permissive)
>>> +             *overflow_p = true;
>>> +           *non_constant_p = true;
>>> +
>>> +           return t;
>>> +         }
>>>          tree op = cxx_eval_constant_expression (ctx, oldop,
>>
>> Why doesn't the call to cxx_eval_constant_expression at the bottom here
>> handle oldop having TREE_OVERFLOW set?
>
> I just handled the case that we see here a wrapping NOP_EXPR around an overflow.  As this isn't handled by cxx_eval_constant_expression.

How does it need to be handled?  A NOP_EXPR wrapped around an overflow 
is there to indicated that the expression is non-constant, and it can't 
be simplified any farther.

Please give an example of what was going wrong.

>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
>>> gimple_seq *post_p)
>>>
>>>     switch (code)
>>>       {
>>> +    case SIZEOF_EXPR:
>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
>>> (*expr_p,
>>> +                                                                      0)),
>>> +                                             SIZEOF_EXPR, false);
>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p, 0),
>>> +                                             SIZEOF_EXPR, false);
>>> +      else
>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p, 0),
>>> +                                             SIZEOF_EXPR, false);
>>> +      if (*expr_p == error_mark_node)
>>> +       *expr_p = size_one_node;
>>> +
>>> +      *expr_p = maybe_constant_value (*expr_p);
>>> +      ret = GS_OK;
>>> +      break;
>>
>> Why are these surviving until gimplification time?
>
> This might be still necessary. I will retest, when bootstrap works.  As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all expressions a sizeof can occure, this shouldn't be necessary anymore.  AFAIR I saw here some issues about initialzation for global-variables, which weren't caught.

Hmm, I wonder why you would see issues with global initializers that 
aren't seen on trunk?  In any case, if the issue is with global 
initializers, they should be handled sooner, not here.

>>> +static tree
>>> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
>>
>> Looks like cp_fold still doesn't call maybe_constant_value.
>
> Yes, it should do this just in case of seen PTRMEM_CST.  Or shall we try to invoke it on each iteration within cp_fold.  Later might be a bit costy, isn't it?

I was thinking the latter; as I keep saying, we want to fold constexpr 
function calls at this point, too.

Yes, it might be too costly without some adjustments to cache 
intermediate values, or at least whether particular subexpressions are 
constant.

>>> +  case CALL_EXPR:
>>> +    r = fold (x);
>>> +    if (TREE_CODE (r) != CALL_EXPR)
>>> +      {
>>> +       x = cp_fold (r, fold_hash);
>>> +       break;
>>> +      }
>>> +    {
>>> +      int i, m = call_expr_nargs (x);
>>> +      for (i = 0; i < m; i++)
>>> +        {
>>> +         CALL_EXPR_ARG (x, i) = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
>>> +       }
>>> +    }
>>> +    r = fold (x);
>>> +    if (TREE_CODE (r) != CALL_EXPR)
>>> +      {
>>> +       x = cp_fold (r, fold_hash);
>>> +       break;
>>> +      }
>>> +    return org_x;
>>
>> Why return org_x here?  Don't we still want to add this to the hash table?
>
> No, as we just tried here to fold expression-arguments, so that later fold might be able to optimize.  So x is intermediate, and we don't want to cache it.
>
> But well, we might want to hash here org_x itself ...

Right, that's what I was thinking.

>> I'm also nervous about clobbering the args in the original CALL_EXPR.
>> In most of cp_fold you build a new expression rather than change the
>> operands of the original one.
>
> Well, this shouldn't be problematic IMP.  I just wanted to avoid to make use of a node-copy, which might be for a call-expression expensive.  But well, as we now have cp_try_fold_to_constant, this could lead indeed to folded call-expressions too early.  Before cp_fold was just used in the final folding before gimplification, where these modifications weren't problematic at all.
> So we might want to avoid such argument-conversion in context of cp_try_fold_to_constant at all?

You could use a temporary vector like in the TREE_VEC folding code, and 
only create a new CALL_EXPR if there's a change?

>>> @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
>>>       }
>>>     else
>>>       {
>>> -      conv = fold_convert (type, expr);
>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>> +        conv = fold_convert (type, expr);
>>> +      else
>>> +        conv = convert (type, expr);
>>
>> I still think that cp_fold_convert should always call fold_convert, and
>> callers that we don't want to fold should call convert instead, or
>> another function that folds only conversion of constants.  We had talked
>> about the name "fold_cst", but I think that name isn't very clear; would
>> it make sense to just have convert always fold conversions of constants?
>
> We could introduce that, but we still have the issues about some unary-operations on constants, too.  So we could do for any conversion afterwards a call to cp_try_fold_to_constant, which should reflect that pretty well, beside within template-declarations ...

I think cp_try_fold_to_constant would do too much folding.  I think we 
only want to immediately fold conversions and negation.

>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree expr,
>>> bool complain)
>>>     tree basetype = TREE_TYPE (expr);
>>>     tree conv = NULL_TREE;
>>>     tree winner = NULL_TREE;
>>> +  /* Want to see if EXPR is a constant.  See below checks for null_node.
>>> */
>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>
>>> -  if (expr == null_node
>>> +  STRIP_NOPS (expr_folded);
>>> +  if (expr_folded == null_node
>>
>> Again, we shouldn't need to fold to check for null_node, it only occurs
>> when explicitly written.  Folding should never produce null_node unless
>> the argument was already null_node.
>
> Well, we need to do this for diagnostic messages AFAIR.  We want to see if expression folded gets a constant, so that diagnostics getting displayed right.

Again, null_node is special.  It indicates that the user typed "__null". 
  That's what we're checking for here.  Folding is both unnecessary and 
undesirable.

>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree expr,
>>> bool complain)
>>>       switch (TREE_CODE (basetype))
>>>         {
>>>         case INTEGER_TYPE:
>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>
>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
>> fold in null_ptr_cst_p.
>
> We need to avoid useless conversion, so we should reduce to simple constant-value ...

No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A 
more complex expression that folds to 0 is NOT a null pointer constant. 
  Folding is actively harmful here.

And again, in C++98 mode null_ptr_cst_p already folds, so doing it here 
is redundant.

Was I unclear?

>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
>>> tsubst_flags_t complain)
>>>         SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>         return itype;
>>>       }
>>> -
>>> +
>>> +  /* We need to do fully folding to determine if we have VLA, or not.  */
>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>
>> Again, we already called maybe_constant_value.
>
> Sure, but maybe_constant_value still produces nops ...

If someone tries to create an array with a size that involves arithmetic 
overflow, that's undefined behavior and we should probably give an error 
rather than fold it away.

>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
>>> enumtype, tree attributes,
>>>     if (value)
>>>       STRIP_TYPE_NOPS (value);
>>>
>>> +  if (value)
>>> +    value = cp_try_fold_to_constant (value);
>>
>> Again, this is unnecessary because we call cxx_constant_value below.
>
> See nops, and other unary-operations we want to reduce here to real constant value ...

The cxx_constant_value call below will deal with them.

>>> @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree
>>> enumtype, tree attributes,
>>>            if (value != NULL_TREE)
>>>              {
>>>                value = cxx_constant_value (value);
>>> +             STRIP_NOPS (value);
>>
>> Again, the only time a constant result should have a NOP_EXPR around it
>> is if it isn't really constant.  Why do you want to strip that?
>
> As for an enumerator-value we might have overflows, which are silently ignored.

They shouldn't be ignored.  C++ requires that the value be constant, and 
overflow makes it non-constant.

> I will recheck this what example we have for this when bootstrap is working again.
>
>>> @@ -6136,6 +6139,10 @@ push_to_top_level (void)
>>>     else
>>>       need_pop = false;
>>>
>>> +  if (scope_chain)
>>> +    fm = scope_chain->fold_map;
>>> +  else
>>> +    fm = NULL;
>>>     if (scope_chain && previous_class_level)
>>>       store_class_bindings (previous_class_level->class_shadowed,
>>>                            &s->old_bindings);
>>> @@ -6167,6 +6174,9 @@ push_to_top_level (void)
>>>     FOR_EACH_VEC_SAFE_ELT (s->old_bindings, i, sb)
>>>       IDENTIFIER_MARKED (sb->identifier) = 0;
>>>
>>> +  if (!fm)
>>> +    fm = new hash_map<tree, tree>;
>>
>> Why are these hunks so far apart?  I would expect them to be all together.
>
> Oh, nothing special.  I just wanted to have base initialization together with the other if initializes, and doing then later near assignment the optional allocation.
> I can change this, if you prefer.

Thanks, I would prefer that.

>>> @@ -6473,7 +6473,8 @@ cp_parser_array_notation (location_t loc, cp_parser
>>> *parser, tree *init_index,
>>>           2. ARRAY [ EXP : EXP ]
>>>           3. ARRAY [ EXP : EXP : EXP ]  */
>>>
>>> -      *init_index = cp_parser_expression (parser);
>>> +      *init_index = cp_parser_expression (parser);
>>> +      *init_index = cp_try_fold_to_constant (*init_index);
>>>         if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
>>>          {
>>>            /* This indicates that we have a normal array expression.  */
>>> @@ -6484,10 +6485,12 @@ cp_parser_array_notation (location_t loc, cp_parser
>>> *parser, tree *init_index,
>>>         /* Consume the ':'.  */
>>>         cp_lexer_consume_token (parser->lexer);
>>>         length_index = cp_parser_expression (parser);
>>> +      length_index = cp_try_fold_to_constant (length_index);
>>>         if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
>>>          {
>>>            cp_lexer_consume_token (parser->lexer);
>>>            stride = cp_parser_expression (parser);
>>> +         stride = cp_try_fold_to_constant (stride);
>>
>> Again, why fold here, rather than later when something really wants a
>> constant?  If that ever actually occurs?
>
> This code for cilk expects that these statements are folded to constants.  It doesn't make much difference to move those folders to later locations, as we have to fold them early anyway.

Yes, I think we should fold them in the cilk code that expects that.

>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression (cp_parser
>>> *parser,
>>>          index = cp_parser_expression (parser);
>>>       }
>>>
>>> +  /* For offsetof and declaration of types we need
>>> +     constant integeral values.
>>> +     Also we meed to fold for negative constants so that diagnostic in
>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>> +  if (for_offsetof || decltype_p
>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>>> (index, 0)) == INTEGER_CST))
>>> +    index = cp_try_fold_to_constant (index);
>>
>> Similarly, for offsetof the folding should happen closer to where it is
>> needed.
>>
>> Why is it needed for decltype, which is querying the type of an expression?
>>
>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>> constant; this isn't the right place to do it.
>
> Same as above, we need in those cases (and for -1 too) the constant values early anyway.  So I saw it as more logical to have done this conversion as soon as possible after initialization.

I don't think this is as soon as possible; we can fold the NEGATE_EXPR 
immediately when we build it, at the end of cp_build_unary_op.

I still wonder why any folding is necessary for decltype.  When I ask 
why, I want to know *why*, not just have you tell me again that it's 
needed.  I don't think it is.

For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to 
handle whatever additional folding is needed here.  If not, then fold in 
finish_offsetof, before calling fold_offsetof.

>>> @@ -8031,7 +8041,9 @@ cp_parser_cast_expression (cp_parser *parser, bool
>>> address_p, bool cast_p,
>>>                  return error_mark_node;
>>>
>>>                /* Perform the cast.  */
>>> -             expr = build_c_cast (input_location, type, expr);
>>> +             /* We don't want to resolve cast too early.  Therefore we
>>> don't
>>> +                be able to use build_c_cast.  */
>>> +             expr = cp_build_c_cast (type, expr, tf_warning_or_error);
>>
>> Huh?  build_c_cast just calls cp_build_c_cast.
>
> Yes, as we don't want to do cast-folding too early.

My point is that this change doesn't actually change anything; either 
way we're calling cp_build_c_cast, with the same arguments.

>>> @@ -9869,6 +9881,7 @@ cp_parser_label_for_labeled_statement (cp_parser*
>>> parser, tree attributes)
>>>          cp_lexer_consume_token (parser->lexer);
>>>          /* Parse the constant-expression.  */
>>>          expr = cp_parser_constant_expression (parser);
>>> +       expr = cp_try_fold_to_constant (expr);
>>>          if (check_for_bare_parameter_packs (expr))
>>>            expr = error_mark_node;
>>>
>>> @@ -9878,6 +9891,7 @@ cp_parser_label_for_labeled_statement (cp_parser*
>>> parser, tree attributes)
>>>              /* Consume the `...' token.  */
>>>              cp_lexer_consume_token (parser->lexer);
>>>              expr_hi = cp_parser_constant_expression (parser);
>>> +           expr_hi = cp_try_fold_to_constant (expr_hi);
>>
>> Again, this seems redundant with the call to cxx_constant_value in
>> case_conversion.
>
> Well, but we want to do here check_for_bare_parameter_packs directly after that, and so we need folded value early.

Why would check_for_bare_parameter_packs need a folded value?

>>> @@ -16115,6 +16133,7 @@ cp_parser_enumerator_definition (cp_parser* parser,
>>> tree type)
>>>         cp_lexer_consume_token (parser->lexer);
>>>         /* Parse the value.  */
>>>         value = cp_parser_constant_expression (parser);
>>> +      value = cp_try_fold_to_constant (value);
>>
>> Again, this is redundant with the code in build_enumerator.
>
> Hmm, don't see here redundancy.  I just see that we need folded-value for leter call of check_for_bare_parameter_packs.  But might not see the obvious

As above, I don't see any connection between 
check_for_bare_parameter_packs and folding.

>>> @@ -19354,12 +19374,10 @@ cp_parser_initializer_clause (cp_parser* parser,
>>> bool* non_constant_p)
>>>     /* If it is not a `{', then we are looking at an
>>>        assignment-expression.  */
>>>     if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
>>> -    {
>>> -      initializer
>>> -       = cp_parser_constant_expression (parser,
>>> -                                       /*allow_non_constant_p=*/true,
>>> -                                       non_constant_p);
>>> -    }
>>> +    initializer
>>> +      = cp_parser_constant_expression (parser,
>>> +                                     /*allow_non_constant_p=*/true,
>>> +                                     non_constant_p);
>>
>> Let's not reformat unrelated code in a big project like this.
>
> Well, but it violates coding-rules.  anyway agreed ;)

If you want to apply that fix to the trunk, go ahead, but it's 
distracting when looking at the branch.  :)

>>> @@ -20955,9 +20973,11 @@ cp_parser_member_declaration (cp_parser* parser)
>>>
>>>                /* Consume the `:' token.  */
>>>                cp_lexer_consume_token (parser->lexer);
>>> +
>>>                /* Get the width of the bitfield.  */
>>>                width
>>>                  = cp_parser_constant_expression (parser);
>>> +             width = maybe_constant_value (width);
>>
>> Again, this seems redundant with the call to cxx_constant_value in
>> check_bitfield_decl.
>
> Ah, this escaped.  This should be a cp_try_fold_to_constant.

It should be removed entirely, because it's redundant.

>> Again, it seems like you added maybe_constant_value or
>> cp_try_fold_to_constant after every occurrence of
>> cp_parser_constant_expression, and I suspect that few are actually
>> needed, and the ones that are should go closer to the code that really
>> needs a constant.  I'd prefer to avoid calling it at all in parser.c.
>
> Actually it should be cp_try_fold_to_constant, as at those places we need to deal anyway with constant-values.  At some please we use those values already for some diagnostics, so I thoght it is more consistent to do this folding to constant directly after parsing it.  To delay that into builder-routines is IMO just less clear, and could lead to double-doing foldings.  Additionally the chance to conflict here with shared parts with C is much less.
>
> Anyway, if you prefer, we can do this in builder-routines, and remove at places constants aren't needed directly after parsing it those calls.

I want to delay it to:

1) the places where we actually care about constant values, all of which 
already call maybe_constant_value or cxx_constant_value, so they 
shouldn't need much change; and
2) the places where we want a simplified expression for warnings, where 
we should call cp_fully_fold.

Folding in the parser is wrong, most of all because template 
substitution doesn't go through the parser.

>>>   finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
>>>                        tsubst_flags_t complain)
>>>   {
>>> +  tree expr_ovl = expr;
>>>     tree result = build_x_unary_op (loc, code, expr, complain);
>>> +  tree result_ovl = result;
>>> +
>>> +  STRIP_NOPS (expr_ovl);
>>> +  switch (code)
>>> +    {
>>> +    case ABS_EXPR:
>>> +    case NEGATE_EXPR:
>>> +      if (TREE_CODE (expr) == INTEGER_CST
>>> +         || TREE_CODE (expr) == REAL_CST
>>> +         || TREE_CODE (expr) == VECTOR_CST
>>> +         || TREE_CODE (expr) == FIXED_CST
>>> +         || TREE_CODE (expr) == COMPLEX_CST)
>>> +      result_ovl = fold (result);
>>> +      break;
>>> +    default:
>>> +      break;
>>> +    }
>>
>> Not cp_fully_fold?
>
> Hmm, yeah,  I changed the switch to a call to cp_try_fold_to_constant, which should be pretty exactly what we are looking here for diagnostics.

For diagnostics we want cp_fully_fold, so we get a simplified expression 
even if it isn't constant.

>>> @@ -6301,8 +6321,9 @@ handle_omp_for_class_iterator (int i, location_t
>>> locus, tree declv, tree initv,
>>>                                      tf_warning_or_error);
>>>         if (error_operand_p (iter_incr))
>>>          return true;
>>> -      else if (TREE_CODE (incr) == PREINCREMENT_EXPR
>>> -              || TREE_CODE (incr) == POSTINCREMENT_EXPR)
>>> +      iter_incr = fold (iter_incr);
>>> +      if (TREE_CODE (incr) == PREINCREMENT_EXPR
>>> +         || TREE_CODE (incr) == POSTINCREMENT_EXPR)
>>> @@ -6357,6 +6376,7 @@ handle_omp_for_class_iterator (int i, location_t
>>> locus, tree declv, tree initv,
>>>                                                   tf_warning_or_error);
>>>                    if (error_operand_p (iter_incr))
>>>                      return true;
>>> +                 iter_incr = fold (iter_incr);
>>>                    iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs),
>>>                                                     iter, NOP_EXPR,
>>>                                                     iter_incr,
>>> @@ -6364,6 +6384,7 @@ handle_omp_for_class_iterator (int i, location_t
>>> locus, tree declv, tree initv,
>>>                    if (error_operand_p (iter_incr))
>>>                      return true;
>>>                    incr = TREE_OPERAND (rhs, 0);
>>> +                 incr = fold (incr);
>>
>> Why are these folds needed?

Still wondering.

>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>     else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>       fn = AGGR_INIT_EXPR_FN (init);
>>>     else
>>> -    return convert (type, init);
>>> +    return fold (convert (type, init));
>>
>> Why fold here?
>
> We had this already in prior thread.  fold (convert ()) != fold_convert () for C++.  The fold is just there to make sure we fold away useless casts.

But why here?  Can't we fold away useless casts earlier (in convert) or 
later (when we care about having a simplified expression)?

>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree, va_gc>
>>> **values, tree fndecl,
>>>            && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>          val = TREE_OPERAND (val, 0);
>>>
>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>> +       val = fold (val);
>>
>> Why?
>
> As builtin-handlers are expecting to see constant values.

Doesn't cp_fold fold the arguments before trying to fold the calls?

Hmm, I guess build_cxx_call calls check_builtin_function_arguments, 
which expects constants for some builtins.  Maybe a C++ wrapper for that 
function could fold the arguments before passing them along.

> Otherwise the produce either ICE, or other funny things.  We could call here instead also the cp_try_fold... function.
> Btw some lines above there is a comment about NOP_EXPR being extended to indicate that a value isn't lvalue.  Not sure if this NOP_EXPR strip is still necessary, as we don't call anymore directly into build_c_cast ().  I need to check if cp-version does the same.
>
>>> @@ -4941,7 +4938,7 @@ cp_build_binary_op (location_t location,
>>>               from being kept in a register.
>>>               Instead, make copies of the our local variables and
>>>               pass the copies by reference, then copy them back afterward.
>>>               */
>>> -         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
>>> +         tree xop0 = fold (op0), xop1 = fold (op1), xresult_type =
>>> result_type;
>>
>> Again, this seems wrong.  In fact, the whole short_compare business
>> seems like the sort of early folding we want to do away with.
>>
>>> @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
>>>       }
>>>
>>>     result = build2 (resultcode, build_type, op0, op1);
>>> -  result = fold_if_not_in_template (result);
>>>     if (final_type != 0)
>>>       result = cp_convert (final_type, result, complain);
>>> -
>>> -  if (TREE_OVERFLOW_P (result)
>>> +  op0 = fold_non_dependent_expr (op0);
>>> +  op1 = fold_non_dependent_expr (op1);
>>> +  STRIP_NOPS (op0);
>>> +  STRIP_NOPS (op1);
>>> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
>>> +  if (TREE_OVERFLOW_P (result_ovl)
>>>         && !TREE_OVERFLOW_P (op0)
>>>         && !TREE_OVERFLOW_P (op1))
>>> -    overflow_warning (location, result);
>>> +    overflow_warning (location, result_ovl);
>>
>> Don't you want to use cp_fully_fold here?

?

>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
>>>         /* Handle OMP_FOR_COND.  */
>>>         t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>         gcc_assert (COMPARISON_CLASS_P (t));
>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) ==
>>> decl);
>>
>> Why didn't delayed folding canonicalize this so that the decl is in op0?
>
> Delay folding doesn't canonicalize this.

Why not?  Doesn't it fold all expressions?

> Actually we don't want to touch here anything in parsered tree.  We could do this in generalization-pass before gimplification.  Seems to be something we don't catch for now, which makes me wonder a bit.
>
>>> @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct
>>> omp_for_data *fd,
>>>            gcc_assert (gimple_omp_for_kind (for_stmt)
>>>                        == GF_OMP_FOR_KIND_CILKSIMD
>>>                        || (gimple_omp_for_kind (for_stmt)
>>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>>> +                     || (gimple_omp_for_kind (for_stmt)
>>> +                         == GF_OMP_FOR_KIND_FOR));
>>
>> This still seems like a red flag; how is delayed folding changing the
>> OMP for kind?
>
> It doesn't.  The issue is that some canonical operations of fold aren't happening anymore on which omp depends.

That seems like a problem.

>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>>>   {
>>>     tree t = make_node (COMPLEX_CST);
>>>
>>> +  real = fold (real);
>>> +  imag = fold (imag);
>>
>> I still think this is wrong.  The arguments should be sufficiently folded.
>
> As we don't fold unary-operators on constants, we need to fold it at some place.  AFAICS is the C++ FE not calling directly build_complex.  So this place was the easiest way to avoid issues with things like '-' '1' etc.

Is this because of the
>       value = build_complex (NULL_TREE, convert (const_type,
>                                                  integer_zero_node), value);
in interpret_float?  I think "convert" definitely needs to do some 
folding, since it's called from middle-end code that expects that.

>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state *local,
>>> unsigned int bit_offset)
>>>     while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>           || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>       local->val = TREE_OPERAND (local->val, 0);
>>> +  local->val = fold (local->val);
>>
>> Likewise.
>
> As soon as we can be sure that values getting fully_folded, or at least folded for constants, we should be able to remove this.

Yep, they need to be folded before we get here.

It looks like your latest checkin added more redundant folding:

> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree low_value, tree hi
> gh_value)
>    low_value = case_conversion (type, low_value);
>    high_value = case_conversion (type, high_value);
>
> +  low_value = cp_fully_fold (low_value);
> +  high_value = cp_fully_fold (high_value);

Again, case_conversion should have already folded constants.

> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>  {
>    tree expr_type;
>
> +  expr = cp_try_fold_to_constant (expr);
> +
>    /* Detect immediately string literals as invalid non-type argument.
>       This special-case is not needed for correctness (we would easily
>       catch this later), but only to provide better diagnostic for this
> @@ -5852,6 +5854,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>        else if (TYPE_PTR_OR_PTRMEM_P (type))
>         {
>           tree folded = maybe_constant_value (expr);
> +         folded = cp_try_fold_to_constant (expr);

And here, convert_nontype_argument already uses 
maybe_constant_value/cxx_constant_value for folding constants.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-06-13  7:58   ` Jason Merrill
@ 2015-07-27 19:01     ` Jason Merrill
  2015-07-28  2:40       ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-07-27 19:01 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

I've trimmed this to the previously mentioned issues that still need to 
be addressed; I'll do another full review after these are dealt with.

On 06/13/2015 12:15 AM, Jason Merrill wrote:
> On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>>   {
>>>>     if (TREE_TYPE (temp) == type)
>>>>       return temp;
>>>> +  STRIP_NOPS (temp);
>>>> +  if (TREE_TYPE (temp) == type)
>>>> +    return temp;
>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>> *ctx,
>>>> tree t,
>>>>   bool
>>>>   reduced_constant_expression_p (tree t)
>>>>   {
>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>> +  STRIP_NOPS (t);
>>>
>>> Within the constexpr code we should be folding away NOPs as they are
>>> generated, they shouldn't live this long.
>>
>> Well, we might see them on overflows ...
>
> We shouldn't within the constexpr code.  NOPs for expressions that are
> non-constant due to overflow are added in
> cxx_eval_outermost_constant_expr, so we shouldn't see them in the middle
> of constexpr evaluation.
>
>>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>>>> *ctx, tree t,
>>>>            && is_dummy_object (x))
>>>>          {
>>>>            x = ctx->object;
>>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>>> +         if (x)
>>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>>> +         else
>>>> +           x = get_nth_callarg (t, i);
>>>
>>> This still should not be necessary.
>>
>> Yeah, most likely.  But I got initially here some issues, so I don't
>> see that this code would worsen things.
>
> If this code path is hit, that means something has broken my design, and
> I don't want to just paper over that.  Please revert this change.
>
>>>>       case SIZEOF_EXPR:
>>>> +      if (processing_template_decl
>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>> +       return t;
>>>
>>> Why is this necessary?
>>
>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>> incomplete types, of if its size isn't fixed.  Issue is that we
>> otherwise get issues about expressions without existing type (as usual
>> within template-declarations for some expressions).
>
> Yes, but we shouldn't have gotten this far with a dependent sizeof;
> maybe_constant_value just returns if
> instantiation_dependent_expression_p is true.
>
>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>> constexpr_ctx
>>>> *ctx, tree t,
>>>>       case CONVERT_EXPR:
>>>>       case VIEW_CONVERT_EXPR:
>>>>       case NOP_EXPR:
>>>> +    case UNARY_PLUS_EXPR:
>>>>         {
>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>          tree oldop = TREE_OPERAND (t, 0);
>>>> +
>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
>>>> TREE_OVERFLOW_P (oldop))
>>>> +         {
>>>> +           if (!ctx->quiet)
>>>> +             permerror (input_location, "overflow in constant
>>>> expression");
>>>> +           /* If we're being permissive (and are in an enforcing
>>>> +               context), ignore the overflow.  */
>>>> +           if (!flag_permissive)
>>>> +             *overflow_p = true;
>>>> +           *non_constant_p = true;
>>>> +
>>>> +           return t;
>>>> +         }
>>>>          tree op = cxx_eval_constant_expression (ctx, oldop,
>>>
>>> Why doesn't the call to cxx_eval_constant_expression at the bottom here
>>> handle oldop having TREE_OVERFLOW set?
>>
>> I just handled the case that we see here a wrapping NOP_EXPR around an
>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>
> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
> is there to indicated that the expression is non-constant, and it can't
> be simplified any farther.
>
> Please give an example of what was going wrong.
>
>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
>>>> gimple_seq *post_p)
>>>>
>>>>     switch (code)
>>>>       {
>>>> +    case SIZEOF_EXPR:
>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
>>>> (*expr_p,
>>>> +
>>>> 0)),
>>>> +                                             SIZEOF_EXPR, false);
>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>> 0),
>>>> +                                             SIZEOF_EXPR, false);
>>>> +      else
>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>> 0),
>>>> +                                             SIZEOF_EXPR, false);
>>>> +      if (*expr_p == error_mark_node)
>>>> +       *expr_p = size_one_node;
>>>> +
>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>> +      ret = GS_OK;
>>>> +      break;
>>>
>>> Why are these surviving until gimplification time?
>>
>> This might be still necessary. I will retest, when bootstrap works.
>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>> AFAIR I saw here some issues about initialzation for global-variables,
>> which weren't caught.
>
> Hmm, I wonder why you would see issues with global initializers that
> aren't seen on trunk?  In any case, if the issue is with global
> initializers, they should be handled sooner, not here.
>
>>>> @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
>>>>       }
>>>>     else
>>>>       {
>>>> -      conv = fold_convert (type, expr);
>>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>>> +        conv = fold_convert (type, expr);
>>>> +      else
>>>> +        conv = convert (type, expr);
>>>
>>> I still think that cp_fold_convert should always call fold_convert, and
>>> callers that we don't want to fold should call convert instead, or
>>> another function that folds only conversion of constants.  We had talked
>>> about the name "fold_cst", but I think that name isn't very clear; would
>>> it make sense to just have convert always fold conversions of constants?
>>
>> We could introduce that, but we still have the issues about some
>> unary-operations on constants, too.  So we could do for any conversion
>> afterwards a call to cp_try_fold_to_constant, which should reflect
>> that pretty well, beside within template-declarations ...

Now we've been talking about calling it "fold_simple".

>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>> expr,
>>>> bool complain)
>>>>     tree basetype = TREE_TYPE (expr);
>>>>     tree conv = NULL_TREE;
>>>>     tree winner = NULL_TREE;
>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>> null_node.
>>>> */
>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>
>>>> -  if (expr == null_node
>>>> +  STRIP_NOPS (expr_folded);
>>>> +  if (expr_folded == null_node
>>>
>>> Again, we shouldn't need to fold to check for null_node, it only occurs
>>> when explicitly written.  Folding should never produce null_node unless
>>> the argument was already null_node.
>>
>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>> see if expression folded gets a constant, so that diagnostics getting
>> displayed right.
>
> Again, null_node is special.  It indicates that the user typed "__null".
> That's what we're checking for here.  Folding is both unnecessary and
> undesirable.
>
>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>> expr,
>>>> bool complain)
>>>>       switch (TREE_CODE (basetype))
>>>>         {
>>>>         case INTEGER_TYPE:
>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>
>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
>>> fold in null_ptr_cst_p.
>>
>> We need to avoid useless conversion, so we should reduce to simple
>> constant-value ...
>
> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
> more complex expression that folds to 0 is NOT a null pointer constant.
> Folding is actively harmful here.
>
> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
> is redundant.
>
> Was I unclear?
>
>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
>>>> tsubst_flags_t complain)
>>>>         SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>         return itype;
>>>>       }
>>>> -
>>>> +
>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>> not.  */
>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>
>>> Again, we already called maybe_constant_value.
>>
>> Sure, but maybe_constant_value still produces nops ...
>
> If someone tries to create an array with a size that involves arithmetic
> overflow, that's undefined behavior and we should probably give an error
> rather than fold it away.
>
>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
>>>> enumtype, tree attributes,
>>>>     if (value)
>>>>       STRIP_TYPE_NOPS (value);
>>>>
>>>> +  if (value)
>>>> +    value = cp_try_fold_to_constant (value);
>>>
>>> Again, this is unnecessary because we call cxx_constant_value below.
>>
>> See nops, and other unary-operations we want to reduce here to real
>> constant value ...
>
> The cxx_constant_value call below will deal with them.

Likewise for grokbitfield.

>>>> @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree
>>>> enumtype, tree attributes,
>>>>            if (value != NULL_TREE)
>>>>              {
>>>>                value = cxx_constant_value (value);
>>>> +             STRIP_NOPS (value);
>>>
>>> Again, the only time a constant result should have a NOP_EXPR around it
>>> is if it isn't really constant.  Why do you want to strip that?
>>
>> As for an enumerator-value we might have overflows, which are silently
>> ignored.
>
> They shouldn't be ignored.  C++ requires that the value be constant, and
> overflow makes it non-constant.
>
>> I will recheck this what example we have for this when bootstrap is
>> working again.
>>
>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>> (cp_parser
>>>> *parser,
>>>>          index = cp_parser_expression (parser);
>>>>       }
>>>>
>>>> +  /* For offsetof and declaration of types we need
>>>> +     constant integeral values.
>>>> +     Also we meed to fold for negative constants so that diagnostic in
>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>> +  if (for_offsetof || decltype_p
>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>>>> (index, 0)) == INTEGER_CST))
>>>> +    index = cp_try_fold_to_constant (index);
>>>
>>> Similarly, for offsetof the folding should happen closer to where it is
>>> needed.
>>>
>>> Why is it needed for decltype, which is querying the type of an
>>> expression?
>>>
>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>> constant; this isn't the right place to do it.
>>
>> Same as above, we need in those cases (and for -1 too) the constant
>> values early anyway.  So I saw it as more logical to have done this
>> conversion as soon as possible after initialization.
>
> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
> immediately when we build it, at the end of cp_build_unary_op.
>
> I still wonder why any folding is necessary for decltype.  When I ask
> why, I want to know *why*, not just have you tell me again that it's
> needed.  I don't think it is.
>
> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
> handle whatever additional folding is needed here.  If not, then fold in
> finish_offsetof, before calling fold_offsetof.

I see that this is now an unconditional fold_simple, but I still don't 
understand why it needs to be folded here, in the parser.

 >....
>> Anyway, if you prefer, we can do this in builder-routines, and remove
>> at places constants aren't needed directly after parsing it those calls.
>
> I want to delay it to:
>
> 1) the places where we actually care about constant values, all of which
> already call maybe_constant_value or cxx_constant_value, so they
> shouldn't need much change; and
> 2) the places where we want a simplified expression for warnings, where
> we should call fold_simple.

> Folding in the parser is wrong, most of all because template
> substitution doesn't go through the parser.

There are still several folds in cp_parser_omp_* that should move later.

>  finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
>                       tsubst_flags_t complain)
>  {
> +  tree expr_ovl = expr;
>    tree result = build_x_unary_op (loc, code, expr, complain);
> +  tree result_ovl =  result;
> +
> +  expr_ovl = fold_simple (expr_ovl);
> +  STRIP_NOPS (expr_ovl);

Why both fold_simple and STRIP_NOPS?

>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>     else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>       fn = AGGR_INIT_EXPR_FN (init);
>>>>     else
>>>> -    return convert (type, init);
>>>> +    return fold (convert (type, init));
>>>
>>> Why fold here?
>>
>> We had this already in prior thread.  fold (convert ()) !=
>> fold_convert () for C++.  The fold is just there to make sure we fold
>> away useless casts.
>
> But why here?  Can't we fold away useless casts earlier (in convert) or
> later (when we care about having a simplified expression)?
>
>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>> va_gc>
>>>> **values, tree fndecl,
>>>>            && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>          val = TREE_OPERAND (val, 0);
>>>>
>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>> +       val = fold (val);
>>>
>>> Why?
>>
>> As builtin-handlers are expecting to see constant values.

I would think this should be maybe_constant_value then.

>>>> @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
>>>>       }
>>>>
>>>>     result = build2 (resultcode, build_type, op0, op1);
>>>> -  result = fold_if_not_in_template (result);
>>>>     if (final_type != 0)
>>>>       result = cp_convert (final_type, result, complain);
>>>> -
>>>> -  if (TREE_OVERFLOW_P (result)
>>>> +  op0 = fold_non_dependent_expr (op0);
>>>> +  op1 = fold_non_dependent_expr (op1);
>>>> +  STRIP_NOPS (op0);
>>>> +  STRIP_NOPS (op1);
>>>> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
>>>> +  if (TREE_OVERFLOW_P (result_ovl)
>>>>         && !TREE_OVERFLOW_P (op0)
>>>>         && !TREE_OVERFLOW_P (op1))
>>>> -    overflow_warning (location, result);
>>>> +    overflow_warning (location, result_ovl);
>>>
>>> Don't you want to use cp_fully_fold here?
>
> ?

Introducing *_non_dependent_expr is definitely wrong here.

>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>> *pre_p)
>>>>         /* Handle OMP_FOR_COND.  */
>>>>         t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>         gcc_assert (COMPARISON_CLASS_P (t));
>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>> 1) ==
>>>> decl);
>>>
>>> Why didn't delayed folding canonicalize this so that the decl is in op0?
>>
>> Delay folding doesn't canonicalize this.
>
> Why not?  Doesn't it fold all expressions?

?

>> Actually we don't want to touch here anything in parsered tree.  We
>> could do this in generalization-pass before gimplification.  Seems to
>> be something we don't catch for now, which makes me wonder a bit.
>>
>>>> @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct
>>>> omp_for_data *fd,
>>>>            gcc_assert (gimple_omp_for_kind (for_stmt)
>>>>                        == GF_OMP_FOR_KIND_CILKSIMD
>>>>                        || (gimple_omp_for_kind (for_stmt)
>>>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>>>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>>>> +                     || (gimple_omp_for_kind (for_stmt)
>>>> +                         == GF_OMP_FOR_KIND_FOR));
>>>
>>> This still seems like a red flag; how is delayed folding changing the
>>> OMP for kind?
>>
>> It doesn't.  The issue is that some canonical operations of fold
>> aren't happening anymore on which omp depends.
>
> That seems like a problem.

> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab binoptab,
>          are truncated to the mode size.  */
>        carries = expand_binop (word_mode, reverse_unsigned_shift,
>                               outof_input, const1_rtx, 0, unsignedp, methods);
> -      if (shift_mask == BITS_PER_WORD - 1)
> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))

These should still be unnecessary.

>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>>>>   {
>>>>     tree t = make_node (COMPLEX_CST);
>>>>
>>>> +  real = fold (real);
>>>> +  imag = fold (imag);
>>>
>>> I still think this is wrong.  The arguments should be sufficiently
>>> folded.
>>
>> As we don't fold unary-operators on constants, we need to fold it at
>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>> So this place was the easiest way to avoid issues with things like '-'
>> '1' etc.
>
> Is this because of the
>>       value = build_complex (NULL_TREE, convert (const_type,
>>                                                  integer_zero_node),
>> value);
> in interpret_float?  I think "convert" definitely needs to do some
> folding, since it's called from middle-end code that expects that.

I remember talking about "convert" doing some folding (and cp_convert 
not) in our 1:1 last week.

>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>> *local,
>>>> unsigned int bit_offset)
>>>>     while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>           || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>       local->val = TREE_OPERAND (local->val, 0);
>>>> +  local->val = fold (local->val);
>>>
>>> Likewise.
>>
>> As soon as we can be sure that values getting fully_folded, or at
>> least folded for constants, we should be able to remove this.
>
> Yep, they need to be folded before we get here.
>
> It looks like your latest checkin added more redundant folding:
>
>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>> low_value, tree hi
>> gh_value)
>>    low_value = case_conversion (type, low_value);
>>    high_value = case_conversion (type, high_value);
>>
>> +  low_value = cp_fully_fold (low_value);
>> +  high_value = cp_fully_fold (high_value);
>
> Again, case_conversion should have already folded constants.
>
>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>> tsubst_flags_t complain)
>>  {
>>    tree expr_type;
>>
>> +  expr = cp_try_fold_to_constant (expr);
>> +
>>    /* Detect immediately string literals as invalid non-type argument.
>>       This special-case is not needed for correctness (we would easily
>>       catch this later), but only to provide better diagnostic for this
>> @@ -5852,6 +5854,7 @@ convert_nontype_argument (tree type, tree expr,
>> tsubst_flags_t complain)
>>        else if (TYPE_PTR_OR_PTRMEM_P (type))
>>         {
>>           tree folded = maybe_constant_value (expr);
>> +         folded = cp_try_fold_to_constant (expr);
>
> And here, convert_nontype_argument already uses
> maybe_constant_value/cxx_constant_value for folding constants.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-27 19:01     ` Jason Merrill
@ 2015-07-28  2:40       ` Kai Tietz
  2015-07-28 20:35         ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-07-28  2:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-07-27 18:51 GMT+02:00 Jason Merrill <jason@redhat.com>:
> I've trimmed this to the previously mentioned issues that still need to be
> addressed; I'll do another full review after these are dealt with.

Thanks for doing this summary of missing parts of prior review.

> On 06/13/2015 12:15 AM, Jason Merrill wrote:
>>
>> On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>>>>
>>>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>>>   {
>>>>>     if (TREE_TYPE (temp) == type)
>>>>>       return temp;
>>>>> +  STRIP_NOPS (temp);
>>>>> +  if (TREE_TYPE (temp) == type)
>>>>> +    return temp;
>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>>> *ctx,
>>>>> tree t,
>>>>>   bool
>>>>>   reduced_constant_expression_p (tree t)
>>>>>   {
>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>> +  STRIP_NOPS (t);
>>>>
>>>>
>>>> Within the constexpr code we should be folding away NOPs as they are
>>>> generated, they shouldn't live this long.
>>>
>>>
>>> Well, we might see them on overflows ...
>>
>>
>> We shouldn't within the constexpr code.  NOPs for expressions that are
>> non-constant due to overflow are added in
>> cxx_eval_outermost_constant_expr, so we shouldn't see them in the middle
>> of constexpr evaluation.
>>
>>>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>>>>> *ctx, tree t,
>>>>>            && is_dummy_object (x))
>>>>>          {
>>>>>            x = ctx->object;
>>>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>> +         if (x)
>>>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>> +         else
>>>>> +           x = get_nth_callarg (t, i);
>>>>
>>>>
>>>> This still should not be necessary.
>>>
>>>
>>> Yeah, most likely.  But I got initially here some issues, so I don't
>>> see that this code would worsen things.
>>
>>
>> If this code path is hit, that means something has broken my design, and
>> I don't want to just paper over that.  Please revert this change.
>>
>>>>>       case SIZEOF_EXPR:
>>>>> +      if (processing_template_decl
>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>>> +       return t;
>>>>
>>>>
>>>> Why is this necessary?
>>>
>>>
>>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>> otherwise get issues about expressions without existing type (as usual
>>> within template-declarations for some expressions).
>>
>>
>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>> maybe_constant_value just returns if
>> instantiation_dependent_expression_p is true.
>>
>>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>>> constexpr_ctx
>>>>> *ctx, tree t,
>>>>>       case CONVERT_EXPR:
>>>>>       case VIEW_CONVERT_EXPR:
>>>>>       case NOP_EXPR:
>>>>> +    case UNARY_PLUS_EXPR:
>>>>>         {
>>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>>          tree oldop = TREE_OPERAND (t, 0);
>>>>> +
>>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
>>>>> TREE_OVERFLOW_P (oldop))
>>>>> +         {
>>>>> +           if (!ctx->quiet)
>>>>> +             permerror (input_location, "overflow in constant
>>>>> expression");
>>>>> +           /* If we're being permissive (and are in an enforcing
>>>>> +               context), ignore the overflow.  */
>>>>> +           if (!flag_permissive)
>>>>> +             *overflow_p = true;
>>>>> +           *non_constant_p = true;
>>>>> +
>>>>> +           return t;
>>>>> +         }
>>>>>          tree op = cxx_eval_constant_expression (ctx, oldop,
>>>>
>>>>
>>>> Why doesn't the call to cxx_eval_constant_expression at the bottom here
>>>> handle oldop having TREE_OVERFLOW set?
>>>
>>>
>>> I just handled the case that we see here a wrapping NOP_EXPR around an
>>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>>
>>
>> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
>> is there to indicated that the expression is non-constant, and it can't
>> be simplified any farther.
>>
>> Please give an example of what was going wrong.
>>
>>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
>>>>> gimple_seq *post_p)
>>>>>
>>>>>     switch (code)
>>>>>       {
>>>>> +    case SIZEOF_EXPR:
>>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
>>>>> (*expr_p,
>>>>> +
>>>>> 0)),
>>>>> +                                             SIZEOF_EXPR, false);
>>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>>> 0),
>>>>> +                                             SIZEOF_EXPR, false);
>>>>> +      else
>>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>>> 0),
>>>>> +                                             SIZEOF_EXPR, false);
>>>>> +      if (*expr_p == error_mark_node)
>>>>> +       *expr_p = size_one_node;
>>>>> +
>>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>>> +      ret = GS_OK;
>>>>> +      break;
>>>>
>>>>
>>>> Why are these surviving until gimplification time?
>>>
>>>
>>> This might be still necessary. I will retest, when bootstrap works.
>>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>>> AFAIR I saw here some issues about initialzation for global-variables,
>>> which weren't caught.
>>
>>
>> Hmm, I wonder why you would see issues with global initializers that
>> aren't seen on trunk?  In any case, if the issue is with global
>> initializers, they should be handled sooner, not here.
>>
>>>>> @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
>>>>>       }
>>>>>     else
>>>>>       {
>>>>> -      conv = fold_convert (type, expr);
>>>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>>>> +        conv = fold_convert (type, expr);
>>>>> +      else
>>>>> +        conv = convert (type, expr);
>>>>
>>>>
>>>> I still think that cp_fold_convert should always call fold_convert, and
>>>> callers that we don't want to fold should call convert instead, or
>>>> another function that folds only conversion of constants.  We had talked
>>>> about the name "fold_cst", but I think that name isn't very clear; would
>>>> it make sense to just have convert always fold conversions of constants?
>>>
>>>
>>> We could introduce that, but we still have the issues about some
>>> unary-operations on constants, too.  So we could do for any conversion
>>> afterwards a call to cp_try_fold_to_constant, which should reflect
>>> that pretty well, beside within template-declarations ...
>
>
> Now we've been talking about calling it "fold_simple".

Yes, rename happened. I will send a patch for that.  By reading
cp_fold_convert, I agree that folding can be assumed ....

>
>>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>>> expr,
>>>>> bool complain)
>>>>>     tree basetype = TREE_TYPE (expr);
>>>>>     tree conv = NULL_TREE;
>>>>>     tree winner = NULL_TREE;
>>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>>> null_node.
>>>>> */
>>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>>
>>>>> -  if (expr == null_node
>>>>> +  STRIP_NOPS (expr_folded);
>>>>> +  if (expr_folded == null_node
>>>>
>>>>
>>>> Again, we shouldn't need to fold to check for null_node, it only occurs
>>>> when explicitly written.  Folding should never produce null_node unless
>>>> the argument was already null_node.
>>>
>>>
>>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>>> see if expression folded gets a constant, so that diagnostics getting
>>> displayed right.
>>
>>
>> Again, null_node is special.  It indicates that the user typed "__null".
>> That's what we're checking for here.  Folding is both unnecessary and
>> undesirable.
>>
>>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>>> expr,
>>>>> bool complain)
>>>>>       switch (TREE_CODE (basetype))
>>>>>         {
>>>>>         case INTEGER_TYPE:
>>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>>
>>>>
>>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
>>>> fold in null_ptr_cst_p.
>>>
>>>
>>> We need to avoid useless conversion, so we should reduce to simple
>>> constant-value ...
>>
>>
>> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
>> more complex expression that folds to 0 is NOT a null pointer constant.
>> Folding is actively harmful here.
>>
>> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
>> is redundant.
>>
>> Was I unclear?
>>
>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
>>>>> tsubst_flags_t complain)
>>>>>         SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>         return itype;
>>>>>       }
>>>>> -
>>>>> +
>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>> not.  */
>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>
>>>>
>>>> Again, we already called maybe_constant_value.
>>>
>>>
>>> Sure, but maybe_constant_value still produces nops ...
>>
>>
>> If someone tries to create an array with a size that involves arithmetic
>> overflow, that's undefined behavior and we should probably give an error
>> rather than fold it away.
>>
>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
>>>>> enumtype, tree attributes,
>>>>>     if (value)
>>>>>       STRIP_TYPE_NOPS (value);
>>>>>
>>>>> +  if (value)
>>>>> +    value = cp_try_fold_to_constant (value);
>>>>
>>>>
>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>
>>>
>>> See nops, and other unary-operations we want to reduce here to real
>>> constant value ...
>>
>>
>> The cxx_constant_value call below will deal with them.
>
>
> Likewise for grokbitfield.

Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
will look into it, and come back to you on it.

>>>>> @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree
>>>>> enumtype, tree attributes,
>>>>>            if (value != NULL_TREE)
>>>>>              {
>>>>>                value = cxx_constant_value (value);
>>>>> +             STRIP_NOPS (value);
>>>>
>>>>
>>>> Again, the only time a constant result should have a NOP_EXPR around it
>>>> is if it isn't really constant.  Why do you want to strip that?
>>>
>>>
>>> As for an enumerator-value we might have overflows, which are silently
>>> ignored.
>>
>>
>> They shouldn't be ignored.  C++ requires that the value be constant, and
>> overflow makes it non-constant.
>>
>>> I will recheck this what example we have for this when bootstrap is
>>> working again.
>>>
>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>> (cp_parser
>>>>> *parser,
>>>>>          index = cp_parser_expression (parser);
>>>>>       }
>>>>>
>>>>> +  /* For offsetof and declaration of types we need
>>>>> +     constant integeral values.
>>>>> +     Also we meed to fold for negative constants so that diagnostic in
>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>> +  if (for_offsetof || decltype_p
>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>>>>> (index, 0)) == INTEGER_CST))
>>>>> +    index = cp_try_fold_to_constant (index);
>>>>
>>>>
>>>> Similarly, for offsetof the folding should happen closer to where it is
>>>> needed.
>>>>
>>>> Why is it needed for decltype, which is querying the type of an
>>>> expression?
>>>>
>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>> constant; this isn't the right place to do it.
>>>
>>>
>>> Same as above, we need in those cases (and for -1 too) the constant
>>> values early anyway.  So I saw it as more logical to have done this
>>> conversion as soon as possible after initialization.
>>
>>
>> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
>> immediately when we build it, at the end of cp_build_unary_op.
>>
>> I still wonder why any folding is necessary for decltype.  When I ask
>> why, I want to know *why*, not just have you tell me again that it's
>> needed.  I don't think it is.
>>
>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>> handle whatever additional folding is needed here.  If not, then fold in
>> finish_offsetof, before calling fold_offsetof.
>
>
> I see that this is now an unconditional fold_simple, but I still don't
> understand why it needs to be folded here, in the parser.

The point to fold the 'value' here is for cases
'processing_template_decl' isn't false. We could move it to the
else-case of the 'if (! processing_template_decl)' line for being more
explicit?

>>....
>>>
>>> Anyway, if you prefer, we can do this in builder-routines, and remove
>>> at places constants aren't needed directly after parsing it those calls.
>>
>>
>> I want to delay it to:
>>
>> 1) the places where we actually care about constant values, all of which
>> already call maybe_constant_value or cxx_constant_value, so they
>> shouldn't need much change; and
>> 2) the places where we want a simplified expression for warnings, where
>> we should call fold_simple.
>
>
>> Folding in the parser is wrong, most of all because template
>> substitution doesn't go through the parser.
>
>
> There are still several folds in cp_parser_omp_* that should move later.

In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
'low_bound' as those values getting checked some lines below (see
lines 27936, 27944). We could call here fold_simple instead?
If we would delay it to later, we would need to move diagnostics here too,

In 'cp_parser_omp_clause_aligned','cp_parser_omp_clause_safelen', and
in 'cp_parser_omp_clause_simdlen' I tried to fold early to prevent
early cases assuming that OMP-operands are already folded.
I tested this, and it doesn't seems to be necessary anymore due we
perform full converatge here in the cp_fold_r walker now.
I removed here the fold-invocation of them.

In 'cp_parser_cilk_grainsize' we fold 2nd argument of
'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
operand-folding into cp_parser_cilk_for itself, as we have here just
two users of 'cp_parser_cilk_for'.
One time we pass 'integer_zero_node' as this argument, and the other
time a binary-expression, which might be constant value.
But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?


>>  finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
>>                       tsubst_flags_t complain)
>>  {
>> +  tree expr_ovl = expr;
>>    tree result = build_x_unary_op (loc, code, expr, complain);
>> +  tree result_ovl =  result;
>> +
>> +  expr_ovl = fold_simple (expr_ovl);
>> +  STRIP_NOPS (expr_ovl);
>
>
> Why both fold_simple and STRIP_NOPS?

If we have an overflow-value encapsulated into an nop_expr, we want to
see that overflow-expression itself.
fold_simple preserves the nop_expr conversion, so we want to remove
it, if present.
Not sure, if this really still can happen, I will do some testing on it.

>>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>>     else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>>       fn = AGGR_INIT_EXPR_FN (init);
>>>>>     else
>>>>> -    return convert (type, init);
>>>>> +    return fold (convert (type, init));
>>>>
>>>>
>>>> Why fold here?
>>>
>>>
>>> We had this already in prior thread.  fold (convert ()) !=
>>> fold_convert () for C++.  The fold is just there to make sure we fold
>>> away useless casts.
>>
>>
>> But why here?  Can't we fold away useless casts earlier (in convert) or
>> later (when we care about having a simplified expression)?
>>
>>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>>> va_gc>
>>>>> **values, tree fndecl,
>>>>>            && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>>          val = TREE_OPERAND (val, 0);
>>>>>
>>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>>> +       val = fold (val);
>>>>
>>>>
>>>> Why?
>>>
>>>
>>> As builtin-handlers are expecting to see constant values.
>
>
> I would think this should be maybe_constant_value then.

Why?  At the end we resolve normal-builtin via 'fold_call_expr'.  Of
course we can invoke here maybe_constant_value, but it would end up in
the same folding of a builtin-expression. So calling here directly
'fold' just short-cuts this.


>>>>> @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
>>>>>       }
>>>>>
>>>>>     result = build2 (resultcode, build_type, op0, op1);
>>>>> -  result = fold_if_not_in_template (result);
>>>>>     if (final_type != 0)
>>>>>       result = cp_convert (final_type, result, complain);
>>>>> -
>>>>> -  if (TREE_OVERFLOW_P (result)
>>>>> +  op0 = fold_non_dependent_expr (op0);
>>>>> +  op1 = fold_non_dependent_expr (op1);
>>>>> +  STRIP_NOPS (op0);
>>>>> +  STRIP_NOPS (op1);
>>>>> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
>>>>> +  if (TREE_OVERFLOW_P (result_ovl)
>>>>>         && !TREE_OVERFLOW_P (op0)
>>>>>         && !TREE_OVERFLOW_P (op1))
>>>>> -    overflow_warning (location, result);
>>>>> +    overflow_warning (location, result_ovl);
>>>>
>>>>
>>>> Don't you want to use cp_fully_fold here?
>>
>>
>> ?
>
>
> Introducing *_non_dependent_expr is definitely wrong here.

I don't remember anymore, why I used here *_non_dependent_expr.  I
will see if we can use here instead cp_fully_fold.  If we can get rid
of the STRIP_NOPs, I am not sure, as we are interested in
overflow-bit, and don't want to see it encapsulated into nop_expr ...
>
>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>> *pre_p)
>>>>>         /* Handle OMP_FOR_COND.  */
>>>>>         t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>         gcc_assert (COMPARISON_CLASS_P (t));
>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>> 1) ==
>>>>> decl);
>>>>
>>>>
>>>> Why didn't delayed folding canonicalize this so that the decl is in op0?
>>>
>>>
>>> Delay folding doesn't canonicalize this.
>>
>>
>> Why not?  Doesn't it fold all expressions?
>
>
> ?

It fold them lately.  I will recheck this code-change.  It might be no
longer required due recent changes to omp-folding.  It could be that
original pattern didn't applied here anymore, and therefore statement
didn't been transformed into its canonical form.  Bit I assume this
could be resolved.

>>> Actually we don't want to touch here anything in parsered tree.  We
>>> could do this in generalization-pass before gimplification.  Seems to
>>> be something we don't catch for now, which makes me wonder a bit.
>>>
>>>>> @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct
>>>>> omp_for_data *fd,
>>>>>            gcc_assert (gimple_omp_for_kind (for_stmt)
>>>>>                        == GF_OMP_FOR_KIND_CILKSIMD
>>>>>                        || (gimple_omp_for_kind (for_stmt)
>>>>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>>>>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>>>>> +                     || (gimple_omp_for_kind (for_stmt)
>>>>> +                         == GF_OMP_FOR_KIND_FOR));
>>>>
>>>>
>>>> This still seems like a red flag; how is delayed folding changing the
>>>> OMP for kind?
>>>
>>>
>>> It doesn't.  The issue is that some canonical operations of fold
>>> aren't happening anymore on which omp depends.
>>
>>
>> That seems like a problem.

See above.  I will come up on this tomorrow.

>> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab
>> binoptab,
>>          are truncated to the mode size.  */
>>        carries = expand_binop (word_mode, reverse_unsigned_shift,
>>                               outof_input, const1_rtx, 0, unsignedp,
>> methods);
>> -      if (shift_mask == BITS_PER_WORD - 1)
>> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))
>
>
> These should still be unnecessary.

Yes, they are.  We handle now the avoiding of dead-code for constants
(cond-expression, truthif* expressions, and useless convert-warnings).
So this change is something only interesting for different compiler,
but not related to delayed-folding anymore.
I will check, and remove it tomorrow.

>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>>>>>   {
>>>>>     tree t = make_node (COMPLEX_CST);
>>>>>
>>>>> +  real = fold (real);
>>>>> +  imag = fold (imag);
>>>>
>>>>
>>>> I still think this is wrong.  The arguments should be sufficiently
>>>> folded.
>>>
>>>
>>> As we don't fold unary-operators on constants, we need to fold it at
>>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>>> So this place was the easiest way to avoid issues with things like '-'
>>> '1' etc.
>>
>>
>> Is this because of the
>>>
>>>       value = build_complex (NULL_TREE, convert (const_type,
>>>                                                  integer_zero_node),
>>> value);

Might be.  This should be indeed a 'fold_convert', isn't it?

>> in interpret_float?  I think "convert" definitely needs to do some
>> folding, since it's called from middle-end code that expects that.
>
>
> I remember talking about "convert" doing some folding (and cp_convert not)
> in our 1:1 last week.
>

Can't remember that.  I know that we were talking about the difference
of convert and fold_convert.  convert can be used on C++ specifics,
but fold_convert is something shared with ME.  So first 'fold_convert'
isn't the same as 'fold (convert ())'.
I don't find places we invoke convert () in ME.  We have some calls in
convert.c (see convert_to_integer, convert_to_integer_nofold, and
convert_to_real), which all used in AST only AFAICS.
I remember that we were talking about adding a standard-folding to
convert for operations on constant-values (as we do for
convert_to_integer).  Do you mean this?

>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>> *local,
>>>>> unsigned int bit_offset)
>>>>>     while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>           || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>       local->val = TREE_OPERAND (local->val, 0);
>>>>> +  local->val = fold (local->val);
>>>>
>>>>
>>>> Likewise.
>>>
>>>
>>> As soon as we can be sure that values getting fully_folded, or at
>>> least folded for constants, we should be able to remove this.
>>
>>
>> Yep, they need to be folded before we get here.
>>
>> It looks like your latest checkin added more redundant folding:
>>
>>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>>> low_value, tree hi
>>> gh_value)
>>>    low_value = case_conversion (type, low_value);
>>>    high_value = case_conversion (type, high_value);
>>>
>>> +  low_value = cp_fully_fold (low_value);
>>> +  high_value = cp_fully_fold (high_value);
>>
>>
>> Again, case_conversion should have already folded constants.
>>
>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>>> tsubst_flags_t complain)
>>>  {
>>>    tree expr_type;
>>>
>>> +  expr = cp_try_fold_to_constant (expr);
>>> +
>>>    /* Detect immediately string literals as invalid non-type argument.
>>>       This special-case is not needed for correctness (we would easily
>>>       catch this later), but only to provide better diagnostic for this
>>> @@ -5852,6 +5854,7 @@ convert_nontype_argument (tree type, tree expr,
>>> tsubst_flags_t complain)
>>>        else if (TYPE_PTR_OR_PTRMEM_P (type))
>>>         {
>>>           tree folded = maybe_constant_value (expr);
>>> +         folded = cp_try_fold_to_constant (expr);
>>
>>
>> And here, convert_nontype_argument already uses
>> maybe_constant_value/cxx_constant_value for folding constants.
>
>
> Jason
>

Thanks,
Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-28  2:40       ` Kai Tietz
@ 2015-07-28 20:35         ` Kai Tietz
  2015-07-29 18:48           ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-07-28 20:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-07-28 1:14 GMT+02:00 Kai Tietz <ktietz70@googlemail.com>:
> 2015-07-27 18:51 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> I've trimmed this to the previously mentioned issues that still need to be
>> addressed; I'll do another full review after these are dealt with.
>
> Thanks for doing this summary of missing parts of prior review.
>
>> On 06/13/2015 12:15 AM, Jason Merrill wrote:
>>>
>>> On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>>>>>
>>>>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>>>>   {
>>>>>>     if (TREE_TYPE (temp) == type)
>>>>>>       return temp;
>>>>>> +  STRIP_NOPS (temp);
>>>>>> +  if (TREE_TYPE (temp) == type)
>>>>>> +    return temp;
>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>>>> *ctx,
>>>>>> tree t,
>>>>>>   bool
>>>>>>   reduced_constant_expression_p (tree t)
>>>>>>   {
>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>> +  STRIP_NOPS (t);
>>>>>
>>>>>
>>>>> Within the constexpr code we should be folding away NOPs as they are
>>>>> generated, they shouldn't live this long.
>>>>
>>>>
>>>> Well, we might see them on overflows ...
>>>
>>>
>>> We shouldn't within the constexpr code.  NOPs for expressions that are
>>> non-constant due to overflow are added in
>>> cxx_eval_outermost_constant_expr, so we shouldn't see them in the middle
>>> of constexpr evaluation.
>>>
>>>>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>>>>>> *ctx, tree t,
>>>>>>            && is_dummy_object (x))
>>>>>>          {
>>>>>>            x = ctx->object;
>>>>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>> +         if (x)
>>>>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>> +         else
>>>>>> +           x = get_nth_callarg (t, i);
>>>>>
>>>>>
>>>>> This still should not be necessary.
>>>>
>>>>
>>>> Yeah, most likely.  But I got initially here some issues, so I don't
>>>> see that this code would worsen things.
>>>
>>>
>>> If this code path is hit, that means something has broken my design, and
>>> I don't want to just paper over that.  Please revert this change.
>>>
>>>>>>       case SIZEOF_EXPR:
>>>>>> +      if (processing_template_decl
>>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>>>> +       return t;
>>>>>
>>>>>
>>>>> Why is this necessary?
>>>>
>>>>
>>>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>>> otherwise get issues about expressions without existing type (as usual
>>>> within template-declarations for some expressions).
>>>
>>>
>>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>>> maybe_constant_value just returns if
>>> instantiation_dependent_expression_p is true.
>>>
>>>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>>>> constexpr_ctx
>>>>>> *ctx, tree t,
>>>>>>       case CONVERT_EXPR:
>>>>>>       case VIEW_CONVERT_EXPR:
>>>>>>       case NOP_EXPR:
>>>>>> +    case UNARY_PLUS_EXPR:
>>>>>>         {
>>>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>>>          tree oldop = TREE_OPERAND (t, 0);
>>>>>> +
>>>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
>>>>>> TREE_OVERFLOW_P (oldop))
>>>>>> +         {
>>>>>> +           if (!ctx->quiet)
>>>>>> +             permerror (input_location, "overflow in constant
>>>>>> expression");
>>>>>> +           /* If we're being permissive (and are in an enforcing
>>>>>> +               context), ignore the overflow.  */
>>>>>> +           if (!flag_permissive)
>>>>>> +             *overflow_p = true;
>>>>>> +           *non_constant_p = true;
>>>>>> +
>>>>>> +           return t;
>>>>>> +         }
>>>>>>          tree op = cxx_eval_constant_expression (ctx, oldop,
>>>>>
>>>>>
>>>>> Why doesn't the call to cxx_eval_constant_expression at the bottom here
>>>>> handle oldop having TREE_OVERFLOW set?
>>>>
>>>>
>>>> I just handled the case that we see here a wrapping NOP_EXPR around an
>>>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>>>
>>>
>>> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
>>> is there to indicated that the expression is non-constant, and it can't
>>> be simplified any farther.
>>>
>>> Please give an example of what was going wrong.
>>>
>>>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
>>>>>> gimple_seq *post_p)
>>>>>>
>>>>>>     switch (code)
>>>>>>       {
>>>>>> +    case SIZEOF_EXPR:
>>>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
>>>>>> (*expr_p,
>>>>>> +
>>>>>> 0)),
>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>>>> 0),
>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>> +      else
>>>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>>>> 0),
>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>> +      if (*expr_p == error_mark_node)
>>>>>> +       *expr_p = size_one_node;
>>>>>> +
>>>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>>>> +      ret = GS_OK;
>>>>>> +      break;
>>>>>
>>>>>
>>>>> Why are these surviving until gimplification time?
>>>>
>>>>
>>>> This might be still necessary. I will retest, when bootstrap works.
>>>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>>>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>>>> AFAIR I saw here some issues about initialzation for global-variables,
>>>> which weren't caught.
>>>
>>>
>>> Hmm, I wonder why you would see issues with global initializers that
>>> aren't seen on trunk?  In any case, if the issue is with global
>>> initializers, they should be handled sooner, not here.
>>>
>>>>>> @@ -608,9 +608,13 @@ cp_fold_convert (tree type, tree expr)
>>>>>>       }
>>>>>>     else
>>>>>>       {
>>>>>> -      conv = fold_convert (type, expr);
>>>>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>>>>> +        conv = fold_convert (type, expr);
>>>>>> +      else
>>>>>> +        conv = convert (type, expr);
>>>>>
>>>>>
>>>>> I still think that cp_fold_convert should always call fold_convert, and
>>>>> callers that we don't want to fold should call convert instead, or
>>>>> another function that folds only conversion of constants.  We had talked
>>>>> about the name "fold_cst", but I think that name isn't very clear; would
>>>>> it make sense to just have convert always fold conversions of constants?
>>>>
>>>>
>>>> We could introduce that, but we still have the issues about some
>>>> unary-operations on constants, too.  So we could do for any conversion
>>>> afterwards a call to cp_try_fold_to_constant, which should reflect
>>>> that pretty well, beside within template-declarations ...
>>
>>
>> Now we've been talking about calling it "fold_simple".
>
> Yes, rename happened. I will send a patch for that.  By reading
> cp_fold_convert, I agree that folding can be assumed ....

Changed that on branch.  Users of cp_fold_convert are looking to me
just like artificial-code-generations, and IMO we can keep there usage
of cp_fold_convert.

>>
>>>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>>>> expr,
>>>>>> bool complain)
>>>>>>     tree basetype = TREE_TYPE (expr);
>>>>>>     tree conv = NULL_TREE;
>>>>>>     tree winner = NULL_TREE;
>>>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>>>> null_node.
>>>>>> */
>>>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>>>
>>>>>> -  if (expr == null_node
>>>>>> +  STRIP_NOPS (expr_folded);
>>>>>> +  if (expr_folded == null_node
>>>>>
>>>>>
>>>>> Again, we shouldn't need to fold to check for null_node, it only occurs
>>>>> when explicitly written.  Folding should never produce null_node unless
>>>>> the argument was already null_node.
>>>>
>>>>
>>>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>>>> see if expression folded gets a constant, so that diagnostics getting
>>>> displayed right.
>>>
>>>
>>> Again, null_node is special.  It indicates that the user typed "__null".
>>> That's what we're checking for here.  Folding is both unnecessary and
>>> undesirable.
>>>
>>>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>>>> expr,
>>>>>> bool complain)
>>>>>>       switch (TREE_CODE (basetype))
>>>>>>         {
>>>>>>         case INTEGER_TYPE:
>>>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>>>
>>>>>
>>>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
>>>>> fold in null_ptr_cst_p.
>>>>
>>>>
>>>> We need to avoid useless conversion, so we should reduce to simple
>>>> constant-value ...
>>>
>>>
>>> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
>>> more complex expression that folds to 0 is NOT a null pointer constant.
>>> Folding is actively harmful here.
>>>
>>> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
>>> is redundant.
>>>
>>> Was I unclear?
>>>
>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
>>>>>> tsubst_flags_t complain)
>>>>>>         SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>         return itype;
>>>>>>       }
>>>>>> -
>>>>>> +
>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>> not.  */
>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>
>>>>>
>>>>> Again, we already called maybe_constant_value.
>>>>
>>>>
>>>> Sure, but maybe_constant_value still produces nops ...
>>>
>>>
>>> If someone tries to create an array with a size that involves arithmetic
>>> overflow, that's undefined behavior and we should probably give an error
>>> rather than fold it away.
>>>
>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
>>>>>> enumtype, tree attributes,
>>>>>>     if (value)
>>>>>>       STRIP_TYPE_NOPS (value);
>>>>>>
>>>>>> +  if (value)
>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>
>>>>>
>>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>>
>>>>
>>>> See nops, and other unary-operations we want to reduce here to real
>>>> constant value ...
>>>
>>>
>>> The cxx_constant_value call below will deal with them.
>>
>>
>> Likewise for grokbitfield.
>
> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
> will look into it, and come back to you on it.

I am still on it ...  first did the other points

>>>>>> @@ -13102,6 +13068,7 @@ build_enumerator (tree name, tree value, tree
>>>>>> enumtype, tree attributes,
>>>>>>            if (value != NULL_TREE)
>>>>>>              {
>>>>>>                value = cxx_constant_value (value);
>>>>>> +             STRIP_NOPS (value);
>>>>>
>>>>>
>>>>> Again, the only time a constant result should have a NOP_EXPR around it
>>>>> is if it isn't really constant.  Why do you want to strip that?
>>>>
>>>>
>>>> As for an enumerator-value we might have overflows, which are silently
>>>> ignored.
>>>
>>>
>>> They shouldn't be ignored.  C++ requires that the value be constant, and
>>> overflow makes it non-constant.
>>>
>>>> I will recheck this what example we have for this when bootstrap is
>>>> working again.
>>>>
>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>> (cp_parser
>>>>>> *parser,
>>>>>>          index = cp_parser_expression (parser);
>>>>>>       }
>>>>>>
>>>>>> +  /* For offsetof and declaration of types we need
>>>>>> +     constant integeral values.
>>>>>> +     Also we meed to fold for negative constants so that diagnostic in
>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>> +  if (for_offsetof || decltype_p
>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>>>>>> (index, 0)) == INTEGER_CST))
>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>
>>>>>
>>>>> Similarly, for offsetof the folding should happen closer to where it is
>>>>> needed.
>>>>>
>>>>> Why is it needed for decltype, which is querying the type of an
>>>>> expression?
>>>>>
>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>> constant; this isn't the right place to do it.
>>>>
>>>>
>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>> values early anyway.  So I saw it as more logical to have done this
>>>> conversion as soon as possible after initialization.
>>>
>>>
>>> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
>>> immediately when we build it, at the end of cp_build_unary_op.
>>>
>>> I still wonder why any folding is necessary for decltype.  When I ask
>>> why, I want to know *why*, not just have you tell me again that it's
>>> needed.  I don't think it is.
>>>
>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>> handle whatever additional folding is needed here.  If not, then fold in
>>> finish_offsetof, before calling fold_offsetof.
>>
>>
>> I see that this is now an unconditional fold_simple, but I still don't
>> understand why it needs to be folded here, in the parser.
>
> The point to fold the 'value' here is for cases
> 'processing_template_decl' isn't false. We could move it to the
> else-case of the 'if (! processing_template_decl)' line for being more
> explicit?

Well, on looking here in more detail, we might don't that that initial
folding here.  As for processing_template_decl fold_simple (and
cp_fully_fold) doesn't do much.

>>>....
>>>>
>>>> Anyway, if you prefer, we can do this in builder-routines, and remove
>>>> at places constants aren't needed directly after parsing it those calls.
>>>
>>>
>>> I want to delay it to:
>>>
>>> 1) the places where we actually care about constant values, all of which
>>> already call maybe_constant_value or cxx_constant_value, so they
>>> shouldn't need much change; and
>>> 2) the places where we want a simplified expression for warnings, where
>>> we should call fold_simple.
>>
>>
>>> Folding in the parser is wrong, most of all because template
>>> substitution doesn't go through the parser.
>>
>>
>> There are still several folds in cp_parser_omp_* that should move later.
>
> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
> 'low_bound' as those values getting checked some lines below (see
> lines 27936, 27944). We could call here fold_simple instead?
> If we would delay it to later, we would need to move diagnostics here too,

?

> In 'cp_parser_omp_clause_aligned','cp_parser_omp_clause_safelen', and
> in 'cp_parser_omp_clause_simdlen' I tried to fold early to prevent
> early cases assuming that OMP-operands are already folded.
> I tested this, and it doesn't seems to be necessary anymore due we
> perform full converatge here in the cp_fold_r walker now.
> I removed here the fold-invocation of them.
>
> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
> operand-folding into cp_parser_cilk_for itself, as we have here just
> two users of 'cp_parser_cilk_for'.
> One time we pass 'integer_zero_node' as this argument, and the other
> time a binary-expression, which might be constant value.
> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?

?

>>>  finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
>>>                       tsubst_flags_t complain)
>>>  {
>>> +  tree expr_ovl = expr;
>>>    tree result = build_x_unary_op (loc, code, expr, complain);
>>> +  tree result_ovl =  result;
>>> +
>>> +  expr_ovl = fold_simple (expr_ovl);
>>> +  STRIP_NOPS (expr_ovl);
>>
>>
>> Why both fold_simple and STRIP_NOPS?
>
> If we have an overflow-value encapsulated into an nop_expr, we want to
> see that overflow-expression itself.
> fold_simple preserves the nop_expr conversion, so we want to remove
> it, if present.
> Not sure, if this really still can happen, I will do some testing on it.

No, it doesn't happen anymore.  I removed STRIP_NOP.

>>>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>>>     else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>>>       fn = AGGR_INIT_EXPR_FN (init);
>>>>>>     else
>>>>>> -    return convert (type, init);
>>>>>> +    return fold (convert (type, init));
>>>>>
>>>>>
>>>>> Why fold here?
>>>>
>>>>
>>>> We had this already in prior thread.  fold (convert ()) !=
>>>> fold_convert () for C++.  The fold is just there to make sure we fold
>>>> away useless casts.
>>>
>>>
>>> But why here?  Can't we fold away useless casts earlier (in convert) or
>>> later (when we care about having a simplified expression)?
>>>
>>>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>>>> va_gc>
>>>>>> **values, tree fndecl,
>>>>>>            && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>>>          val = TREE_OPERAND (val, 0);
>>>>>>
>>>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>>>> +       val = fold (val);
>>>>>
>>>>>
>>>>> Why?
>>>>
>>>>
>>>> As builtin-handlers are expecting to see constant values.
>>
>>
>> I would think this should be maybe_constant_value then.
>
> Why?  At the end we resolve normal-builtin via 'fold_call_expr'.  Of
> course we can invoke here maybe_constant_value, but it would end up in
> the same folding of a builtin-expression. So calling here directly
> 'fold' just short-cuts this.

?

>
>>>>>> @@ -5026,18 +5023,21 @@ cp_build_binary_op (location_t location,
>>>>>>       }
>>>>>>
>>>>>>     result = build2 (resultcode, build_type, op0, op1);
>>>>>> -  result = fold_if_not_in_template (result);
>>>>>>     if (final_type != 0)
>>>>>>       result = cp_convert (final_type, result, complain);
>>>>>> -
>>>>>> -  if (TREE_OVERFLOW_P (result)
>>>>>> +  op0 = fold_non_dependent_expr (op0);
>>>>>> +  op1 = fold_non_dependent_expr (op1);
>>>>>> +  STRIP_NOPS (op0);
>>>>>> +  STRIP_NOPS (op1);
>>>>>> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
>>>>>> +  if (TREE_OVERFLOW_P (result_ovl)
>>>>>>         && !TREE_OVERFLOW_P (op0)
>>>>>>         && !TREE_OVERFLOW_P (op1))
>>>>>> -    overflow_warning (location, result);
>>>>>> +    overflow_warning (location, result_ovl);
>>>>>
>>>>>
>>>>> Don't you want to use cp_fully_fold here?
>>>
>>>
>>> ?
>>
>>
>> Introducing *_non_dependent_expr is definitely wrong here.
>
> I don't remember anymore, why I used here *_non_dependent_expr.  I
> will see if we can use here instead cp_fully_fold.  If we can get rid
> of the STRIP_NOPs, I am not sure, as we are interested in
> overflow-bit, and don't want to see it encapsulated into nop_expr ...

I replaced those *_non_dependent_expr calls by fold_simple calls.  The
STRIP_NOPS isn't necessary then too.

>>
>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>> *pre_p)
>>>>>>         /* Handle OMP_FOR_COND.  */
>>>>>>         t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>         gcc_assert (COMPARISON_CLASS_P (t));
>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>> 1) ==
>>>>>> decl);
>>>>>
>>>>>
>>>>> Why didn't delayed folding canonicalize this so that the decl is in op0?
>>>>
>>>>
>>>> Delay folding doesn't canonicalize this.
>>>
>>>
>>> Why not?  Doesn't it fold all expressions?
>>
>>
>> ?
>
> It fold them lately.  I will recheck this code-change.  It might be no
> longer required due recent changes to omp-folding.  It could be that
> original pattern didn't applied here anymore, and therefore statement
> didn't been transformed into its canonical form.  Bit I assume this
> could be resolved.
>
>>>> Actually we don't want to touch here anything in parsered tree.  We
>>>> could do this in generalization-pass before gimplification.  Seems to
>>>> be something we don't catch for now, which makes me wonder a bit.
>>>>
>>>>>> @@ -508,7 +508,9 @@ extract_omp_for_data (gomp_for *for_stmt, struct
>>>>>> omp_for_data *fd,
>>>>>>            gcc_assert (gimple_omp_for_kind (for_stmt)
>>>>>>                        == GF_OMP_FOR_KIND_CILKSIMD
>>>>>>                        || (gimple_omp_for_kind (for_stmt)
>>>>>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>>>>>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>>>>>> +                     || (gimple_omp_for_kind (for_stmt)
>>>>>> +                         == GF_OMP_FOR_KIND_FOR));
>>>>>
>>>>>
>>>>> This still seems like a red flag; how is delayed folding changing the
>>>>> OMP for kind?
>>>>
>>>>
>>>> It doesn't.  The issue is that some canonical operations of fold
>>>> aren't happening anymore on which omp depends.
>>>
>>>
>>> That seems like a problem.
>
> See above.  I will come up on this tomorrow.

I think this is resolved already.  It was related to folding of OMP
conditions.  I will do bootstrap with this humk removed.

>>> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab
>>> binoptab,
>>>          are truncated to the mode size.  */
>>>        carries = expand_binop (word_mode, reverse_unsigned_shift,
>>>                               outof_input, const1_rtx, 0, unsignedp,
>>> methods);
>>> -      if (shift_mask == BITS_PER_WORD - 1)
>>> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))
>>
>>
>> These should still be unnecessary.
>
> Yes, they are.  We handle now the avoiding of dead-code for constants
> (cond-expression, truthif* expressions, and useless convert-warnings).
> So this change is something only interesting for different compiler,
> but not related to delayed-folding anymore.
> I will check, and remove it tomorrow.
>
>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>>>>>>   {
>>>>>>     tree t = make_node (COMPLEX_CST);
>>>>>>
>>>>>> +  real = fold (real);
>>>>>> +  imag = fold (imag);
>>>>>
>>>>>
>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>> folded.
>>>>
>>>>
>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>>>> So this place was the easiest way to avoid issues with things like '-'
>>>> '1' etc.
>>>
>>>
>>> Is this because of the
>>>>
>>>>       value = build_complex (NULL_TREE, convert (const_type,
>>>>                                                  integer_zero_node),
>>>> value);
>
> Might be.  This should be indeed a 'fold_convert', isn't it?
>
>>> in interpret_float?  I think "convert" definitely needs to do some
>>> folding, since it's called from middle-end code that expects that.
>>
>>
>> I remember talking about "convert" doing some folding (and cp_convert not)
>> in our 1:1 last week.
>>
>
> Can't remember that.  I know that we were talking about the difference
> of convert and fold_convert.  convert can be used on C++ specifics,
> but fold_convert is something shared with ME.  So first 'fold_convert'
> isn't the same as 'fold (convert ())'.
> I don't find places we invoke convert () in ME.  We have some calls in
> convert.c (see convert_to_integer, convert_to_integer_nofold, and
> convert_to_real), which all used in AST only AFAICS.
> I remember that we were talking about adding a standard-folding to
> convert for operations on constant-values (as we do for
> convert_to_integer).  Do you mean this?
>
>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>> *local,
>>>>>> unsigned int bit_offset)
>>>>>>     while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>           || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>       local->val = TREE_OPERAND (local->val, 0);
>>>>>> +  local->val = fold (local->val);
>>>>>
>>>>>
>>>>> Likewise.
>>>>
>>>>
>>>> As soon as we can be sure that values getting fully_folded, or at
>>>> least folded for constants, we should be able to remove this.
>>>
>>>
>>> Yep, they need to be folded before we get here.
>>>
>>> It looks like your latest checkin added more redundant folding:
>>>
>>>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>>>> low_value, tree hi
>>>> gh_value)
>>>>    low_value = case_conversion (type, low_value);
>>>>    high_value = case_conversion (type, high_value);
>>>>
>>>> +  low_value = cp_fully_fold (low_value);
>>>> +  high_value = cp_fully_fold (high_value);
>>>
>>>
>>> Again, case_conversion should have already folded constants.
>>>
>>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>>>> tsubst_flags_t complain)
>>>>  {
>>>>    tree expr_type;
>>>>
>>>> +  expr = cp_try_fold_to_constant (expr);
>>>> +
>>>>    /* Detect immediately string literals as invalid non-type argument.
>>>>       This special-case is not needed for correctness (we would easily
>>>>       catch this later), but only to provide better diagnostic for this
>>>> @@ -5852,6 +5854,7 @@ convert_nontype_argument (tree type, tree expr,
>>>> tsubst_flags_t complain)
>>>>        else if (TYPE_PTR_OR_PTRMEM_P (type))
>>>>         {
>>>>           tree folded = maybe_constant_value (expr);
>>>> +         folded = cp_try_fold_to_constant (expr);
>>>
>>>
>>> And here, convert_nontype_argument already uses
>>> maybe_constant_value/cxx_constant_value for folding constants.
>>
>>
>> Jason
>>
>

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-28 20:35         ` Kai Tietz
@ 2015-07-29 18:48           ` Jason Merrill
  2015-07-29 23:03             ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-07-29 18:48 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/28/2015 04:10 PM, Kai Tietz wrote:
> 2015-07-28 1:14 GMT+02:00 Kai Tietz <ktietz70@googlemail.com>:
>> 2015-07-27 18:51 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>> I've trimmed this to the previously mentioned issues that still need to be
>>> addressed; I'll do another full review after these are dealt with.
>>
>> Thanks for doing this summary of missing parts of prior review.
>>
>>> On 06/13/2015 12:15 AM, Jason Merrill wrote:
>>>>
>>>> On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>>>>>>
>>>>>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>>>>>    {
>>>>>>>      if (TREE_TYPE (temp) == type)
>>>>>>>        return temp;
>>>>>>> +  STRIP_NOPS (temp);
>>>>>>> +  if (TREE_TYPE (temp) == type)
>>>>>>> +    return temp;
>>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>>>>> *ctx,
>>>>>>> tree t,
>>>>>>>    bool
>>>>>>>    reduced_constant_expression_p (tree t)
>>>>>>>    {
>>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>>> +  STRIP_NOPS (t);
>>>>>>
>>>>>>
>>>>>> Within the constexpr code we should be folding away NOPs as they are
>>>>>> generated, they shouldn't live this long.
>>>>>
>>>>>
>>>>> Well, we might see them on overflows ...
>>>>
>>>>
>>>> We shouldn't within the constexpr code.  NOPs for expressions that are
>>>> non-constant due to overflow are added in
>>>> cxx_eval_outermost_constant_expr, so we shouldn't see them in the middle
>>>> of constexpr evaluation.

^

>>>>>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>>>>>>> *ctx, tree t,
>>>>>>>             && is_dummy_object (x))
>>>>>>>           {
>>>>>>>             x = ctx->object;
>>>>>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>>> +         if (x)
>>>>>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>>> +         else
>>>>>>> +           x = get_nth_callarg (t, i);
>>>>>>
>>>>>>
>>>>>> This still should not be necessary.
>>>>>
>>>>>
>>>>> Yeah, most likely.  But I got initially here some issues, so I don't
>>>>> see that this code would worsen things.
>>>>
>>>>
>>>> If this code path is hit, that means something has broken my design, and
>>>> I don't want to just paper over that.  Please revert this change.

^

>>>>>>>        case SIZEOF_EXPR:
>>>>>>> +      if (processing_template_decl
>>>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>>>>> +       return t;
>>>>>>
>>>>>>
>>>>>> Why is this necessary?
>>>>>
>>>>>
>>>>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>>>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>>>> otherwise get issues about expressions without existing type (as usual
>>>>> within template-declarations for some expressions).
>>>>
>>>>
>>>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>>>> maybe_constant_value just returns if
>>>> instantiation_dependent_expression_p is true.

^

>>>>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>>>>> constexpr_ctx
>>>>>>> *ctx, tree t,
>>>>>>>        case CONVERT_EXPR:
>>>>>>>        case VIEW_CONVERT_EXPR:
>>>>>>>        case NOP_EXPR:
>>>>>>> +    case UNARY_PLUS_EXPR:
>>>>>>>          {
>>>>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>>>>           tree oldop = TREE_OPERAND (t, 0);
>>>>>>> +
>>>>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) &&
>>>>>>> TREE_OVERFLOW_P (oldop))
>>>>>>> +         {
>>>>>>> +           if (!ctx->quiet)
>>>>>>> +             permerror (input_location, "overflow in constant
>>>>>>> expression");
>>>>>>> +           /* If we're being permissive (and are in an enforcing
>>>>>>> +               context), ignore the overflow.  */
>>>>>>> +           if (!flag_permissive)
>>>>>>> +             *overflow_p = true;
>>>>>>> +           *non_constant_p = true;
>>>>>>> +
>>>>>>> +           return t;
>>>>>>> +         }
>>>>>>>           tree op = cxx_eval_constant_expression (ctx, oldop,
>>>>>>
>>>>>>
>>>>>> Why doesn't the call to cxx_eval_constant_expression at the bottom here
>>>>>> handle oldop having TREE_OVERFLOW set?
>>>>>
>>>>>
>>>>> I just handled the case that we see here a wrapping NOP_EXPR around an
>>>>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>>>>
>>>>
>>>> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
>>>> is there to indicated that the expression is non-constant, and it can't
>>>> be simplified any farther.
>>>>
>>>> Please give an example of what was going wrong.

^

>>>>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
>>>>>>> gimple_seq *post_p)
>>>>>>>
>>>>>>>      switch (code)
>>>>>>>        {
>>>>>>> +    case SIZEOF_EXPR:
>>>>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND
>>>>>>> (*expr_p,
>>>>>>> +
>>>>>>> 0)),
>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>>>>> 0),
>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>> +      else
>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>>>>> 0),
>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>> +      if (*expr_p == error_mark_node)
>>>>>>> +       *expr_p = size_one_node;
>>>>>>> +
>>>>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>>>>> +      ret = GS_OK;
>>>>>>> +      break;
>>>>>>
>>>>>>
>>>>>> Why are these surviving until gimplification time?
>>>>>
>>>>>
>>>>> This might be still necessary. I will retest, when bootstrap works.
>>>>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>>>>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>>>>> AFAIR I saw here some issues about initialzation for global-variables,
>>>>> which weren't caught.
>>>>
>>>>
>>>> Hmm, I wonder why you would see issues with global initializers that
>>>> aren't seen on trunk?  In any case, if the issue is with global
>>>> initializers, they should be handled sooner, not here.

^

>>>>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>>>>> expr,
>>>>>>> bool complain)
>>>>>>>      tree basetype = TREE_TYPE (expr);
>>>>>>>      tree conv = NULL_TREE;
>>>>>>>      tree winner = NULL_TREE;
>>>>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>>>>> null_node.
>>>>>>> */
>>>>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>>>>
>>>>>>> -  if (expr == null_node
>>>>>>> +  STRIP_NOPS (expr_folded);
>>>>>>> +  if (expr_folded == null_node
>>>>>>
>>>>>>
>>>>>> Again, we shouldn't need to fold to check for null_node, it only occurs
>>>>>> when explicitly written.  Folding should never produce null_node unless
>>>>>> the argument was already null_node.
>>>>>
>>>>>
>>>>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>>>>> see if expression folded gets a constant, so that diagnostics getting
>>>>> displayed right.
>>>>
>>>>
>>>> Again, null_node is special.  It indicates that the user typed "__null".
>>>> That's what we're checking for here.  Folding is both unnecessary and
>>>> undesirable.

^

>>>>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>>>>> expr,
>>>>>>> bool complain)
>>>>>>>        switch (TREE_CODE (basetype))
>>>>>>>          {
>>>>>>>          case INTEGER_TYPE:
>>>>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>>>>
>>>>>>
>>>>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>>>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we already
>>>>>> fold in null_ptr_cst_p.
>>>>>
>>>>>
>>>>> We need to avoid useless conversion, so we should reduce to simple
>>>>> constant-value ...
>>>>
>>>>
>>>> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
>>>> more complex expression that folds to 0 is NOT a null pointer constant.
>>>> Folding is actively harmful here.
>>>>
>>>> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
>>>> is redundant.
>>>>
>>>> Was I unclear?

^

>>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree size,
>>>>>>> tsubst_flags_t complain)
>>>>>>>          SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>>          return itype;
>>>>>>>        }
>>>>>>> -
>>>>>>> +
>>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>>> not.  */
>>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>>
>>>>>>
>>>>>> Again, we already called maybe_constant_value.
>>>>>
>>>>>
>>>>> Sure, but maybe_constant_value still produces nops ...
>>>>
>>>>
>>>> If someone tries to create an array with a size that involves arithmetic
>>>> overflow, that's undefined behavior and we should probably give an error
>>>> rather than fold it away.

^

>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value, tree
>>>>>>> enumtype, tree attributes,
>>>>>>>      if (value)
>>>>>>>        STRIP_TYPE_NOPS (value);
>>>>>>>
>>>>>>> +  if (value)
>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>
>>>>>>
>>>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>>>
>>>>>
>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>> constant value ...
>>>>
>>>>
>>>> The cxx_constant_value call below will deal with them.
>>>
>>>
>>> Likewise for grokbitfield.
>>
>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>> will look into it, and come back to you on it.
>
> I am still on it ...  first did the other points

Looks like this hasn't changed.

>>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>>> (cp_parser
>>>>>>> *parser,
>>>>>>>           index = cp_parser_expression (parser);
>>>>>>>        }
>>>>>>>
>>>>>>> +  /* For offsetof and declaration of types we need
>>>>>>> +     constant integeral values.
>>>>>>> +     Also we meed to fold for negative constants so that diagnostic in
>>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>>> +  if (for_offsetof || decltype_p
>>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>>>>>>> (index, 0)) == INTEGER_CST))
>>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>>
>>>>>>
>>>>>> Similarly, for offsetof the folding should happen closer to where it is
>>>>>> needed.
>>>>>>
>>>>>> Why is it needed for decltype, which is querying the type of an
>>>>>> expression?
>>>>>>
>>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>>> constant; this isn't the right place to do it.
>>>>>
>>>>>
>>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>>> values early anyway.  So I saw it as more logical to have done this
>>>>> conversion as soon as possible after initialization.
>>>>
>>>>
>>>> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
>>>> immediately when we build it, at the end of cp_build_unary_op.
>>>>
>>>> I still wonder why any folding is necessary for decltype.  When I ask
>>>> why, I want to know *why*, not just have you tell me again that it's
>>>> needed.  I don't think it is.
>>>>
>>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>>> handle whatever additional folding is needed here.  If not, then fold in
>>>> finish_offsetof, before calling fold_offsetof.
>>>
>>>
>>> I see that this is now an unconditional fold_simple, but I still don't
>>> understand why it needs to be folded here, in the parser.
>>
>> The point to fold the 'value' here is for cases
>> 'processing_template_decl' isn't false. We could move it to the
>> else-case of the 'if (! processing_template_decl)' line for being more
>> explicit?
>
> Well, on looking here in more detail, we might don't that that initial
> folding here.  As for processing_template_decl fold_simple (and
> cp_fully_fold) doesn't do much.

Looks like the fold is still there.

>>>>> Anyway, if you prefer, we can do this in builder-routines, and remove
>>>>> at places constants aren't needed directly after parsing it those calls.
>>>>
>>>>
>>>> I want to delay it to:
>>>>
>>>> 1) the places where we actually care about constant values, all of which
>>>> already call maybe_constant_value or cxx_constant_value, so they
>>>> shouldn't need much change; and
>>>> 2) the places where we want a simplified expression for warnings, where
>>>> we should call fold_simple.
>>>
>>>> Folding in the parser is wrong, most of all because template
>>>> substitution doesn't go through the parser.
>>>
>>> There are still several folds in cp_parser_omp_* that should move later.
>>
>> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
>> 'low_bound' as those values getting checked some lines below (see
>> lines 27936, 27944).

OK, but this seems like an typical case of needing to fold for 
diagnostics; usually in those cases you use the folded value for the 
diagnostics and then keep using the unfolded expression elsewhere.

>> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
>> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
>> operand-folding into cp_parser_cilk_for itself, as we have here just
>> two users of 'cp_parser_cilk_for'.
>> One time we pass 'integer_zero_node' as this argument, and the other
>> time a binary-expression, which might be constant value.
>> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?
>
> ?

Why does the fold need to be in the parser?

>>>>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>>>>      else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>>>>        fn = AGGR_INIT_EXPR_FN (init);
>>>>>>>      else
>>>>>>> -    return convert (type, init);
>>>>>>> +    return fold (convert (type, init));
>>>>>>
>>>>>>
>>>>>> Why fold here?
>>>>>
>>>>>
>>>>> We had this already in prior thread.  fold (convert ()) !=
>>>>> fold_convert () for C++.  The fold is just there to make sure we fold
>>>>> away useless casts.
>>>>
>>>> But why here?  Can't we fold away useless casts earlier (in convert) or
>>>> later (when we care about having a simplified expression)?

^

>>>>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>>>>> va_gc>
>>>>>>> **values, tree fndecl,
>>>>>>>             && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>>>>           val = TREE_OPERAND (val, 0);
>>>>>>>
>>>>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>>>>> +       val = fold (val);
>>>>>>
>>>>>> Why?
>>>>>
>>>>> As builtin-handlers are expecting to see constant values.
>>>
>>> I would think this should be maybe_constant_value then.
>>
>> Why?  At the end we resolve normal-builtin via 'fold_call_expr'.  Of
>> course we can invoke here maybe_constant_value, but it would end up in
>> the same folding of a builtin-expression. So calling here directly
>> 'fold' just short-cuts this.
>
> ?

Wait.  Why are we folding here, again?  Which builtins need to have 
constant values here, before late folding?

>>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>>> *pre_p)
>>>>>>>          /* Handle OMP_FOR_COND.  */
>>>>>>>          t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>>          gcc_assert (COMPARISON_CLASS_P (t));
>>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>>> 1) ==
>>>>>>> decl);
>>>>>>
>>>>>>
>>>>>> Why didn't delayed folding canonicalize this so that the decl is in op0?
>>>>>
>>>>> Delay folding doesn't canonicalize this.
>>>>
>>>> Why not?  Doesn't it fold all expressions?
>>>
>>> ?
>>
>> It fold them lately.  I will recheck this code-change.  It might be no
>> longer required due recent changes to omp-folding.  It could be that
>> original pattern didn't applied here anymore, and therefore statement
>> didn't been transformed into its canonical form.  Bit I assume this
>> could be resolved.

?

>>>> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab
>>>> binoptab,
>>>>           are truncated to the mode size.  */
>>>>         carries = expand_binop (word_mode, reverse_unsigned_shift,
>>>>                                outof_input, const1_rtx, 0, unsignedp,
>>>> methods);
>>>> -      if (shift_mask == BITS_PER_WORD - 1)
>>>> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))
>>>
>>>
>>> These should still be unnecessary.
>>
>> Yes, they are.  We handle now the avoiding of dead-code for constants
>> (cond-expression, truthif* expressions, and useless convert-warnings).
>> So this change is something only interesting for different compiler,
>> but not related to delayed-folding anymore.
>> I will check, and remove it tomorrow.

Looks like this is still there.

>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree imag)
>>>>>>>    {
>>>>>>>      tree t = make_node (COMPLEX_CST);
>>>>>>>
>>>>>>> +  real = fold (real);
>>>>>>> +  imag = fold (imag);
>>>>>>
>>>>>>
>>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>>> folded.
>>>>>
>>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>>>>> So this place was the easiest way to avoid issues with things like '-'
>>>>> '1' etc.
>>>>
>>>> Is this because of the
>>>>>
>>>>>        value = build_complex (NULL_TREE, convert (const_type,
>>>>>                                                   integer_zero_node),
>>>>> value);
>>
>> Might be.  This should be indeed a 'fold_convert', isn't it?

Yes.

>>>> in interpret_float?  I think "convert" definitely needs to do some
>>>> folding, since it's called from middle-end code that expects that.
>>>
>>> I remember talking about "convert" doing some folding (and cp_convert not)
>>> in our 1:1 last week.
>>
>> Can't remember that.  I know that we were talking about the difference
>> of convert and fold_convert.  convert can be used on C++ specifics,
>> but fold_convert is something shared with ME.

convert is called from the ME, which sometimes expects folding.

>> So first 'fold_convert'
>> isn't the same as 'fold (convert ())'.
>> I don't find places we invoke convert () in ME.  We have some calls in
>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
>> convert_to_real), which all used in AST only AFAICS.

I was thinking of convert.c and fold-const.c to be part of the ME, since 
they are language-independent.  But I guess other people think of the ME 
starting with gimple.

And it looks like the only language-independent uses of convert are in 
c-family; I guess many of them should change to fold_convert.

>> I remember that we were talking about adding a standard-folding to
>> convert for operations on constant-values (as we do for
>> convert_to_integer).  Do you mean this?

Yes.  But it seems that isn't necessary.

>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>> *local,
>>>>>>> unsigned int bit_offset)
>>>>>>>      while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>            || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>        local->val = TREE_OPERAND (local->val, 0);
>>>>>>> +  local->val = fold (local->val);
>>>>>>
>>>>>> Likewise.
>>>>>
>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>> least folded for constants, we should be able to remove this.
>>>>
>>>> Yep, they need to be folded before we get here.

^

>>>>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>>>>> low_value, tree hi
>>>>> gh_value)
>>>>>     low_value = case_conversion (type, low_value);
>>>>>     high_value = case_conversion (type, high_value);
>>>>>
>>>>> +  low_value = cp_fully_fold (low_value);
>>>>> +  high_value = cp_fully_fold (high_value);
>>>>
>>>>
>>>> Again, case_conversion should have already folded constants.

^

>>>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>>>>> tsubst_flags_t complain)
>>>>>   {
>>>>>     tree expr_type;
>>>>>
>>>>> +  expr = cp_try_fold_to_constant (expr);
>>>>> +
>>>>
>>>> And here, convert_nontype_argument already uses
>>>> maybe_constant_value/cxx_constant_value for folding constants.

^

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-29 18:48           ` Jason Merrill
@ 2015-07-29 23:03             ` Kai Tietz
  2015-07-30 14:40               ` Kai Tietz
  2015-07-30 18:41               ` Jason Merrill
  0 siblings, 2 replies; 38+ messages in thread
From: Kai Tietz @ 2015-07-29 23:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-07-29 19:48 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 07/28/2015 04:10 PM, Kai Tietz wrote:
>>
>> 2015-07-28 1:14 GMT+02:00 Kai Tietz <ktietz70@googlemail.com>:
>>
>>> 2015-07-27 18:51 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>
>>>> I've trimmed this to the previously mentioned issues that still need to
>>>> be
>>>> addressed; I'll do another full review after these are dealt with.
>>>
>>>
>>> Thanks for doing this summary of missing parts of prior review.
>>>
>>>> On 06/13/2015 12:15 AM, Jason Merrill wrote:
>>>>>
>>>>>
>>>>> On 06/12/2015 12:11 PM, Kai Tietz wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> @@ -1052,6 +1054,9 @@ adjust_temp_type (tree type, tree temp)
>>>>>>>>    {
>>>>>>>>      if (TREE_TYPE (temp) == type)
>>>>>>>>        return temp;
>>>>>>>> +  STRIP_NOPS (temp);
>>>>>>>> +  if (TREE_TYPE (temp) == type)
>>>>>>>> +    return temp;
>>>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>>>>>> *ctx,
>>>>>>>> tree t,
>>>>>>>>    bool
>>>>>>>>    reduced_constant_expression_p (tree t)
>>>>>>>>    {
>>>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>>>> +  STRIP_NOPS (t);
>
> ^
>

Checked, and removing those STRIP_NOPS cause regressions about
vector-casts.  At least the STRIP_NOPS in
reduced_constant_expression_p seems to be required.  See as example
g++.dg/ext/vector20.C as testcase.
It sees that '(vec)(const __vector(2) long int){3l, 4l}' is not a
constant expression.

The change to adjust_temp_type seems to be no more necessary (just
doing tests on it).

>>>>>>>> @@ -1088,7 +1093,10 @@ cxx_bind_parameters_in_call (const
>>>>>>>> constexpr_ctx
>>>>>>>> *ctx, tree t,
>>>>>>>>             && is_dummy_object (x))
>>>>>>>>           {
>>>>>>>>             x = ctx->object;
>>>>>>>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>>>> +         if (x)
>>>>>>>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>>>>>>>> +         else
>>>>>>>> +           x = get_nth_callarg (t, i);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> This still should not be necessary.

Replaced the x = get_nth_callarg (t,i);  by a gcc_unreachable ();,
just to be sure we hit issue, if occures.

>>>>>>
>>>>>>
>>>>>> Yeah, most likely.  But I got initially here some issues, so I don't
>>>>>> see that this code would worsen things.
>>>>>
>>>>>
>>>>>
>>>>> If this code path is hit, that means something has broken my design,
>>>>> and
>>>>> I don't want to just paper over that.  Please revert this change.
>
>
> ^
>
>>>>>>>>        case SIZEOF_EXPR:
>>>>>>>> +      if (processing_template_decl
>>>>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>>>>>> +       return t;
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why is this necessary?

The issue is that by delayed-folding we don't fold sizeof-expressions
until we do the folding after genericize-pass.  So those expressions
remain, and we can run in template on sizeof-operators on incomplete
types, if we invoke here variants of the constexpr-code.  So this
pattern simply verifies that the sizeof-operand can be determined.  We
could simply avoid resolving sizeof-operators in template-decl at all.
But my idea here was to try to resolve them, if the type of the
operand is already complete (and has an constant size).

>>>>>>
>>>>>>
>>>>>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>>>>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>>>>> otherwise get issues about expressions without existing type (as usual
>>>>>> within template-declarations for some expressions).
>>>>>
>>>>>
>>>>>
>>>>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>>>>> maybe_constant_value just returns if
>>>>> instantiation_dependent_expression_p is true.
>
> ^

Well, but we could come here by other routine then
maybe_constant_value. For example cxx_constnat_value doesn't do checks
here.

>
>>>>>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>>>>>> constexpr_ctx
>>>>>>>> *ctx, tree t,
>>>>>>>>        case CONVERT_EXPR:
>>>>>>>>        case VIEW_CONVERT_EXPR:
>>>>>>>>        case NOP_EXPR:
>>>>>>>> +    case UNARY_PLUS_EXPR:
>>>>>>>>          {
>>>>>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>>>>>           tree oldop = TREE_OPERAND (t, 0);
>>>>>>>> +
>>>>>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop)
>>>>>>>> &&
>>>>>>>> TREE_OVERFLOW_P (oldop))
>>>>>>>> +         {
>>>>>>>> +           if (!ctx->quiet)
>>>>>>>> +             permerror (input_location, "overflow in constant
>>>>>>>> expression");
>>>>>>>> +           /* If we're being permissive (and are in an enforcing
>>>>>>>> +               context), ignore the overflow.  */
>>>>>>>> +           if (!flag_permissive)
>>>>>>>> +             *overflow_p = true;
>>>>>>>> +           *non_constant_p = true;
>>>>>>>> +
>>>>>>>> +           return t;
>>>>>>>> +         }
>>>>>>>>           tree op = cxx_eval_constant_expression (ctx, oldop,
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why doesn't the call to cxx_eval_constant_expression at the bottom
>>>>>>> here
>>>>>>> handle oldop having TREE_OVERFLOW set?
>>>>>>
>>>>>>
>>>>>>
>>>>>> I just handled the case that we see here a wrapping NOP_EXPR around an
>>>>>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>>>>>
>>>>>
>>>>>
>>>>> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
>>>>> is there to indicated that the expression is non-constant, and it can't
>>>>> be simplified any farther.
>>>>>
>>>>> Please give an example of what was going wrong.
>
> ^

I did some regression-testing on it.  This looks to me like something
I missed to cleanup.  Most changes within constexpr-code aren't
necessary anymore.  But looking on that, I think I papered over some
issues I had about double-reporting of non-constant expression on
overflows.

>>>>>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq
>>>>>>>> *pre_p,
>>>>>>>> gimple_seq *post_p)
>>>>>>>>
>>>>>>>>      switch (code)
>>>>>>>>        {
>>>>>>>> +    case SIZEOF_EXPR:
>>>>>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE
>>>>>>>> (TREE_OPERAND
>>>>>>>> (*expr_p,
>>>>>>>> +
>>>>>>>> 0)),
>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>>>>>> 0),
>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>> +      else
>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>>>>>> 0),
>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>> +      if (*expr_p == error_mark_node)
>>>>>>>> +       *expr_p = size_one_node;
>>>>>>>> +
>>>>>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>>>>>> +      ret = GS_OK;
>>>>>>>> +      break;
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why are these surviving until gimplification time?
>>>>>>
>>>>>>
>>>>>> This might be still necessary. I will retest, when bootstrap works.
>>>>>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>>>>>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>>>>>> AFAIR I saw here some issues about initialzation for global-variables,
>>>>>> which weren't caught.
>>>>>
>>>>>
>>>>>
>>>>> Hmm, I wonder why you would see issues with global initializers that
>>>>> aren't seen on trunk?  In any case, if the issue is with global
>>>>> initializers, they should be handled sooner, not here.
>

They don't survice in function-context, but outside they might.  On
trunk we never will see an sizeof-expression in such case as they got
folded-away much earlier.

I will try an bootstrap with disabling it.  In ME we don't produce
sizeof-expressions anymore, so we don't need to think about
re-gimplifiying some AST AFAICS.

>
>>>>>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>>>>>> expr,
>>>>>>>> bool complain)
>>>>>>>>      tree basetype = TREE_TYPE (expr);
>>>>>>>>      tree conv = NULL_TREE;
>>>>>>>>      tree winner = NULL_TREE;
>>>>>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>>>>>> null_node.
>>>>>>>> */
>>>>>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>>>>>
>>>>>>>> -  if (expr == null_node
>>>>>>>> +  STRIP_NOPS (expr_folded);
>>>>>>>> +  if (expr_folded == null_node
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Again, we shouldn't need to fold to check for null_node, it only
>>>>>>> occurs
>>>>>>> when explicitly written.  Folding should never produce null_node
>>>>>>> unless
>>>>>>> the argument was already null_node.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>>>>>> see if expression folded gets a constant, so that diagnostics getting
>>>>>> displayed right.
>>>>>
>>>>>
>>>>>
>>>>> Again, null_node is special.  It indicates that the user typed
>>>>> "__null".
>>>>> That's what we're checking for here.  Folding is both unnecessary and
>>>>> undesirable.
>

So, let us remove it ...  I expect issues about casts on integers,
which are reasoned due implicit assignments, expr won't be null_node.

>
>>>>>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>>>>>> expr,
>>>>>>>> bool complain)
>>>>>>>>        switch (TREE_CODE (basetype))
>>>>>>>>          {
>>>>>>>>          case INTEGER_TYPE:
>>>>>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>>>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>>>>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we
>>>>>>> already
>>>>>>> fold in null_ptr_cst_p.
>>>>>>
>>>>>>
>>>>>>
>>>>>> We need to avoid useless conversion, so we should reduce to simple
>>>>>> constant-value ...
>>>>>
>>>>>
>>>>>
>>>>> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
>>>>> more complex expression that folds to 0 is NOT a null pointer constant.
>>>>> Folding is actively harmful here.
>>>>>
>>>>> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
>>>>> is redundant.
>>>>>
>>>>> Was I unclear?
>
>
> ^

See comment above.  I will remove folding, and check.

>>>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree
>>>>>>>> size,
>>>>>>>> tsubst_flags_t complain)
>>>>>>>>          SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>>>          return itype;
>>>>>>>>        }
>>>>>>>> -
>>>>>>>> +
>>>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>>>> not.  */
>>>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Again, we already called maybe_constant_value.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sure, but maybe_constant_value still produces nops ...
>>>>>
>>>>>
>>>>>
>>>>> If someone tries to create an array with a size that involves
>>>>> arithmetic
>>>>> overflow, that's undefined behavior and we should probably give an
>>>>> error
>>>>> rather than fold it away.
>
>
> ^

If we need to do some reduction to constant value here, as expr might
be actually a constant, which isn't folded here.  Eg something like:
struct {
  char abc[sizeof (int) * 8];
};
Due delayed folding array index isn't necessarily reduced here.  So we
need to perform at least constant value folding for diagnostics, as we
do right now.

>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
>>>>>>>> tree
>>>>>>>> enumtype, tree attributes,
>>>>>>>>      if (value)
>>>>>>>>        STRIP_TYPE_NOPS (value);
>>>>>>>>
>>>>>>>> +  if (value)
>>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>>>>
>>>>>>
>>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>>> constant value ...
>>>>>
>>>>>
>>>>>
>>>>> The cxx_constant_value call below will deal with them.
>>>>
>>>>
>>>>
>>>> Likewise for grokbitfield.
>>>
>>>
>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>>> will look into it, and come back to you on it.
>>
>>
>> I am still on it ...  first did the other points
>
>
> Looks like this hasn't changed.

Yes, for grokbitfield current version uses fold_simple for witdth.  So
just expressions based on constants getting reduced to short form.  In
grokbitfield I don't see invocation of cxx_constant_value.  So how can
we be sure that width is reduced to integer-cst?

For build_enumerator the call is indeed superflous.

>>>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>>>> (cp_parser
>>>>>>>> *parser,
>>>>>>>>           index = cp_parser_expression (parser);
>>>>>>>>        }
>>>>>>>>
>>>>>>>> +  /* For offsetof and declaration of types we need
>>>>>>>> +     constant integeral values.
>>>>>>>> +     Also we meed to fold for negative constants so that diagnostic
>>>>>>>> in
>>>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>>>> +  if (for_offsetof || decltype_p
>>>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE
>>>>>>>> (TREE_OPERAND
>>>>>>>> (index, 0)) == INTEGER_CST))
>>>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Similarly, for offsetof the folding should happen closer to where it
>>>>>>> is
>>>>>>> needed.
>>>>>>>
>>>>>>> Why is it needed for decltype, which is querying the type of an
>>>>>>> expression?
>>>>>>>
>>>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>>>> constant; this isn't the right place to do it.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>>>> values early anyway.  So I saw it as more logical to have done this
>>>>>> conversion as soon as possible after initialization.
>>>>>
>>>>>
>>>>>
>>>>> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
>>>>> immediately when we build it, at the end of cp_build_unary_op.
>>>>>
>>>>> I still wonder why any folding is necessary for decltype.  When I ask
>>>>> why, I want to know *why*, not just have you tell me again that it's
>>>>> needed.  I don't think it is.
>>>>>
>>>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>>>> handle whatever additional folding is needed here.  If not, then fold
>>>>> in
>>>>> finish_offsetof, before calling fold_offsetof.
>>>>
>>>>
>>>>
>>>> I see that this is now an unconditional fold_simple, but I still don't
>>>> understand why it needs to be folded here, in the parser.
>>>
>>>
>>> The point to fold the 'value' here is for cases
>>> 'processing_template_decl' isn't false. We could move it to the
>>> else-case of the 'if (! processing_template_decl)' line for being more
>>> explicit?
>>
>>
>> Well, on looking here in more detail, we might don't that that initial
>> folding here.  As for processing_template_decl fold_simple (and
>> cp_fully_fold) doesn't do much.
>
>
> Looks like the fold is still there.

Yes, but a fold_simple one just working on constant values.  It
doesn't fold expressions like 'a == a' to a constant.  I extended
comment in current version on branch.  Additionally it invokes now the
fold_simple always.  We want to reduce index, if possible, for
diagnostics in code in c-family/c-common.c for array-bounds, for types
(they need to be fully folded), and to be sure we simplify basic
operations on constant-values.

>>>>>> Anyway, if you prefer, we can do this in builder-routines, and remove
>>>>>> at places constants aren't needed directly after parsing it those
>>>>>> calls.
>>>>>
>>>>>
>>>>>
>>>>> I want to delay it to:
>>>>>
>>>>> 1) the places where we actually care about constant values, all of
>>>>> which
>>>>> already call maybe_constant_value or cxx_constant_value, so they
>>>>> shouldn't need much change; and
>>>>> 2) the places where we want a simplified expression for warnings, where
>>>>> we should call fold_simple.
>>>>
>>>>
>>>>> Folding in the parser is wrong, most of all because template
>>>>> substitution doesn't go through the parser.
>>>>
>>>>
>>>> There are still several folds in cp_parser_omp_* that should move later.
>>>
>>>
>>> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
>>> 'low_bound' as those values getting checked some lines below (see
>>> lines 27936, 27944).
>
>
> OK, but this seems like an typical case of needing to fold for diagnostics;
> usually in those cases you use the folded value for the diagnostics and then
> keep using the unfolded expression elsewhere.

Right.

>>> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
>>> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
>>> operand-folding into cp_parser_cilk_for itself, as we have here just
>>> two users of 'cp_parser_cilk_for'.
>>> One time we pass 'integer_zero_node' as this argument, and the other
>>> time a binary-expression, which might be constant value.
>>> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?
>>
>>
>> ?
>
>
> Why does the fold need to be in the parser?

Well, if we hit it during our tree-walk in cp_fold_r, then we don't
need to fold it here.  I will check, if this is really necessary.

>>>>>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>>>>>      else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>>>>>        fn = AGGR_INIT_EXPR_FN (init);
>>>>>>>>      else
>>>>>>>> -    return convert (type, init);
>>>>>>>> +    return fold (convert (type, init));
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why fold here?
>>>>>>
>>>>>>
>>>>>>
>>>>>> We had this already in prior thread.  fold (convert ()) !=
>>>>>> fold_convert () for C++.  The fold is just there to make sure we fold
>>>>>> away useless casts.
>>>>>
>>>>>
>>>>> But why here?  Can't we fold away useless casts earlier (in convert) or
>>>>> later (when we care about having a simplified expression)?
>
>
> ^
>
>>>>>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>>>>>> va_gc>
>>>>>>>> **values, tree fndecl,
>>>>>>>>             && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>>>>>           val = TREE_OPERAND (val, 0);
>>>>>>>>
>>>>>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>>>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>>>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>>>>>> +       val = fold (val);
>>>>>>>
>>>>>>>
>>>>>>> Why?
>>>>>>
>>>>>>
>>>>>> As builtin-handlers are expecting to see constant values.
>>>>
>>>>
>>>> I would think this should be maybe_constant_value then.
>>>
>>>
>>> Why?  At the end we resolve normal-builtin via 'fold_call_expr'.  Of
>>> course we can invoke here maybe_constant_value, but it would end up in
>>> the same folding of a builtin-expression. So calling here directly
>>> 'fold' just short-cuts this.
>>
>>
>> ?
>
>
> Wait.  Why are we folding here, again?  Which builtins need to have constant
> values here, before late folding?

Well, I would have assumed here first that on builitin-functions, we
need to fold arguments (at least the constant values), as
builtin-folder-routines are depending on seeing them (eg.
builtin_expect, etc).  But by looking on code, I would assume that
this method doesn't do this ...
I am confused.  So I would assume that this fold in convert_arguments
for builtin-normal functions seems not to be necessary.  We should
handle this at other places already (and better).

>>>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>>>> *pre_p)
>>>>>>>>          /* Handle OMP_FOR_COND.  */
>>>>>>>>          t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>>>          gcc_assert (COMPARISON_CLASS_P (t));
>>>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>>>> 1) ==
>>>>>>>> decl);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why didn't delayed folding canonicalize this so that the decl is in
>>>>>>> op0?
>>>>>>
>>>>>>
>>>>>> Delay folding doesn't canonicalize this.
>>>>>
>>>>>
>>>>> Why not?  Doesn't it fold all expressions?
>>>>
>>>>
>>>> ?
>>>
>>>
>>> It fold them lately.  I will recheck this code-change.  It might be no
>>> longer required due recent changes to omp-folding.  It could be that
>>> original pattern didn't applied here anymore, and therefore statement
>>> didn't been transformed into its canonical form.  Bit I assume this
>>> could be resolved.
>
>
> ?

This hunk is necessary as we don't use cannonical-form produced by
shorten_compare anymore.  Therefore special operand can occure on
right-hand side too.

>>>>> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab
>>>>> binoptab,
>>>>>           are truncated to the mode size.  */
>>>>>         carries = expand_binop (word_mode, reverse_unsigned_shift,
>>>>>                                outof_input, const1_rtx, 0, unsignedp,
>>>>> methods);
>>>>> -      if (shift_mask == BITS_PER_WORD - 1)
>>>>> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))
>>>>
>>>>
>>>>
>>>> These should still be unnecessary.

No more.

> Looks like this is still there.

Right, didn't noticed that I haven't caught them too, while cleaning
those no longer required signed/unsigned cast modifications for
bootstrap.

>>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree
>>>>>>>> imag)
>>>>>>>>    {
>>>>>>>>      tree t = make_node (COMPLEX_CST);
>>>>>>>>
>>>>>>>> +  real = fold (real);
>>>>>>>> +  imag = fold (imag);
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>>>> folded.
>>>>>>
>>>>>>
>>>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>>>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>>>>>> So this place was the easiest way to avoid issues with things like '-'
>>>>>> '1' etc.
>>>>>
>>>>>
>>>>> Is this because of the
>>>>>>
>>>>>>
>>>>>>        value = build_complex (NULL_TREE, convert (const_type,
>>>>>>                                                   integer_zero_node),
>>>>>> value);
>>>
>>>
>>> Might be.  This should be indeed a 'fold_convert', isn't it?
>
>
> Yes.

Applied modification to it.

>>>>> in interpret_float?  I think "convert" definitely needs to do some
>>>>> folding, since it's called from middle-end code that expects that.
>>>>
>>>>
>>>> I remember talking about "convert" doing some folding (and cp_convert
>>>> not)
>>>> in our 1:1 last week.
>>>
>>>
>>> Can't remember that.  I know that we were talking about the difference
>>> of convert and fold_convert.  convert can be used on C++ specifics,
>>> but fold_convert is something shared with ME.
>
>
> convert is called from the ME, which sometimes expects folding.
>
>>> So first 'fold_convert'
>>> isn't the same as 'fold (convert ())'.
>>> I don't find places we invoke convert () in ME.  We have some calls in
>>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
>>> convert_to_real), which all used in AST only AFAICS.
>
>
> I was thinking of convert.c and fold-const.c to be part of the ME, since
> they are language-independent.  But I guess other people think of the ME
> starting with gimple.
>
> And it looks like the only language-independent uses of convert are in
> c-family; I guess many of them should change to fold_convert.

Hmm, in context of this work? Or is this more a general point about future work?

>>> I remember that we were talking about adding a standard-folding to
>>> convert for operations on constant-values (as we do for
>>> convert_to_integer).  Do you mean this?
>
>
> Yes.  But it seems that isn't necessary.
>
>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>>> *local,
>>>>>>>> unsigned int bit_offset)
>>>>>>>>      while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>>            || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>>        local->val = TREE_OPERAND (local->val, 0);
>>>>>>>> +  local->val = fold (local->val);
>>>>>>>
>>>>>>>
>>>>>>> Likewise.
>>>>>>
>>>>>>
>>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>>> least folded for constants, we should be able to remove this.
>>>>>
>>>>>
>>>>> Yep, they need to be folded before we get here.
>

I didn't come to remove this line for testing.  As we fold now for
initializers more early, and cp_fold supports constructors, it could
be that we don't need this anymore.  It is on my pile.

>>>>>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>>>>>> low_value, tree hi
>>>>>> gh_value)
>>>>>>     low_value = case_conversion (type, low_value);
>>>>>>     high_value = case_conversion (type, high_value);
>>>>>>
>>>>>> +  low_value = cp_fully_fold (low_value);
>>>>>> +  high_value = cp_fully_fold (high_value);
>>>>>
>>>>>
>>>>>
>>>>> Again, case_conversion should have already folded constants.
>

Yes, folding is here superflous.  I will remove it.

>
>>>>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>>>>>> tsubst_flags_t complain)
>>>>>>   {
>>>>>>     tree expr_type;
>>>>>>
>>>>>> +  expr = cp_try_fold_to_constant (expr);
>>>>>> +
>>>>>
>>>>>
>>>>> And here, convert_nontype_argument already uses
>>>>> maybe_constant_value/cxx_constant_value for folding constants.
>

Yes, this invocation looks useless too.  I think I introduced it for
the STRING_CST check below, but AFAICS we should assume it as
unnecessary.  I will change it and do regression-testing.

>
> Jason


By recent changes we seem to hit for c++ some additional regression.
They are related to negate-shifts for c++11.  We are hitting now the
check within cxx_constant_value.  The cxx_eval_check_shift_p sees now
that left-hand operand is negative and produces two new errors for
following tests: c-c++-common Wshift-negateive-value-*.c cases.
So we will need adjust those cases, or invoke within this
eval-function instead maybe_constant_value to avoid that ?

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-29 23:03             ` Kai Tietz
@ 2015-07-30 14:40               ` Kai Tietz
  2015-07-30 18:41               ` Jason Merrill
  1 sibling, 0 replies; 38+ messages in thread
From: Kai Tietz @ 2015-07-30 14:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-07-30 0:56 GMT+02:00 Kai Tietz <ktietz70@googlemail.com>:
> 2015-07-29 19:48 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 07/28/2015 04:10 PM, Kai Tietz wrote:
> The change to adjust_temp_type seems to be no more necessary (just
> doing tests on it).

Yes, committed it.

>>
>>>>>>>>> @@ -3391,8 +3431,23 @@ cxx_eval_constant_expression (const
>>>>>>>>> constexpr_ctx
>>>>>>>>> *ctx, tree t,
>>>>>>>>>        case CONVERT_EXPR:
>>>>>>>>>        case VIEW_CONVERT_EXPR:
>>>>>>>>>        case NOP_EXPR:
>>>>>>>>> +    case UNARY_PLUS_EXPR:
>>>>>>>>>          {
>>>>>>>>> +       enum tree_code tcode = TREE_CODE (t);
>>>>>>>>>           tree oldop = TREE_OPERAND (t, 0);
>>>>>>>>> +
>>>>>>>>> +       if (tcode == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop)
>>>>>>>>> &&
>>>>>>>>> TREE_OVERFLOW_P (oldop))
>>>>>>>>> +         {
>>>>>>>>> +           if (!ctx->quiet)
>>>>>>>>> +             permerror (input_location, "overflow in constant
>>>>>>>>> expression");
>>>>>>>>> +           /* If we're being permissive (and are in an enforcing
>>>>>>>>> +               context), ignore the overflow.  */
>>>>>>>>> +           if (!flag_permissive)
>>>>>>>>> +             *overflow_p = true;
>>>>>>>>> +           *non_constant_p = true;
>>>>>>>>> +
>>>>>>>>> +           return t;
>>>>>>>>> +         }
>>>>>>>>>           tree op = cxx_eval_constant_expression (ctx, oldop,
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Why doesn't the call to cxx_eval_constant_expression at the bottom
>>>>>>>> here
>>>>>>>> handle oldop having TREE_OVERFLOW set?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I just handled the case that we see here a wrapping NOP_EXPR around an
>>>>>>> overflow.  As this isn't handled by cxx_eval_constant_expression.
>>>>>>
>>>>>>
>>>>>>
>>>>>> How does it need to be handled?  A NOP_EXPR wrapped around an overflow
>>>>>> is there to indicated that the expression is non-constant, and it can't
>>>>>> be simplified any farther.
>>>>>>
>>>>>> Please give an example of what was going wrong.
>>
>> ^
>
> I did some regression-testing on it.  This looks to me like something
> I missed to cleanup.  Most changes within constexpr-code aren't
> necessary anymore.  But looking on that, I think I papered over some
> issues I had about double-reporting of non-constant expression on
> overflows.

Committed change to branch for removing this.

>>>>>>>>> @@ -565,6 +571,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq
>>>>>>>>> *pre_p,
>>>>>>>>> gimple_seq *post_p)
>>>>>>>>>
>>>>>>>>>      switch (code)
>>>>>>>>>        {
>>>>>>>>> +    case SIZEOF_EXPR:
>>>>>>>>> +      if (SIZEOF_EXPR_TYPE_P (*expr_p))
>>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_TYPE
>>>>>>>>> (TREE_OPERAND
>>>>>>>>> (*expr_p,
>>>>>>>>> +
>>>>>>>>> 0)),
>>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>>> +      else if (TYPE_P (TREE_OPERAND (*expr_p, 0)))
>>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (*expr_p,
>>>>>>>>> 0),
>>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>>> +      else
>>>>>>>>> +       *expr_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (*expr_p,
>>>>>>>>> 0),
>>>>>>>>> +                                             SIZEOF_EXPR, false);
>>>>>>>>> +      if (*expr_p == error_mark_node)
>>>>>>>>> +       *expr_p = size_one_node;
>>>>>>>>> +
>>>>>>>>> +      *expr_p = maybe_constant_value (*expr_p);
>>>>>>>>> +      ret = GS_OK;
>>>>>>>>> +      break;
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Why are these surviving until gimplification time?
>>>>>>>
>>>>>>>
>>>>>>> This might be still necessary. I will retest, when bootstrap works.
>>>>>>> As we now added SIZEOF_EXPR folding to cp_fold, and if we catch all
>>>>>>> expressions a sizeof can occure, this shouldn't be necessary anymore.
>>>>>>> AFAIR I saw here some issues about initialzation for global-variables,
>>>>>>> which weren't caught.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Hmm, I wonder why you would see issues with global initializers that
>>>>>> aren't seen on trunk?  In any case, if the issue is with global
>>>>>> initializers, they should be handled sooner, not here.
>>
>
> They don't survice in function-context, but outside they might.  On
> trunk we never will see an sizeof-expression in such case as they got
> folded-away much earlier.
>
> I will try an bootstrap with disabling it.  In ME we don't produce
> sizeof-expressions anymore, so we don't need to think about
> re-gimplifiying some AST AFAICS.

Tested.  We seems not to need the handle of SIZEOF_EXPR in gimplifier
anymore.  so removed hunk.

>>
>>>>>>>>> @@ -1529,8 +1532,11 @@ build_expr_type_conversion (int desires, tree
>>>>>>>>> expr,
>>>>>>>>> bool complain)
>>>>>>>>>      tree basetype = TREE_TYPE (expr);
>>>>>>>>>      tree conv = NULL_TREE;
>>>>>>>>>      tree winner = NULL_TREE;
>>>>>>>>> +  /* Want to see if EXPR is a constant.  See below checks for
>>>>>>>>> null_node.
>>>>>>>>> */
>>>>>>>>> +  tree expr_folded = cp_try_fold_to_constant (expr);
>>>>>>>>>
>>>>>>>>> -  if (expr == null_node
>>>>>>>>> +  STRIP_NOPS (expr_folded);
>>>>>>>>> +  if (expr_folded == null_node
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Again, we shouldn't need to fold to check for null_node, it only
>>>>>>>> occurs
>>>>>>>> when explicitly written.  Folding should never produce null_node
>>>>>>>> unless
>>>>>>>> the argument was already null_node.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Well, we need to do this for diagnostic messages AFAIR.  We want to
>>>>>>> see if expression folded gets a constant, so that diagnostics getting
>>>>>>> displayed right.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Again, null_node is special.  It indicates that the user typed
>>>>>> "__null".
>>>>>> That's what we're checking for here.  Folding is both unnecessary and
>>>>>> undesirable.
>>
>
> So, let us remove it ...  I expect issues about casts on integers,
> which are reasoned due implicit assignments, expr won't be null_node.

I was wrong about this.  I removed the folding from
build_expr_type_conversion routine.

>>
>>>>>>>>> @@ -1548,7 +1554,7 @@ build_expr_type_conversion (int desires, tree
>>>>>>>>> expr,
>>>>>>>>> bool complain)
>>>>>>>>>        switch (TREE_CODE (basetype))
>>>>>>>>>          {
>>>>>>>>>          case INTEGER_TYPE:
>>>>>>>>> -       if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
>>>>>>>>> +       if ((desires & WANT_NULL) && null_ptr_cst_p (expr_folded))
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Again, we don't want to fold before calling null_ptr_cst_p, since in
>>>>>>>> C++11 only a literal 0 is a null pointer constant.  For C++98 we
>>>>>>>> already
>>>>>>>> fold in null_ptr_cst_p.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> We need to avoid useless conversion, so we should reduce to simple
>>>>>>> constant-value ...
>>>>>>
>>>>>>
>>>>>>
>>>>>> No.  Again, in C++11 only "0" or "0L" is a null pointer constant.   A
>>>>>> more complex expression that folds to 0 is NOT a null pointer constant.
>>>>>> Folding is actively harmful here.
>>>>>>
>>>>>> And again, in C++98 mode null_ptr_cst_p already folds, so doing it here
>>>>>> is redundant.
>>>>>>
>>>>>> Was I unclear?
>>
>>
>> ^

See comment above. Cleaned up.

>>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
>>>>>>>>> tree
>>>>>>>>> enumtype, tree attributes,
>>>>>>>>>      if (value)
>>>>>>>>>        STRIP_TYPE_NOPS (value);
>>>>>>>>>
>>>>>>>>> +  if (value)
>>>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>>>>>
>>>>>>>
>>>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>>>> constant value ...
>>>>>>
>>>>>>
>>>>>>
>>>>>> The cxx_constant_value call below will deal with them.
>>>>>
>>>>>
>>>>>
>>>>> Likewise for grokbitfield.
>>>>
>>>>
>>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>>>> will look into it, and come back to you on it.
>>>
>>>
>>> I am still on it ...  first did the other points
>>
>>
>> Looks like this hasn't changed.
>
> Yes, for grokbitfield current version uses fold_simple for witdth.  So
> just expressions based on constants getting reduced to short form.  In
> grokbitfield I don't see invocation of cxx_constant_value.  So how can
> we be sure that width is reduced to integer-cst?
>
> For build_enumerator the call is indeed superflous.
I modified build_enumerator not to fold additionally.


>>>>>>>>> @@ -441,7 +441,7 @@ build_aggr_init_expr (tree type, tree init)
>>>>>>>>>      else if (TREE_CODE (init) == AGGR_INIT_EXPR)
>>>>>>>>>        fn = AGGR_INIT_EXPR_FN (init);
>>>>>>>>>      else
>>>>>>>>> -    return convert (type, init);
>>>>>>>>> +    return fold (convert (type, init));
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Why fold here?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> We had this already in prior thread.  fold (convert ()) !=
>>>>>>> fold_convert () for C++.  The fold is just there to make sure we fold
>>>>>>> away useless casts.
>>>>>>
>>>>>>
>>>>>> But why here?  Can't we fold away useless casts earlier (in convert) or
>>>>>> later (when we care about having a simplified expression)?
>>
>>
>> ^

I removed that fold.

>>>>>>>>> @@ -3664,6 +3660,10 @@ convert_arguments (tree typelist, vec<tree,
>>>>>>>>> va_gc>
>>>>>>>>> **values, tree fndecl,
>>>>>>>>>             && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
>>>>>>>>>           val = TREE_OPERAND (val, 0);
>>>>>>>>>
>>>>>>>>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>>>>>>>>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>>>>>>>>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>>>>>>>>> +       val = fold (val);
>>>>>>>>
>>>>>>>>
>>>>>>>> Why?
>>>>>>>
>>>>>>>
>>>>>>> As builtin-handlers are expecting to see constant values.
>>>>>
>>>>>
>>>>> I would think this should be maybe_constant_value then.
>>>>
>>>>
>>>> Why?  At the end we resolve normal-builtin via 'fold_call_expr'.  Of
>>>> course we can invoke here maybe_constant_value, but it would end up in
>>>> the same folding of a builtin-expression. So calling here directly
>>>> 'fold' just short-cuts this.
>>>
>>>
>>> ?
>>
>>
>> Wait.  Why are we folding here, again?  Which builtins need to have constant
>> values here, before late folding?
>
> Well, I would have assumed here first that on builitin-functions, we
> need to fold arguments (at least the constant values), as
> builtin-folder-routines are depending on seeing them (eg.
> builtin_expect, etc).  But by looking on code, I would assume that
> this method doesn't do this ...
> I am confused.  So I would assume that this fold in convert_arguments
> for builtin-normal functions seems not to be necessary.  We should
> handle this at other places already (and better).

I removed this hunk, and retested.  It isn't necessary anymore, so I removed it.

>>>>>> @@ -867,7 +867,7 @@ expand_subword_shift (machine_mode op1_mode, optab
>>>>>> binoptab,
>>>>>>           are truncated to the mode size.  */
>>>>>>         carries = expand_binop (word_mode, reverse_unsigned_shift,
>>>>>>                                outof_input, const1_rtx, 0, unsignedp,
>>>>>> methods);
>>>>>> -      if (shift_mask == BITS_PER_WORD - 1)
>>>>>> +      if (shift_mask == (unsigned HOST_WIDE_INT) (BITS_PER_WORD - 1))
>>>>>
>>>>>
>>>>>
>>>>> These should still be unnecessary.
>
> No more.
>
>> Looks like this is still there.
>
> Right, didn't noticed that I haven't caught them too, while cleaning
> those no longer required signed/unsigned cast modifications for
> bootstrap.

Removed it.

>>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>>>> *local,
>>>>>>>>> unsigned int bit_offset)
>>>>>>>>>      while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>>>            || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>>>        local->val = TREE_OPERAND (local->val, 0);
>>>>>>>>> +  local->val = fold (local->val);
>>>>>>>>
>>>>>>>>
>>>>>>>> Likewise.
>>>>>>>
>>>>>>>
>>>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>>>> least folded for constants, we should be able to remove this.
>>>>>>
>>>>>>
>>>>>> Yep, they need to be folded before we get here.
>>
>
> I didn't come to remove this line for testing.  As we fold now for
> initializers more early, and cp_fold supports constructors, it could
> be that we don't need this anymore.  It is on my pile.

That fold is still required.  By removing it, I saw boostrap issue due
'invalid initializer'.

>>>>>>> @@ -3311,6 +3311,9 @@ finish_case_label (location_t loc, tree
>>>>>>> low_value, tree hi
>>>>>>> gh_value)
>>>>>>>     low_value = case_conversion (type, low_value);
>>>>>>>     high_value = case_conversion (type, high_value);
>>>>>>>
>>>>>>> +  low_value = cp_fully_fold (low_value);
>>>>>>> +  high_value = cp_fully_fold (high_value);
>>>>>>
>>>>>>
>>>>>>
>>>>>> Again, case_conversion should have already folded constants.
>>
>
> Yes, folding is here superflous.  I will remove it.

Removed it from branch.

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-29 23:03             ` Kai Tietz
  2015-07-30 14:40               ` Kai Tietz
@ 2015-07-30 18:41               ` Jason Merrill
  2015-07-30 21:33                 ` Kai Tietz
  2015-07-31  4:00                 ` Jeff Law
  1 sibling, 2 replies; 38+ messages in thread
From: Jason Merrill @ 2015-07-30 18:41 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/29/2015 06:56 PM, Kai Tietz wrote:
>>>>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const constexpr_ctx
>>>>>>>>> *ctx,
>>>>>>>>> tree t,
>>>>>>>>>     bool
>>>>>>>>>     reduced_constant_expression_p (tree t)
>>>>>>>>>     {
>>>>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>>>>> +  STRIP_NOPS (t);
>
> Checked, and removing those STRIP_NOPS cause regressions about
> vector-casts.  At least the STRIP_NOPS in
> reduced_constant_expression_p seems to be required.  See as example
> g++.dg/ext/vector20.C as testcase.
> It sees that '(vec)(const __vector(2) long int){3l, 4l}' is not a
> constant expression.

But when was that NOP_EXPR added?  It should have been folded away 
before we get here.

>>>>>>>>>         case SIZEOF_EXPR:
>>>>>>>>> +      if (processing_template_decl
>>>>>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>>>>>>>>> +       return t;
>>>>>>>>
>>>>>>>> Why is this necessary?
>
> The issue is that by delayed-folding we don't fold sizeof-expressions
> until we do the folding after genericize-pass.  So those expressions
> remain, and we can run in template on sizeof-operators on incomplete
> types, if we invoke here variants of the constexpr-code.  So this
> pattern simply verifies that the sizeof-operand can be determined.  We
> could simply avoid resolving sizeof-operators in template-decl at all.
> But my idea here was to try to resolve them, if the type of the
> operand is already complete (and has an constant size).

But this condition will never be true, as TREE_TYPE (t) is always 
size_t.  So this code isn't actually addressing the situation you describe.

>>>>>>> We don't want to resolve SIZEOF_EXPR within template-declarations for
>>>>>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>>>>>> otherwise get issues about expressions without existing type (as usual
>>>>>>> within template-declarations for some expressions).
>>>>>>
>>>>>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>>>>>> maybe_constant_value just returns if
>>>>>> instantiation_dependent_expression_p is true.
>
> Well, but we could come here by other routine then
> maybe_constant_value. For example cxx_constnat_value doesn't do checks
> here.

Calling cxx_constant_value on a dependent expression will tend to ICE, 
so we don't need to worry about that.

>>>>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree
>>>>>>>>> size,
>>>>>>>>> tsubst_flags_t complain)
>>>>>>>>>           SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>>>>           return itype;
>>>>>>>>>         }
>>>>>>>>> -
>>>>>>>>> +
>>>>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>>>>> not.  */
>>>>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>>>>
>>>>>>>> Again, we already called maybe_constant_value.
>>>>>>>
>>>>>>> Sure, but maybe_constant_value still produces nops ...
>>>>>>
>>>>>> If someone tries to create an array with a size that involves arithmetic
>>>>>> overflow, that's undefined behavior and we should probably give an
>>>>>> error rather than fold it away.
>
> If we need to do some reduction to constant value here, as expr might
> be actually a constant, which isn't folded here.  Eg something like:
> struct {
>    char abc[sizeof (int) * 8];
> };
> Due delayed folding array index isn't necessarily reduced here.  So we
> need to perform at least constant value folding for diagnostics, as we
> do right now.

Yes, we need to do some folding, that's why we call maybe_constant_value!

>>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
>>>>>>>>> tree
>>>>>>>>> enumtype, tree attributes,
>>>>>>>>>       if (value)
>>>>>>>>>         STRIP_TYPE_NOPS (value);
>>>>>>>>>
>>>>>>>>> +  if (value)
>>>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>>>
>>>>>>>> Again, this is unnecessary because we call cxx_constant_value below.
>>>>>>>
>>>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>>>> constant value ...
>>>>>>
>>>>>> The cxx_constant_value call below will deal with them.
>>>>>
>>>>> Likewise for grokbitfield.
>>>>
>>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>>>> will look into it, and come back to you on it.
>>>
>>> I am still on it ...  first did the other points
>>
>> Looks like this hasn't changed.
>
> Yes, for grokbitfield current version uses fold_simple for witdth.  So
> just expressions based on constants getting reduced to short form.  In
> grokbitfield I don't see invocation of cxx_constant_value.  So how can
> we be sure that width is reduced to integer-cst?

We call cxx_constant_value on bit-field widths in check_bitfield_decl.

>>>>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>>>>> (cp_parser
>>>>>>>>> *parser,
>>>>>>>>>            index = cp_parser_expression (parser);
>>>>>>>>>         }
>>>>>>>>>
>>>>>>>>> +  /* For offsetof and declaration of types we need
>>>>>>>>> +     constant integeral values.
>>>>>>>>> +     Also we meed to fold for negative constants so that diagnostic
>>>>>>>>> in
>>>>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>>>>> +  if (for_offsetof || decltype_p
>>>>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE
>>>>>>>>> (TREE_OPERAND
>>>>>>>>> (index, 0)) == INTEGER_CST))
>>>>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>>>>
>>>>>>>> Similarly, for offsetof the folding should happen closer to where it
>>>>>>>> is needed.
>>>>>>>>
>>>>>>>> Why is it needed for decltype, which is querying the type of an
>>>>>>>> expression?
>>>>>>>>
>>>>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>>>>> constant; this isn't the right place to do it.
>>>>>>>
>>>>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>>>>> values early anyway.  So I saw it as more logical to have done this
>>>>>>> conversion as soon as possible after initialization.
>>>>>>
>>>>>> I don't think this is as soon as possible; we can fold the NEGATE_EXPR
>>>>>> immediately when we build it, at the end of cp_build_unary_op.
>>>>>>
>>>>>> I still wonder why any folding is necessary for decltype.  When I ask
>>>>>> why, I want to know *why*, not just have you tell me again that it's
>>>>>> needed.  I don't think it is.
>>>>>>
>>>>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>>>>> handle whatever additional folding is needed here.  If not, then fold
>>>>>> in finish_offsetof, before calling fold_offsetof.
>>>>>
>>>>> I see that this is now an unconditional fold_simple, but I still don't
>>>>> understand why it needs to be folded here, in the parser.
>>>>
>>>> The point to fold the 'value' here is for cases
>>>> 'processing_template_decl' isn't false. We could move it to the
>>>> else-case of the 'if (! processing_template_decl)' line for being more
>>>> explicit?
>>>
>>> Well, on looking here in more detail, we might don't that that initial
>>> folding here.  As for processing_template_decl fold_simple (and
>>> cp_fully_fold) doesn't do much.
>>
>> Looks like the fold is still there.
>
> Yes, but a fold_simple one just working on constant values.  It
> doesn't fold expressions like 'a == a' to a constant.  I extended
> comment in current version on branch.  Additionally it invokes now the
> fold_simple always.

> We want to reduce index, if possible, for
> diagnostics in code in c-family/c-common.c

Why not closer to the diagnostics?

> for array-bounds,

We already fold array bounds.

> for types (they need to be fully folded)

WHY?  How many times do I need to ask you for SOME reason?  You keep 
just saying it's necessary without any evidence.

> and to be sure we simplify basic operations on constant-values.

Why here, rather than closer to where we care about such simplification?

Again:

>>>>>> I want to delay it to:
>>>>>>
>>>>>> 1) the places where we actually care about constant values, all of
>>>>>> which
>>>>>> already call maybe_constant_value or cxx_constant_value, so they
>>>>>> shouldn't need much change; and
>>>>>> 2) the places where we want a simplified expression for warnings, where
>>>>>> we should call fold_simple.
>>>>>
>>>>>> Folding in the parser is wrong, most of all because template
>>>>>> substitution doesn't go through the parser.


>>>> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
>>>> 'low_bound' as those values getting checked some lines below (see
>>>> lines 27936, 27944).
>>
>> OK, but this seems like an typical case of needing to fold for diagnostics;
>> usually in those cases you use the folded value for the diagnostics and then
>> keep using the unfolded expression elsewhere.
>
> Right.

So are you going to make that change here?

>>>> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
>>>> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
>>>> operand-folding into cp_parser_cilk_for itself, as we have here just
>>>> two users of 'cp_parser_cilk_for'.
>>>> One time we pass 'integer_zero_node' as this argument, and the other
>>>> time a binary-expression, which might be constant value.
>>>> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?
>>
>> Why does the fold need to be in the parser?
>
> Well, if we hit it during our tree-walk in cp_fold_r, then we don't
> need to fold it here.  I will check, if this is really necessary.

?

>>>>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>>>>> *pre_p)
>>>>>>>>>           /* Handle OMP_FOR_COND.  */
>>>>>>>>>           t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>>>>           gcc_assert (COMPARISON_CLASS_P (t));
>>>>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>>>>> 1) ==
>>>>>>>>> decl);
>>>>>>>>
>>>>>>>> Why didn't delayed folding canonicalize this so that the decl is in
>>>>>>>> op0?
>>>>>>>
>>>>>>> Delay folding doesn't canonicalize this.
>>>>>>
>>>>>> Why not?  Doesn't it fold all expressions?
>>>>>
>>>>> ?
>>>>
>>>> It fold them lately.  I will recheck this code-change.  It might be no
>>>> longer required due recent changes to omp-folding.  It could be that
>>>> original pattern didn't applied here anymore, and therefore statement
>>>> didn't been transformed into its canonical form.  Bit I assume this
>>>> could be resolved.
>>
>> ?
>
> This hunk is necessary as we don't use canonical-form produced by
> shorten_compare anymore.  Therefore special operand can occur on
> right-hand side too.

That seems like a problem, if the middle end is expecting the canonical 
form.  What is your plan for dealing with shorten_compare issues, again?

>>>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree
>>>>>>>>> imag)
>>>>>>>>>     {
>>>>>>>>>       tree t = make_node (COMPLEX_CST);
>>>>>>>>>
>>>>>>>>> +  real = fold (real);
>>>>>>>>> +  imag = fold (imag);
>>>>>>>>
>>>>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>>>>> folded.
>>>>>>>
>>>>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>>>>> some place.  AFAICS is the C++ FE not calling directly build_complex.
>>>>>>> So this place was the easiest way to avoid issues with things like '-'
>>>>>>> '1' etc.
>>>>>>
>>>>>> Is this because of the
>>>>>>>
>>>>>>>         value = build_complex (NULL_TREE, convert (const_type,
>>>>>>>                                                    integer_zero_node),
>>>>>>> value);
>>>>
>>>> Might be.  This should be indeed a 'fold_convert', isn't it?
>>
>> Yes.
>
> Applied modification to it.

So can we remove the fold in build_complex now?

>>>>>> in interpret_float?  I think "convert" definitely needs to do some
>>>>>> folding, since it's called from middle-end code that expects that.
>>>>>
>>>>> I remember talking about "convert" doing some folding (and cp_convert
>>>>> not) in our 1:1 last week.
>>>>
>>>> Can't remember that.  I know that we were talking about the difference
>>>> of convert and fold_convert.  convert can be used on C++ specifics,
>>>> but fold_convert is something shared with ME.
>>
>> convert is called from the ME, which sometimes expects folding.
>>
>>>> So first 'fold_convert'
>>>> isn't the same as 'fold (convert ())'.
>>>> I don't find places we invoke convert () in ME.  We have some calls in
>>>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
>>>> convert_to_real), which all used in AST only AFAICS.
>>
>> I was thinking of convert.c and fold-const.c to be part of the ME, since
>> they are language-independent.  But I guess other people think of the ME
>> starting with gimple.
>>
>> And it looks like the only language-independent uses of convert are in
>> c-family; I guess many of them should change to fold_convert.
>
> Hmm, in context of this work? Or is this more a general point about future work?

In the context of this work, if they are introducing problematic NOPs.

>>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>>>> *local,
>>>>>>>>> unsigned int bit_offset)
>>>>>>>>>       while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>>>             || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>>>         local->val = TREE_OPERAND (local->val, 0);
>>>>>>>>> +  local->val = fold (local->val);
>>>>>>>>
>>>>>>>> Likewise.
>>>>>>>
>>>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>>>> least folded for constants, we should be able to remove this.
>>>>>>
>>>>>> Yep, they need to be folded before we get here.
>
> I didn't come to remove this line for testing.  As we fold now for
> initializers more early, and cp_fold supports constructors, it could
> be that we don't need this anymore.  It is on my pile.

> That fold is still required.  By removing it, I saw boostrap issue due
> 'invalid initializer'.

That indicates a folding problem earlier on, that will cause some 
initialization that should be performed at compile time to happen at run 
time instead.

Please investigate the bootstrap issue further.

>>>>>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree expr,
>>>>>>> tsubst_flags_t complain)
>>>>>>>    {
>>>>>>>      tree expr_type;
>>>>>>>
>>>>>>> +  expr = cp_try_fold_to_constant (expr);
>>>>>>
>>>>>> And here, convert_nontype_argument already uses
>>>>>> maybe_constant_value/cxx_constant_value for folding constants.
>
> Yes, this invocation looks useless too.  I think I introduced it for
> the STRING_CST check below, but AFAICS we should assume it as
> unnecessary.  I will change it and do regression-testing.

Is this still in process?

> By recent changes we seem to hit for c++ some additional regression.
> They are related to negate-shifts for c++11.  We are hitting now the
> check within cxx_constant_value.  The cxx_eval_check_shift_p sees now
> that left-hand operand is negative and produces two new errors for
> following tests: c-c++-common Wshift-negative-value-*.c cases.

Which lines are affected?  Are the new messages correct or not?

> So we will need adjust those cases, or invoke within this
> eval-function instead maybe_constant_value to avoid that ?

This eval function is part of constexpr evaluation, so it wouldn't make 
sense to call maybe_constant_value here.  And the arguments to this 
function have just gone through cxx_eval_constant_expression.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-30 18:41               ` Jason Merrill
@ 2015-07-30 21:33                 ` Kai Tietz
  2015-07-31  0:43                   ` Jason Merrill
  2015-07-31  4:00                 ` Jeff Law
  1 sibling, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-07-30 21:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-07-30 18:52 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 07/29/2015 06:56 PM, Kai Tietz wrote:
>>>>>>>>>>
>>>>>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const
>>>>>>>>>> constexpr_ctx
>>>>>>>>>> *ctx,
>>>>>>>>>> tree t,
>>>>>>>>>>     bool
>>>>>>>>>>     reduced_constant_expression_p (tree t)
>>>>>>>>>>     {
>>>>>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>>>>>> +  STRIP_NOPS (t);
>>
>>
>> Checked, and removing those STRIP_NOPS cause regressions about
>> vector-casts.  At least the STRIP_NOPS in
>> reduced_constant_expression_p seems to be required.  See as example
>> g++.dg/ext/vector20.C as testcase.
>> It sees that '(vec)(const __vector(2) long int){3l, 4l}' is not a
>> constant expression.
>
>
> But when was that NOP_EXPR added?  It should have been folded away before we
> get here.

See below for this.  This might be related to the store_init_value issue.


>>>>>>>>>>         case SIZEOF_EXPR:
>>>>>>>>>> +      if (processing_template_decl
>>>>>>>>>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>>>>>>>>>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) !=
>>>>>>>>>> INTEGER_CST))
>>>>>>>>>> +       return t;
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Why is this necessary?
>>
>>
>> The issue is that by delayed-folding we don't fold sizeof-expressions
>> until we do the folding after genericize-pass.  So those expressions
>> remain, and we can run in template on sizeof-operators on incomplete
>> types, if we invoke here variants of the constexpr-code.  So this
>> pattern simply verifies that the sizeof-operand can be determined.  We
>> could simply avoid resolving sizeof-operators in template-decl at all.
>> But my idea here was to try to resolve them, if the type of the
>> operand is already complete (and has an constant size).
>
>
> But this condition will never be true, as TREE_TYPE (t) is always size_t.
> So this code isn't actually addressing the situation you describe.

Hmm, right.  sizeof's type is always size_t.  Its operand would make
here a difference, but this I don't check.  I will remove it and test.

>>>>>>>> We don't want to resolve SIZEOF_EXPR within template-declarations
>>>>>>>> for
>>>>>>>> incomplete types, of if its size isn't fixed.  Issue is that we
>>>>>>>> otherwise get issues about expressions without existing type (as
>>>>>>>> usual
>>>>>>>> within template-declarations for some expressions).
>>>>>>>
>>>>>>>
>>>>>>> Yes, but we shouldn't have gotten this far with a dependent sizeof;
>>>>>>> maybe_constant_value just returns if
>>>>>>> instantiation_dependent_expression_p is true.
>>
>>
>> Well, but we could come here by other routine then
>> maybe_constant_value. For example cxx_constnat_value doesn't do checks
>> here.
>
>
> Calling cxx_constant_value on a dependent expression will tend to ICE, so we
> don't need to worry about that.
>
>>>>>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree
>>>>>>>>>> size,
>>>>>>>>>> tsubst_flags_t complain)
>>>>>>>>>>           SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>>>>>           return itype;
>>>>>>>>>>         }
>>>>>>>>>> -
>>>>>>>>>> +
>>>>>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>>>>>> not.  */
>>>>>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Again, we already called maybe_constant_value.
>>>>>>>>
>>>>>>>>
>>>>>>>> Sure, but maybe_constant_value still produces nops ...
>>>>>>>
>>>>>>>
>>>>>>> If someone tries to create an array with a size that involves
>>>>>>> arithmetic
>>>>>>> overflow, that's undefined behavior and we should probably give an
>>>>>>> error rather than fold it away.
>>
>>
>> If we need to do some reduction to constant value here, as expr might
>> be actually a constant, which isn't folded here.  Eg something like:
>> struct {
>>    char abc[sizeof (int) * 8];
>> };
>> Due delayed folding array index isn't necessarily reduced here.  So we
>> need to perform at least constant value folding for diagnostics, as we
>> do right now.
>
>
> Yes, we need to do some folding, that's why we call maybe_constant_value!
>
>>>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
>>>>>>>>>> tree
>>>>>>>>>> enumtype, tree attributes,
>>>>>>>>>>       if (value)
>>>>>>>>>>         STRIP_TYPE_NOPS (value);
>>>>>>>>>>
>>>>>>>>>> +  if (value)
>>>>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Again, this is unnecessary because we call cxx_constant_value
>>>>>>>>> below.
>>>>>>>>
>>>>>>>>
>>>>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>>>>> constant value ...
>>>>>>>
>>>>>>>
>>>>>>> The cxx_constant_value call below will deal with them.
>>>>>>
>>>>>>
>>>>>> Likewise for grokbitfield.
>>>>>
>>>>>
>>>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>>>>> will look into it, and come back to you on it.
>>>>
>>>>
>>>> I am still on it ...  first did the other points
>>>
>>>
>>> Looks like this hasn't changed.
>>
>>
>> Yes, for grokbitfield current version uses fold_simple for witdth.  So
>> just expressions based on constants getting reduced to short form.  In
>> grokbitfield I don't see invocation of cxx_constant_value.  So how can
>> we be sure that width is reduced to integer-cst?
>
>
> We call cxx_constant_value on bit-field widths in check_bitfield_decl.

Hmm, ok.  But I don't see that this function gets called in context of
grokbitfield, after we set DECL_INITIAL.
By removing this folding here, we get new failures in
g++.dg/warn/overflow-warn-1.C testcase:
New errors are at lin 32 that 'bif-foeld 's::<anonymous>' width not an
integer constant'
and at same line ''(1 / 0) is not a constant expression'.  Those
message don't look wrong.

The testcase next to this 'overflow-warn-3.C and overflow-warn-4.C'
failing in the same manner for (1 / 0) case.  But there are no other
regressions in g++.dg & libstdc++

Shall I extend the testcases for this message?

>
>>>>>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>>>>>> (cp_parser
>>>>>>>>>> *parser,
>>>>>>>>>>            index = cp_parser_expression (parser);
>>>>>>>>>>         }
>>>>>>>>>>
>>>>>>>>>> +  /* For offsetof and declaration of types we need
>>>>>>>>>> +     constant integeral values.
>>>>>>>>>> +     Also we meed to fold for negative constants so that
>>>>>>>>>> diagnostic
>>>>>>>>>> in
>>>>>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>>>>>> +  if (for_offsetof || decltype_p
>>>>>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE
>>>>>>>>>> (TREE_OPERAND
>>>>>>>>>> (index, 0)) == INTEGER_CST))
>>>>>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Similarly, for offsetof the folding should happen closer to where
>>>>>>>>> it
>>>>>>>>> is needed.
>>>>>>>>>
>>>>>>>>> Why is it needed for decltype, which is querying the type of an
>>>>>>>>> expression?
>>>>>>>>>
>>>>>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>>>>>> constant; this isn't the right place to do it.
>>>>>>>>
>>>>>>>>
>>>>>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>>>>>> values early anyway.  So I saw it as more logical to have done this
>>>>>>>> conversion as soon as possible after initialization.
>>>>>>>
>>>>>>>
>>>>>>> I don't think this is as soon as possible; we can fold the
>>>>>>> NEGATE_EXPR
>>>>>>> immediately when we build it, at the end of cp_build_unary_op.
>>>>>>>
>>>>>>> I still wonder why any folding is necessary for decltype.  When I ask
>>>>>>> why, I want to know *why*, not just have you tell me again that it's
>>>>>>> needed.  I don't think it is.
>>>>>>>
>>>>>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>>>>>> handle whatever additional folding is needed here.  If not, then fold
>>>>>>> in finish_offsetof, before calling fold_offsetof.
>>>>>>
>>>>>>
>>>>>> I see that this is now an unconditional fold_simple, but I still don't
>>>>>> understand why it needs to be folded here, in the parser.
>>>>>
>>>>>
>>>>> The point to fold the 'value' here is for cases
>>>>> 'processing_template_decl' isn't false. We could move it to the
>>>>> else-case of the 'if (! processing_template_decl)' line for being more
>>>>> explicit?
>>>>
>>>>
>>>> Well, on looking here in more detail, we might don't that that initial
>>>> folding here.  As for processing_template_decl fold_simple (and
>>>> cp_fully_fold) doesn't do much.
>>>
>>>
>>> Looks like the fold is still there.
>>
>>
>> Yes, but a fold_simple one just working on constant values.  It
>> doesn't fold expressions like 'a == a' to a constant.  I extended
>> comment in current version on branch.  Additionally it invokes now the
>> fold_simple always.
>
>
>> We want to reduce index, if possible, for
>> diagnostics in code in c-family/c-common.c
>
>
> Why not closer to the diagnostics?

It seemed to me like the most efficient way to do this reduction.  Do
you have a different place in mind?

>> for array-bounds,
>
>
> We already fold array bounds.

Bounds we fold, but the we fold here the index to be constant value to
be able to compare against type's bounds.

>> for types (they need to be fully folded)
>
>
> WHY?  How many times do I need to ask you for SOME reason?  You keep just
> saying it's necessary without any evidence.

AFAIR we have talked about that.  But for other readers, types aren't
delayed in folding, as we share it with ME, and we aren't be able to
use them in a delayed-folded state in FE. Type-sizes, and alignments,
etc need to be reduced here.  It wouldn't make much sense to delay
folding for them too, as we need those types already while parsing.

>> and to be sure we simplify basic operations on constant-values.
>
>
> Why here, rather than closer to where we care about such simplification?
>
> Again:
>
>>>>>>> I want to delay it to:
>>>>>>>
>>>>>>> 1) the places where we actually care about constant values, all of
>>>>>>> which
>>>>>>> already call maybe_constant_value or cxx_constant_value, so they
>>>>>>> shouldn't need much change; and
>>>>>>> 2) the places where we want a simplified expression for warnings,
>>>>>>> where
>>>>>>> we should call fold_simple.
>>>>>>
>>>>>>
>>>>>>> Folding in the parser is wrong, most of all because template
>>>>>>> substitution doesn't go through the parser.
>
>
>
>>>>> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
>>>>> 'low_bound' as those values getting checked some lines below (see
>>>>> lines 27936, 27944).
>>>
>>>
>>> OK, but this seems like an typical case of needing to fold for
>>> diagnostics;
>>> usually in those cases you use the folded value for the diagnostics and
>>> then
>>> keep using the unfolded expression elsewhere.
>>
>>
>> Right.
>
>
> So are you going to make that change here?

I intend so.  I need first to complete regression-runs for the changes
below.  This seems to me more like a smaller issue.

>>>>> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
>>>>> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
>>>>> operand-folding into cp_parser_cilk_for itself, as we have here just
>>>>> two users of 'cp_parser_cilk_for'.
>>>>> One time we pass 'integer_zero_node' as this argument, and the other
>>>>> time a binary-expression, which might be constant value.
>>>>> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?
>>>
>>>
>>> Why does the fold need to be in the parser?
>>
>>
>> Well, if we hit it during our tree-walk in cp_fold_r, then we don't
>> need to fold it here.  I will check, if this is really necessary.

See tree_walk_1 ... and we walk into it, so this folding of gain
should be removable.  I will commit it after regression-testing.

>>>>>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>>>>>> *pre_p)
>>>>>>>>>>           /* Handle OMP_FOR_COND.  */
>>>>>>>>>>           t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>>>>>           gcc_assert (COMPARISON_CLASS_P (t));
>>>>>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>>>>>> 1) ==
>>>>>>>>>> decl);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Why didn't delayed folding canonicalize this so that the decl is in
>>>>>>>>> op0?
>>>>>>>>
>>>>>>>>
>>>>>>>> Delay folding doesn't canonicalize this.
>>>>>>>
>>>>>>>
>>>>>>> Why not?  Doesn't it fold all expressions?
>>>>>>
>>>>>>
>>>>>> ?
>>>>>
>>>>>
>>>>> It fold them lately.  I will recheck this code-change.  It might be no
>>>>> longer required due recent changes to omp-folding.  It could be that
>>>>> original pattern didn't applied here anymore, and therefore statement
>>>>> didn't been transformed into its canonical form.  Bit I assume this
>>>>> could be resolved.
>>>
>>>
>>> ?
>>
>>
>> This hunk is necessary as we don't use canonical-form produced by
>> shorten_compare anymore.  Therefore special operand can occur on
>> right-hand side too.
>
>
> That seems like a problem, if the middle end is expecting the canonical
> form.  What is your plan for dealing with shorten_compare issues, again?

Actually ME deals with none-cannonical form too.  It just asserts on
it at this place.  After delayed-folding work I will continue work
(Jeff pushed first parts of this work already to ML) on eliminating
use of shorten_compare completely, and move its folding-patterns to
match.pd.

>>>>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree
>>>>>>>>>> imag)
>>>>>>>>>>     {
>>>>>>>>>>       tree t = make_node (COMPLEX_CST);
>>>>>>>>>>
>>>>>>>>>> +  real = fold (real);
>>>>>>>>>> +  imag = fold (imag);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>>>>>> folded.
>>>>>>>>
>>>>>>>>
>>>>>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>>>>>> some place.  AFAICS is the C++ FE not calling directly
>>>>>>>> build_complex.
>>>>>>>> So this place was the easiest way to avoid issues with things like
>>>>>>>> '-'
>>>>>>>> '1' etc.
>>>>>>>
>>>>>>>
>>>>>>> Is this because of the
>>>>>>>>
>>>>>>>>
>>>>>>>>         value = build_complex (NULL_TREE, convert (const_type,
>>>>>>>>
>>>>>>>> integer_zero_node),
>>>>>>>> value);
>>>>>
>>>>>
>>>>> Might be.  This should be indeed a 'fold_convert', isn't it?
>>>
>>>
>>> Yes.
>>
>>
>> Applied modification to it.
>
>
> So can we remove the fold in build_complex now?
>
>>>>>>> in interpret_float?  I think "convert" definitely needs to do some
>>>>>>> folding, since it's called from middle-end code that expects that.
>>>>>>
>>>>>>
>>>>>> I remember talking about "convert" doing some folding (and cp_convert
>>>>>> not) in our 1:1 last week.
>>>>>
>>>>>
>>>>> Can't remember that.  I know that we were talking about the difference
>>>>> of convert and fold_convert.  convert can be used on C++ specifics,
>>>>> but fold_convert is something shared with ME.
>>>
>>>
>>> convert is called from the ME, which sometimes expects folding.
>>>
>>>>> So first 'fold_convert'
>>>>> isn't the same as 'fold (convert ())'.
>>>>> I don't find places we invoke convert () in ME.  We have some calls in
>>>>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
>>>>> convert_to_real), which all used in AST only AFAICS.
>>>
>>>
>>> I was thinking of convert.c and fold-const.c to be part of the ME, since
>>> they are language-independent.  But I guess other people think of the ME
>>> starting with gimple.
>>>
>>> And it looks like the only language-independent uses of convert are in
>>> c-family; I guess many of them should change to fold_convert.
>>
>>
>> Hmm, in context of this work? Or is this more a general point about future
>> work?
>
>
> In the context of this work, if they are introducing problematic NOPs.

Ok, I will take a closer look to convert () usage in c-family/.  By
quick looking this seems to be the only place for now we needed to
change.

>>>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>>>>> *local,
>>>>>>>>>> unsigned int bit_offset)
>>>>>>>>>>       while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>>>>             || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>>>>         local->val = TREE_OPERAND (local->val, 0);
>>>>>>>>>> +  local->val = fold (local->val);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Likewise.
>>>>>>>>
>>>>>>>>
>>>>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>>>>> least folded for constants, we should be able to remove this.
>>>>>>>
>>>>>>>
>>>>>>> Yep, they need to be folded before we get here.
>>
>>
>> I didn't come to remove this line for testing.  As we fold now for
>> initializers more early, and cp_fold supports constructors, it could
>> be that we don't need this anymore.  It is on my pile.
>
>
>> That fold is still required.  By removing it, I saw boostrap issue due
>> 'invalid initializer'.
>
>
> That indicates a folding problem earlier on, that will cause some
> initialization that should be performed at compile time to happen at run
> time instead.
>
> Please investigate the bootstrap issue further.

Yes, I do. I assume it is related to 'store_init_value'.  For cases
decl_maybe_constant_var_p() is true, or decl is a static, we are
calling maybe_constant_init on the value, but for other cases we don't
simplify value. (Btw this might be related to the
STRIP_NOPS-requirement in 'reduced_constant_expression_p').  So by
adding the following hunk it seems to work (still need to verify)

Index: typeck2.c
===================================================================
--- typeck2.c   (Revision 226401)
+++ typeck2.c   (Arbeitskopie)
@@ -833,6 +833,8 @@ store_init_value (tree decl, tree init, vec<tree,
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
       TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
     }
+  else
+    value = fold_simple (value);

   if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
     /* Handle aggregate NSDMI in non-constant initializers, too.  */


>>>>>>>> @@ -5776,6 +5776,8 @@ convert_nontype_argument (tree type, tree
>>>>>>>> expr,
>>>>>>>> tsubst_flags_t complain)
>>>>>>>>    {
>>>>>>>>      tree expr_type;
>>>>>>>>
>>>>>>>> +  expr = cp_try_fold_to_constant (expr);
>>>>>>>
>>>>>>>
>>>>>>> And here, convert_nontype_argument already uses
>>>>>>> maybe_constant_value/cxx_constant_value for folding constants.
>>
>>
>> Yes, this invocation looks useless too.  I think I introduced it for
>> the STRING_CST check below, but AFAICS we should assume it as
>> unnecessary.  I will change it and do regression-testing.
>
>
> Is this still in process?

Yes, it was still in process.  It is not necessary.  So I removed that hunk.

>> By recent changes we seem to hit for c++ some additional regression.
>> They are related to negate-shifts for c++11.  We are hitting now the
>> check within cxx_constant_value.  The cxx_eval_check_shift_p sees now
>> that left-hand operand is negative and produces two new errors for
>> following tests: c-c++-common Wshift-negative-value-*.c cases.
>
>
> Which lines are affected?  Are the new messages correct or not?

For all those testcases it is the line 9.  And error-messages are
looking correct to me, as those testcases are enabling -std=c++11.

>> So we will need adjust those cases, or invoke within this
>> eval-function instead maybe_constant_value to avoid that ?
>
>
> This eval function is part of constexpr evaluation, so it wouldn't make
> sense to call maybe_constant_value here.  And the arguments to this function
> have just gone through cxx_eval_constant_expression.

Yes.  I have adjusted testcases on branch and added dg-error rules for
them at bottom of testcases.

> Jason

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-30 21:33                 ` Kai Tietz
@ 2015-07-31  0:43                   ` Jason Merrill
  2015-07-31  7:08                     ` Jeff Law
  2015-07-31 23:00                     ` Kai Tietz
  0 siblings, 2 replies; 38+ messages in thread
From: Jason Merrill @ 2015-07-31  0:43 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/30/2015 05:00 PM, Kai Tietz wrote:
> 2015-07-30 18:52 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 07/29/2015 06:56 PM, Kai Tietz wrote:
>>>>>>>>>>>
>>>>>>>>>>> @@ -1430,6 +1438,8 @@ cxx_eval_call_expression (const
>>>>>>>>>>> constexpr_ctx
>>>>>>>>>>> *ctx,
>>>>>>>>>>> tree t,
>>>>>>>>>>>      bool
>>>>>>>>>>>      reduced_constant_expression_p (tree t)
>>>>>>>>>>>      {
>>>>>>>>>>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>>>>>>>>>>> +  STRIP_NOPS (t);
>>>
>>>
>>> Checked, and removing those STRIP_NOPS cause regressions about
>>> vector-casts.  At least the STRIP_NOPS in
>>> reduced_constant_expression_p seems to be required.  See as example
>>> g++.dg/ext/vector20.C as testcase.
>>> It sees that '(vec)(const __vector(2) long int){3l, 4l}' is not a
>>> constant expression.
>>
>>
>> But when was that NOP_EXPR added?  It should have been folded away before we
>> get here.
>
> See below for this.  This might be related to the store_init_value issue.
>
>
>>>>>>>>>>> @@ -8496,16 +8467,18 @@ compute_array_index_type (tree name, tree
>>>>>>>>>>> size,
>>>>>>>>>>> tsubst_flags_t complain)
>>>>>>>>>>>            SET_TYPE_STRUCTURAL_EQUALITY (itype);
>>>>>>>>>>>            return itype;
>>>>>>>>>>>          }
>>>>>>>>>>> -
>>>>>>>>>>> +
>>>>>>>>>>> +  /* We need to do fully folding to determine if we have VLA, or
>>>>>>>>>>> not.  */
>>>>>>>>>>> +  tree size_constant = cp_try_fold_to_constant (size);
>>>>>>>>>>
>>>>>>>>>> Again, we already called maybe_constant_value.
>>>>>>>>>
>>>>>>>>> Sure, but maybe_constant_value still produces nops ...
>>>>>>>>
>>>>>>>> If someone tries to create an array with a size that involves
>>>>>>>> arithmetic
>>>>>>>> overflow, that's undefined behavior and we should probably give an
>>>>>>>> error rather than fold it away.
>>>
>>> If we need to do some reduction to constant value here, as expr might
>>> be actually a constant, which isn't folded here.  Eg something like:
>>> struct {
>>>     char abc[sizeof (int) * 8];
>>> };
>>> Due delayed folding array index isn't necessarily reduced here.  So we
>>> need to perform at least constant value folding for diagnostics, as we
>>> do right now.
>>
>> Yes, we need to do some folding, that's why we call maybe_constant_value!

...so we shouldn't need cp_fully_fold.

>>>>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
>>>>>>>>>>> tree
>>>>>>>>>>> enumtype, tree attributes,
>>>>>>>>>>>        if (value)
>>>>>>>>>>>          STRIP_TYPE_NOPS (value);
>>>>>>>>>>>
>>>>>>>>>>> +  if (value)
>>>>>>>>>>> +    value = cp_try_fold_to_constant (value);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Again, this is unnecessary because we call cxx_constant_value
>>>>>>>>>> below.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> See nops, and other unary-operations we want to reduce here to real
>>>>>>>>> constant value ...
>>>>>>>>
>>>>>>>>
>>>>>>>> The cxx_constant_value call below will deal with them.
>>>>>>>
>>>>>>>
>>>>>>> Likewise for grokbitfield.
>>>>>>
>>>>>>
>>>>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
>>>>>> will look into it, and come back to you on it.
>>>>>
>>>>>
>>>>> I am still on it ...  first did the other points
>>>>
>>>>
>>>> Looks like this hasn't changed.
>>>
>>>
>>> Yes, for grokbitfield current version uses fold_simple for witdth.  So
>>> just expressions based on constants getting reduced to short form.  In
>>> grokbitfield I don't see invocation of cxx_constant_value.  So how can
>>> we be sure that width is reduced to integer-cst?
>>
>>
>> We call cxx_constant_value on bit-field widths in check_bitfield_decl.
>
> Hmm, ok.  But I don't see that this function gets called in context of
> grokbitfield, after we set DECL_INITIAL.

Nope, it's called later on as part of finish_struct.

> By removing this folding here, we get new failures in
> g++.dg/warn/overflow-warn-1.C testcase:
> New errors are at lin 32 that 'bif-foeld 's::<anonymous>' width not an
> integer constant'
> and at same line ''(1 / 0) is not a constant expression'.  Those
> message don't look wrong.
>
> The testcase next to this 'overflow-warn-3.C and overflow-warn-4.C'
> failing in the same manner for (1 / 0) case.  But there are no other
> regressions in g++.dg & libstdc++
>
> Shall I extend the testcases for this message?

Please.

>>>>>>>>>>> @@ -6575,6 +6578,13 @@ cp_parser_postfix_open_square_expression
>>>>>>>>>>> (cp_parser
>>>>>>>>>>> *parser,
>>>>>>>>>>>             index = cp_parser_expression (parser);
>>>>>>>>>>>          }
>>>>>>>>>>>
>>>>>>>>>>> +  /* For offsetof and declaration of types we need
>>>>>>>>>>> +     constant integeral values.
>>>>>>>>>>> +     Also we meed to fold for negative constants so that
>>>>>>>>>>> diagnostic
>>>>>>>>>>> in
>>>>>>>>>>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>>>>>>>>>>> +  if (for_offsetof || decltype_p
>>>>>>>>>>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE
>>>>>>>>>>> (TREE_OPERAND
>>>>>>>>>>> (index, 0)) == INTEGER_CST))
>>>>>>>>>>> +    index = cp_try_fold_to_constant (index);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Similarly, for offsetof the folding should happen closer to where
>>>>>>>>>> it
>>>>>>>>>> is needed.
>>>>>>>>>>
>>>>>>>>>> Why is it needed for decltype, which is querying the type of an
>>>>>>>>>> expression?
>>>>>>>>>>
>>>>>>>>>> For NEGATE_EXPR, we had talked about always folding a NEGATE of a
>>>>>>>>>> constant; this isn't the right place to do it.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Same as above, we need in those cases (and for -1 too) the constant
>>>>>>>>> values early anyway.  So I saw it as more logical to have done this
>>>>>>>>> conversion as soon as possible after initialization.
>>>>>>>>
>>>>>>>>
>>>>>>>> I don't think this is as soon as possible; we can fold the
>>>>>>>> NEGATE_EXPR
>>>>>>>> immediately when we build it, at the end of cp_build_unary_op.
>>>>>>>>
>>>>>>>> I still wonder why any folding is necessary for decltype.  When I ask
>>>>>>>> why, I want to know *why*, not just have you tell me again that it's
>>>>>>>> needed.  I don't think it is.
>>>>>>>>
>>>>>>>> For offsetof, I wonder if it makes sense to extend fold_offsetof_1 to
>>>>>>>> handle whatever additional folding is needed here.  If not, then fold
>>>>>>>> in finish_offsetof, before calling fold_offsetof.
>>>>>>>
>>>>>>>
>>>>>>> I see that this is now an unconditional fold_simple, but I still don't
>>>>>>> understand why it needs to be folded here, in the parser.
>>>>>>
>>>>>>
>>>>>> The point to fold the 'value' here is for cases
>>>>>> 'processing_template_decl' isn't false. We could move it to the
>>>>>> else-case of the 'if (! processing_template_decl)' line for being more
>>>>>> explicit?
>>>>>
>>>>>
>>>>> Well, on looking here in more detail, we might don't that that initial
>>>>> folding here.  As for processing_template_decl fold_simple (and
>>>>> cp_fully_fold) doesn't do much.
>>>>
>>>>
>>>> Looks like the fold is still there.
>>>
>>>
>>> Yes, but a fold_simple one just working on constant values.  It
>>> doesn't fold expressions like 'a == a' to a constant.  I extended
>>> comment in current version on branch.  Additionally it invokes now the
>>> fold_simple always.
>>
>>
>>> We want to reduce index, if possible, for
>>> diagnostics in code in c-family/c-common.c
>>
>>
>> Why not closer to the diagnostics?
>
> It seemed to me like the most efficient way to do this reduction.  Do
> you have a different place in mind?

Wherever the diagnostic is.

>>> for array-bounds,
>>
>> We already fold array bounds.
>
> Bounds we fold, but the we fold here the index to be constant value to
> be able to compare against type's bounds.

Compare where?

>>> for types (they need to be fully folded)
>>
>> WHY?  How many times do I need to ask you for SOME reason?  You keep just
>> saying it's necessary without any evidence.
>
> AFAIR we have talked about that.  But for other readers, types aren't
> delayed in folding, as we share it with ME, and we aren't be able to
> use them in a delayed-folded state in FE. Type-sizes, and alignments,
> etc need to be reduced here.  It wouldn't make much sense to delay
> folding for them too, as we need those types already while parsing.

Well, here we're dealing with expressions, not types.  Definitely type 
sizes and alignments need to be reduced, but that isn't what we're 
dealing with here in the parser.  Here we're parsing an expression.  I 
don't see the connection.

>>> and to be sure we simplify basic operations on constant-values.
>>
>> Why here, rather than closer to where we care about such simplification?
>>
>> Again:
>>
>>>>>>>> I want to delay it to:
>>>>>>>>
>>>>>>>> 1) the places where we actually care about constant values, all of
>>>>>>>> which
>>>>>>>> already call maybe_constant_value or cxx_constant_value, so they
>>>>>>>> shouldn't need much change; and
>>>>>>>> 2) the places where we want a simplified expression for warnings,
>>>>>>>> where
>>>>>>>> we should call fold_simple.
>>>>>>>
>>>>>>>
>>>>>>>> Folding in the parser is wrong, most of all because template
>>>>>>>> substitution doesn't go through the parser.
>>
>>>>>> In 'cp_parser_omp_var_list_no_open' we need to fold 'length' can
>>>>>> 'low_bound' as those values getting checked some lines below (see
>>>>>> lines 27936, 27944).
>>>>
>>>>
>>>> OK, but this seems like an typical case of needing to fold for
>>>> diagnostics;
>>>> usually in those cases you use the folded value for the diagnostics and
>>>> then
>>>> keep using the unfolded expression elsewhere.
>>>
>>>
>>> Right.
>>
>>
>> So are you going to make that change here?
>
> I intend so.  I need first to complete regression-runs for the changes
> below.  This seems to me more like a smaller issue.
>
>>>>>> In 'cp_parser_cilk_grainsize' we fold 2nd argument of
>>>>>> 'cp_paser_cild_for' by 'fold_simple'.  Not sure if it is worth to move
>>>>>> operand-folding into cp_parser_cilk_for itself, as we have here just
>>>>>> two users of 'cp_parser_cilk_for'.
>>>>>> One time we pass 'integer_zero_node' as this argument, and the other
>>>>>> time a binary-expression, which might be constant value.
>>>>>> But sure we can move it into 'cp_parser_cilk_grainsize'.if you prefer?
>>>>
>>>>
>>>> Why does the fold need to be in the parser?
>>>
>>>
>>> Well, if we hit it during our tree-walk in cp_fold_r, then we don't
>>> need to fold it here.  I will check, if this is really necessary.
>
> See tree_walk_1 ... and we walk into it, so this folding of gain
> should be removable.  I will commit it after regression-testing.
>
>>>>>>>>>>> @@ -7249,7 +7249,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq
>>>>>>>>>>> *pre_p)
>>>>>>>>>>>            /* Handle OMP_FOR_COND.  */
>>>>>>>>>>>            t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
>>>>>>>>>>>            gcc_assert (COMPARISON_CLASS_P (t));
>>>>>>>>>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>>>>>>>>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t,
>>>>>>>>>>> 1) ==
>>>>>>>>>>> decl);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Why didn't delayed folding canonicalize this so that the decl is in
>>>>>>>>>> op0?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Delay folding doesn't canonicalize this.
>>>>>>>>
>>>>>>>>
>>>>>>>> Why not?  Doesn't it fold all expressions?
>>>>>>>
>>>>>>>
>>>>>>> ?
>>>>>>
>>>>>>
>>>>>> It fold them lately.  I will recheck this code-change.  It might be no
>>>>>> longer required due recent changes to omp-folding.  It could be that
>>>>>> original pattern didn't applied here anymore, and therefore statement
>>>>>> didn't been transformed into its canonical form.  Bit I assume this
>>>>>> could be resolved.
>>>>
>>>>
>>>> ?
>>>
>>>
>>> This hunk is necessary as we don't use canonical-form produced by
>>> shorten_compare anymore.  Therefore special operand can occur on
>>> right-hand side too.
>>
>>
>> That seems like a problem, if the middle end is expecting the canonical
>> form.  What is your plan for dealing with shorten_compare issues, again?
>
> Actually ME deals with none-cannonical form too.  It just asserts on
> it at this place.  After delayed-folding work I will continue work
> (Jeff pushed first parts of this work already to ML) on eliminating
> use of shorten_compare completely, and move its folding-patterns to
> match.pd.

It looks like c_finish_omp_for should have done this canonicalization 
for the condition.  And various places assume that the OMP for condition 
has had this canonicalization done, this is just the only place there's 
an assert.  We need to make sure that it's done, somehow.

>>>>>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree
>>>>>>>>>>> imag)
>>>>>>>>>>>      {
>>>>>>>>>>>        tree t = make_node (COMPLEX_CST);
>>>>>>>>>>>
>>>>>>>>>>> +  real = fold (real);
>>>>>>>>>>> +  imag = fold (imag);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> I still think this is wrong.  The arguments should be sufficiently
>>>>>>>>>> folded.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> As we don't fold unary-operators on constants, we need to fold it at
>>>>>>>>> some place.  AFAICS is the C++ FE not calling directly
>>>>>>>>> build_complex.
>>>>>>>>> So this place was the easiest way to avoid issues with things like
>>>>>>>>> '-'
>>>>>>>>> '1' etc.
>>>>>>>>
>>>>>>>>
>>>>>>>> Is this because of the
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>          value = build_complex (NULL_TREE, convert (const_type,
>>>>>>>>>
>>>>>>>>> integer_zero_node),
>>>>>>>>> value);
>>>>>>
>>>>>>
>>>>>> Might be.  This should be indeed a 'fold_convert', isn't it?
>>>>
>>>>
>>>> Yes.
>>>
>>>
>>> Applied modification to it.
>>
>>
>> So can we remove the fold in build_complex now?

?

>>>>>>>> in interpret_float?  I think "convert" definitely needs to do some
>>>>>>>> folding, since it's called from middle-end code that expects that.
>>>>>>>
>>>>>>>
>>>>>>> I remember talking about "convert" doing some folding (and cp_convert
>>>>>>> not) in our 1:1 last week.
>>>>>>
>>>>>>
>>>>>> Can't remember that.  I know that we were talking about the difference
>>>>>> of convert and fold_convert.  convert can be used on C++ specifics,
>>>>>> but fold_convert is something shared with ME.
>>>>
>>>>
>>>> convert is called from the ME, which sometimes expects folding.
>>>>
>>>>>> So first 'fold_convert'
>>>>>> isn't the same as 'fold (convert ())'.
>>>>>> I don't find places we invoke convert () in ME.  We have some calls in
>>>>>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
>>>>>> convert_to_real), which all used in AST only AFAICS.
>>>>
>>>>
>>>> I was thinking of convert.c and fold-const.c to be part of the ME, since
>>>> they are language-independent.  But I guess other people think of the ME
>>>> starting with gimple.
>>>>
>>>> And it looks like the only language-independent uses of convert are in
>>>> c-family; I guess many of them should change to fold_convert.
>>>
>>>
>>> Hmm, in context of this work? Or is this more a general point about future
>>> work?
>>
>>
>> In the context of this work, if they are introducing problematic NOPs.
>
> Ok, I will take a closer look to convert () usage in c-family/.  By
> quick looking this seems to be the only place for now we needed to
> change.
>
>>>>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
>>>>>>>>>>> *local,
>>>>>>>>>>> unsigned int bit_offset)
>>>>>>>>>>>        while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>>>>>>>>>>              || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>>>>>>>>>>          local->val = TREE_OPERAND (local->val, 0);
>>>>>>>>>>> +  local->val = fold (local->val);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Likewise.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> As soon as we can be sure that values getting fully_folded, or at
>>>>>>>>> least folded for constants, we should be able to remove this.
>>>>>>>>
>>>>>>>>
>>>>>>>> Yep, they need to be folded before we get here.
>>>
>>>
>>> I didn't come to remove this line for testing.  As we fold now for
>>> initializers more early, and cp_fold supports constructors, it could
>>> be that we don't need this anymore.  It is on my pile.
>>
>>
>>> That fold is still required.  By removing it, I saw boostrap issue due
>>> 'invalid initializer'.
>>
>>
>> That indicates a folding problem earlier on, that will cause some
>> initialization that should be performed at compile time to happen at run
>> time instead.
>>
>> Please investigate the bootstrap issue further.
>
> Yes, I do. I assume it is related to 'store_init_value'.  For cases
> decl_maybe_constant_var_p() is true, or decl is a static, we are
> calling maybe_constant_init on the value, but for other cases we don't
> simplify value. (Btw this might be related to the
> STRIP_NOPS-requirement in 'reduced_constant_expression_p').  So by
> adding the following hunk it seems to work (still need to verify)
>
> Index: typeck2.c
> ===================================================================
> --- typeck2.c   (Revision 226401)
> +++ typeck2.c   (Arbeitskopie)
> @@ -833,6 +833,8 @@ store_init_value (tree decl, tree init, vec<tree,
>         DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
>         TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
>       }
> +  else
> +    value = fold_simple (value);
>
>     if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
>       /* Handle aggregate NSDMI in non-constant initializers, too.  */

I guess we want to extend the code for handling statics and constants to 
also handle the case where the initializer is a CONSTRUCTOR.  And also 
fold individual elements in split_nonconstant_init.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-30 18:41               ` Jason Merrill
  2015-07-30 21:33                 ` Kai Tietz
@ 2015-07-31  4:00                 ` Jeff Law
  2015-07-31 16:26                   ` Jason Merrill
  1 sibling, 1 reply; 38+ messages in thread
From: Jeff Law @ 2015-07-31  4:00 UTC (permalink / raw)
  To: Jason Merrill, Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/30/2015 10:52 AM, Jason Merrill wrote:
>>
>> This hunk is necessary as we don't use canonical-form produced by
>> shorten_compare anymore.  Therefore special operand can occur on
>> right-hand side too.
>
> That seems like a problem, if the middle end is expecting the canonical
> form.  What is your plan for dealing with shorten_compare issues, again?
We want to handle the shorten_compare stuff independently of delayed 
folding if at all possible.  It's a bit of a rats nest.

One of the general problems we have is that shorten_compare also does 
canonicalization and issues warnings.  If we're no longer getting into 
shorten_compare for some code, then that canonicalization isn't being done.

Note, anything outside of the C/C++ front-ends depending on that 
canonicalization done by shorten_compare is, IMHO, broken.

I've extracted a patch from Kai's shorten_compare work to move the 
canonicalization into match.pd *but* that runs into testsuite 
regressions because shorten_compare is also where we emit certain 
warnings for comparisons that are always true/false.

With the canonicalization moved to match.pd, shorten_compare no longer 
recognizes a particular sequence and we lose the warning.  I haven't yet 
found a good place to relocate that warning.  This has been pushed down 
several items in my TODO stack.

Jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31  0:43                   ` Jason Merrill
@ 2015-07-31  7:08                     ` Jeff Law
  2015-07-31 23:00                     ` Kai Tietz
  1 sibling, 0 replies; 38+ messages in thread
From: Jeff Law @ 2015-07-31  7:08 UTC (permalink / raw)
  To: Jason Merrill, Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/30/2015 05:02 PM, Jason Merrill wrote:
>>
>> Actually ME deals with none-cannonical form too.  It just asserts on
>> it at this place.  After delayed-folding work I will continue work
>> (Jeff pushed first parts of this work already to ML) on eliminating
>> use of shorten_compare completely, and move its folding-patterns to
>> match.pd.
>
> It looks like c_finish_omp_for should have done this canonicalization
> for the condition.  And various places assume that the OMP for condition
> has had this canonicalization done, this is just the only place there's
> an assert.  We need to make sure that it's done, somehow.
One possibility would be to try to get Richi to accept the 
canonicalization patterns to match.pd without removing the equivalent 
code from shorten_compare.

That might fix the problem y'all are running into without regressing on 
the warning that I ran into (I haven't tested that).

Thoughts?

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31  4:00                 ` Jeff Law
@ 2015-07-31 16:26                   ` Jason Merrill
  2015-07-31 16:43                     ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-07-31 16:26 UTC (permalink / raw)
  To: Jeff Law, Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/30/2015 10:48 PM, Jeff Law wrote:
> Note, anything outside of the C/C++ front-ends depending on that
> canonicalization done by shorten_compare is, IMHO, broken.

I think the OMP code isn't relying on it being done by shorten_compare; 
it's trying to do it itself in c_finish_omp_for but is somehow thwarted 
by delayed folding.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31 16:26                   ` Jason Merrill
@ 2015-07-31 16:43                     ` Kai Tietz
  2015-07-31 16:52                       ` Jakub Jelinek
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-07-31 16:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Kai Tietz, gcc-patches List

2015-07-31 18:14 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 07/30/2015 10:48 PM, Jeff Law wrote:
>>
>> Note, anything outside of the C/C++ front-ends depending on that
>> canonicalization done by shorten_compare is, IMHO, broken.
>
>
> I think the OMP code isn't relying on it being done by shorten_compare; it's
> trying to do it itself in c_finish_omp_for but is somehow thwarted by
> delayed folding.
>
> Jason
>

Well, this seems to be reasoned by finish_omp_for (), which gets
invoked in parser.c cp_parser_omp_for_loop, and/or pt.c: tsubst_expr.
In all those cases arguments aren't folded anymore.  So
c_finish_omp_for's patterns don't match anymore.  I guess we might
want to do this cannonical form in genericize-pass?

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31 16:43                     ` Kai Tietz
@ 2015-07-31 16:52                       ` Jakub Jelinek
  2015-07-31 16:53                         ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Jakub Jelinek @ 2015-07-31 16:52 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Jason Merrill, Jeff Law, Kai Tietz, gcc-patches List

On Fri, Jul 31, 2015 at 06:25:57PM +0200, Kai Tietz wrote:
> 2015-07-31 18:14 GMT+02:00 Jason Merrill <jason@redhat.com>:
> > On 07/30/2015 10:48 PM, Jeff Law wrote:
> >>
> >> Note, anything outside of the C/C++ front-ends depending on that
> >> canonicalization done by shorten_compare is, IMHO, broken.
> >
> >
> > I think the OMP code isn't relying on it being done by shorten_compare; it's
> > trying to do it itself in c_finish_omp_for but is somehow thwarted by
> > delayed folding.
> >
> > Jason
> >
> 
> Well, this seems to be reasoned by finish_omp_for (), which gets
> invoked in parser.c cp_parser_omp_for_loop, and/or pt.c: tsubst_expr.
> In all those cases arguments aren't folded anymore.  So
> c_finish_omp_for's patterns don't match anymore.  I guess we might
> want to do this cannonical form in genericize-pass?

Or just fold in finish_omp_for before calling c_finish_omp_for, so that it
is in the expected form?

	Jakub

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31 16:52                       ` Jakub Jelinek
@ 2015-07-31 16:53                         ` Jason Merrill
  2015-07-31 21:31                           ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-07-31 16:53 UTC (permalink / raw)
  To: Jakub Jelinek, Kai Tietz; +Cc: Jeff Law, Kai Tietz, gcc-patches List

On 07/31/2015 12:46 PM, Jakub Jelinek wrote:
> On Fri, Jul 31, 2015 at 06:25:57PM +0200, Kai Tietz wrote:
>> 2015-07-31 18:14 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>> On 07/30/2015 10:48 PM, Jeff Law wrote:
>>>>
>>>> Note, anything outside of the C/C++ front-ends depending on that
>>>> canonicalization done by shorten_compare is, IMHO, broken.
>>>
>>> I think the OMP code isn't relying on it being done by shorten_compare; it's
>>> trying to do it itself in c_finish_omp_for but is somehow thwarted by
>>> delayed folding.
>>
>> Well, this seems to be reasoned by finish_omp_for (), which gets
>> invoked in parser.c cp_parser_omp_for_loop, and/or pt.c: tsubst_expr.
>> In all those cases arguments aren't folded anymore.  So
>> c_finish_omp_for's patterns don't match anymore.  I guess we might
>> want to do this cannonical form in genericize-pass?
>
> Or just fold in finish_omp_for before calling c_finish_omp_for, so that it
> is in the expected form?

That certainly sounds simpler.

Jason


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31 16:53                         ` Jason Merrill
@ 2015-07-31 21:31                           ` Kai Tietz
  0 siblings, 0 replies; 38+ messages in thread
From: Kai Tietz @ 2015-07-31 21:31 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, Kai Tietz, Jeff Law, gcc-patches List

----- Ursprüngliche Mail -----
> On 07/31/2015 12:46 PM, Jakub Jelinek wrote:
> > On Fri, Jul 31, 2015 at 06:25:57PM +0200, Kai Tietz wrote:
> >> 2015-07-31 18:14 GMT+02:00 Jason Merrill <jason@redhat.com>:
> >>> On 07/30/2015 10:48 PM, Jeff Law wrote:
> >>>>
> >>>> Note, anything outside of the C/C++ front-ends depending on that
> >>>> canonicalization done by shorten_compare is, IMHO, broken.
> >>>
> >>> I think the OMP code isn't relying on it being done by shorten_compare;
> >>> it's
> >>> trying to do it itself in c_finish_omp_for but is somehow thwarted by
> >>> delayed folding.
> >>
> >> Well, this seems to be reasoned by finish_omp_for (), which gets
> >> invoked in parser.c cp_parser_omp_for_loop, and/or pt.c: tsubst_expr.
> >> In all those cases arguments aren't folded anymore.  So
> >> c_finish_omp_for's patterns don't match anymore.  I guess we might
> >> want to do this cannonical form in genericize-pass?
> >
> > Or just fold in finish_omp_for before calling c_finish_omp_for, so that it
> > is in the expected form?
> 
> That certainly sounds simpler.
> 
> Jason


Well, it sounds easier. We need to do here this special COND-folding (means operands only), and pass this into c_finish_omp.  Of course we should just fold OMP_FOR's COND part.  I will try a patch for this-

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31  0:43                   ` Jason Merrill
  2015-07-31  7:08                     ` Jeff Law
@ 2015-07-31 23:00                     ` Kai Tietz
  2015-08-03  3:49                       ` Jason Merrill
  1 sibling, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-07-31 23:00 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

----- Ursprüngliche Mail -----
> On 07/30/2015 05:00 PM, Kai Tietz wrote:
> > 2015-07-30 18:52 GMT+02:00 Jason Merrill <jason@redhat.com>:
> >> On 07/29/2015 06:56 PM, Kai Tietz wrote:
> >>>>>>>>>>> @@ -13078,6 +13042,8 @@ build_enumerator (tree name, tree value,
> >>>>>>>>>>> tree
> >>>>>>>>>>> enumtype, tree attributes,
> >>>>>>>>>>>        if (value)
> >>>>>>>>>>>          STRIP_TYPE_NOPS (value);
> >>>>>>>>>>>
> >>>>>>>>>>> +  if (value)
> >>>>>>>>>>> +    value = cp_try_fold_to_constant (value);
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>> Again, this is unnecessary because we call cxx_constant_value
> >>>>>>>>>> below.
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> See nops, and other unary-operations we want to reduce here to real
> >>>>>>>>> constant value ...
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> The cxx_constant_value call below will deal with them.
> >>>>>>>
> >>>>>>>
> >>>>>>> Likewise for grokbitfield.
> >>>>>>
> >>>>>>
> >>>>>> Hmm, AFAIR we don't call cxx_constant_value in all code-paths.  But I
> >>>>>> will look into it, and come back to you on it.
> >>>>>
> >>>>>
> >>>>> I am still on it ...  first did the other points
> >>>>
> >>>>
> >>>> Looks like this hasn't changed.
> >>>
> >>>
> >>> Yes, for grokbitfield current version uses fold_simple for witdth.  So
> >>> just expressions based on constants getting reduced to short form.  In
> >>> grokbitfield I don't see invocation of cxx_constant_value.  So how can
> >>> we be sure that width is reduced to integer-cst?
> >>
> >>
> >> We call cxx_constant_value on bit-field widths in check_bitfield_decl.
> >
> > Hmm, ok.  But I don't see that this function gets called in context of
> > grokbitfield, after we set DECL_INITIAL.
> 
> Nope, it's called later on as part of finish_struct.
> 

Ok, adjusted.

> > By removing this folding here, we get new failures in
> > g++.dg/warn/overflow-warn-1.C testcase:
> > New errors are at lin 32 that 'bif-foeld 's::<anonymous>' width not an
> > integer constant'
> > and at same line ''(1 / 0) is not a constant expression'.  Those
> > message don't look wrong.
> >
> > The testcase next to this 'overflow-warn-3.C and overflow-warn-4.C'
> > failing in the same manner for (1 / 0) case.  But there are no other
> > regressions in g++.dg & libstdc++
> >
> > Shall I extend the testcases for this message?
> 
> Please.

Done.
 
> >>>>>>>>>>> @@ -1947,6 +1947,8 @@ build_complex (tree type, tree real, tree
> >>>>>>>>>>> imag)
> >>>>>>>>>>>      {
> >>>>>>>>>>>        tree t = make_node (COMPLEX_CST);
> >>>>>>>>>>>
> >>>>>>>>>>> +  real = fold (real);
> >>>>>>>>>>> +  imag = fold (imag);
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>> I still think this is wrong.  The arguments should be sufficiently
> >>>>>>>>>> folded.
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> As we don't fold unary-operators on constants, we need to fold it
> >>>>>>>>> at
> >>>>>>>>> some place.  AFAICS is the C++ FE not calling directly
> >>>>>>>>> build_complex.
> >>>>>>>>> So this place was the easiest way to avoid issues with things like
> >>>>>>>>> '-'
> >>>>>>>>> '1' etc.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> Is this because of the
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>          value = build_complex (NULL_TREE, convert (const_type,
> >>>>>>>>>
> >>>>>>>>> integer_zero_node),
> >>>>>>>>> value);
> >>>>>>
> >>>>>>
> >>>>>> Might be.  This should be indeed a 'fold_convert', isn't it?
> >>>>
> >>>>
> >>>> Yes.
> >>>
> >>>
> >>> Applied modification to it.
> >>
> >>
> >> So can we remove the fold in build_complex now?
> 

Yes. Done.

> 
> >>>>>>>> in interpret_float?  I think "convert" definitely needs to do some
> >>>>>>>> folding, since it's called from middle-end code that expects that.
> >>>>>>>
> >>>>>>>
> >>>>>>> I remember talking about "convert" doing some folding (and cp_convert
> >>>>>>> not) in our 1:1 last week.
> >>>>>>
> >>>>>>
> >>>>>> Can't remember that.  I know that we were talking about the difference
> >>>>>> of convert and fold_convert.  convert can be used on C++ specifics,
> >>>>>> but fold_convert is something shared with ME.
> >>>>
> >>>>
> >>>> convert is called from the ME, which sometimes expects folding.
> >>>>
> >>>>>> So first 'fold_convert'
> >>>>>> isn't the same as 'fold (convert ())'.
> >>>>>> I don't find places we invoke convert () in ME.  We have some calls in
> >>>>>> convert.c (see convert_to_integer, convert_to_integer_nofold, and
> >>>>>> convert_to_real), which all used in AST only AFAICS.
> >>>>
> >>>>
> >>>> I was thinking of convert.c and fold-const.c to be part of the ME, since
> >>>> they are language-independent.  But I guess other people think of the ME
> >>>> starting with gimple.
> >>>>
> >>>> And it looks like the only language-independent uses of convert are in
> >>>> c-family; I guess many of them should change to fold_convert.
> >>>
> >>>
> >>> Hmm, in context of this work? Or is this more a general point about
> >>> future
> >>> work?
> >>
> >>
> >> In the context of this work, if they are introducing problematic NOPs.
> >
> > Ok, I will take a closer look to convert () usage in c-family/.  By
> > quick looking this seems to be the only place for now we needed to
> > change.
> >
> >>>>>>>>>>> @@ -5080,6 +5081,7 @@ output_constructor_bitfield (oc_local_state
> >>>>>>>>>>> *local,
> >>>>>>>>>>> unsigned int bit_offset)
> >>>>>>>>>>>        while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
> >>>>>>>>>>>              || TREE_CODE (local->val) == NON_LVALUE_EXPR)
> >>>>>>>>>>>          local->val = TREE_OPERAND (local->val, 0);
> >>>>>>>>>>> +  local->val = fold (local->val);
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>> Likewise.
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> As soon as we can be sure that values getting fully_folded, or at
> >>>>>>>>> least folded for constants, we should be able to remove this.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> Yep, they need to be folded before we get here.
> >>>
> >>>
> >>> I didn't come to remove this line for testing.  As we fold now for
> >>> initializers more early, and cp_fold supports constructors, it could
> >>> be that we don't need this anymore.  It is on my pile.
> >>
> >>
> >>> That fold is still required.  By removing it, I saw boostrap issue due
> >>> 'invalid initializer'.
> >>
> >>
> >> That indicates a folding problem earlier on, that will cause some
> >> initialization that should be performed at compile time to happen at run
> >> time instead.
> >>
> >> Please investigate the bootstrap issue further.
> >
> > Yes, I do. I assume it is related to 'store_init_value'.  For cases
> > decl_maybe_constant_var_p() is true, or decl is a static, we are
> > calling maybe_constant_init on the value, but for other cases we don't
> > simplify value. (Btw this might be related to the
> > STRIP_NOPS-requirement in 'reduced_constant_expression_p').  So by
> > adding the following hunk it seems to work (still need to verify)
> >
> > Index: typeck2.c
> > ===================================================================
> > --- typeck2.c   (Revision 226401)
> > +++ typeck2.c   (Arbeitskopie)
> > @@ -833,6 +833,8 @@ store_init_value (tree decl, tree init, vec<tree,
> >         DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
> >         TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p
> >         (decl);
> >       }
> > +  else
> > +    value = fold_simple (value);
> >
> >     if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
> >       /* Handle aggregate NSDMI in non-constant initializers, too.  */
> 
> I guess we want to extend the code for handling statics and constants to
> also handle the case where the initializer is a CONSTRUCTOR.  And also
> fold individual elements in split_nonconstant_init.

Yes, I added a general full folding to store_init_value, and to split_nonconstant_init a folding to CONSTRUCTOR handling for RECORD_TYPES, etc.  By this I was able to remove the fold from varasm.c's output-function, too.
The invocation in split_nonconstant_init might not be necessary, but there are other callers then store_init_value.  So for them folding in those cases might be still benifitial.


The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could remove, but for one case in constexpr.  Without folding we don't do type-sinking/raising.  So binary/unary operations might be containing cast, which were in the past unexpected.  On verify_constant we check by reduced_constant_expression_p, if value is a constant.  We don't handle here, that NOP_EXPRs are something we want to look through here, as it doesn't change anything if this is a constant, or not.
So I suggest following patch, so we are able to remove the STRIP_NOPS from reduced_constant_expression_p.

--- constexpr.c	(revision 226452)
+++ constexpr.c	(working copy)
@@ -1441,8 +1441,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx
 bool
 reduced_constant_expression_p (tree t)
 {
-  /* Make sure we remove useless initial NOP_EXPRs.  */
-  STRIP_NOPS (t);
   switch (TREE_CODE (t))
     {
     case PTRMEM_CST:
@@ -1476,7 +1474,10 @@ static bool
 verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
 		 bool *overflow_p)
 {
-  if (!*non_constant_p && !reduced_constant_expression_p (t))
+  tree rde = t;
+
+  STRIP_NOPS (rde);
+  if (!*non_constant_p && !reduced_constant_expression_p (rde))
     {
       if (!allow_non_constant)
 	error ("%q+E is not a constant expression", t);


Regards,
Kai
 
> Jason
> 
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-07-31 23:00                     ` Kai Tietz
@ 2015-08-03  3:49                       ` Jason Merrill
  2015-08-03  9:42                         ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-08-03  3:49 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 07/31/2015 05:54 PM, Kai Tietz wrote:
> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could remove, but for one case in constexpr.  Without folding we don't do type-sinking/raising.

Right.

> So binary/unary operations might be containing cast, which were in the past unexpected.

Why aren't the casts folded away?

> On verify_constant we check by reduced_constant_expression_p, if value is a constant.  We don't handle here, that NOP_EXPRs are something we want to look through here, as it doesn't change anything if this is a constant, or not.

NOPs around constants should have been folded away by the time we get there.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-03  3:49                       ` Jason Merrill
@ 2015-08-03  9:42                         ` Kai Tietz
  2015-08-03 15:39                           ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-08-03  9:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>
>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could
>> remove, but for one case in constexpr.  Without folding we don't do
>> type-sinking/raising.
>
>
> Right.
>
>> So binary/unary operations might be containing cast, which were in the
>> past unexpected.
>
>
> Why aren't the casts folded away?

On such cast constructs, as for this vector-sample, we can't fold away
the cast chain.  The difference here to none-delayed-folding branch is
that the cast isn't moved out of the plus-expr.  What we see now is
(plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
(plus (const vector ...) { ... }).

>> On verify_constant we check by reduced_constant_expression_p, if value is
>> a constant.  We don't handle here, that NOP_EXPRs are something we want to
>> look through here, as it doesn't change anything if this is a constant, or
>> not.
>
>
> NOPs around constants should have been folded away by the time we get there.

Not in this cases, as the we actually have here a switch from const to
none-const.  So there is an attribute-change, which we can't ignore in
general.  But I agree that for constexpr's we could special case cast
from const to none-const (as required in expressions like const vec v
= v + 1).

> Jason
>

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-03  9:42                         ` Kai Tietz
@ 2015-08-03 15:39                           ` Jason Merrill
  2015-08-24  7:20                             ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-08-03 15:39 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 08/03/2015 05:42 AM, Kai Tietz wrote:
> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>
>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could
>>> remove, but for one case in constexpr.  Without folding we don't do
>>> type-sinking/raising.
>>
>>
>> Right.
>>
>>> So binary/unary operations might be containing cast, which were in the
>>> past unexpected.
>>
>> Why aren't the casts folded away?
>
> On such cast constructs, as for this vector-sample, we can't fold away

Which testcase is this?

> the cast chain.  The difference here to none-delayed-folding branch is
> that the cast isn't moved out of the plus-expr.  What we see now is
> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
> (plus (const vector ...) { ... }).

How could a PLUS_EXPR be considered a reduced constant, regardless of 
where the cast is?

>>> On verify_constant we check by reduced_constant_expression_p, if value is
>>> a constant.  We don't handle here, that NOP_EXPRs are something we want to
>>> look through here, as it doesn't change anything if this is a constant, or
>>> not.
>>
>> NOPs around constants should have been folded away by the time we get there.
>
> Not in this cases, as the we actually have here a switch from const to
> none-const.  So there is an attribute-change, which we can't ignore in
> general.

I wasn't suggesting we ignore it, we should be able to change the type 
of the vector_cst.

> But I agree that for constexpr's we could special case cast
> from const to none-const (as required in expressions like const vec v
> = v + 1).

Right.  But really this should happen in convert.c, it shouldn't be 
specific to C++.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-03 15:39                           ` Jason Merrill
@ 2015-08-24  7:20                             ` Kai Tietz
  2015-08-27  2:57                               ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-08-24  7:20 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

Hello Jason,

after a longer delay the answer to your question.

2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>
>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>
>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>
>>>>
>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could
>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>> type-sinking/raising.
>>>
>>>
>>>
>>> Right.
>>>
>>>> So binary/unary operations might be containing cast, which were in the
>>>> past unexpected.
>>>
>>>
>>> Why aren't the casts folded away?
>>
>>
>> On such cast constructs, as for this vector-sample, we can't fold away
>
>
> Which testcase is this?

It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
testcase already earlier as reference, but I might be wrong here.

>> the cast chain.  The difference here to none-delayed-folding branch is
>> that the cast isn't moved out of the plus-expr.  What we see now is
>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>> (plus (const vector ...) { ... }).
>
>
> How could a PLUS_EXPR be considered a reduced constant, regardless of where
> the cast is?

Of course it is just possible to sink out a cast from PLUS_EXPR, in
pretty few circumstance (eg. on constants if both types just differ in
const-attribute, if conversion is no view-convert).

>>>> On verify_constant we check by reduced_constant_expression_p, if value
>>>> is
>>>> a constant.  We don't handle here, that NOP_EXPRs are something we want
>>>> to
>>>> look through here, as it doesn't change anything if this is a constant,
>>>> or
>>>> not.
>>>
>>>
>>> NOPs around constants should have been folded away by the time we get
>>> there.
>>
>>
>> Not in this cases, as the we actually have here a switch from const to
>> none-const.  So there is an attribute-change, which we can't ignore in
>> general.
>
>
> I wasn't suggesting we ignore it, we should be able to change the type of
> the vector_cst.

Well, the vector_cst we can change type, but this wouldn't help
AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
other operand.
So the way to solve it would be to move such conversion out of the
expression.  For integer-scalars we do this, and for some
floating-points too.  So it might be something we don't handle for
operations with vector-type.

>> But I agree that for constexpr's we could special case cast
>> from const to none-const (as required in expressions like const vec v
>> = v + 1).
>
>
> Right.  But really this should happen in convert.c, it shouldn't be specific
> to C++.

Hmm, maybe.  But isn't one of our different goals to move such
implicit code-modification to match.pd instead?

> Jason
>


Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-24  7:20                             ` Kai Tietz
@ 2015-08-27  2:57                               ` Jason Merrill
  2015-08-27 10:54                                 ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-08-27  2:57 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 08/24/2015 03:15 AM, Kai Tietz wrote:
> 2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>>
>>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I could
>>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>>> type-sinking/raising.
>>>>
>>>> Right.
>>>>
>>>>> So binary/unary operations might be containing cast, which were in the
>>>>> past unexpected.
>>>>
>>>> Why aren't the casts folded away?
>>>
>>> On such cast constructs, as for this vector-sample, we can't fold away
>>
>> Which testcase is this?
>
> It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
> testcase already earlier as reference, but I might be wrong here.

I don't see any casts in that testcase.  So the compiler is introducing 
introducing conversions back and forth between const and non-const, 
then?  I suppose it doesn't so much matter where they come from, they 
should be folded away regardless.

>>> the cast chain.  The difference here to none-delayed-folding branch is
>>> that the cast isn't moved out of the plus-expr.  What we see now is
>>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>>> (plus (const vector ...) { ... }).
>>
>> How could a PLUS_EXPR be considered a reduced constant, regardless of where
>> the cast is?
>
> Of course it is just possible to sink out a cast from PLUS_EXPR, in
> pretty few circumstance (eg. on constants if both types just differ in
> const-attribute, if conversion is no view-convert).

I don't understand how this is an answer to my question.

>>>>> On verify_constant we check by reduced_constant_expression_p, if value is
>>>>> a constant.  We don't handle here, that NOP_EXPRs are something we want to
>>>>> look through here, as it doesn't change anything if this is a constant, or
>>>>> not.
>>>>
>>>> NOPs around constants should have been folded away by the time we get
>>>> there.
>>>
>>> Not in this cases, as the we actually have here a switch from const to
>>> none-const.  So there is an attribute-change, which we can't ignore in
>>> general.
>>
>> I wasn't suggesting we ignore it, we should be able to change the type of
>> the vector_cst.
>
> Well, the vector_cst we can change type, but this wouldn't help
> AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
> other operand.

Isn't the other operand also constant?  In constexpr evaluation, either 
we're dealing with a bunch of constants, in which case we should be 
folding things fully, including conversions between const and non-const, 
or we don't care.

> So the way to solve it would be to move such conversion out of the
> expression.  For integer-scalars we do this, and for some
> floating-points too.  So it might be something we don't handle for
> operations with vector-type.

We don't need to worry about that in constexpr evaluation, since we only 
care about constant operands.

>>> But I agree that for constexpr's we could special case cast
>>> from const to none-const (as required in expressions like const vec v
>>> = v + 1).
>>
>> Right.  But really this should happen in convert.c, it shouldn't be specific
>> to C++.
>
> Hmm, maybe.  But isn't one of our different goals to move such
> implicit code-modification to match.pd instead?

Folding const into a constant is hardly code modification.  But perhaps 
it should go into fold_unary_loc:VIEW_CONVERT_EXPR rather than into 
convert.c.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27  2:57                               ` Jason Merrill
@ 2015-08-27 10:54                                 ` Kai Tietz
  2015-08-27 13:35                                   ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-08-27 10:54 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-08-27 4:56 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 08/24/2015 03:15 AM, Kai Tietz wrote:
>>
>> 2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>
>>> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>>>
>>>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>
>>>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>>>
>>>>>>
>>>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I
>>>>>> could
>>>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>>>> type-sinking/raising.
>>>>>
>>>>>
>>>>> Right.
>>>>>
>>>>>> So binary/unary operations might be containing cast, which were in the
>>>>>> past unexpected.
>>>>>
>>>>>
>>>>> Why aren't the casts folded away?
>>>>
>>>>
>>>> On such cast constructs, as for this vector-sample, we can't fold away
>>>
>>>
>>> Which testcase is this?
>>
>>
>> It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
>> testcase already earlier as reference, but I might be wrong here.
>
>
> I don't see any casts in that testcase.  So the compiler is introducing
> introducing conversions back and forth between const and non-const, then?  I
> suppose it doesn't so much matter where they come from, they should be
> folded away regardless.

The cast gets introduced in convert.c about line 836 in function
convert_to_integer_1 AFAIK.  There should be the alternative solution
for this issue by disallowing for PLUS/MINUS/... expressions the
sinking of the cast into the expression, if dofold is false, and type
has same width as inner_type, and is of vector-kind.

>>>> the cast chain.  The difference here to none-delayed-folding branch is
>>>> that the cast isn't moved out of the plus-expr.  What we see now is
>>>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>>>> (plus (const vector ...) { ... }).
>>>
>>>
>>> How could a PLUS_EXPR be considered a reduced constant, regardless of
>>> where
>>> the cast is?
>>
>>
>> Of course it is just possible to sink out a cast from PLUS_EXPR, in
>> pretty few circumstance (eg. on constants if both types just differ in
>> const-attribute, if conversion is no view-convert).
>
>
> I don't understand how this is an answer to my question.

(vec) (const vector) { ... } expression can't be folded.  This cast to
none-const variant happens due the 'constexpr v = v +
<constant-value>' pattern in testcase.  v is still of type vec, even
if function itself is constexpr.

>>>>>> On verify_constant we check by reduced_constant_expression_p, if value
>>>>>> is
>>>>>> a constant.  We don't handle here, that NOP_EXPRs are something we
>>>>>> want to
>>>>>> look through here, as it doesn't change anything if this is a
>>>>>> constant, or
>>>>>> not.
>>>>>
>>>>>
>>>>> NOPs around constants should have been folded away by the time we get
>>>>> there.
>>>>
>>>>
>>>> Not in this cases, as the we actually have here a switch from const to
>>>> none-const.  So there is an attribute-change, which we can't ignore in
>>>> general.
>>>
>>>
>>> I wasn't suggesting we ignore it, we should be able to change the type of
>>> the vector_cst.
>>
>>
>> Well, the vector_cst we can change type, but this wouldn't help
>> AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
>> other operand.
>
>
> Isn't the other operand also constant?  In constexpr evaluation, either
> we're dealing with a bunch of constants, in which case we should be folding
> things fully, including conversions between const and non-const, or we don't
> care.

No other operand isn't a constant-value.  See code-pattern in
testcase.  It is of type 'vec', which isn't constant (well, 'v' is,
but constexpr doesn't know about it).

The bogus error-message happens in:

#1  0x00668c20 in verify_constant (t=t@entry=0xffd3cbe8,
    allow_non_constant=<optimized out>,
    non_constant_p=non_constant_p@entry=0xe5fa6fa,
    overflow_p=overflow_p@entry=0xe5fa6fb)
    at ../../src/gcc/cp/constexpr.c:1480
#2  0x0066c710 in cxx_eval_binary_expression (overflow_p=0xe5fa6fb,
    non_constant_p=0xe5fa6fa, t=0xffd3cba0, ctx=0xe5fa6fc)
    at ../../src/gcc/cp/constexpr.c:1620
#3  cxx_eval_constant_expression (ctx=ctx@entry=0xe5fa6fc,
    t=t@entry=0xffd3cba0, lval=lval@entry=false,
    non_constant_p=non_constant_p@entry=0xe5fa6fa,
    overflow_p=overflow_p@entry=0xe5fa6fb, jump_target=jump_target@entry=0x0)
    at ../../src/gcc/cp/constexpr.c:3491

#2  0x0066c710 in cxx_eval_binary_expression (overflow_p=0xe5fa6fb,
    non_constant_p=0xe5fa6fa, t=0xffd3cba0, ctx=0xe5fa6fc)
    at ../../src/gcc/cp/constexpr.c:1620
1620        VERIFY_CONSTANT (lhs);

>> So the way to solve it would be to move such conversion out of the
>> expression.  For integer-scalars we do this, and for some
>> floating-points too.  So it might be something we don't handle for
>> operations with vector-type.
>
>
> We don't need to worry about that in constexpr evaluation, since we only
> care about constant operands.

Sure, but the variable 'v' is the problem, not a constant-value itself.

>>>> But I agree that for constexpr's we could special case cast
>>>> from const to none-const (as required in expressions like const vec v
>>>> = v + 1).
>>>
>>>
>>> Right.  But really this should happen in convert.c, it shouldn't be
>>> specific
>>> to C++.
>>
>>
>> Hmm, maybe.  But isn't one of our different goals to move such
>> implicit code-modification to match.pd instead?
>
> Folding const into a constant is hardly code modification.  But perhaps it
> should go into fold_unary_loc:VIEW_CONVERT_EXPR rather than into convert.c.

Hmm, it isn't related to a view-convert.  So moving it into
fold_unary_loc wouldn't solve here anything.  Issue is in constexpr
code, not in folding itself.

> Jason
>

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27 10:54                                 ` Kai Tietz
@ 2015-08-27 13:35                                   ` Jason Merrill
  2015-08-27 13:44                                     ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-08-27 13:35 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 08/27/2015 06:39 AM, Kai Tietz wrote:
> 2015-08-27 4:56 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 08/24/2015 03:15 AM, Kai Tietz wrote:
>>> 2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>>>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>>>>
>>>>>>>
>>>>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I
>>>>>>> could
>>>>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>>>>> type-sinking/raising.
>>>>>>
>>>>>>
>>>>>> Right.
>>>>>>
>>>>>>> So binary/unary operations might be containing cast, which were in the
>>>>>>> past unexpected.
>>>>>>
>>>>>>
>>>>>> Why aren't the casts folded away?
>>>>>
>>>>>
>>>>> On such cast constructs, as for this vector-sample, we can't fold away
>>>>
>>>>
>>>> Which testcase is this?
>>>
>>>
>>> It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
>>> testcase already earlier as reference, but I might be wrong here.
>>
>>
>> I don't see any casts in that testcase.  So the compiler is introducing
>> introducing conversions back and forth between const and non-const, then?  I
>> suppose it doesn't so much matter where they come from, they should be
>> folded away regardless.
>
> The cast gets introduced in convert.c about line 836 in function
> convert_to_integer_1 AFAIK.  There should be the alternative solution
> for this issue by disallowing for PLUS/MINUS/... expressions the
> sinking of the cast into the expression, if dofold is false, and type
> has same width as inner_type, and is of vector-kind.

Why would we be calling convert_to_integer for conversions between 
vector types?

>>>>> the cast chain.  The difference here to none-delayed-folding branch is
>>>>> that the cast isn't moved out of the plus-expr.  What we see now is
>>>>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>>>>> (plus (const vector ...) { ... }).
>>>>
>>>>
>>>> How could a PLUS_EXPR be considered a reduced constant, regardless of
>>>> where
>>>> the cast is?
>>>
>>>
>>> Of course it is just possible to sink out a cast from PLUS_EXPR, in
>>> pretty few circumstance (eg. on constants if both types just differ in
>>> const-attribute, if conversion is no view-convert).
>>
>>
>> I don't understand how this is an answer to my question.
>
> (vec) (const vector) { ... } expression can't be folded.

It currently isn't folded, but why can't we change that?

> This cast to
> none-const variant happens due the 'constexpr v = v +
> <constant-value>' pattern in testcase.  v is still of type vec, even
> if function itself is constexpr.

I don't see that pattern in the testcase:

typedef long vec __attribute__((vector_size (2 * sizeof (long))));
constexpr vec v = { 3, 4 };
constexpr vec s = v + v;
constexpr vec w = __builtin_shuffle (v, v);

If we have v + constant-value, that's because we pulled out the constant 
value of one of the v's, which we ought to be doing for both of them.

>>>>>>> On verify_constant we check by reduced_constant_expression_p, if value
>>>>>>> is
>>>>>>> a constant.  We don't handle here, that NOP_EXPRs are something we
>>>>>>> want to
>>>>>>> look through here, as it doesn't change anything if this is a
>>>>>>> constant, or
>>>>>>> not.
>>>>>>
>>>>>>
>>>>>> NOPs around constants should have been folded away by the time we get
>>>>>> there.
>>>>>
>>>>>
>>>>> Not in this cases, as the we actually have here a switch from const to
>>>>> none-const.  So there is an attribute-change, which we can't ignore in
>>>>> general.
>>>>
>>>>
>>>> I wasn't suggesting we ignore it, we should be able to change the type of
>>>> the vector_cst.
>>>
>>>
>>> Well, the vector_cst we can change type, but this wouldn't help
>>> AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
>>> other operand.
>>
>>
>> Isn't the other operand also constant?  In constexpr evaluation, either
>> we're dealing with a bunch of constants, in which case we should be folding
>> things fully, including conversions between const and non-const, or we don't
>> care.
>
> No other operand isn't a constant-value.  See code-pattern in
> testcase.  It is of type 'vec', which isn't constant (well, 'v' is,
> but constexpr doesn't know about it).

What do you mean, "constexpr doesn't know about it"?

>>> So the way to solve it would be to move such conversion out of the
>>> expression.  For integer-scalars we do this, and for some
>>> floating-points too.  So it might be something we don't handle for
>>> operations with vector-type.
>>
>>
>> We don't need to worry about that in constexpr evaluation, since we only
>> care about constant operands.
>
> Sure, but the variable 'v' is the problem, not a constant-value itself.

>>>>> But I agree that for constexpr's we could special case cast
>>>>> from const to none-const (as required in expressions like const vec v
>>>>> = v + 1).
>>>>
>>>>
>>>> Right.  But really this should happen in convert.c, it shouldn't be
>>>> specific
>>>> to C++.
>>>
>>>
>>> Hmm, maybe.  But isn't one of our different goals to move such
>>> implicit code-modification to match.pd instead?
>>
>> Folding const into a constant is hardly code modification.  But perhaps it
>> should go into fold_unary_loc:VIEW_CONVERT_EXPR rather than into convert.c.
>
> Hmm, it isn't related to a view-convert.  So moving it into
> fold_unary_loc wouldn't solve here anything.  Issue is in constexpr
> code, not in folding itself.

What TREE_CODE does the conversion (vec) (const vector) { ... } use?

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27 13:35                                   ` Jason Merrill
@ 2015-08-27 13:44                                     ` Kai Tietz
  2015-08-27 18:15                                       ` Kai Tietz
  2015-08-28  2:12                                       ` Jason Merrill
  0 siblings, 2 replies; 38+ messages in thread
From: Kai Tietz @ 2015-08-27 13:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-08-27 15:27 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 08/27/2015 06:39 AM, Kai Tietz wrote:
>>
>> 2015-08-27 4:56 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>
>>> On 08/24/2015 03:15 AM, Kai Tietz wrote:
>>>>
>>>> 2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>
>>>>> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>>>>>
>>>>>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>>>
>>>>>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I
>>>>>>>> could
>>>>>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>>>>>> type-sinking/raising.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Right.
>>>>>>>
>>>>>>>> So binary/unary operations might be containing cast, which were in
>>>>>>>> the
>>>>>>>> past unexpected.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Why aren't the casts folded away?
>>>>>>
>>>>>>
>>>>>>
>>>>>> On such cast constructs, as for this vector-sample, we can't fold away
>>>>>
>>>>>
>>>>>
>>>>> Which testcase is this?
>>>>
>>>>
>>>>
>>>> It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
>>>> testcase already earlier as reference, but I might be wrong here.
>>>
>>>
>>>
>>> I don't see any casts in that testcase.  So the compiler is introducing
>>> introducing conversions back and forth between const and non-const, then?
>>> I
>>> suppose it doesn't so much matter where they come from, they should be
>>> folded away regardless.
>>
>>
>> The cast gets introduced in convert.c about line 836 in function
>> convert_to_integer_1 AFAIK.  There should be the alternative solution
>> for this issue by disallowing for PLUS/MINUS/... expressions the
>> sinking of the cast into the expression, if dofold is false, and type
>> has same width as inner_type, and is of vector-kind.
>
>
> Why would we be calling convert_to_integer for conversions between vector
> types?
>
>>>>>> the cast chain.  The difference here to none-delayed-folding branch is
>>>>>> that the cast isn't moved out of the plus-expr.  What we see now is
>>>>>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>>>>>> (plus (const vector ...) { ... }).
>>>>>
>>>>>
>>>>>
>>>>> How could a PLUS_EXPR be considered a reduced constant, regardless of
>>>>> where
>>>>> the cast is?
>>>>
>>>>
>>>>
>>>> Of course it is just possible to sink out a cast from PLUS_EXPR, in
>>>> pretty few circumstance (eg. on constants if both types just differ in
>>>> const-attribute, if conversion is no view-convert).
>>>
>>>
>>>
>>> I don't understand how this is an answer to my question.
>>
>>
>> (vec) (const vector) { ... } expression can't be folded.
>
>
> It currently isn't folded, but why can't we change that?
>
>> This cast to
>> none-const variant happens due the 'constexpr v = v +
>> <constant-value>' pattern in testcase.  v is still of type vec, even
>> if function itself is constexpr.
>
>
> I don't see that pattern in the testcase:
>
> typedef long vec __attribute__((vector_size (2 * sizeof (long))));
> constexpr vec v = { 3, 4 };
> constexpr vec s = v + v;
> constexpr vec w = __builtin_shuffle (v, v);
>
> If we have v + constant-value, that's because we pulled out the constant
> value of one of the v's, which we ought to be doing for both of them.
>
>>>>>>>> On verify_constant we check by reduced_constant_expression_p, if
>>>>>>>> value
>>>>>>>> is
>>>>>>>> a constant.  We don't handle here, that NOP_EXPRs are something we
>>>>>>>> want to
>>>>>>>> look through here, as it doesn't change anything if this is a
>>>>>>>> constant, or
>>>>>>>> not.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> NOPs around constants should have been folded away by the time we get
>>>>>>> there.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Not in this cases, as the we actually have here a switch from const to
>>>>>> none-const.  So there is an attribute-change, which we can't ignore in
>>>>>> general.
>>>>>
>>>>>
>>>>>
>>>>> I wasn't suggesting we ignore it, we should be able to change the type
>>>>> of
>>>>> the vector_cst.
>>>>
>>>>
>>>>
>>>> Well, the vector_cst we can change type, but this wouldn't help
>>>> AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
>>>> other operand.
>>>
>>>
>>>
>>> Isn't the other operand also constant?  In constexpr evaluation, either
>>> we're dealing with a bunch of constants, in which case we should be
>>> folding
>>> things fully, including conversions between const and non-const, or we
>>> don't
>>> care.
>>
>>
>> No other operand isn't a constant-value.  See code-pattern in
>> testcase.  It is of type 'vec', which isn't constant (well, 'v' is,
>> but constexpr doesn't know about it).
>
>
> What do you mean, "constexpr doesn't know about it"?
>
>>>> So the way to solve it would be to move such conversion out of the
>>>> expression.  For integer-scalars we do this, and for some
>>>> floating-points too.  So it might be something we don't handle for
>>>> operations with vector-type.
>>>
>>>
>>>
>>> We don't need to worry about that in constexpr evaluation, since we only
>>> care about constant operands.
>>
>>
>> Sure, but the variable 'v' is the problem, not a constant-value itself.
>
>
>>>>>> But I agree that for constexpr's we could special case cast
>>>>>> from const to none-const (as required in expressions like const vec v
>>>>>> = v + 1).
>>>>>
>>>>>
>>>>>
>>>>> Right.  But really this should happen in convert.c, it shouldn't be
>>>>> specific
>>>>> to C++.
>>>>
>>>>
>>>>
>>>> Hmm, maybe.  But isn't one of our different goals to move such
>>>> implicit code-modification to match.pd instead?
>>>
>>>
>>> Folding const into a constant is hardly code modification.  But perhaps
>>> it
>>> should go into fold_unary_loc:VIEW_CONVERT_EXPR rather than into
>>> convert.c.
>>
>>
>> Hmm, it isn't related to a view-convert.  So moving it into
>> fold_unary_loc wouldn't solve here anything.  Issue is in constexpr
>> code, not in folding itself.
>
>
> What TREE_CODE does the conversion (vec) (const vector) { ... } use?

The tree code is a NOP_EXPR.

(gdb) call debug_tree (lhs)
 <nop_expr 0xffd3cbe8
    type <vector_type 0xffd4a140 vec
        type <integer_type 0xffcd04e0 long int public SI
            size <integer_cst 0xffde0ff0 constant 32>
            unit size <integer_cst 0xffde1008 constant 4>
            align 32 symtab 0 alias set -1 canonical type 0xffcd04e0
precision 32 min <integer_cst 0xffde1038 -2147483648> max <integer_cst
0xffde1050 2147483647>
            pointer_to_this <pointer_type 0xffcd3f00>>
        V2SI
        size <integer_cst 0xffde0db0 constant 64>
        unit size <integer_cst 0xffde0dc8 constant 8>
        align 64 symtab 0 alias set -1 canonical type 0xffd4a0e0 nunits 2>
    constant
    arg 0 <vector_cst 0xffd3cb40
        type <vector_type 0xffd4a1a0 vec type <integer_type 0xffcd04e0 long int>
            readonly V2SI size <integer_cst 0xffde0db0 64> unit size
<integer_cst 0xffde0dc8 8>
            align 64 symtab 0 alias set -1 canonical type 0xffd4a200 nunits 2>
        constant
        elt0:  <integer_cst 0xffd3cb10 constant 3>
        elt1:  <integer_cst 0xffd3cb28 constant 4>>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27 13:44                                     ` Kai Tietz
@ 2015-08-27 18:15                                       ` Kai Tietz
  2015-08-28  3:03                                         ` Jason Merrill
  2015-08-28  2:12                                       ` Jason Merrill
  1 sibling, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-08-27 18:15 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

With following patch testcase passes:

Index: fold-const.c
===================================================================
--- fold-const.c        (Revision 227111)
+++ fold-const.c        (Arbeitskopie)
@@ -2110,6 +2110,17 @@ fold_convert_const (enum tree_code code, tree type
       else if (TREE_CODE (arg1) == REAL_CST)
        return fold_convert_const_fixed_from_real (type, arg1);
     }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      if (TREE_CODE (arg1) == VECTOR_CST
+         && code == NOP_EXPR
+         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
+       {
+         tree r = copy_node (arg1);
+         TREE_TYPE (arg1) = type;
+         return r;
+       }
+    }
   return NULL_TREE;
 }
Index: cp/constexpr.c
===================================================================
--- constexpr.c (Revision 227111)
+++ constexpr.c (Arbeitskopie)
@@ -1441,8 +1441,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx
 bool
 reduced_constant_expression_p (tree t)
 {
-  /* Make sure we remove useless initial NOP_EXPRs.  */
-  STRIP_NOPS (t);
   switch (TREE_CODE (t))
     {
     case PTRMEM_CST:

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27 13:44                                     ` Kai Tietz
  2015-08-27 18:15                                       ` Kai Tietz
@ 2015-08-28  2:12                                       ` Jason Merrill
  1 sibling, 0 replies; 38+ messages in thread
From: Jason Merrill @ 2015-08-28  2:12 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 08/27/2015 09:38 AM, Kai Tietz wrote:
> 2015-08-27 15:27 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 08/27/2015 06:39 AM, Kai Tietz wrote:
>>>
>>> 2015-08-27 4:56 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>
>>>> On 08/24/2015 03:15 AM, Kai Tietz wrote:
>>>>>
>>>>> 2015-08-03 17:39 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>>
>>>>>> On 08/03/2015 05:42 AM, Kai Tietz wrote:
>>>>>>>
>>>>>>> 2015-08-03 5:49 GMT+02:00 Jason Merrill <jason@redhat.com>:
>>>>>>>>
>>>>>>>> On 07/31/2015 05:54 PM, Kai Tietz wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The "STRIP_NOPS-requirement in 'reduced_constant_expression_p'" I
>>>>>>>>> could
>>>>>>>>> remove, but for one case in constexpr.  Without folding we don't do
>>>>>>>>> type-sinking/raising.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Right.
>>>>>>>>
>>>>>>>>> So binary/unary operations might be containing cast, which were in
>>>>>>>>> the
>>>>>>>>> past unexpected.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Why aren't the casts folded away?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On such cast constructs, as for this vector-sample, we can't fold away
>>>>>>
>>>>>>
>>>>>>
>>>>>> Which testcase is this?
>>>>>
>>>>>
>>>>>
>>>>> It is the g++.dg/ext/vector20.C testcase.  IIRC I mentioned this
>>>>> testcase already earlier as reference, but I might be wrong here.
>>>>
>>>>
>>>>
>>>> I don't see any casts in that testcase.  So the compiler is introducing
>>>> introducing conversions back and forth between const and non-const, then?
>>>> I
>>>> suppose it doesn't so much matter where they come from, they should be
>>>> folded away regardless.
>>>
>>>
>>> The cast gets introduced in convert.c about line 836 in function
>>> convert_to_integer_1 AFAIK.  There should be the alternative solution
>>> for this issue by disallowing for PLUS/MINUS/... expressions the
>>> sinking of the cast into the expression, if dofold is false, and type
>>> has same width as inner_type, and is of vector-kind.
>>
>>
>> Why would we be calling convert_to_integer for conversions between vector
>> types?
>>
>>>>>>> the cast chain.  The difference here to none-delayed-folding branch is
>>>>>>> that the cast isn't moved out of the plus-expr.  What we see now is
>>>>>>> (plus ((vec) (const vector ...) { .... }), ...).  Before we had (vec)
>>>>>>> (plus (const vector ...) { ... }).
>>>>>>
>>>>>>
>>>>>>
>>>>>> How could a PLUS_EXPR be considered a reduced constant, regardless of
>>>>>> where
>>>>>> the cast is?
>>>>>
>>>>>
>>>>>
>>>>> Of course it is just possible to sink out a cast from PLUS_EXPR, in
>>>>> pretty few circumstance (eg. on constants if both types just differ in
>>>>> const-attribute, if conversion is no view-convert).
>>>>
>>>>
>>>>
>>>> I don't understand how this is an answer to my question.
>>>
>>>
>>> (vec) (const vector) { ... } expression can't be folded.
>>
>>
>> It currently isn't folded, but why can't we change that?
>>
>>> This cast to
>>> none-const variant happens due the 'constexpr v = v +
>>> <constant-value>' pattern in testcase.  v is still of type vec, even
>>> if function itself is constexpr.
>>
>>
>> I don't see that pattern in the testcase:
>>
>> typedef long vec __attribute__((vector_size (2 * sizeof (long))));
>> constexpr vec v = { 3, 4 };
>> constexpr vec s = v + v;
>> constexpr vec w = __builtin_shuffle (v, v);
>>
>> If we have v + constant-value, that's because we pulled out the constant
>> value of one of the v's, which we ought to be doing for both of them.
>>
>>>>>>>>> On verify_constant we check by reduced_constant_expression_p, if
>>>>>>>>> value
>>>>>>>>> is
>>>>>>>>> a constant.  We don't handle here, that NOP_EXPRs are something we
>>>>>>>>> want to
>>>>>>>>> look through here, as it doesn't change anything if this is a
>>>>>>>>> constant, or
>>>>>>>>> not.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> NOPs around constants should have been folded away by the time we get
>>>>>>>> there.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Not in this cases, as the we actually have here a switch from const to
>>>>>>> none-const.  So there is an attribute-change, which we can't ignore in
>>>>>>> general.
>>>>>>
>>>>>>
>>>>>>
>>>>>> I wasn't suggesting we ignore it, we should be able to change the type
>>>>>> of
>>>>>> the vector_cst.
>>>>>
>>>>>
>>>>>
>>>>> Well, the vector_cst we can change type, but this wouldn't help
>>>>> AFAICS.  As there is still one cast surviving within PLUS_EXPR for the
>>>>> other operand.
>>>>
>>>>
>>>>
>>>> Isn't the other operand also constant?  In constexpr evaluation, either
>>>> we're dealing with a bunch of constants, in which case we should be
>>>> folding
>>>> things fully, including conversions between const and non-const, or we
>>>> don't
>>>> care.
>>>
>>>
>>> No other operand isn't a constant-value.  See code-pattern in
>>> testcase.  It is of type 'vec', which isn't constant (well, 'v' is,
>>> but constexpr doesn't know about it).
>>
>>
>> What do you mean, "constexpr doesn't know about it"?
>>
>>>>> So the way to solve it would be to move such conversion out of the
>>>>> expression.  For integer-scalars we do this, and for some
>>>>> floating-points too.  So it might be something we don't handle for
>>>>> operations with vector-type.
>>>>
>>>>
>>>>
>>>> We don't need to worry about that in constexpr evaluation, since we only
>>>> care about constant operands.
>>>
>>>
>>> Sure, but the variable 'v' is the problem, not a constant-value itself.
>>
>>
>>>>>>> But I agree that for constexpr's we could special case cast
>>>>>>> from const to none-const (as required in expressions like const vec v
>>>>>>> = v + 1).
>>>>>>
>>>>>>
>>>>>>
>>>>>> Right.  But really this should happen in convert.c, it shouldn't be
>>>>>> specific
>>>>>> to C++.
>>>>>
>>>>>
>>>>>
>>>>> Hmm, maybe.  But isn't one of our different goals to move such
>>>>> implicit code-modification to match.pd instead?
>>>>
>>>>
>>>> Folding const into a constant is hardly code modification.  But perhaps
>>>> it
>>>> should go into fold_unary_loc:VIEW_CONVERT_EXPR rather than into
>>>> convert.c.
>>>
>>>
>>> Hmm, it isn't related to a view-convert.  So moving it into
>>> fold_unary_loc wouldn't solve here anything.  Issue is in constexpr
>>> code, not in folding itself.
>>
>>
>> What TREE_CODE does the conversion (vec) (const vector) { ... } use?
>
> The tree code is a NOP_EXPR.

That's probably a bug, seeing as fold_convert and convert_to_vector use 
VIEW_CONVERT_EXPR.

Jason


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-27 18:15                                       ` Kai Tietz
@ 2015-08-28  3:03                                         ` Jason Merrill
  2015-08-28  7:43                                           ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-08-28  3:03 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Kai Tietz, gcc-patches List

On 08/27/2015 02:12 PM, Kai Tietz wrote:
> +  else if (TREE_CODE (type) == VECTOR_TYPE)
> +    {
> +      if (TREE_CODE (arg1) == VECTOR_CST
> +         && code == NOP_EXPR
> +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
> +       {
> +         tree r = copy_node (arg1);
> +         TREE_TYPE (arg1) = type;
> +         return r;
> +       }
> +    }

I would drop the check on 'code' and add a check that

  TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (arg1))

Does that still pass?

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-28  3:03                                         ` Jason Merrill
@ 2015-08-28  7:43                                           ` Kai Tietz
  2015-08-28 11:18                                             ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-08-28  7:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-08-28 4:11 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 08/27/2015 02:12 PM, Kai Tietz wrote:
>>
>> +  else if (TREE_CODE (type) == VECTOR_TYPE)
>> +    {
>> +      if (TREE_CODE (arg1) == VECTOR_CST
>> +         && code == NOP_EXPR
>> +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
>> +       {
>> +         tree r = copy_node (arg1);
>> +         TREE_TYPE (arg1) = type;
>> +         return r;
>> +       }
>> +    }
>
>
> I would drop the check on 'code' and add a check that
>
>  TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
>
> Does that still pass?

Yes, is still passes.  To check here for main-variant seems to be more
robust.  I commit it to branch, and will do complete
regression-testing for it.

> Jason

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-08-28  7:43                                           ` Kai Tietz
@ 2015-08-28 11:18                                             ` Kai Tietz
  0 siblings, 0 replies; 38+ messages in thread
From: Kai Tietz @ 2015-08-28 11:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Kai Tietz, gcc-patches List

2015-08-28 9:19 GMT+02:00 Kai Tietz <ktietz70@googlemail.com>:
> 2015-08-28 4:11 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> On 08/27/2015 02:12 PM, Kai Tietz wrote:
>>>
>>> +  else if (TREE_CODE (type) == VECTOR_TYPE)
>>> +    {
>>> +      if (TREE_CODE (arg1) == VECTOR_CST
>>> +         && code == NOP_EXPR
>>> +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
>>> +       {
>>> +         tree r = copy_node (arg1);
>>> +         TREE_TYPE (arg1) = type;
>>> +         return r;
>>> +       }
>>> +    }
>>
>>
>> I would drop the check on 'code' and add a check that
>>
>>  TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
>>
>> Does that still pass?
>
> Yes, is still passes.  To check here for main-variant seems to be more
> robust.  I commit it to branch, and will do complete
> regression-testing for it.

Completed regression-testing.  No new regressions.

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-04-28 12:06     ` Kai Tietz
@ 2015-04-28 13:57       ` Jason Merrill
  0 siblings, 0 replies; 38+ messages in thread
From: Jason Merrill @ 2015-04-28 13:57 UTC (permalink / raw)
  To: Kai Tietz; +Cc: gcc-patches List

On 04/28/2015 08:06 AM, Kai Tietz wrote:
> 2015-04-24 20:25 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> So for warning folding, I think
>> the caching approach we were talking about in the call today is the way to
>> go.
>
> Ok.  Just a question about where to hook up the hash-variable.  What
> would be a good place to create (well this we could do lazy too) it,
> and of more importance where to destroy the hash? We could destroy it
> after genericize-pass?

The important thing is to avoid keeping exprs in the hash table that 
have already been ggc_collected.  So we want to destroy the hash table 
at least after every top-level declaration, but destroying it more 
frequently would be fine too if memory bloat seems like an issue.

>> Certainly a constant value from maybe_constant_value should not have a
>> useless type conversion wrapped around it, as that makes it appear
>> non-constant.
>
> Well, beside an overflow was seen.

Right.

> The interesting point is here to
> find the proper place to do for constructor-elements proper folding,
> or at least constant-value folding.

cxx_eval_bare_aggregate should already be doing constant-value folding 
of constructor elements.

>> I think that's exactly what I was saying above: "we can't just use
>> maybe_constant_value because that only folds C++ constant-expressions, and
>> we want to fold more things than that."
>
> maybe_constant_value folds constants, too.  That was actually the
> reason to use it.  Nevertheless I admit that we could call instead a
> ..fully_fold here too.

Call it where?

> One point I see here about creating a function using
> maybe_constant_value + cp_fold is that maybe_constant_value is
> something we can call safely in all cases.

Right, we would still want the current maybe_constant_value for the few 
situations where constant expressions affect language semantics but are 
not required, such as initializers and array bounds.

I'm suggesting that we should add maybe_constant_value to cp_fold, not 
the other way around.

>> My point is that cp_fold should be a superset of maybe_constant_value, to
>> fix bugs like 53792.  And the easiest way to get that would seem to be by
>> calling maybe_constant_value from cp_fold.
>
> Agreed, that bugs like PR 53792 could be solved that way.
> Nevertheless they aren't directly linked to the delayed-folding
> problem, are they?  We could deal with those cases also in
> genericize-pass lately, as we want to catch here just a missed
> optimization, aren't we?

They aren't due to premature folding, but they are due to the lack of 
delayed folding.  If we're going to fully fold expressions at genericize 
time (and at other times for warnings), that needs to include folding 
calls to constexpr functions, or it isn't "full" folding.  We want to 
handle them together rather than separately because they can interact: 
simplifying one expression with fold may turn it into a C++ 
constant-expression (which is why we have premature-folding bugs), and 
simplifying a constant-expression may expose more opportunities for 
fold.  And we only want a single hash table.

>> OK, that makes sense.  Say, a function called like "fold" that only folds
>> conversions (and NEGATE_EXPR) of constants.  It might make sense to do that
>> and otherwise continue to delay folding of conversions.  In that context I
>> guess this change makes sense.
>
> Fine, any preferences about place for this function?  I suggest the
> name 'fold_cst' for it.

Sounds good.

>> Yes, but we already called maybe_constant_value [in compute_array_index_type].  Calling it again shouldn't
>> make any difference.
>
> We just call it in non-dependent tree,

If the expression is dependent, maybe_constant_value does nothing.

> and even here just for special cases.

Special cases?  It looks like it's called if the expression is not a 
magic C++98 NOP_EXPR with TREE_SIDE_EFFECTS and it is convertible to 
integral or enumeration type.  That seems to cover all cases of constant 
array bounds.

Do you have a testcase that motivates this?

>>>>> -      itype = fold (itype);
>>>>> +      itype = maybe_constant_value (itype);
>>>>> -               itype = variable_size (fold (newitype));
>>>>> +               itype = variable_size (maybe_constant_value (newitype));
>>>>
>>>> Maybe these should use cp_fully_fold?
>>>
>>> We could use fully_fold, but we would also modify none-constant
>>> expressions by this.  Do we actually want that here?
>>
>> For the first one, I actually think a plain fold is enough, or perhaps
>> change the cp_build_binary_op to size_binop.
>
> Hmm, I doubt that a simple fold would be enough here.  As itype is
> calculated as minus of two converts (and cp_converts aren't
> automatically folded).

Sure, the converts need to be folded as well, but we were just saying 
that we are going to automatically fold conversion of a constant, right?

>>>>> @@ -13090,6 +13092,8 @@ build_enumerator (tree name, tree value, tree
>>>>> enumtype, location_t loc)
>>>>> +  if (value)
>>>>> +    value = maybe_constant_value (value);

>> As above, calling the constexpr code twice shouldn't make a difference.
>
> Well, issue is that cxx_constant_value is just called for
> !processing_template_decl case.

Is that important?  Is there a testcase?  Perhaps some change is called 
for, but adding a redundant call to the constexpr code is not that change.

> Additionally we try to
> perform_implicit_conversion_flags on it, which can add new
> cast-operation, which gets resolved by call for cxx_constant_value.

That's after your call to maybe_constant_value, so I don't see how it 
makes any difference.

>> How does delayed folding result in a different OMP_FOR_KIND?
>
> Well,  I guess it is related to optimizations/normalization done early
> on parsing-state, which isn't triggered anymore on later folds.  As
> OMP-stuff isn't that good reading, it is hard to tell why
> normalization doesn't happen here anymore.  I will try to look into
> that, but not sure if it is worth the effort at the very end ...

Hmm, sounds like it could be a significant missed optimization.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-04-24 18:25   ` Jason Merrill
@ 2015-04-28 12:06     ` Kai Tietz
  2015-04-28 13:57       ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-04-28 12:06 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

2015-04-24 20:25 GMT+02:00 Jason Merrill <jason@redhat.com>:
> On 04/24/2015 09:46 AM, Kai Tietz wrote:
>>
>> Sure, we can use here instead *_fully_fold, but for what costs?  In
>> general we need to deal here a simple one-level fold for simplifying
>> constant-values, and/or removing useless type-conversions.
>
>
> Well, here you're doing a two-level fold.  And in general fold relies on
> subexpressions being appropriately folded.  So for warning folding, I think
> the caching approach we were talking about in the call today is the way to
> go.

Ok.  Just a question about where to hook up the hash-variable.  What
would be a good place to create (well this we could do lazy too) it,
and of more importance where to destroy the hash? We could destroy it
after genericize-pass?

>>>> @@ -597,9 +597,9 @@ null_member_pointer_value_p (tree t)
>>>>       return false;
>>>>     else if (TYPE_PTRMEMFUNC_P (type))
>>>>       return (TREE_CODE (t) == CONSTRUCTOR
>>>> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
>>>> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>>>>     else if (TYPE_PTRDATAMEM_P (type))
>>>> -    return integer_all_onesp (t);
>>>> +    return integer_all_onesp (fold (t));
>>>
>>>
>>>
>>> Calling fold here is wrong; it doesn't handle constexpr, and we should
>>> have
>>> folded before we got here.
>>
>>
>> s.o. we need to make sure constant-values get rid of useless
>> types-conversions/negates/etc ...
>
>
> Certainly a constant value from maybe_constant_value should not have a
> useless type conversion wrapped around it, as that makes it appear
> non-constant.

Well, beside an overflow was seen.  The interesting point is here to
find the proper place to do for constructor-elements proper folding,
or at least constant-value folding.  I made here already some tries to
find a proper place for this, but ran by this into troubles that not
in all cases maybe_constant_value was callable (endless recursion).
Additionally it happens in some cases for constructor-elements that
nop-casts are added on assign.  At least I ran into that.
In general there is the question if we shouldn't do for constructors
call a ...fully_fold?

>>>> @@ -576,7 +576,6 @@ build_simple_base_path (tree expr, tree binfo)
>>>>          expr = build3 (COMPONENT_REF,
>>>>                         cp_build_qualified_type (type, type_quals),
>>>>                         expr, field, NULL_TREE);
>>>> -       expr = fold_if_not_in_template (expr);
>>>
>>>
>>> I don't think we need to remove this fold, since it is part of compiler
>>> internals rather than something the user wrote.  Really, we should
>>> represent
>>> the base conversion with something like a CONVERT_EXPR and only call this
>>> function when we want to fold it.  But that can wait for a later patch.
>>
>>
>> Ok.  I remove this fold-case due simply removing
>> fold_if_not_in_template function.  So well, we could re-add a call for
>> fold, if not in template.
>
>
> Let's try not checking for being in a template, see if it breaks.

I tested to use here just a fold (), and I ddn't noticed any fallout
by this.  So I committed it to branch.

>>>> +static tree
>>>> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
>>>> +{
>>>
>>>
>>> ....
>>>
>>> I still think we need a hybrid of this and the constexpr code: it isn't
>>> full
>>> folding if we aren't doing constexpr evaluation.  But we can't just use
>>> maybe_constant_value because that only folds C++ constant-expressions,
>>> and
>>> we want to fold more things than that.  I suppose one simple approach for
>>> now would be to call maybe_constant_value from cp_fold.
>>
>>
>> Well, the functionality of cp_fold and maybe_constant_value (well,
>> actually how constexpr.c works) are different in cases of
>> non-constant results.
>
>
> I think that's exactly what I was saying above: "we can't just use
> maybe_constant_value because that only folds C++ constant-expressions, and
> we want to fold more things than that."

maybe_constant_value folds constants, too.  That was actually the
reason to use it.  Nevertheless I admit that we could call instead a
..fully_fold here too.
One point I see here about creating a function using
maybe_constant_value + cp_fold is that maybe_constant_value is
something we can call safely in all cases.

> My point is that cp_fold should be a superset of maybe_constant_value, to
> fix bugs like 53792.  And the easiest way to get that would seem to be by
> calling maybe_constant_value from cp_fold.

Agreed, that bugs like PR 53792 could be solved that way.
Nevertheless they aren't directly linked to the delayed-folding
problem, are they?  We could deal with those cases also in
genericize-pass lately, as we want to catch here just a missed
optimization, aren't we?

>>>> @@ -614,9 +614,13 @@ cp_fold_convert (tree type, tree expr)
>>>>       }
>>>>     else
>>>>       {
>>>> -      conv = fold_convert (type, expr);
>>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>>> +        conv = fold_convert (type, expr);
>>>> +      else
>>>> +        conv = convert (type, expr);
>>>
>>>
>>> Why?  If we're calling cp_fold_convert in a place where we don't want to
>>> fold, we should stop calling it rather than change it.
>
>
>> See, that we want to take care that constant-value is found here.
>> Otherwise we don't want anything folded.   Well, we could introduce
>> for this a special routine to abstract intention here.
>
>
> OK, that makes sense.  Say, a function called like "fold" that only folds
> conversions (and NEGATE_EXPR) of constants.  It might make sense to do that
> and otherwise continue to delay folding of conversions.  In that context I
> guess this change makes sense.

Fine, any preferences about place for this function?  I suggest the
name 'fold_cst' for it.

>>>> @@ -8502,16 +8502,18 @@ compute_array_index_type (tree name, tree size,
>>>> tsubst_flags_t complain)
>>>> +  /* We need to do fully folding to determine if we have VLA, or not.
>>>> */
>>>> +  tree size_constant = maybe_constant_value (size);
>>>
>>>
>>> Why is this needed?  We already call maybe_constant_value earlier in
>>> compute_array_index_type.
>>
>>
>> Well, see above.  We might have constant-value not simplified.  So we
>> need a way to make sure we simplify in such case, but if it is
>> none-constant, we don't want an modified expression.  So
>> maybe_constant_value does this ...
>
>
> Yes, but we already called maybe_constant_value.  Calling it again shouldn't
> make any difference.

We just call it in none-dependent tree, and even here just for special
cases.  We need to make sure to simplifiy to constant.  Well, we could
use here instead fold_cst instead (which calls internally
...fully_fold, but just returns altered tree if result is constant).

>>>> -      itype = fold (itype);
>>>> +      itype = maybe_constant_value (itype);
>>>> -               itype = variable_size (fold (newitype));
>>>> +               itype = variable_size (maybe_constant_value (newitype));
>>>
>>>
>>> Maybe these should use cp_fully_fold?
>>
>>
>> We could use fully_fold, but we would also modify none-constant
>> expressions by this.  Do we actually want that here?
>
>
> For the first one, I actually think a plain fold is enough, or perhaps
> change the cp_build_binary_op to size_binop.

Hmm, I doubt that a simple fold would be enough here.  As itype is
calculated as minux of two converts (and cp_converts aren't
automatically folded).

> For the second, can we drop that whole block (the one starting with "if
> (TREE_CODE (itype) != SAVE_EXPR)") and rely on late folding to handle
> SIZEOF_EXPR?

I am testing

>>>> @@ -13090,6 +13092,8 @@ build_enumerator (tree name, tree value, tree
>>>> enumtype, location_t loc)
>>>> +  if (value)
>>>> +    value = maybe_constant_value (value);
>>>
>>>
>>>
>>> This seems unnecessary, since we call cxx_constant_value below.
>>
>>
>> See the other places
>
>
> As above, calling the constexpr code twice shouldn't make a difference.

Well, issue is that cxx_constant_value is just called for
!processing_template_decl case. Additionally we try to
perform_implicit_conversion_flags on it, which can add new
cast-operation, which gets resulved by call for cxx_constant_value.
So it makes a difference AFAIC, but I might misread here

>
> How does delayed folding result in a different OMP_FOR_KIND?

Well,  I guess it is related to optimizations/normalization done early
on parsing-state, which isn't triggered anymore on later folds.  As
OMP-stuff isn't that good reading, it is hard to tell why
normalization doesn't happen here anymore.  I will try to look into
that, but not sure if it is worth the effort at the very end ...

>
> Jason
>

Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-04-24 13:46 ` Kai Tietz
@ 2015-04-24 18:25   ` Jason Merrill
  2015-04-28 12:06     ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-04-24 18:25 UTC (permalink / raw)
  To: Kai Tietz; +Cc: gcc-patches List

On 04/24/2015 09:46 AM, Kai Tietz wrote:
> Sure, we can use here instead *_fully_fold, but for what costs?  In
> general we need to deal here a simple one-level fold for simplifying
> constant-values, and/or removing useless type-conversions.

Well, here you're doing a two-level fold.  And in general fold relies on 
subexpressions being appropriately folded.  So for warning folding, I 
think the caching approach we were talking about in the call today is 
the way to go.

>>> @@ -597,9 +597,9 @@ null_member_pointer_value_p (tree t)
>>>       return false;
>>>     else if (TYPE_PTRMEMFUNC_P (type))
>>>       return (TREE_CODE (t) == CONSTRUCTOR
>>> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
>>> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>>>     else if (TYPE_PTRDATAMEM_P (type))
>>> -    return integer_all_onesp (t);
>>> +    return integer_all_onesp (fold (t));
>>
>>
>> Calling fold here is wrong; it doesn't handle constexpr, and we should have
>> folded before we got here.
>
> s.o. we need to make sure constant-values get rid of useless
> types-conversions/negates/etc ...

Certainly a constant value from maybe_constant_value should not have a 
useless type conversion wrapped around it, as that makes it appear 
non-constant.

> Well, fold_convert isn't necessarily the same as fold (convert ())
> within C++, due convert handles special cases fold_convert doesn't.

Ah, true.

>>> @@ -576,7 +576,6 @@ build_simple_base_path (tree expr, tree binfo)
>>>          expr = build3 (COMPONENT_REF,
>>>                         cp_build_qualified_type (type, type_quals),
>>>                         expr, field, NULL_TREE);
>>> -       expr = fold_if_not_in_template (expr);
>>
>> I don't think we need to remove this fold, since it is part of compiler
>> internals rather than something the user wrote.  Really, we should represent
>> the base conversion with something like a CONVERT_EXPR and only call this
>> function when we want to fold it.  But that can wait for a later patch.
>
> Ok.  I remove this fold-case due simply removing
> fold_if_not_in_template function.  So well, we could re-add a call for
> fold, if not in template.

Let's try not checking for being in a template, see if it breaks.

>> That said, we should probably just remove this case and the next, as they
>> are obsolete.  I'll remove them on the trunk.

Done.

>>> +static tree
>>> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
>>> +{
>>
>> ....
>>
>> I still think we need a hybrid of this and the constexpr code: it isn't full
>> folding if we aren't doing constexpr evaluation.  But we can't just use
>> maybe_constant_value because that only folds C++ constant-expressions, and
>> we want to fold more things than that.  I suppose one simple approach for
>> now would be to call maybe_constant_value from cp_fold.
>
> Well, the functionality of cp_fold and maybe_constant_value (well,
> actually how constexpr.c works) are different in cases of
> non-constant results.

I think that's exactly what I was saying above: "we can't just use
maybe_constant_value because that only folds C++ constant-expressions, 
and we want to fold more things than that."

My point is that cp_fold should be a superset of maybe_constant_value, 
to fix bugs like 53792.  And the easiest way to get that would seem to 
be by calling maybe_constant_value from cp_fold.

>>> @@ -614,9 +614,13 @@ cp_fold_convert (tree type, tree expr)
>>>       }
>>>     else
>>>       {
>>> -      conv = fold_convert (type, expr);
>>> +      if (TREE_CODE (expr) == INTEGER_CST)
>>> +        conv = fold_convert (type, expr);
>>> +      else
>>> +        conv = convert (type, expr);
>>
>> Why?  If we're calling cp_fold_convert in a place where we don't want to
>> fold, we should stop calling it rather than change it.

> See, that we want to take care that constant-value is found here.
> Otherwise we don't want anything folded.   Well, we could introduce
> for this a special routine to abstract intention here.

OK, that makes sense.  Say, a function called like "fold" that only 
folds conversions (and NEGATE_EXPR) of constants.  It might make sense 
to do that and otherwise continue to delay folding of conversions.  In 
that context I guess this change makes sense.

>>> @@ -8502,16 +8502,18 @@ compute_array_index_type (tree name, tree size,
>>> tsubst_flags_t complain)
>>> +  /* We need to do fully folding to determine if we have VLA, or not.  */
>>> +  tree size_constant = maybe_constant_value (size);
>>
>> Why is this needed?  We already call maybe_constant_value earlier in
>> compute_array_index_type.
>
> Well, see above.  We might have constant-value not simplified.  So we
> need a way to make sure we simplify in such case, but if it is
> none-constant, we don't want an modified expression.  So
> maybe_constant_value does this ...

Yes, but we already called maybe_constant_value.  Calling it again 
shouldn't make any difference.

>>> -      itype = fold (itype);
>>> +      itype = maybe_constant_value (itype);
>>> -               itype = variable_size (fold (newitype));
>>> +               itype = variable_size (maybe_constant_value (newitype));
>>
>> Maybe these should use cp_fully_fold?
>
> We could use fully_fold, but we would also modify none-constant
> expressions by this.  Do we actually want that here?

For the first one, I actually think a plain fold is enough, or perhaps 
change the cp_build_binary_op to size_binop.

For the second, can we drop that whole block (the one starting with "if 
(TREE_CODE (itype) != SAVE_EXPR)") and rely on late folding to handle 
SIZEOF_EXPR?

>>> @@ -13090,6 +13092,8 @@ build_enumerator (tree name, tree value, tree
>>> enumtype, location_t loc)
>>> +  if (value)
>>> +    value = maybe_constant_value (value);
>>
>>
>> This seems unnecessary, since we call cxx_constant_value below.
>
> See the other places

As above, calling the constexpr code twice shouldn't make a difference.

>>> -         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
>>> +         gcc_assert (val1->v.val_unsigned
>>> +                     == (unsigned HOST_WIDE_INT) DWARF2_ADDR_SIZE);
>>
>>
>> We need to fix this warning so this change is unnecessary.
>
> Well, those following changes got already acked by Jeff for 4.9.

Because we want the compiler to build with a wide range of other 
compilers.  It's still a warning regression that needs to be fixed.

>>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) ==
>>> decl);
>>
>>
>> This change doesn't seem to have anything to do with delayed folding.
>
> It gets raised by delayed folding, so it is required to run.

We're in gimplification, so we should have been through cp_fold, so this 
should have been folded appropriately by now.

>>>                        || (gimple_omp_for_kind (for_stmt)
>>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>>> +                     || (gimple_omp_for_kind (for_stmt)
>>> +                         == GF_OMP_FOR_KIND_FOR));
>>
>> Nor this one.
>
> Same thing ...

How does delayed folding result in a different OMP_FOR_KIND?

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: C++ delayed folding branch review
  2015-04-24  4:23 Jason Merrill
@ 2015-04-24 13:46 ` Kai Tietz
  2015-04-24 18:25   ` Jason Merrill
  0 siblings, 1 reply; 38+ messages in thread
From: Kai Tietz @ 2015-04-24 13:46 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

2015-04-24 6:22 GMT+02:00 Jason Merrill <jason@redhat.com>:
>> +  expr = fold (expr);
>>    /* This may happen, because for LHS op= RHS we preevaluate
>>       RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
>>       means we could no longer see the code of the EXPR.  */
>>    if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
>>      expr = C_MAYBE_CONST_EXPR_EXPR (expr);
>>    if (TREE_CODE (expr) == SAVE_EXPR)
>> -    expr = TREE_OPERAND (expr, 0);
>> +    expr = fold (TREE_OPERAND (expr, 0));
>
>
> How about moving the first fold after the SAVE_EXPR block, so that we only
> need to call fold once?

I will try.  It might be required to fold in front to strip of useless
type-conversions ...

>> +    case NEGATE_EXPR:
>> +    case BIT_NOT_EXPR:
>> +    case CONVERT_EXPR:
>> +    case VIEW_CONVERT_EXPR:
>> +    case NOP_EXPR:
>> +    case FIX_TRUNC_EXPR:
>> +      {
>> +       tree op1 = TREE_OPERAND (expr, 0);
>> +       tree fop1 = fold (op1);
>> +       if (fop1 && op1 != fop1)
>> +         fop1 = fold_build1_loc (loc, TREE_CODE (expr), TREE_TYPE (expr),
>> +                                 fop1);

well, AFAIR was the idea here to make sure we do constant-value folding ...

>
> Isn't this redundant with the call to fold above?  If not, it seems that the
> above call should be to *_fully_fold.  I suppose we want an entry point
> defined by both front ends that c-common code can call which does full
> folding of an expression.

Sure, we can use here instead *_fully_fold, but for what costs?  In
general we need to deal here a simple one-level fold for simplifying
constant-values, and/or removing useless type-conversions.  As convert
doesn't fold them away anymore, it can stay with such NOP_EXPR before
constant-values, which cause us to fail on later value-analyzis.  So
sure, we can use *_fully_fold, but actually we don't need a full-fold.
(this applies to other places below too, where you mentioned the same
issue, too).

>> @@ -597,9 +597,9 @@ null_member_pointer_value_p (tree t)
>>      return false;
>>    else if (TYPE_PTRMEMFUNC_P (type))
>>      return (TREE_CODE (t) == CONSTRUCTOR
>> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
>> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>>    else if (TYPE_PTRDATAMEM_P (type))
>> -    return integer_all_onesp (t);
>> +    return integer_all_onesp (fold (t));
>
>
> Calling fold here is wrong; it doesn't handle constexpr, and we should have
> folded before we got here.

s.o. we need to make sure constant-values get rid of useless
types-conversions/negates/etc ...

>>                 warn_logical_operator (loc, code, boolean_type_node,
>> -                                      code_orig_arg1, arg1,
>> -                                      code_orig_arg2, arg2);
>> +                                      code_orig_arg1, fold (arg1),
>> +                                      code_orig_arg2, fold (arg2));
>
>
> I think warn_logical_operator should call back into *_fully_fold. Likewise
> for most similar added calls to fold.

Same as above.  It isn't necessary for further analysis to perform
fully_fold on arg1/arg2.  But of course we can introduce this load
here.

>> @@ -7356,8 +7354,13 @@ build_over_call (struct z_candidate *cand, int
>> flags, tsu
>> bst_flags_t complain)
>>
>>    gcc_assert (j <= nargs);
>>    nargs = j;
>> +  {
>> +    tree *fargs = (!nargs ? argarray : (tree *) alloca (nargs * sizeof
>> (tree)))
>> ;
>> +    for (j = 0; j < nargs; j++)
>> +      fargs[j] = fold_non_dependent_expr (argarray[j]);
>
>
> Similarly, this and build_cxx_call should use cp_fully_fold.

Well, cp_fully_fold wouldn't resolve constexpr ... at least not in completeness.

>> @@ -7602,7 +7614,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
>>        && current_function_decl
>>        && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
>>      optimize = 1;
>> -  fn = fold_if_not_in_template (fn);
>>    optimize = optimize_sav;
>
>
> Since we're removing the fold, we can also remove the changes to "optimize".

Yeah, I missed that.  I removed superfluous code-path and committed it
on branch.

>> @@ -443,7 +443,7 @@ build_base_path (enum tree_code code,
>>
>>           t = TREE_TYPE (TYPE_VFIELD (current_class_type));
>>           t = build_pointer_type (t);
>> -         v_offset = convert (t, current_vtt_parm);
>> +         v_offset = fold (convert (t, current_vtt_parm));
>
> fold_convert should work here.

Well, fold_const isn't necessarily the same as fold (convert ())
within C++, due convert handles special cases fold_const doesn't.  At
least I ran here into issues for templates within templates AFAIR.


>> @@ -576,7 +576,6 @@ build_simple_base_path (tree expr, tree binfo)
>>         expr = build3 (COMPONENT_REF,
>>                        cp_build_qualified_type (type, type_quals),
>>                        expr, field, NULL_TREE);
>> -       expr = fold_if_not_in_template (expr);
>
>
> I don't think we need to remove this fold, since it is part of compiler
> internals rather than something the user wrote.  Really, we should represent
> the base conversion with something like a CONVERT_EXPR and only call this
> function when we want to fold it.  But that can wait for a later patch.

Ok.  I remove this fold-case due simply removing
fold_if_not_in_template function.  So well, we could re-add a call for
fold, if not in template.

>> @@ -1046,6 +1048,9 @@ adjust_temp_type (tree type, tree temp)
>>  {
>>    if (TREE_TYPE (temp) == type)
>>      return temp;
>> +  STRIP_NOPS (temp);
>> +  if (TREE_TYPE (temp) == type)
>> +    return temp;
>
> ...

s.a. for why there might be useless NOPS

>>
>>  reduced_constant_expression_p (tree t)
>>  {
>> +  /* Make sure we remove useless initial NOP_EXPRs.  */
>> +  STRIP_NOPS (t);
>
>
>
> Where are these NOPs coming from?

See above ...

>> @@ -1082,7 +1087,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx
>> *ctx, tree t,
>>           && is_dummy_object (x))
>>         {
>>           x = ctx->object;
>> -         x = cp_build_addr_expr (x, tf_warning_or_error);
>> +         if (x)
>> +           x = cp_build_addr_expr (x, tf_warning_or_error);
>> +         else
>> +           x = get_nth_callarg (t, i);
>
>
> This should not be necessary.

Yeah, could be.  It might be something remaining to work-a-round an
older issue.  I will retest to see if we can remove this.

>> @@ -1765,7 +1780,8 @@ cxx_eval_component_reference (const constexpr_ctx
>> *ctx, tree t,
>>        if (field == part)
>>         {
>>           if (value)
>> -           return value;
>> +           return cxx_eval_constant_expression (ctx, value, lval,
>> +                                                non_constant_p,
>> overflow_p);
>
> ...
>>
>> @@ -1849,7 +1865,8 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx,
>> tree t,
>>      {
>>        tree bitpos = bit_position (field);
>>        if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
>> -       return value;
>> +       return cxx_eval_constant_expression (ctx, value, lval,
>> +                                             non_constant_p, overflow_p);
>
>
> This shouldn't be necessary, either; the elements of the CONSTRUCTOR should
> be fully evaluated already.

Well, I will recheck.  I think it had something to do with the
possible none-optimized constant-values, which are requiring here a
folding.

>> @@ -1560,14 +1570,19 @@ cxx_eval_unary_expression (const constexpr_ctx
>> *ctx, tre
>> e t,
>>    location_t loc = EXPR_LOCATION (t);
>>    enum tree_code code = TREE_CODE (t);
>>    tree type = TREE_TYPE (t);
>> -  r = fold_unary_loc (loc, code, type, arg);
>> -  if (r == NULL_TREE)
>> +  if (TREE_CODE (t) == UNARY_PLUS_EXPR)
>> +    r = fold_convert_loc (loc, TREE_TYPE (t), arg);
>
>
> We don't want to handle UNARY_PLUS_EXPR here; we should handle it like
> NOP_EXPR.  And so you shouldn't need the call to unify_constant.

Hmm, ok.  I will replace that.  I liked the unify_constant function
for making it easier to read code-flow ... but yes, it isn't really
something necessary.

>>      case BIT_NOT_EXPR:
>>      case TRUTH_NOT_EXPR:
>>      case FIXED_CONVERT_EXPR:
>> +    case UNARY_PLUS_EXPR:
>>        r = cxx_eval_unary_expression (ctx, t, lval,
>
>
> So this case should be down with NOP_EXPR.

Ok.

>> @@ -2954,19 +2987,15 @@ cxx_eval_constant_expression (const constexpr_ctx
>> *ctx,
>> tree t,
>>    constexpr_ctx new_ctx;
>>    tree r = t;
>>
>> -  if (t == error_mark_node)
>> +  if (!t || t == error_mark_node)
>
>
> Where are null expressions coming from?

I will retest.  AFAIR this might be a work-a-round for
return-expressions.  It got fixed on stage 3 for 4.9, so this change
might be indeed superfluous now.

>>      case SIZEOF_EXPR:
>> +      if (processing_template_decl
>> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
>> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
>> +       return t;
>
>
> The type of a SIZEOF_EXPR will always be size_t, so this isn't actually
> accomplishing anything, and should be removed.

Well, true, but I remember that I had seen issues in templates within
template cases where we might get incomlete types.  I will recheck.

>> +      /* See this can happen for case like g++.dg/init/static2.C
>> testcase.  */
>> +      if (!ctx || !ctx->ctor || (lval && !ctx->object)
>> +         || !same_type_ignoring_top_level_qualifiers_p
>> +              (TREE_TYPE (t), TREE_TYPE (ctx->ctor))
>> +         || CONSTRUCTOR_NELTS (ctx->ctor) != 0)
>> +       {
>> +         *non_constant_p = true;
>> +         break;
>> +       }
>
>
> Why can this happen on the branch but not on trunk?  I think the problem is
> elsewhere.
>
>>      case NOP_EXPR:
>>        {
>>         tree oldop = TREE_OPERAND (t, 0);
>> +       if (TREE_CODE (t) == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE
>> (oldop) && TREE_OVERFLOW_P (oldop))
>> +         {
>> +           if (!ctx->quiet)
>> +             permerror (input_location, "overflow in constant
>> expression");
>> +           /* If we're being permissive (and are in an enforcing
>> +               context), ignore the overflow.  */
>> +           if (!flag_permissive)
>> +             *overflow_p = true;
>> +           *non_constant_p = true;
>> +
>> +           return t;
>> +         }
>
>
> This doesn't seem like the right place to handle this; why didn't we
> diagnose the overflow when it happened?

This is recent by convert-change for not-folding.  So a nop-expression
might be present, but isn't necessarily a overflow.  We need to handle
this special now.  Prior we simply added a nop before an
overflow-value to prevent further warnings.

>>  maybe_constant_init (tree t, tree decl)
>>  {
>> +  if (!t)
>> +    return t;
>
>
> Where are null initializers coming from?
>
>>      case MINUS_EXPR:
>>        /* -- a subtraction where both operands are pointers.   */
>>        if (TYPE_PTR_P (TREE_OPERAND (t, 0))
>> -          && TYPE_PTR_P (TREE_OPERAND (t, 1)))
>> +          && TYPE_PTR_P (TREE_OPERAND (t, 1))
>> +         && TREE_OPERAND (t, 0) != TREE_OPERAND (t, 1))
>
>
> Why?  From where are we getting a pointer subtracted from itself?
>
> That said, we should probably just remove this case and the next, as they
> are obsolete.  I'll remove them on the trunk.

Ok.

>> +static tree
>> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
>> +{
>
> ....
>
> I still think we need a hybrid of this and the constexpr code: it isn't full
> folding if we aren't doing constexpr evaluation.  But we can't just use
> maybe_constant_value because that only folds C++ constant-expressions, and
> we want to fold more things than that.  I suppose one simple approach for
> now would be to call maybe_constant_value from cp_fold.

Well, the functionality of cp_fold and maybe_constant_value (well,
actually how constexpr.c works) are different in cases of
none-constant results.
if we call cp_fold, we really want simplified expression, regardless
if it's result is a constant-value, or not.  Additionally handles
cp_fold parts of the optimization constexpr.c won't do (eg
pointer-arithmetics, more complex statement replacements, etc).
So I don't think it is a really sane thing to merge those two
different functionalities here.  But we can discuss this today in our
meeting further.

>> @@ -614,9 +614,13 @@ cp_fold_convert (tree type, tree expr)
>>      }
>>    else
>>      {
>> -      conv = fold_convert (type, expr);
>> +      if (TREE_CODE (expr) == INTEGER_CST)
>> +        conv = fold_convert (type, expr);
>> +      else
>> +        conv = convert (type, expr);
>
>
> Why?  If we're calling cp_fold_convert in a place where we don't want to
> fold, we should stop calling it rather than change it.
See, that we want to take care that constant-value is found here.
Otherwise we don't want anything folded.   Well, we could introduce
for this a special routine to abstract intention here.

>>  cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>>  {
>> -  tree result;
>> +  tree result, ret;
>>
>>    if (TREE_TYPE (expr) == type)
>>      return expr;
>>
>> -  result = cp_convert (type, expr, complain);
>> +  result = ret = cp_convert (type, expr, complain);
>>
>>    if ((complain & tf_warning)
>>        && c_inhibit_evaluation_warnings == 0)
>> @@ -652,6 +656,7 @@ cp_convert_and_check (tree type, tree expr,
>> tsubst_flags_t complain)
>>        tree stripped = folded;
>>        tree folded_result
>>         = folded != expr ? cp_convert (type, folded, complain) : result;
>> +      folded_result = fold (folded_result);
>>
>>        /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in
>> a
>>          NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
>> @@ -663,7 +668,7 @@ cp_convert_and_check (tree type, tree expr,
>> tsubst_flags_t complain)
>>                                         folded_result);
>>      }
>>
>> -  return result;
>> +  return ret;
>
>
> Why introduce the "ret" variable?  It doesn't seem to do anything different
> from "result".  And instead of the added fold, maybe change the cp_convert
> on the previous line to cp_fold_convert?

Good point, I will look close to it today.

>> @@ -1535,8 +1538,10 @@ build_expr_type_conversion (int desires, tree expr,
>> bool complain)
>> +  tree expr_folded = maybe_constant_value (expr);
>>
>> -  if (expr == null_node
>> +  STRIP_NOPS (expr_folded);
>> +  if (expr_folded == null_node
>
>
> We shouldn't need to fold to check for null_node, it only occurs when
> explicitly written.  And we don't want to fold before calling
> null_ptr_cst_p, since in C++11 only a literal 0 is a null pointer constant.
> For C++98 we already fold in null_ptr_cst_p.
>
>> @@ -8502,16 +8502,18 @@ compute_array_index_type (tree name, tree size,
>> tsubst_flags_t complain)
>> +  /* We need to do fully folding to determine if we have VLA, or not.  */
>> +  tree size_constant = maybe_constant_value (size);
>
>
> Why is this needed?  We already call maybe_constant_value earlier in
> compute_array_index_type.

Well, see above.  We might have constant-value not simplified.  So we
need a way to make sure we simplify in such case, but if it is
none-constant, we don't want an modified expression.  So
maybe_constant_value does this ...

>> -      itype = fold (itype);
>> +      itype = maybe_constant_value (itype);
>> -               itype = variable_size (fold (newitype));
>> +               itype = variable_size (maybe_constant_value (newitype));
>
> Maybe these should use cp_fully_fold?

We could use fully_fold, but we would also modify none-constant
expressions by this.  Do we actually want that here?  I will revisit
this and see if we can assume that

>> @@ -13090,6 +13092,8 @@ build_enumerator (tree name, tree value, tree
>> enumtype, location_t loc)
>> +  if (value)
>> +    value = maybe_constant_value (value);
>
>
> This seems unnecessary, since we call cxx_constant_value below.

See the other places

>>               value = cxx_constant_value (value);
>> +             STRIP_NOPS (value);
>
>
> The only time a constant result should have a NOP_EXPR around it is if it
> isn't really constant.  Why do you want to strip that?


See above ....

>> -          value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
>> +          value = fold (convert (ENUM_UNDERLYING_TYPE (enumtype),
>> value));
>
>
> fold_convert again.

Like the other case above.  fold_convert isn't necessarily for C++ the
same as 'fold (convert ())'.  For cast from classes it caused issues.
I will revisit if this is still true, but I would assume so.

>> @@ -188,9 +188,9 @@ build_zero_init_1 (tree type, tree nelts, bool
>> static_storage_p,
>> -    init = convert (type, nullptr_node);
>> +    init = fold (convert (type, nullptr_node));
>
>
> fold_convert
>
>> @@ -783,7 +783,8 @@ perform_member_init (tree member, tree init)
>> +      if (init)
>> +       init = fold (init);
>
>
> Why fold here?  This doesn't seem like a place that needs early folding.
>
>> @@ -6480,7 +6480,8 @@ cp_parser_array_notation (location_t loc, cp_parser
>> *parser, tree *init_index,
>> -      *init_index = cp_parser_expression (parser);
>> +      *init_index = cp_parser_expression (parser);
>> +      *init_index = maybe_constant_value (*init_index);
>
> ...
>>
>> +      length_index = maybe_constant_value (length_index);
>
> ...
>>
>> +         stride = maybe_constant_value (stride);
>
>
> Why fold here, rather than later when something really wants a constant?  If
> that ever actually occurs?
>
>> +  /* For offsetof and declaration of types we need
>> +     constant integeral values.
>> +     Also we meed to fold for negative constants so that diagnostic in
>> +     c-family/c-common.c doesn't fail for array-bounds.  */
>> +  if (for_offsetof || decltype_p
>> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND
>> (index, 0)) == INTEGER_CST))
>> +    index = maybe_constant_value (index);
>
>
> Likewise.  For offsetof we should either use OFFSETOF_EXPR until late
> folding, or fold in offsetof evaluation.  I don't know why decltype would
> need anything special.  And for diagnostics we should be folding closer to
> the diagnostic.
>
>> @@ -9876,6 +9888,7 @@ cp_parser_label_for_labeled_statement (cp_parser*
>> parser, tree attributes)
>> +       expr = maybe_constant_value (expr);
>
>
> This seems redundant with the call to cxx_constant_value in case_conversion.
>
>> @@ -12190,6 +12204,10 @@ cp_parser_static_assert(cp_parser *parser, bool
>> member_p)
>> +  /* Make sure we folded it completely before doing trying to get
>> +     constant value.  */
>> +  condition = fold_non_dependent_expr (condition);
>
>
> This shouldn't be necessary; if the constexpr code needs to do more folding,
> that should be fixed.
>
>> @@ -16081,6 +16099,7 @@ cp_parser_enumerator_definition (cp_parser*
>> parser, tree type)
>> +      value = maybe_constant_value (value);
>
>
> This seems redundant with the call to cxx_constant_value in
> build_enumerator.
>
>> +             width = maybe_constant_value (width);
>
>
> This seems redundant with the call to cxx_constant_value in
> check_bitfield_decl.
>
> And so on.  It seems like you added maybe_constant_value after every
> occurrence of cp_parser_constant_expression, and I suspect that few are
> actually needed, and the ones that are should go closer to the code that
> really needs a constant.  I'd prefer to avoid calling it at all in parser.c.
>
>> @@ -449,7 +449,7 @@ build_aggr_init_expr (tree type, tree init)
>> -    return convert (type, init);
>> +    return fold (convert (type, init));
>
>
> fold_convert

See prior comments for this ...

>> @@ -3394,6 +3394,8 @@ handle_init_priority_attribute (tree* node,
>> +  if (initp_expr)
>> +    initp_expr = maybe_constant_value (initp_expr);
>
>
> Let's use cxx_constant_value instead of this and the non-constant diagnostic
> just below.

Ok.

>> @@ -3371,7 +3367,7 @@ get_member_function_from_ptrfunc (tree
>> *instance_ptrptr, tree function,
>> -      e2 = fold_convert (TREE_TYPE (e3), e2);
>> +      e2 = fold (convert (TREE_TYPE (e3), e2));
>
>
> Why?

Hmm, I will recheck, but indeed I assume I missed to make it again a
fold_convert out of it again.

>> @@ -3667,6 +3663,10 @@ convert_arguments (tree typelist, vec<tree, va_gc>
>> **valu
>> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
>> +      if (fndecl && DECL_BUILT_IN (fndecl)
>> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>> +       val = fold (val);
>
>
> This should be cp_fully_fold, and lower down, after all the conversions.

Maybe, it is here more a question of load.  It is again more a thing
to make sure we get rid of useless-typeconversions, and doing basic
constant-value folding (eg for '-' 1 -> -1 etc).

>> -         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
>> +         tree xop0 = fold (op0), xop1 = fold (op1), xresult_type =
>> result_type;
>
>
> This seems wrong.  In fact, the whole short_compare business seems like the
> sort of early folding we want to do away with.
>
>> -  if (TREE_OVERFLOW_P (result)
>> +  op0 = fold_non_dependent_expr (op0);
>> +  op1 = fold_non_dependent_expr (op1);
>> +  STRIP_NOPS (op0);
>> +  STRIP_NOPS (op1);
>> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
>> +  if (TREE_OVERFLOW_P (result_ovl)
>>        && !TREE_OVERFLOW_P (op0)
>>        && !TREE_OVERFLOW_P (op1))
>> -    overflow_warning (location, result);
>> +    overflow_warning (location, result_ovl);
>
>
> What if we don't try to fold for this warning early, and instead give the
> warning later when we're folding?  I suppose that might apply to lots of the
> warnings that we're currently folding early for.

Yes, I tried to mimic prior-behavior for diagnostics.  As otherwise we
might loose diagnostic.  So for now this is the best place IMO to deal
with that.  Of course in follow-up changes we can do as you suggested,
and improve behavior here

>> @@ -7983,7 +7978,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree
>> *pfn)
>>        tree binfo = binfo_or_else (orig_class, fn_class);
>>        *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
>>                        *delta, BINFO_OFFSET (binfo));
>> -      *delta = fold_if_not_in_template (*delta);
>
>
> I think all the calls to fold_if_not_in_template in expand_ptrmemfunc_cst
> should become regular folds.  Or rather, change the build2 to fold_build2.
> This is very much compiler internals, and we should only get here when
> folding anyway.

Ok, we should just deal with in-template case here.

>> -         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
>> +         gcc_assert (val1->v.val_unsigned
>> +                     == (unsigned HOST_WIDE_INT) DWARF2_ADDR_SIZE);
>
>
> We need to fix this warning so this change is unnecessary.

Well, those following changes got already acked by Jeff for 4.9.  I
didn't applied it there as I have my concerns for them too, but I
don't see a good chance to modify shared-parts with C here.  Sadly
does C still do folding on cast-operations

>> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
>> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) ==
>> decl);
>
>
> This change doesn't seem to have anything to do with delayed folding.

It gets raised by delayed folding, so it is required to run.  So as it
gets triggered by it, we need to deal it here (btw pattern seems
absolutely right - issue will be some canonical operations before done
by fold-machinery ...)

>>                       || (gimple_omp_for_kind (for_stmt)
>> -                         == GF_OMP_FOR_KIND_CILKFOR));
>> +                         == GF_OMP_FOR_KIND_CILKFOR)
>> +                     || (gimple_omp_for_kind (for_stmt)
>> +                         == GF_OMP_FOR_KIND_FOR));
>
>
> Nor this one.

Same thing ...

>> +++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
>> +// { dg-options "-Wno-pointer-arith" }
>
>
> There isn't any user-written pointer arithmetic in this testcase, so any
> such warnings are bogus.
>
>> +++ b/gcc/testsuite/g++.dg/warn/Wconversion-pr34389.C
>> @@ -50,5 +50,5 @@ short  mask5(int x)
>>
>>  short  mask6(short x)
>>  {
>> -  return x & -1;
>> +  return x & -1; // { dg-warning "conversion" }
>
>
> This is also a false positive.
>
>> +++ b/gcc/testsuite/g++.dg/warn/skip-1.C
>> -// Check that we don't warn about code that will not be executed.
>> +// For delayed folding we will warn about code that will not be executed
>> too.
>
>
> This is not an improvement.
>
>> @@ -1791,6 +1791,9 @@ evaluate_stmt (gimple stmt)
>>        && (likelyvalue == CONSTANT || is_gimple_call (stmt)
>>           || (gimple_assign_single_p (stmt)
>>               && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
>> +      && (likelyvalue == CONSTANT || is_gimple_call (stmt)
>> +         || (gimple_assign_single_p (stmt)
>> +             && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
>
>
> Merge error?

Ah, this is indeed unrelated.  It is a early fix of Richi about
pointer-alignment.  I will revert it on branch

>> @@ -1956,6 +1956,8 @@ build_complex (tree type, tree real, tree imag)
>>  {
>>    tree t = make_node (COMPLEX_CST);
>>
>> +  real = fold (real);
>> +  imag = fold (imag);
>
>
> I don't think we want to introduce folding into language-independent code
> like here.

Well, issue is that we want to do folding here for '-' CST etc.  so
this place seemed to me like the best place to deal with.  We can
think about other solution here.  I agree that this place is a bit
awkward.

>> @@ -5062,6 +5063,7 @@ output_constructor_bitfield (oc_local_state *local,
>> unsigned int bit_offset)
>>    while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>>          || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>>      local->val = TREE_OPERAND (local->val, 0);
>> +  local->val = fold (local->val);
>
>
> Or here.

Another place dealing with those converts/final simplifications for
constants ... (btw another Jeff acked already IIRC).

> Jason


Kai

^ permalink raw reply	[flat|nested] 38+ messages in thread

* C++ delayed folding branch review
@ 2015-04-24  4:23 Jason Merrill
  2015-04-24 13:46 ` Kai Tietz
  0 siblings, 1 reply; 38+ messages in thread
From: Jason Merrill @ 2015-04-24  4:23 UTC (permalink / raw)
  To: Kai Tietz; +Cc: gcc-patches List

> +  expr = fold (expr);
>    /* This may happen, because for LHS op= RHS we preevaluate
>       RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
>       means we could no longer see the code of the EXPR.  */
>    if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
>      expr = C_MAYBE_CONST_EXPR_EXPR (expr);
>    if (TREE_CODE (expr) == SAVE_EXPR)
> -    expr = TREE_OPERAND (expr, 0);
> +    expr = fold (TREE_OPERAND (expr, 0));

How about moving the first fold after the SAVE_EXPR block, so that we 
only need to call fold once?

> +    case NEGATE_EXPR:
> +    case BIT_NOT_EXPR:
> +    case CONVERT_EXPR:
> +    case VIEW_CONVERT_EXPR:
> +    case NOP_EXPR:
> +    case FIX_TRUNC_EXPR:
> +      {
> +       tree op1 = TREE_OPERAND (expr, 0);
> +       tree fop1 = fold (op1);
> +       if (fop1 && op1 != fop1)
> +         fop1 = fold_build1_loc (loc, TREE_CODE (expr), TREE_TYPE (expr),
> +                                 fop1);

Isn't this redundant with the call to fold above?  If not, it seems that 
the above call should be to *_fully_fold.  I suppose we want an entry 
point defined by both front ends that c-common code can call which does 
full folding of an expression.

> @@ -597,9 +597,9 @@ null_member_pointer_value_p (tree t)
>      return false;
>    else if (TYPE_PTRMEMFUNC_P (type))
>      return (TREE_CODE (t) == CONSTRUCTOR
> -           && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
> +           && integer_zerop (fold (CONSTRUCTOR_ELT (t, 0)->value)));
>    else if (TYPE_PTRDATAMEM_P (type))
> -    return integer_all_onesp (t);
> +    return integer_all_onesp (fold (t));

Calling fold here is wrong; it doesn't handle constexpr, and we should 
have folded before we got here.

>                 warn_logical_operator (loc, code, boolean_type_node,
> -                                      code_orig_arg1, arg1,
> -                                      code_orig_arg2, arg2);
> +                                      code_orig_arg1, fold (arg1),
> +                                      code_orig_arg2, fold (arg2));

I think warn_logical_operator should call back into *_fully_fold. 
Likewise for most similar added calls to fold.

> @@ -7356,8 +7354,13 @@ build_over_call (struct z_candidate *cand, int flags, tsu
> bst_flags_t complain)
>
>    gcc_assert (j <= nargs);
>    nargs = j;
> +  {
> +    tree *fargs = (!nargs ? argarray : (tree *) alloca (nargs * sizeof (tree)))
> ;
> +    for (j = 0; j < nargs; j++)
> +      fargs[j] = fold_non_dependent_expr (argarray[j]);

Similarly, this and build_cxx_call should use cp_fully_fold.

> @@ -7602,7 +7614,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
>        && current_function_decl
>        && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
>      optimize = 1;
> -  fn = fold_if_not_in_template (fn);
>    optimize = optimize_sav;

Since we're removing the fold, we can also remove the changes to "optimize".

> @@ -443,7 +443,7 @@ build_base_path (enum tree_code code,
>
>           t = TREE_TYPE (TYPE_VFIELD (current_class_type));
>           t = build_pointer_type (t);
> -         v_offset = convert (t, current_vtt_parm);
> +         v_offset = fold (convert (t, current_vtt_parm));

fold_convert should work here.

> @@ -576,7 +576,6 @@ build_simple_base_path (tree expr, tree binfo)
>         expr = build3 (COMPONENT_REF,
>                        cp_build_qualified_type (type, type_quals),
>                        expr, field, NULL_TREE);
> -       expr = fold_if_not_in_template (expr);

I don't think we need to remove this fold, since it is part of compiler 
internals rather than something the user wrote.  Really, we should 
represent the base conversion with something like a CONVERT_EXPR and 
only call this function when we want to fold it.  But that can wait for 
a later patch.

> @@ -1046,6 +1048,9 @@ adjust_temp_type (tree type, tree temp)
>  {
>    if (TREE_TYPE (temp) == type)
>      return temp;
> +  STRIP_NOPS (temp);
> +  if (TREE_TYPE (temp) == type)
> +    return temp;
...
>  reduced_constant_expression_p (tree t)
>  {
> +  /* Make sure we remove useless initial NOP_EXPRs.  */
> +  STRIP_NOPS (t);


Where are these NOPs coming from?

> @@ -1082,7 +1087,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
>           && is_dummy_object (x))
>         {
>           x = ctx->object;
> -         x = cp_build_addr_expr (x, tf_warning_or_error);
> +         if (x)
> +           x = cp_build_addr_expr (x, tf_warning_or_error);
> +         else
> +           x = get_nth_callarg (t, i);

This should not be necessary.

> @@ -1765,7 +1780,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>        if (field == part)
>         {
>           if (value)
> -           return value;
> +           return cxx_eval_constant_expression (ctx, value, lval,
> +                                                non_constant_p, overflow_p);
...
> @@ -1849,7 +1865,8 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
>      {
>        tree bitpos = bit_position (field);
>        if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
> -       return value;
> +       return cxx_eval_constant_expression (ctx, value, lval,
> +                                             non_constant_p, overflow_p);

This shouldn't be necessary, either; the elements of the CONSTRUCTOR 
should be fully evaluated already.

> @@ -1560,14 +1570,19 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tre
> e t,
>    location_t loc = EXPR_LOCATION (t);
>    enum tree_code code = TREE_CODE (t);
>    tree type = TREE_TYPE (t);
> -  r = fold_unary_loc (loc, code, type, arg);
> -  if (r == NULL_TREE)
> +  if (TREE_CODE (t) == UNARY_PLUS_EXPR)
> +    r = fold_convert_loc (loc, TREE_TYPE (t), arg);

We don't want to handle UNARY_PLUS_EXPR here; we should handle it like 
NOP_EXPR.  And so you shouldn't need the call to unify_constant.

>      case BIT_NOT_EXPR:
>      case TRUTH_NOT_EXPR:
>      case FIXED_CONVERT_EXPR:
> +    case UNARY_PLUS_EXPR:
>        r = cxx_eval_unary_expression (ctx, t, lval,

So this case should be down with NOP_EXPR.

> @@ -2954,19 +2987,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx,
> tree t,
>    constexpr_ctx new_ctx;
>    tree r = t;
>
> -  if (t == error_mark_node)
> +  if (!t || t == error_mark_node)

Where are null expressions coming from?

>      case SIZEOF_EXPR:
> +      if (processing_template_decl
> +         && (!COMPLETE_TYPE_P (TREE_TYPE (t))
> +         || TREE_CODE (TYPE_SIZE (TREE_TYPE (t))) != INTEGER_CST))
> +       return t;

The type of a SIZEOF_EXPR will always be size_t, so this isn't actually 
accomplishing anything, and should be removed.

> +      /* See this can happen for case like g++.dg/init/static2.C testcase.  */
> +      if (!ctx || !ctx->ctor || (lval && !ctx->object)
> +         || !same_type_ignoring_top_level_qualifiers_p
> +              (TREE_TYPE (t), TREE_TYPE (ctx->ctor))
> +         || CONSTRUCTOR_NELTS (ctx->ctor) != 0)
> +       {
> +         *non_constant_p = true;
> +         break;
> +       }

Why can this happen on the branch but not on trunk?  I think the problem 
is elsewhere.

>      case NOP_EXPR:
>        {
>         tree oldop = TREE_OPERAND (t, 0);
> +       if (TREE_CODE (t) == NOP_EXPR && TREE_TYPE (t) == TREE_TYPE (oldop) && TREE_OVERFLOW_P (oldop))
> +         {
> +           if (!ctx->quiet)
> +             permerror (input_location, "overflow in constant expression");
> +           /* If we're being permissive (and are in an enforcing
> +               context), ignore the overflow.  */
> +           if (!flag_permissive)
> +             *overflow_p = true;
> +           *non_constant_p = true;
> +
> +           return t;
> +         }

This doesn't seem like the right place to handle this; why didn't we 
diagnose the overflow when it happened?

>  maybe_constant_init (tree t, tree decl)
>  {
> +  if (!t)
> +    return t;

Where are null initializers coming from?

>      case MINUS_EXPR:
>        /* -- a subtraction where both operands are pointers.   */
>        if (TYPE_PTR_P (TREE_OPERAND (t, 0))
> -          && TYPE_PTR_P (TREE_OPERAND (t, 1)))
> +          && TYPE_PTR_P (TREE_OPERAND (t, 1))
> +         && TREE_OPERAND (t, 0) != TREE_OPERAND (t, 1))

Why?  From where are we getting a pointer subtracted from itself?

That said, we should probably just remove this case and the next, as 
they are obsolete.  I'll remove them on the trunk.

> +static tree
> +cp_fold (tree x, hash_map<tree, tree> *fold_hash)
> +{
....

I still think we need a hybrid of this and the constexpr code: it isn't 
full folding if we aren't doing constexpr evaluation.  But we can't just 
use maybe_constant_value because that only folds C++ 
constant-expressions, and we want to fold more things than that.  I 
suppose one simple approach for now would be to call 
maybe_constant_value from cp_fold.

> @@ -614,9 +614,13 @@ cp_fold_convert (tree type, tree expr)
>      }
>    else
>      {
> -      conv = fold_convert (type, expr);
> +      if (TREE_CODE (expr) == INTEGER_CST)
> +        conv = fold_convert (type, expr);
> +      else
> +        conv = convert (type, expr);

Why?  If we're calling cp_fold_convert in a place where we don't want to 
fold, we should stop calling it rather than change it.

>  cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>  {
> -  tree result;
> +  tree result, ret;
>
>    if (TREE_TYPE (expr) == type)
>      return expr;
>
> -  result = cp_convert (type, expr, complain);
> +  result = ret = cp_convert (type, expr, complain);
>
>    if ((complain & tf_warning)
>        && c_inhibit_evaluation_warnings == 0)
> @@ -652,6 +656,7 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>        tree stripped = folded;
>        tree folded_result
>         = folded != expr ? cp_convert (type, folded, complain) : result;
> +      folded_result = fold (folded_result);
>
>        /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
>          NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
> @@ -663,7 +668,7 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
>                                         folded_result);
>      }
>
> -  return result;
> +  return ret;

Why introduce the "ret" variable?  It doesn't seem to do anything 
different from "result".  And instead of the added fold, maybe change 
the cp_convert on the previous line to cp_fold_convert?

> @@ -1535,8 +1538,10 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
> +  tree expr_folded = maybe_constant_value (expr);
>
> -  if (expr == null_node
> +  STRIP_NOPS (expr_folded);
> +  if (expr_folded == null_node

We shouldn't need to fold to check for null_node, it only occurs when 
explicitly written.  And we don't want to fold before calling 
null_ptr_cst_p, since in C++11 only a literal 0 is a null pointer 
constant.  For C++98 we already fold in null_ptr_cst_p.

> @@ -8502,16 +8502,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> +  /* We need to do fully folding to determine if we have VLA, or not.  */
> +  tree size_constant = maybe_constant_value (size);

Why is this needed?  We already call maybe_constant_value earlier in 
compute_array_index_type.

> -      itype = fold (itype);
> +      itype = maybe_constant_value (itype);
> -               itype = variable_size (fold (newitype));
> +               itype = variable_size (maybe_constant_value (newitype));

Maybe these should use cp_fully_fold?

> @@ -13090,6 +13092,8 @@ build_enumerator (tree name, tree value, tree enumtype, location_t loc)
> +  if (value)
> +    value = maybe_constant_value (value);

This seems unnecessary, since we call cxx_constant_value below.

>               value = cxx_constant_value (value);
> +             STRIP_NOPS (value);

The only time a constant result should have a NOP_EXPR around it is if 
it isn't really constant.  Why do you want to strip that?

> -          value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
> +          value = fold (convert (ENUM_UNDERLYING_TYPE (enumtype), value));

fold_convert again.

> @@ -188,9 +188,9 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
> -    init = convert (type, nullptr_node);
> +    init = fold (convert (type, nullptr_node));

fold_convert

> @@ -783,7 +783,8 @@ perform_member_init (tree member, tree init)
> +      if (init)
> +       init = fold (init);

Why fold here?  This doesn't seem like a place that needs early folding.

> @@ -6480,7 +6480,8 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
> -      *init_index = cp_parser_expression (parser);
> +      *init_index = cp_parser_expression (parser);
> +      *init_index = maybe_constant_value (*init_index);
...
> +      length_index = maybe_constant_value (length_index);
...
> +         stride = maybe_constant_value (stride);

Why fold here, rather than later when something really wants a constant? 
  If that ever actually occurs?

> +  /* For offsetof and declaration of types we need
> +     constant integeral values.
> +     Also we meed to fold for negative constants so that diagnostic in
> +     c-family/c-common.c doesn't fail for array-bounds.  */
> +  if (for_offsetof || decltype_p
> +      || (TREE_CODE (index) == NEGATE_EXPR && TREE_CODE (TREE_OPERAND (index, 0)) == INTEGER_CST))
> +    index = maybe_constant_value (index);

Likewise.  For offsetof we should either use OFFSETOF_EXPR until late 
folding, or fold in offsetof evaluation.  I don't know why decltype 
would need anything special.  And for diagnostics we should be folding 
closer to the diagnostic.

> @@ -9876,6 +9888,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
> +       expr = maybe_constant_value (expr);

This seems redundant with the call to cxx_constant_value in case_conversion.

> @@ -12190,6 +12204,10 @@ cp_parser_static_assert(cp_parser *parser, bool member_p)
> +  /* Make sure we folded it completely before doing trying to get
> +     constant value.  */
> +  condition = fold_non_dependent_expr (condition);

This shouldn't be necessary; if the constexpr code needs to do more 
folding, that should be fixed.

> @@ -16081,6 +16099,7 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
> +      value = maybe_constant_value (value);

This seems redundant with the call to cxx_constant_value in 
build_enumerator.

> +             width = maybe_constant_value (width);

This seems redundant with the call to cxx_constant_value in 
check_bitfield_decl.

And so on.  It seems like you added maybe_constant_value after every 
occurrence of cp_parser_constant_expression, and I suspect that few are 
actually needed, and the ones that are should go closer to the code that 
really needs a constant.  I'd prefer to avoid calling it at all in parser.c.

> @@ -449,7 +449,7 @@ build_aggr_init_expr (tree type, tree init)
> -    return convert (type, init);
> +    return fold (convert (type, init));

fold_convert

> @@ -3394,6 +3394,8 @@ handle_init_priority_attribute (tree* node,
> +  if (initp_expr)
> +    initp_expr = maybe_constant_value (initp_expr);

Let's use cxx_constant_value instead of this and the non-constant 
diagnostic just below.

> @@ -3371,7 +3367,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function,
> -      e2 = fold_convert (TREE_TYPE (e3), e2);
> +      e2 = fold (convert (TREE_TYPE (e3), e2));

Why?

> @@ -3667,6 +3663,10 @@ convert_arguments (tree typelist, vec<tree, va_gc> **valu
> +      /* For BUILT_IN_NORMAL we want to fold constants.  */
> +      if (fndecl && DECL_BUILT_IN (fndecl)
> +         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> +       val = fold (val);

This should be cp_fully_fold, and lower down, after all the conversions.

> -         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
> +         tree xop0 = fold (op0), xop1 = fold (op1), xresult_type = result_type;

This seems wrong.  In fact, the whole short_compare business seems like 
the sort of early folding we want to do away with.

> -  if (TREE_OVERFLOW_P (result)
> +  op0 = fold_non_dependent_expr (op0);
> +  op1 = fold_non_dependent_expr (op1);
> +  STRIP_NOPS (op0);
> +  STRIP_NOPS (op1);
> +  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
> +  if (TREE_OVERFLOW_P (result_ovl)
>        && !TREE_OVERFLOW_P (op0)
>        && !TREE_OVERFLOW_P (op1))
> -    overflow_warning (location, result);
> +    overflow_warning (location, result_ovl);

What if we don't try to fold for this warning early, and instead give 
the warning later when we're folding?  I suppose that might apply to 
lots of the warnings that we're currently folding early for.

> @@ -7983,7 +7978,6 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
>        tree binfo = binfo_or_else (orig_class, fn_class);
>        *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
>                        *delta, BINFO_OFFSET (binfo));
> -      *delta = fold_if_not_in_template (*delta);

I think all the calls to fold_if_not_in_template in 
expand_ptrmemfunc_cst should become regular folds.  Or rather, change 
the build2 to fold_build2.  This is very much compiler internals, and we 
should only get here when folding anyway.

> -         gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
> +         gcc_assert (val1->v.val_unsigned
> +                     == (unsigned HOST_WIDE_INT) DWARF2_ADDR_SIZE);

We need to fix this warning so this change is unnecessary.

> -      gcc_assert (TREE_OPERAND (t, 0) == decl);
> +      gcc_assert (TREE_OPERAND (t, 0) == decl || TREE_OPERAND (t, 1) == decl);

This change doesn't seem to have anything to do with delayed folding.

>                       || (gimple_omp_for_kind (for_stmt)
> -                         == GF_OMP_FOR_KIND_CILKFOR));
> +                         == GF_OMP_FOR_KIND_CILKFOR)
> +                     || (gimple_omp_for_kind (for_stmt)
> +                         == GF_OMP_FOR_KIND_FOR));

Nor this one.

> +++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
> +// { dg-options "-Wno-pointer-arith" }

There isn't any user-written pointer arithmetic in this testcase, so any 
such warnings are bogus.

> +++ b/gcc/testsuite/g++.dg/warn/Wconversion-pr34389.C
> @@ -50,5 +50,5 @@ short  mask5(int x)
>
>  short  mask6(short x)
>  {
> -  return x & -1;
> +  return x & -1; // { dg-warning "conversion" }

This is also a false positive.

> +++ b/gcc/testsuite/g++.dg/warn/skip-1.C
> -// Check that we don't warn about code that will not be executed.
> +// For delayed folding we will warn about code that will not be executed too.

This is not an improvement.

> @@ -1791,6 +1791,9 @@ evaluate_stmt (gimple stmt)
>        && (likelyvalue == CONSTANT || is_gimple_call (stmt)
>           || (gimple_assign_single_p (stmt)
>               && gimple_assign_rhs_code (stmt) == ADDR_EXPR))
> +      && (likelyvalue == CONSTANT || is_gimple_call (stmt)
> +         || (gimple_assign_single_p (stmt)
> +             && gimple_assign_rhs_code (stmt) == ADDR_EXPR))

Merge error?

> @@ -1956,6 +1956,8 @@ build_complex (tree type, tree real, tree imag)
>  {
>    tree t = make_node (COMPLEX_CST);
>
> +  real = fold (real);
> +  imag = fold (imag);

I don't think we want to introduce folding into language-independent 
code like here.

> @@ -5062,6 +5063,7 @@ output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset)
>    while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
>          || TREE_CODE (local->val) == NON_LVALUE_EXPR)
>      local->val = TREE_OPERAND (local->val, 0);
> +  local->val = fold (local->val);

Or here.

Jason

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2015-08-28 10:15 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-12  5:41 C++ delayed folding branch review Jason Merrill
2015-06-12 16:17 ` Kai Tietz
2015-06-13  7:58   ` Jason Merrill
2015-07-27 19:01     ` Jason Merrill
2015-07-28  2:40       ` Kai Tietz
2015-07-28 20:35         ` Kai Tietz
2015-07-29 18:48           ` Jason Merrill
2015-07-29 23:03             ` Kai Tietz
2015-07-30 14:40               ` Kai Tietz
2015-07-30 18:41               ` Jason Merrill
2015-07-30 21:33                 ` Kai Tietz
2015-07-31  0:43                   ` Jason Merrill
2015-07-31  7:08                     ` Jeff Law
2015-07-31 23:00                     ` Kai Tietz
2015-08-03  3:49                       ` Jason Merrill
2015-08-03  9:42                         ` Kai Tietz
2015-08-03 15:39                           ` Jason Merrill
2015-08-24  7:20                             ` Kai Tietz
2015-08-27  2:57                               ` Jason Merrill
2015-08-27 10:54                                 ` Kai Tietz
2015-08-27 13:35                                   ` Jason Merrill
2015-08-27 13:44                                     ` Kai Tietz
2015-08-27 18:15                                       ` Kai Tietz
2015-08-28  3:03                                         ` Jason Merrill
2015-08-28  7:43                                           ` Kai Tietz
2015-08-28 11:18                                             ` Kai Tietz
2015-08-28  2:12                                       ` Jason Merrill
2015-07-31  4:00                 ` Jeff Law
2015-07-31 16:26                   ` Jason Merrill
2015-07-31 16:43                     ` Kai Tietz
2015-07-31 16:52                       ` Jakub Jelinek
2015-07-31 16:53                         ` Jason Merrill
2015-07-31 21:31                           ` Kai Tietz
  -- strict thread matches above, loose matches on Subject: below --
2015-04-24  4:23 Jason Merrill
2015-04-24 13:46 ` Kai Tietz
2015-04-24 18:25   ` Jason Merrill
2015-04-28 12:06     ` Kai Tietz
2015-04-28 13:57       ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).