https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81435
Bug ID: 81435 Summary: missing strlen optimization for strcat past the beginning of clear array Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- The tree-ssa-strlen pass is able to track the lengths of some dynamically created and modified strings by calls to strcpy and strcat. But in at least one case where the strcat optimization could achieve parity with strcpy it does not: when strcat is called to copy a string of known length pasty the beginning of a zeroed-out buffer as is done in function g1() below the same optimization done for strcpy is not done, and the pass loses track of the length of the appended (copied) string. $ cat a.c && gcc -O2 -S -Wall -Wextra -fdump-tree-strlen=/dev/stdout a.c void f0 (void) { char a[4] = "234"; char b[5] = "1"; __builtin_strcpy (b + 1, a); if (__builtin_strlen (b + 1) != 3) // optimized into 3 __builtin_abort (); } void f1 (void) { char a[4] = "234"; char b[5] = ""; __builtin_strcpy (b + 1, a); if (__builtin_strlen (b + 1) != 3) // optimized into 3 __builtin_abort (); } void g0 (void) { char a[4] = "234"; char b[5] = "1"; __builtin_strcat (b + 1, a); if (__builtin_strlen (b + 1) != 3) // optimized into 3 __builtin_abort (); } void g1 (void) { char a[4] = "234"; char b[5] = ""; __builtin_strcat (b + 1, a); if (__builtin_strlen (b + 1) != 3) // not optimized __builtin_abort (); } ;; Function f0 (f0, funcdef_no=0, decl_uid=1815, cgraph_uid=0, symbol_order=0) f0 () { char b[5]; char a[4]; long unsigned int _1; <bb 2> [100.00%] [count: INV]: a = "234"; b = "1"; __builtin_memcpy (&MEM[(void *)&b + 1B], &a, 4); _1 = 3; if (_1 != 3) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: a ={v} {CLOBBER}; b ={v} {CLOBBER}; return; } ;; Function f1 (f1, funcdef_no=1, decl_uid=1820, cgraph_uid=1, symbol_order=1) f1 () { char b[5]; char a[4]; long unsigned int _1; <bb 2> [100.00%] [count: INV]: a = "234"; b = ""; __builtin_memcpy (&MEM[(void *)&b + 1B], &a, 4); _1 = 3; if (_1 != 3) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: a ={v} {CLOBBER}; b ={v} {CLOBBER}; return; } ;; Function g0 (g0, funcdef_no=2, decl_uid=1825, cgraph_uid=2, symbol_order=2) g0 () { char b[5]; char a[4]; long unsigned int _1; <bb 2> [100.00%] [count: INV]: a = "234"; b = "1"; __builtin_memcpy (&MEM[(void *)&b + 1B], &a, 4); _1 = 3; if (_1 != 3) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: a ={v} {CLOBBER}; b ={v} {CLOBBER}; return; } ;; Function g1 (g1, funcdef_no=3, decl_uid=1830, cgraph_uid=3, symbol_order=3) g1 () { char b[5]; char a[4]; long unsigned int _1; <bb 2> [100.00%] [count: INV]: a = "234"; b = ""; __builtin_strcat (&MEM[(void *)&b + 1B], &a); _1 = __builtin_strlen (&MEM[(void *)&b + 1B]); if (_1 != 3) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: a ={v} {CLOBBER}; b ={v} {CLOBBER}; return; }