On 08/08/2017 03:18 PM, Richard Biener wrote:
> On Tue, Aug 8, 2017 at 1:47 PM, Martin Liška <mli...@suse.cz> wrote:
>> On 11/09/2016 11:22 AM, Richard Biener wrote:
>>> On Fri, Nov 4, 2016 at 2:33 PM, Martin Liška <mli...@suse.cz> wrote:
>>>> On 11/03/2016 02:00 PM, Jan Hubicka wrote:
>>>>>> On 11/03/2016 01:12 PM, Martin Liška wrote:
>>>>>>> +  tree init = DECL_INITIAL (decl);
>>>>>>> +  if (init
>>>>>>> +      && TREE_READONLY (decl)
>>>>>>> +      && can_convert_ctor_to_string_cst (init))
>>>>>>> +    DECL_INITIAL (decl) = build_string_cst_from_ctor (init);
>>>>>>
>>>>>> I'd merge these two new functions since they're only ever called
>>>>>> together. We'd then have something like
>>>>>>
>>>>>> if (init && TREE_READONLY (decl))
>>>>>>   init = convert_ctor_to_string_cst (init);
>>>>>> if (init)
>>>>>>   DECL_INITIAL (decl) = init;
>>>>
>>>> Done.
>>>>
>>>>>>
>>>>>> I'll defer to Jan on whether finalize_decl seems like a good place
>>>>>> to do this.
>>>>>
>>>>> I think finalize_decl may be bit too early because frontends may expects 
>>>>> the
>>>>> ctors to be in a way they produced them.  We only want to convert those 
>>>>> arrays
>>>>> seen by middle-end so I would move the logic to varpool_node::analyze
>>>>>
>>>>> Otherwise the patch seems fine to me.
>>>>>
>>>>> Honza
>>>>>>
>>>>>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple.c 
>>>>>>> b/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple.c
>>>>>>> index 283bd1c..b2d1fd5 100644
>>>>>>> --- a/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple.c
>>>>>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple.c
>>>>>>> @@ -4,12 +4,15 @@
>>>>>>> char *buffer1;
>>>>>>> char *buffer2;
>>>>>>>
>>>>>>> +const char global[] = {'a', 'b', 'c', 'd', '\0'};
>>>>>>> +
>>>>>>> #define SIZE 1000
>>>>>>>
>>>>>>> int
>>>>>>> main (void)
>>>>>>> {
>>>>>>>   const char* const foo1 = "hello world";
>>>>>>> +  const char local[] = "abcd";
>>>>>>>
>>>>>>>   buffer1 = __builtin_malloc (SIZE);
>>>>>>>   __builtin_strcpy (buffer1, foo1);
>>>>>>> @@ -45,6 +48,10 @@ main (void)
>>>>>>>     __builtin_abort ();
>>>>>>>   if (__builtin_memchr (foo1, null, 12) != foo1 + 11)
>>>>>>>     __builtin_abort ();
>>>>>>> +  if (__builtin_memchr (global, null, 5) == 0)
>>>>>>> +    __builtin_abort ();
>>>>>>> +  if (__builtin_memchr (local, null, 5) == 0)
>>>>>>> +    __builtin_abort ();
>>>>>>
>>>>>> How is that a meaningful test? This seems to work even with an
>>>>>> unpatched gcc. I'd have expected something that shows a benefit for
>>>>>> doing this conversion, and maybe also a test that shows it isn't
>>>>>> done in cases where it's not allowed.
>>>>
>>>> It's meaningful as it scans that there's no __builtin_memchr in optimized 
>>>> dump.
>>>> I'm adding new tests that does the opposite test.
>>>>
>>>>>>
>>>>>>> tree
>>>>>>> -build_string_literal (int len, const char *str)
>>>>>>> +build_string_literal (int len, const char *str, bool build_addr_expr)
>>>>>>
>>>>>> New arguments should be documented in the function comment.
>>>>
>>>> Yep, improved.
>>>>
>>>>>>
>>>>>>> +/* Return TRUE when CTOR can be converted to a string constant.  */
>>>>>>
>>>>>> "if", not "when".
>>>>
>>>> Done.
>>>>
>>>>>>
>>>>>>> +  unsigned HOST_WIDE_INT elements = CONSTRUCTOR_NELTS (ctor);
>>>>>>> +  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, key, value)
>>>>>>> +    {
>>>>>>> +      if (key == NULL_TREE
>>>>>>> +     || TREE_CODE (key) != INTEGER_CST
>>>>>>> +     || !tree_fits_uhwi_p (value)
>>>>>>> +     || !useless_type_conversion_p (TREE_TYPE (value), char_type_node))
>>>>>>> +   return false;
>>>>>>
>>>>>> Shouldn't all elements have the same type, or do you really have to
>>>>>> call useless_type_conversion in a loop?
>>>>>>
>>>>>>> +      /* Allow zero character just at the end of a string.  */
>>>>>>> +      if (integer_zerop (value))
>>>>>>> +   return idx == elements - 1;
>>>>>>
>>>>>> Don't you also have to explicitly check it's there?
>>>>>>
>>>>>>
>>>>>> Bernd
>>>>
>>>>
>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>>
>>> I'm curious about the
>>>
>>> @@ -1495,7 +1495,8 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
>>>         {
>>>           if (!TREE_STATIC (decl))
>>>             {
>>> -             DECL_INITIAL (decl) = NULL_TREE;
>>> +             if (!TREE_READONLY (decl) || TREE_CODE (init) != STRING_CST)
>>> +               DECL_INITIAL (decl) = NULL_TREE;
>>>               init = build2 (INIT_EXPR, void_type_node, decl, init);
>>>               gimplify_and_add (init, seq_p);
>>>               ggc_free (init);
>>>
>>> change.  Why keep DECL_INITIAL if you build a INIT_EXPR anyway?
>>>
>>> @@ -4438,6 +4439,19 @@ gimplify_init_constructor (tree *expr_p,
>>> gimple_seq *pre_p, gimple_seq *post_p,
>>>             break;
>>>           }
>>>
>>> +       /* Replace a ctor with a string constant with possible.  */
>>> +       if (TREE_READONLY (object)
>>> +           && VAR_P (object))
>>> +         {
>>> +           tree string_ctor = convert_ctor_to_string_cst (ctor);
>>> +           if (string_ctor)
>>> +             {
>>> +               TREE_OPERAND (*expr_p, 1) = string_ctor;
>>> +               DECL_INITIAL (object) = string_ctor;
>>> +               break;
>>> +             }
>>> +         }
>>> +
>>>         /* Fetch information about the constructor to direct later 
>>> processing.
>>>            We might want to make static versions of it in various cases, and
>>>            can only do so if it known to be a valid constant initializer.  
>>> */
>>>
>>> hmm, so both these hunks will end up keeping a DECL_INITIAL
>>> for non-static local consts?  Usually we end up with
>>>
>>> main ()
>>> {
>>>   const char local[5];
>>>
>>>   <bb 2>:
>>>   local = "abcd";
>>>
>>> here.  So you keep DECL_INITIAL for folding?
>>>
>>> I believe we should create CONST_DECLs for the above (and make
>>> CONST_DECLs first-class
>>> symtab citizens), thus avoid runtime stack initialization for the
>>> above and instead emit
>>> "abcd" to the constant pool?
>>
>> Hi Richi.
>>
>> I've just returned to this in order to resolve long pending unfinished stuff.
>> I have couple of questions:
>>
>> a) what should create a CONST_DECL, a FE or gimplifier when it identifies 
>> that
>> it can be converted to CONST_DECL?
> 
> The gimplifier (prototype patches of mine did it that way when trying
> to get rid of
> &STRING_CST).
> 
>> b) Why do we need to put such local variables to symtab?
> 
> We don't need to, but we eventually should?
> 
>> c) Do we have a target that uses CONST_DECL for such (or similar) purpose?
> 
> Not sure.  gimplify_init_constructor ends up with .LC0* on for example aarch64
> for initializers of arrays for example.
> 
> Attached old &STRING_CST -> &CONST_DECL gimplification patch (no
> longer applies).

Can you please Richi send me the patch in unified format so that I can apply the
rejected hunks. Looks one just needs to put it into gimple-expr.c.

Thanks,
Martin

> 
> Richard.
> 
>> Thanks,
>> Martin
>>
>>>
>>> +  /* Skip constructors with a hole.  */
>>> +  if (CONSTRUCTOR_NELTS (ctor) != ctor_length)
>>> +    return false;
>>>
>>> not sure if that's maybe too clever ;)
>>>
>>> +  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, key, value)
>>> +    {
>>> +      if (key == NULL_TREE
>>> +         || !tree_fits_uhwi_p (key)
>>> +         || !tree_fits_uhwi_p (value))
>>> +       return false;
>>>
>>> I think key == NULL is very well valid (you are not using it...).  I'd
>>> instead do
>>>
>>>      if (key && compare_tree_int (key, idx) != 0)
>>>        return false;
>>>
>>> for the hole check.  value should always fit uhwi given the earlier
>>> element type check.
>>>
>>> +tree
>>> +convert_ctor_to_string_cst (tree ctor)
>>> +{
>>> +  if (!can_convert_ctor_to_string_cst (ctor))
>>> +    return NULL_TREE;
>>> +
>>> +  unsigned HOST_WIDE_INT idx;
>>> +  tree value;
>>> +  vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
>>> +  char *str = XNEWVEC (char, elts->length ());
>>> +
>>> +  FOR_EACH_CONSTRUCTOR_VALUE (elts, idx, value)
>>> +    str[idx] = (char)tree_to_uhwi (value);
>>> +
>>> +  tree init = build_string_literal (elts->length (),
>>> +                                   ggc_alloc_string (str, elts->length ()),
>>> +                                   false);
>>> +  free (str);
>>>
>>> why alloc str on the heap, copy it to gc and the copy it again?
>>> That is, you can pass 'str' to build_string_literal directly I think.
>>>
>>> In fact as you are refactoring build_string_literal please
>>> refactor build_string into a build_string_raw taking just 'len'
>>> (thus leaving out the actual string initialization apart from
>>> 'appending' '\0') and then avoid the heap allocation.
>>>
>>> Refactor build_string_literal to take a tree STRING_CST
>>> and build_string_literal_addr to build it's address.
>>>
>>> Thanks,
>>> Richard.
>>>
>>>
>>>
>>>
>>>> Martin
>>>>
>>

Reply via email to