This backport contains 3 patchs from gcc main stream tree. The commit id of these patchs list as following in the order of time. 0001-tree-ssa-dse.c-initialize_ao_ref_for_dse-Handle-_chk.patch 4a61cf9c62212fd04f21704efc2decffe9544651 0002-tree-ssa-dse.c-initialize_ao_ref_for_dse-Fix-formatt.patch caffb6e56c2914e64e65f3c336b770c178f265a3 0003-tree-ssa-dse.c-initialize_ao_ref_for_dse-Handle-strn.patch 192ece9e15d25fd9b6534b2a8bd271684bf76d38 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp index 3560a1ff2..e9d3c9aab 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp @@ -37,7 +37,7 @@ load_lib c-torture.exp torture-init set-torture-options $C_TORTURE_OPTIONS {{}} $LTO_TORTURE_OPTIONS -set additional_flags "-fno-tree-loop-distribute-patterns -fno-tracer -fno-ipa-ra -fno-inline-functions" +set additional_flags "-fno-tree-dse -fno-tree-loop-distribute-patterns -fno-tracer -fno-ipa-ra -fno-inline-functions" if [istarget "powerpc-*-darwin*"] { lappend additional_flags "-Wl,-multiply_defined,suppress" } diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c index afd07ddd0..40cfa0472 100644 --- a/gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c +++ b/gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c @@ -1,7 +1,7 @@ /* Test whether buffer overflow warnings for __*_chk builtins are emitted properly. */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wno-format -std=gnu99 -ftrack-macro-expansion=0" } */ +/* { dg-options "-O2 -Wno-format -std=gnu99 -ftrack-macro-expansion=0 -fno-tree-dse" } */ // { dg-skip-if "packed attribute missing for t" { "epiphany-*-*" } } extern void abort (void); diff --git a/gcc/testsuite/gcc.dg/memcpy-2.c b/gcc/testsuite/gcc.dg/memcpy-2.c index 7f839d27a..6ad887416 100644 --- a/gcc/testsuite/gcc.dg/memcpy-2.c +++ b/gcc/testsuite/gcc.dg/memcpy-2.c @@ -1,6 +1,6 @@ /* PR middle-end/38454 */ /* { dg-do compile } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -fno-tree-dse" } */ typedef __SIZE_TYPE__ size_t; diff --git a/gcc/testsuite/gcc.dg/pr40340-1.c b/gcc/testsuite/gcc.dg/pr40340-1.c index 8fbb206a2..6307e064c 100644 --- a/gcc/testsuite/gcc.dg/pr40340-1.c +++ b/gcc/testsuite/gcc.dg/pr40340-1.c @@ -1,6 +1,6 @@ /* PR middle-end/40340 */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -Wno-system-headers" } */ +/* { dg-options "-O2 -Wall -Wno-system-headers -fno-tree-dse" } */ #include "pr40340.h" diff --git a/gcc/testsuite/gcc.dg/pr40340-2.c b/gcc/testsuite/gcc.dg/pr40340-2.c index 10083acd1..ea76e1008 100644 --- a/gcc/testsuite/gcc.dg/pr40340-2.c +++ b/gcc/testsuite/gcc.dg/pr40340-2.c @@ -1,6 +1,6 @@ /* PR middle-end/40340 */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -Wno-system-headers" } */ +/* { dg-options "-O2 -Wall -Wno-system-headers -fno-tree-dse" } */ #include "pr40340.h" diff --git a/gcc/testsuite/gcc.dg/pr40340-5.c b/gcc/testsuite/gcc.dg/pr40340-5.c index 0e48a2ca9..99e58f2ab 100644 --- a/gcc/testsuite/gcc.dg/pr40340-5.c +++ b/gcc/testsuite/gcc.dg/pr40340-5.c @@ -1,6 +1,6 @@ /* PR middle-end/40340 */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -Wsystem-headers -g" } */ +/* { dg-options "-O2 -Wall -Wsystem-headers -g -fno-tree-dse" } */ #define TEST3 #include "pr40340.h" diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-37.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-37.c new file mode 100644 index 000000000..56251fc34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-37.c @@ -0,0 +1,60 @@ +/* { dg-options "-O2 -fdump-tree-dse-details -fno-tree-fre" } */ + + +#ifndef SCOPE +#define SCOPE +#endif + +extern void frob (char *); + +void g (char *s) +{ + SCOPE char a[8]; + __builtin_strncpy (a, s, sizeof a); + __builtin_memset (a, 0, sizeof a); + frob (a); +} + +void h (char *s) +{ + SCOPE char a[8]; + __builtin_memset (a, 0, sizeof a); + __builtin_strncpy (a, s, sizeof a); + frob (a); +} + +void i (char *s) +{ + SCOPE char a[8]; + __builtin_strncpy (a, s, sizeof a); + __builtin_memset (a, 0, sizeof a - 5); + frob (a); +} + +void j (char *s) +{ + SCOPE char a[8]; + __builtin_memset (a, 0, sizeof a); + __builtin_strncpy (a, s, sizeof a - 5); + frob (a); +} + +void l (char *s) +{ + SCOPE char a[8]; + __builtin_strncpy (a, s, sizeof a); + __builtin_memset (a + 2, 0, sizeof a - 2); + frob (a); +} + +void m (char *s) +{ + SCOPE char a[8]; + __builtin_memset (a, 0, sizeof a); + __builtin_strncpy (a + 2, s, sizeof a - 2); + frob (a); +} + +/* { dg-final { scan-tree-dump-times "Deleted dead call" 2 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "Trimming statement " 4 "dse1" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-38.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-38.c new file mode 100644 index 000000000..7ae33bfd1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-38.c @@ -0,0 +1,12 @@ +/* { dg-options "-O2 -fdump-tree-dse-details -fno-tree-fre" } */ + + +/* This changes the scope of the destination object and exposes + missed optimizations in DSE. */ +#define SCOPE extern +#include "ssa-dse-37.c" + +/* { dg-final { scan-tree-dump-times "Deleted dead call" 2 "dse1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "Trimming statement " 4 "dse1" { xfail *-*-* } } } */ + + diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index 2fb471b69..b593b0d81 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -100,39 +100,42 @@ initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write) { switch (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))) { - case BUILT_IN_MEMCPY: - case BUILT_IN_MEMMOVE: - case BUILT_IN_MEMSET: - { - tree size = NULL_TREE; - if (gimple_call_num_args (stmt) == 3) - size = gimple_call_arg (stmt, 2); - tree ptr = gimple_call_arg (stmt, 0); - ao_ref_init_from_ptr_and_size (write, ptr, size); - return true; - } + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_MEMSET: + case BUILT_IN_MEMCPY_CHK: + case BUILT_IN_MEMMOVE_CHK: + case BUILT_IN_MEMSET_CHK: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCPY_CHK: + { + tree size = gimple_call_arg (stmt, 2); + tree ptr = gimple_call_arg (stmt, 0); + ao_ref_init_from_ptr_and_size (write, ptr, size); + return true; + } - /* A calloc call can never be dead, but it can make - subsequent stores redundant if they store 0 into - the same memory locations. */ - case BUILT_IN_CALLOC: - { - tree nelem = gimple_call_arg (stmt, 0); - tree selem = gimple_call_arg (stmt, 1); - tree lhs; - if (TREE_CODE (nelem) == INTEGER_CST - && TREE_CODE (selem) == INTEGER_CST - && (lhs = gimple_call_lhs (stmt)) != NULL_TREE) - { - tree size = fold_build2 (MULT_EXPR, TREE_TYPE (nelem), - nelem, selem); - ao_ref_init_from_ptr_and_size (write, lhs, size); - return true; - } - } + /* A calloc call can never be dead, but it can make + subsequent stores redundant if they store 0 into + the same memory locations. */ + case BUILT_IN_CALLOC: + { + tree nelem = gimple_call_arg (stmt, 0); + tree selem = gimple_call_arg (stmt, 1); + tree lhs; + if (TREE_CODE (nelem) == INTEGER_CST + && TREE_CODE (selem) == INTEGER_CST + && (lhs = gimple_call_lhs (stmt)) != NULL_TREE) + { + tree size = fold_build2 (MULT_EXPR, TREE_TYPE (nelem), + nelem, selem); + ao_ref_init_from_ptr_and_size (write, lhs, size); + return true; + } + } - default: - break; + default: + break; } } else if (is_gimple_assign (stmt)) @@ -459,6 +462,10 @@ maybe_trim_memstar_call (ao_ref *ref, sbitmap live, gimple *stmt) { case BUILT_IN_MEMCPY: case BUILT_IN_MEMMOVE: + case BUILT_IN_STRNCPY: + case BUILT_IN_MEMCPY_CHK: + case BUILT_IN_MEMMOVE_CHK: + case BUILT_IN_STRNCPY_CHK: { int head_trim, tail_trim; compute_trims (ref, live, &head_trim, &tail_trim, stmt); @@ -480,6 +487,7 @@ maybe_trim_memstar_call (ao_ref *ref, sbitmap live, gimple *stmt) } case BUILT_IN_MEMSET: + case BUILT_IN_MEMSET_CHK: { int head_trim, tail_trim; compute_trims (ref, live, &head_trim, &tail_trim, stmt); @@ -956,54 +964,60 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi) tree fndecl = gimple_call_fndecl (stmt); switch (DECL_FUNCTION_CODE (fndecl)) { - case BUILT_IN_MEMCPY: - case BUILT_IN_MEMMOVE: - case BUILT_IN_MEMSET: - { - /* Occasionally calls with an explicit length of zero - show up in the IL. It's pointless to do analysis - on them, they're trivially dead. */ - tree size = gimple_call_arg (stmt, 2); - if (integer_zerop (size)) - { - delete_dead_or_redundant_call (gsi, "dead"); - return; - } - - /* If this is a memset call that initializes an object - to zero, it may be redundant with an earlier memset - or empty CONSTRUCTOR of a larger object. */ - if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET - || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHK) - && integer_zerop (gimple_call_arg (stmt, 1))) - dse_optimize_redundant_stores (stmt); - - enum dse_store_status store_status; - m_byte_tracking_enabled - = setup_live_bytes_from_ref (&ref, m_live_bytes); - store_status = dse_classify_store (&ref, stmt, - m_byte_tracking_enabled, - m_live_bytes); - if (store_status == DSE_STORE_LIVE) - return; - - if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD) - { - maybe_trim_memstar_call (&ref, m_live_bytes, stmt); - return; - } - - if (store_status == DSE_STORE_DEAD) + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_STRNCPY: + case BUILT_IN_MEMSET: + case BUILT_IN_MEMCPY_CHK: + case BUILT_IN_MEMMOVE_CHK: + case BUILT_IN_STRNCPY_CHK: + case BUILT_IN_MEMSET_CHK: + { + /* Occasionally calls with an explicit length of zero + show up in the IL. It's pointless to do analysis + on them, they're trivially dead. */ + tree size = gimple_call_arg (stmt, 2); + if (integer_zerop (size)) + { delete_dead_or_redundant_call (gsi, "dead"); + return; + } + + /* If this is a memset call that initializes an object + to zero, it may be redundant with an earlier memset + or empty CONSTRUCTOR of a larger object. */ + if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET + || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHK) + && integer_zerop (gimple_call_arg (stmt, 1))) + dse_optimize_redundant_stores (stmt); + + enum dse_store_status store_status; + m_byte_tracking_enabled + = setup_live_bytes_from_ref (&ref, m_live_bytes); + store_status = dse_classify_store (&ref, stmt, + m_byte_tracking_enabled, + m_live_bytes); + if (store_status == DSE_STORE_LIVE) return; - } - case BUILT_IN_CALLOC: - /* We already know the arguments are integer constants. */ - dse_optimize_redundant_stores (stmt); + if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD) + { + maybe_trim_memstar_call (&ref, m_live_bytes, stmt); + return; + } - default: + if (store_status == DSE_STORE_DEAD) + delete_dead_or_redundant_call (gsi, "dead"); return; + } + + case BUILT_IN_CALLOC: + /* We already know the arguments are integer constants. */ + dse_optimize_redundant_stores (stmt); + return; + + default: + return; } }