C++ delayed folding branch review
Jason Merrill
jason@redhat.com
Thu Jul 30 18:41:00 GMT 2015
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
More information about the Gcc-patches
mailing list