On Fri, May 12, 2017 at 08:28:38PM +0000, Joseph Myers wrote: > On Fri, 12 May 2017, Marek Polacek wrote: > > > In the effort of reducing early folding, we should avoid calling > > c_fully_fold > > blithely, except when needed for e.g. initializers. This is a teeny tiny > > step > > Note there are several reasons for early folding in the C front end: at > least (a) cases where logically needed (initializers and other places > where constants are needed), (b) because warnings need a folded > expression, (c) when the expression will go somewhere c_fully_fold does > not recurse inside. Also (d) convert, at least, folds regardless of > whether it's actually necessary. > > There is a case for avoiding (b) by putting the necessary information in > the IR so the warnings can happen later from c_fully_fold, though there > may be other possible approaches. > > > @@ -146,8 +140,7 @@ convert (tree type, tree expr) > > > > case COMPLEX_TYPE: > > /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE > > - and e is not COMPLEX_EXPR, convert_to_complex uses save_expr, > > - but for the C FE c_save_expr needs to be called instead. */ > > + and E is not COMPLEX_EXPR, convert_to_complex uses save_expr. */ > > if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE) > > { > > if (TREE_CODE (e) != COMPLEX_EXPR) > > The point of this comment is to explain why we don't just call > convert_to_complex here (see PR 47150). So with your changes it would > seem appropriate to change c-convert.c back to calling convert_to_complex > here. Thanks for pointing this out! The new version:
Bootstrapped/regtested on x86_64-linux. 2017-05-15 Marek Polacek <pola...@redhat.com> * c-common.c (c_save_expr): Remove. (c_common_truthvalue_conversion): Remove a call to c_save_expr. * c-common.h (c_save_expr): Remove declaration. * c-convert.c (convert): Replace c_save_expr with save_expr. Don't call c_fully_fold. (convert) <case COMPLEX_TYPE>: Remove special handling of COMPLEX_TYPEs. * c-decl.c (grokdeclarator): Replace c_save_expr with save_expr. * c-fold.c (c_fully_fold_internal): Handle SAVE_EXPR. * c-parser.c (c_parser_declaration_or_fndef): Replace c_save_expr with save_expr. (c_parser_conditional_expression): Likewise. * c-tree.h (SAVE_EXPR_FOLDED_P): Define. * c-typeck.c (build_modify_expr): Replace c_save_expr with save_expr. (process_init_element): Likewise. (build_binary_op): Likewise. (handle_omp_array_sections_1): Likewise. diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index ad686d2..f606e94 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -3164,24 +3164,6 @@ c_wrap_maybe_const (tree expr, bool non_const) return expr; } -/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but - for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR - around the SAVE_EXPR if needed so that c_fully_fold does not need - to look inside SAVE_EXPRs. */ - -tree -c_save_expr (tree expr) -{ - bool maybe_const = true; - if (c_dialect_cxx ()) - return save_expr (expr); - expr = c_fully_fold (expr, false, &maybe_const); - expr = save_expr (expr); - if (!maybe_const) - expr = c_wrap_maybe_const (expr, true); - return expr; -} - /* Return whether EXPR is a declaration whose address can never be NULL. */ @@ -3436,7 +3418,7 @@ c_common_truthvalue_conversion (location_t location, tree expr) if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) { - tree t = (in_late_binary_op ? save_expr (expr) : c_save_expr (expr)); + tree t = save_expr (expr); expr = (build_binary_op (EXPR_LOCATION (expr), (TREE_SIDE_EFFECTS (expr) diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h index 9e3982d..3981544 100644 --- gcc/c-family/c-common.h +++ gcc/c-family/c-common.h @@ -836,7 +836,6 @@ extern enum conversion_safety unsafe_conversion_p (location_t, tree, tree, extern bool decl_with_nonnull_addr_p (const_tree); extern tree c_fully_fold (tree, bool, bool *); extern tree c_wrap_maybe_const (tree, bool); -extern tree c_save_expr (tree); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); diff --git gcc/c/c-convert.c gcc/c/c-convert.c index 163feff..b8117b4 100644 --- gcc/c/c-convert.c +++ gcc/c/c-convert.c @@ -111,13 +111,7 @@ convert (tree type, tree expr) && COMPLETE_TYPE_P (type) && do_ubsan_in_current_function ()) { - if (in_late_binary_op) - expr = save_expr (expr); - else - { - expr = c_save_expr (expr); - expr = c_fully_fold (expr, false, NULL); - } + expr = save_expr (expr); tree check = ubsan_instrument_float_cast (loc, type, expr); expr = fold_build1 (FIX_TRUNC_EXPR, type, expr); if (check == NULL_TREE) @@ -145,31 +139,6 @@ convert (tree type, tree expr) goto maybe_fold; case COMPLEX_TYPE: - /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE - and e is not COMPLEX_EXPR, convert_to_complex uses save_expr, - but for the C FE c_save_expr needs to be called instead. */ - if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE) - { - if (TREE_CODE (e) != COMPLEX_EXPR) - { - tree subtype = TREE_TYPE (type); - tree elt_type = TREE_TYPE (TREE_TYPE (e)); - - if (in_late_binary_op) - e = save_expr (e); - else - e = c_save_expr (e); - ret - = fold_build2_loc (loc, COMPLEX_EXPR, type, - convert (subtype, - fold_build1 (REALPART_EXPR, - elt_type, e)), - convert (subtype, - fold_build1 (IMAGPART_EXPR, - elt_type, e))); - goto maybe_fold; - } - } ret = convert_to_complex (type, e); goto maybe_fold; diff --git gcc/c/c-decl.c gcc/c/c-decl.c index b779d37..8ae09c4 100644 --- gcc/c/c-decl.c +++ gcc/c/c-decl.c @@ -6076,7 +6076,7 @@ grokdeclarator (const struct c_declarator *declarator, && do_ubsan_in_current_function ()) { /* Evaluate the array size only once. */ - size = c_save_expr (size); + size = save_expr (size); size = c_fully_fold (size, false, NULL); size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size), ubsan_instrument_vla (loc, size), diff --git gcc/c/c-fold.c gcc/c/c-fold.c index b060d76..1baee44 100644 --- gcc/c/c-fold.c +++ gcc/c/c-fold.c @@ -120,12 +120,11 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, bool unused_p; source_range old_range; - /* Constants, declarations, statements, errors, SAVE_EXPRs and - anything else not counted as an expression cannot usefully be - folded further at this point. */ + /* Constants, declarations, statements, errors, and anything else not + counted as an expression cannot usefully be folded further at this + point. */ if (!IS_EXPR_CODE_CLASS (kind) - || kind == tcc_statement - || code == SAVE_EXPR) + || kind == tcc_statement) return expr; if (IS_EXPR_CODE_CLASS (kind)) @@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, appropriate in any particular case. */ gcc_unreachable (); + case SAVE_EXPR: + /* Make sure to fold the contents of a SAVE_EXPR exactly once. */ + if (!SAVE_EXPR_FOLDED_P (expr)) + { + op0 = TREE_OPERAND (expr, 0); + op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, + maybe_const_itself, for_int_const); + /* Don't wrap the folded tree in a SAVE_EXPR if we don't + have to. */ + if (tree_invariant_p (op0)) + ret = op0; + else + { + TREE_OPERAND (expr, 0) = op0; + SAVE_EXPR_FOLDED_P (expr) = true; + } + } + goto out; + default: /* Various codes may appear through folding built-in functions and their arguments. */ diff --git gcc/c/c-parser.c gcc/c/c-parser.c index 90d2d17..96c0749 100644 --- gcc/c/c-parser.c +++ gcc/c/c-parser.c @@ -1880,7 +1880,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool vm_type = variably_modified_type_p (init_type, NULL_TREE); if (vm_type) - init.value = c_save_expr (init.value); + init.value = save_expr (init.value); finish_init (); specs->typespec_kind = ctsk_typeof; specs->locations[cdw_typedef] = init_loc; @@ -6500,7 +6500,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, e = TREE_OPERAND (e, 1); warn_for_omitted_condop (middle_loc, e); /* Make sure first operand is calculated only once. */ - exp1.value = c_save_expr (default_conversion (cond.value)); + exp1.value = save_expr (default_conversion (cond.value)); if (eptype) exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); exp1.original_type = NULL; diff --git gcc/c/c-tree.h gcc/c/c-tree.h index 8d232a4..42172f8 100644 --- gcc/c/c-tree.h +++ gcc/c/c-tree.h @@ -113,6 +113,10 @@ along with GCC; see the file COPYING3. If not see subexpression meaning it is not a constant expression. */ #define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR)) +/* For a SAVE_EXPR, nonzero if the operand of the SAVE_EXPR has already + been folded. */ +#define SAVE_EXPR_FOLDED_P(EXP) TREE_LANG_FLAG_1 (SAVE_EXPR_CHECK (EXP)) + /* Record parser information about an expression that is irrelevant for code generation alongside a tree representing its value. */ struct c_expr diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c index 6f9909c..1edf521 100644 --- gcc/c/c-typeck.c +++ gcc/c/c-typeck.c @@ -5777,7 +5777,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, that modify LHS. */ if (TREE_SIDE_EFFECTS (rhs)) { - newrhs = in_late_binary_op ? save_expr (rhs) : c_save_expr (rhs); + newrhs = save_expr (rhs); rhseval = newrhs; } newrhs = build_binary_op (location, @@ -9301,7 +9301,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, semantic_type = TREE_TYPE (value.value); value.value = TREE_OPERAND (value.value, 0); } - value.value = c_save_expr (value.value); + value.value = save_expr (value.value); if (semantic_type) value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value.value); @@ -11621,7 +11621,7 @@ build_binary_op (location_t location, enum tree_code code, return error_mark_node; if (first_complex) { - op0 = c_save_expr (op0); + op0 = save_expr (op0); real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR, op0, true); imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR, @@ -11630,7 +11630,7 @@ build_binary_op (location_t location, enum tree_code code, { case MULT_EXPR: case TRUNC_DIV_EXPR: - op1 = c_save_expr (op1); + op1 = save_expr (op1); imag = build2 (resultcode, real_type, imag, op1); /* Fall through. */ case PLUS_EXPR: @@ -11643,7 +11643,7 @@ build_binary_op (location_t location, enum tree_code code, } else { - op1 = c_save_expr (op1); + op1 = save_expr (op1); real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR, op1, true); imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR, @@ -11651,7 +11651,7 @@ build_binary_op (location_t location, enum tree_code code, switch (code) { case MULT_EXPR: - op0 = c_save_expr (op0); + op0 = save_expr (op0); imag = build2 (resultcode, real_type, op0, imag); /* Fall through. */ case PLUS_EXPR: @@ -11835,8 +11835,8 @@ build_binary_op (location_t location, enum tree_code code, && !require_constant_value) { /* OP0 and/or OP1 might have side-effects. */ - op0 = c_save_expr (op0); - op1 = c_save_expr (op1); + op0 = save_expr (op0); + op1 = save_expr (op1); op0 = c_fully_fold (op0, false, NULL); op1 = c_fully_fold (op1, false, NULL); if (doing_div_or_mod && (flag_sanitize & (SANITIZE_DIVIDE @@ -12435,7 +12435,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, /* For [lb:] we will need to evaluate lb more than once. */ if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) { - tree lb = c_save_expr (low_bound); + tree lb = save_expr (low_bound); if (lb != low_bound) { TREE_PURPOSE (t) = lb; @@ -12480,7 +12480,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) types.safe_push (TREE_TYPE (ret)); /* We will need to evaluate lb more than once. */ - tree lb = c_save_expr (low_bound); + tree lb = save_expr (low_bound); if (lb != low_bound) { TREE_PURPOSE (t) = lb; Marek