diff mbox series

expr.cc: Optimize if char array initialization consists of all zeros

Message ID 8f71494f-c3c7-e782-6e57-281eb4c8a393@yahoo.co.jp
State New
Headers show
Series expr.cc: Optimize if char array initialization consists of all zeros | expand

Commit Message

Takayuki 'January June' Suwa May 31, 2022, 3:35 a.m. UTC
Hi all,

In some targets, initialization code for char array may be split into two
parts even if the initialization consists of all zeros:

/* example */
extern void foo(char*);
void test(void) {
   char a[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   foo(a);
}

;; Xtensa (xtensa-lx106)
.LC0:
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.zero   246
test:
	movi	a9, 0x110
	sub	sp, sp, a9
	l32r	a3, .LC1
	movi.n	a4, 0xa
	mov.n	a2, sp
	s32i	a0, sp, 268
	call0	memcpy
	movi	a4, 0xf6
	movi.n	a3, 0
	addi.n	a2, sp, 10
	call0	memset
	mov.n	a2, sp
	call0	foo
	l32i	a0, sp, 268
	movi	a9, 0x110
	add.n	sp, sp, a9
	ret.n

;; H8/300 (-mh -mint32)
.LC0:
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.string ""
	.zero   246
_test:
	sub.l	#256,er7
	sub.l	er2,er2
	add.b	#10,r2l
	mov.l	#.LC0,er1
	mov.l	er7,er0
	jsr	@_memcpy
	sub.l	er2,er2
	add.b	#246,r2l
	sub.l	er1,er1
	sub.l	er0,er0
	add.b	#10,r0l
	add.l	er7,er0
	jsr	@_memset
	mov.l	er7,er0
	jsr	@_foo
	add.l	#256,er7
	rts

i386 target (both 32 and 64bit) does not show such behavior.

     gcc/ChangeLog:

	* expr.cc (store_expr): Add check if the initialization content
	consists of all zeros.
---
  gcc/expr.cc | 7 +++++++
  1 file changed, 7 insertions(+)

Comments

Richard Biener June 1, 2022, 8:57 a.m. UTC | #1
On Tue, May 31, 2022 at 5:37 AM Takayuki 'January June' Suwa via
Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>
> Hi all,
>
> In some targets, initialization code for char array may be split into two
> parts even if the initialization consists of all zeros:
>
> /* example */
> extern void foo(char*);
> void test(void) {
>    char a[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
>    foo(a);
> }
>
> ;; Xtensa (xtensa-lx106)
> .LC0:
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .zero   246
> test:
>         movi    a9, 0x110
>         sub     sp, sp, a9
>         l32r    a3, .LC1
>         movi.n  a4, 0xa
>         mov.n   a2, sp
>         s32i    a0, sp, 268
>         call0   memcpy
>         movi    a4, 0xf6
>         movi.n  a3, 0
>         addi.n  a2, sp, 10
>         call0   memset
>         mov.n   a2, sp
>         call0   foo
>         l32i    a0, sp, 268
>         movi    a9, 0x110
>         add.n   sp, sp, a9
>         ret.n
>
> ;; H8/300 (-mh -mint32)
> .LC0:
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .string ""
>         .zero   246
> _test:
>         sub.l   #256,er7
>         sub.l   er2,er2
>         add.b   #10,r2l
>         mov.l   #.LC0,er1
>         mov.l   er7,er0
>         jsr     @_memcpy
>         sub.l   er2,er2
>         add.b   #246,r2l
>         sub.l   er1,er1
>         sub.l   er0,er0
>         add.b   #10,r0l
>         add.l   er7,er0
>         jsr     @_memset
>         mov.l   er7,er0
>         jsr     @_foo
>         add.l   #256,er7
>         rts
>
> i386 target (both 32 and 64bit) does not show such behavior.
>
>      gcc/ChangeLog:
>
>         * expr.cc (store_expr): Add check if the initialization content
>         consists of all zeros.
> ---
>   gcc/expr.cc | 7 +++++++
>   1 file changed, 7 insertions(+)
>
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index 7197996cec7..f94310dc7b9 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -6015,6 +6015,7 @@ store_expr (tree exp, rtx target, int call_param_p,
>         rtx dest_mem;
>         tree str = TREE_CODE (exp) == STRING_CST
>                  ? exp : TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
> +      char ch;
>
>         exp_len = int_expr_size (exp);
>         if (exp_len <= 0)
> @@ -6032,6 +6033,12 @@ store_expr (tree exp, rtx target, int call_param_p,
>         }
>
>         str_copy_len = TREE_STRING_LENGTH (str);
> +      /* If str contains only zeroes, no need to store to target.  */
> +      ch = 0;
> +      for (HOST_WIDE_INT i = 0; i < str_copy_len; ++i)
> +       ch |= TREE_STRING_POINTER (str)[i];
> +      if (ch == 0)
> +       str_copy_len = 0;

Not sure if I decipher the current code correctly but maybe we instead
want to prune str_copy_len from the end for trailing \0 bytes instead of
just special-casing all-zero initializers?

>         if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
>         {
>           str_copy_len += STORE_MAX_PIECES - 1;
> --
> 2.20.1
Jeff Law June 26, 2022, 7:34 p.m. UTC | #2
On 5/30/2022 9:35 PM, Takayuki 'January June' Suwa via Gcc-patches wrote:
> Hi all,
>
> In some targets, initialization code for char array may be split into two
> parts even if the initialization consists of all zeros:
>
> /* example */
> extern void foo(char*);
> void test(void) {
>   char a[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
>   foo(a);
> }
>
> ;; Xtensa (xtensa-lx106)
> .LC0:
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .zero   246
> test:
>     movi    a9, 0x110
>     sub    sp, sp, a9
>     l32r    a3, .LC1
>     movi.n    a4, 0xa
>     mov.n    a2, sp
>     s32i    a0, sp, 268
>     call0    memcpy
>     movi    a4, 0xf6
>     movi.n    a3, 0
>     addi.n    a2, sp, 10
>     call0    memset
>     mov.n    a2, sp
>     call0    foo
>     l32i    a0, sp, 268
>     movi    a9, 0x110
>     add.n    sp, sp, a9
>     ret.n
>
> ;; H8/300 (-mh -mint32)
> .LC0:
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .string ""
>     .zero   246
> _test:
>     sub.l    #256,er7
>     sub.l    er2,er2
>     add.b    #10,r2l
>     mov.l    #.LC0,er1
>     mov.l    er7,er0
>     jsr    @_memcpy
>     sub.l    er2,er2
>     add.b    #246,r2l
>     sub.l    er1,er1
>     sub.l    er0,er0
>     add.b    #10,r0l
>     add.l    er7,er0
>     jsr    @_memset
>     mov.l    er7,er0
>     jsr    @_foo
>     add.l    #256,er7
>     rts
>
> i386 target (both 32 and 64bit) does not show such behavior.
>
>     gcc/ChangeLog:
>
>     * expr.cc (store_expr): Add check if the initialization content
>     consists of all zeros.
It's not entirely clear what you're trying to accomplish.  Is it the 
.zero which allocates space in the .rodata you're trying to remove? If 
so, it looks like that is already addressed on the trunk to me (I 
checked H8 with and without optimization).

jeff
diff mbox series

Patch

diff --git a/gcc/expr.cc b/gcc/expr.cc
index 7197996cec7..f94310dc7b9 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6015,6 +6015,7 @@  store_expr (tree exp, rtx target, int call_param_p,
        rtx dest_mem;
        tree str = TREE_CODE (exp) == STRING_CST
  		 ? exp : TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+      char ch;

        exp_len = int_expr_size (exp);
        if (exp_len <= 0)
@@ -6032,6 +6033,12 @@  store_expr (tree exp, rtx target, int call_param_p,
  	}

        str_copy_len = TREE_STRING_LENGTH (str);
+      /* If str contains only zeroes, no need to store to target.  */
+      ch = 0;
+      for (HOST_WIDE_INT i = 0; i < str_copy_len; ++i)
+	ch |= TREE_STRING_POINTER (str)[i];
+      if (ch == 0)
+	str_copy_len = 0;
        if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
  	{
  	  str_copy_len += STORE_MAX_PIECES - 1;