Message ID | CAAgBjMkiA6FwzYYVDBA7vymvRDhd_a08vamPf_42JQ5DV5SQ8g@mail.gmail.com |
---|---|
State | New |
Headers | show |
On 05/18/2017 12:55 PM, Prathamesh Kulkarni wrote: > Hi, > The attached patch tries to fix PR80806 by warning when a variable is > set using memset (and friends) but not used. I chose to warn in dse > pass since dse would detect if the variable passed as 1st argument is > a dead store. Does this approach look OK ? > > There were following fallouts observed during bootstrap build: > > * double-int.c (div_and_round_double): > Warning emitted 'den' set but not used for following call to memset: > memset (den, 0, sizeof den); > > I assume the warning is correct since there's immediately call to: > encode (den, lden, hden); > > and encode overwrites all the contents of den. > Should the above call to memset be removed from the source ? Unsure. Yes, it's dead, but from a readability standpoint should it stay? I don't know. This one isn't very clear. > > * tree-streamer.c (streamer_check_handled_ts_structures) > The function defines a local array bool handled_p[LAST_TS_ENUM]; > and the warning is emitted for: > memset (&handled_p, 0, sizeof (handled_p)); > > That's because the function then initializes each element of the array > handled_p to true > making the memset call redundant. > I am not sure if warning for the above case is a good idea ? The call > to memset() seems deliberate, to initialize all elements to 0, and > later assert checks if all the elements were explicitly set to true. This one looks like it should stay to me. It's there for defensive purposes to catch cases if programming errors. > > * value-prof.c (free_hist): > Warns for the call to memset: > > static int > free_hist (void **slot, void *data ATTRIBUTE_UNUSED) > { > histogram_value hist = *(histogram_value *) slot; > free (hist->hvalue.counters); > if (flag_checking) > memset (hist, 0xab, sizeof (*hist)); > free (hist); > return 1; > } > > Assuming flag_checking was true, the call to memset would be dead > anyway since it would be immediately freed ? Um, I don't understand > the purpose of memset in the above function. It's been like that from the day the code was introduced (initially surrounded with an ENABLE_CHECKING. Given the call to free, the memset is going to get removed. This one probably falls into the "should just be removed" bucket. > > * testsuite fallout > I verified regressing test-cases were not false positives and added > -Wno-unused-but-set-variable. I think the real question is do we want to warn here. I can certainly see both sides of the issue. jeff
On 22 May 2017 at 10:03, Jeff Law <law@redhat.com> wrote: > On 05/18/2017 12:55 PM, Prathamesh Kulkarni wrote: >> Hi, >> The attached patch tries to fix PR80806 by warning when a variable is >> set using memset (and friends) but not used. I chose to warn in dse >> pass since dse would detect if the variable passed as 1st argument is >> a dead store. Does this approach look OK ? >> >> There were following fallouts observed during bootstrap build: >> >> * double-int.c (div_and_round_double): >> Warning emitted 'den' set but not used for following call to memset: >> memset (den, 0, sizeof den); >> >> I assume the warning is correct since there's immediately call to: >> encode (den, lden, hden); >> >> and encode overwrites all the contents of den. >> Should the above call to memset be removed from the source ? > Unsure. Yes, it's dead, but from a readability standpoint should it > stay? I don't know. This one isn't very clear. > > >> >> * tree-streamer.c (streamer_check_handled_ts_structures) >> The function defines a local array bool handled_p[LAST_TS_ENUM]; >> and the warning is emitted for: >> memset (&handled_p, 0, sizeof (handled_p)); >> >> That's because the function then initializes each element of the array >> handled_p to true >> making the memset call redundant. >> I am not sure if warning for the above case is a good idea ? The call >> to memset() seems deliberate, to initialize all elements to 0, and >> later assert checks if all the elements were explicitly set to true. > This one looks like it should stay to me. It's there for defensive > purposes to catch cases if programming errors. > > >> >> * value-prof.c (free_hist): >> Warns for the call to memset: >> >> static int >> free_hist (void **slot, void *data ATTRIBUTE_UNUSED) >> { >> histogram_value hist = *(histogram_value *) slot; >> free (hist->hvalue.counters); >> if (flag_checking) >> memset (hist, 0xab, sizeof (*hist)); >> free (hist); >> return 1; >> } >> >> Assuming flag_checking was true, the call to memset would be dead >> anyway since it would be immediately freed ? Um, I don't understand >> the purpose of memset in the above function. > It's been like that from the day the code was introduced (initially > surrounded with an ENABLE_CHECKING. Given the call to free, the memset > is going to get removed. This one probably falls into the "should > just be removed" bucket. > > >> >> * testsuite fallout >> I verified regressing test-cases were not false positives and added >> -Wno-unused-but-set-variable. > I think the real question is do we want to warn here. I can certainly > see both sides of the issue. Hi Jeff, Thanks for the suggestions. I agree that warning for the above cases in tree-streamer.c and double-int.c may not be ideal. Should we perhaps only warn if there's a single use of the pointer in the call to memset (and friends) like in the test-case reported in PR ? But then I fear the warning may end up being a bit artificial. Thanks, Prathamesh > > jeff >
On 05/18/2017 12:55 PM, Prathamesh Kulkarni wrote: > Hi, > The attached patch tries to fix PR80806 by warning when a variable is > set using memset (and friends) but not used. I chose to warn in dse > pass since dse would detect if the variable passed as 1st argument is > a dead store. Does this approach look OK ? [ ... ] So I think the biggest question is whether or not the case like Martin's deserves a warning. What we have is an object that is conditionally set but not used depending on inlining context. We've generally "allowed" inlining to expose new warnings in the sense that inlining may (for example) allow us to remove the addressibility property on an object -- which makes the object subject to the usual -Wuninitialized analysis. In fact, I think we've generally considered that a positive outcome because it's exposing bugs in subtle paths. I'm less sure that this case falls into that same category. What we're really talking about is warning for a partially dead store. Would we want a warning if rather than a memset this was a simple store? Is that the right guiding principle here? I hate to say it, but I wonder if this is another case where there likely won't be a clear consensus and we're going to end up with a two level warning system? For something like Martin's case what I really think we should do is sink the memset call into the conditional. In cases where "i" is not a constant, but actually has the value zero at runtime we win. -- So I've got no objections to the idea of using DSE to detect the dead store and potentially warn. My concern is are we in a case where that warning is going to annoy users and we end up needing a level of -Wunused-but-set. Jeff
On Thu, 29 Jun 2017, Jeff Law wrote: > On 05/18/2017 12:55 PM, Prathamesh Kulkarni wrote: > > Hi, > > The attached patch tries to fix PR80806 by warning when a variable is > > set using memset (and friends) but not used. I chose to warn in dse > > pass since dse would detect if the variable passed as 1st argument is > > a dead store. Does this approach look OK ? > [ ... ] > So I think the biggest question is whether or not the case like Martin's > deserves a warning. > > What we have is an object that is conditionally set but not used > depending on inlining context. We've generally "allowed" inlining to > expose new warnings in the sense that inlining may (for example) allow > us to remove the addressibility property on an object -- which makes the > object subject to the usual -Wuninitialized analysis. In fact, I think > we've generally considered that a positive outcome because it's exposing > bugs in subtle paths. But set-but-not-used isn't a warning like that, it's a warning like 'unused variable' which directs the user to simply delete the affected stmts (and variable). So the warning should only trigger if that would not make the program fail to compile. > I'm less sure that this case falls into that same category. What we're > really talking about is warning for a partially dead store. Would we > want a warning if rather than a memset this was a simple store? Is > that the right guiding principle here? We had a -Wunreachable-code that was quite useless because it basically triggered at DCE so was full of useless false positives. It was merely an optimization report. I fear this one will be similar (warning: we applied DSE!). > I hate to say it, but I wonder if this is another case where there > likely won't be a clear consensus and we're going to end up with a two > level warning system? > > For something like Martin's case what I really think we should do is > sink the memset call into the conditional. In cases where "i" is not a > constant, but actually has the value zero at runtime we win. > > -- > > So I've got no objections to the idea of using DSE to detect the dead > store and potentially warn. My concern is are we in a case where that > warning is going to annoy users and we end up needing a level of > -Wunused-but-set. It's not a warning. It's an hint for an optimization the user could apply (sink the thing!) or a report for an optimization we do. Do not go down the route of -Wunreachable-code again please. Richard. > Jeff > >
On Fri, Jun 30, 2017 at 10:25:51AM +0200, Richard Biener wrote:
> Do not go down the route of -Wunreachable-code again please.
Yeah, I don't think we want -Wunused-but-set* as a late warning,
it is intentionally in the FE where is the only place where the false
positive ratio of the warning can stay under control, and even then many
projects like the Linux kernel turn the warning off.
If we want to special case memset/memcpy dest arg for DECL_READ_P, let's do
it, but in the FE only.
Jakub
diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c index 895a50e2677..6cbcc419976 100644 --- a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c +++ b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c @@ -1,7 +1,7 @@ /* Test -Wsizeof-pointer-memaccess warnings. */ /* { dg-do compile } */ -/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -ftrack-macro-expansion=0" } */ -/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-c++-compat -ftrack-macro-expansion=0" {target c} } */ +/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-unused-but-set-variable -ftrack-macro-expansion=0" } */ +/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-c++-compat -Wno-unused-but-set-variable -ftrack-macro-expansion=0" {target c} } */ /* { dg-require-effective-target alloca } */ #define bos(ptr) __builtin_object_size (ptr, 1) diff --git a/gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-vla-1.c b/gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-vla-1.c index 87f5ef9d171..c42e3270db9 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-vla-1.c +++ b/gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-vla-1.c @@ -1,6 +1,6 @@ /* PR 41673: bogus -Wstrict-aliasing warning from VLA dereference. */ /* { dg-do compile } */ -/* { dg-options "-std=gnu99 -O2 -Wall" } */ +/* { dg-options "-std=gnu99 -O2 -Wall -Wno-unused-but-set-variable" } */ /* { dg-require-effective-target alloca } */ int main(int argc, char *argv[]) diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size.c b/gcc/testsuite/gcc.dg/attr-alloc_size.c index f50ba7c53db..8d71b3a4e6d 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ +/* { dg-options "-O2 -Wall -Wno-unused-but-set-variable -ftrack-macro-expansion=0" } */ extern void abort (void); diff --git a/gcc/testsuite/gcc.dg/pr79715.c b/gcc/testsuite/gcc.dg/pr79715.c index 0f0f90f7122..cd59f6dbf14 100644 --- a/gcc/testsuite/gcc.dg/pr79715.c +++ b/gcc/testsuite/gcc.dg/pr79715.c @@ -1,7 +1,7 @@ /* PR tree-optimization/79715 - hand-rolled strdup with unused result not eliminated { dg-do compile } - { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + { dg-options "-O2 -Wall -Wno-unused-but-set-variable -fdump-tree-optimized" } */ void f (const char *s) { diff --git a/gcc/testsuite/gcc.dg/pr80806.c b/gcc/testsuite/gcc.dg/pr80806.c new file mode 100644 index 00000000000..551555c8fd1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr80806.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wall" } */ + +void f1(void) +{ + char *p = __builtin_malloc (10); + __builtin_memset (p, 0, 10); /* { dg-warning "'p' set but not used" } */ +} + +void f2(void) +{ + char buf[10]; + __builtin_memset (buf, 0, 10); /* { dg-warning "'buf' set but not used" } */ +} diff --git a/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c index a73e45fb809..9ca9b287d25 100644 --- a/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c +++ b/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c @@ -1,6 +1,6 @@ /* Test -Wsizeof-pointer-memaccess warnings. */ /* { dg-do compile } */ -/* { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow" } */ +/* { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-unused-but-set-variable" } */ /* Test just twice, once with -O0 non-fortified, once with -O2 fortified. */ /* { dg-skip-if "" { *-*-* } { "*" } { "-O0" "-O2" } } */ /* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */ diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index 90230abe822..f6d583f8034 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfgcleanup.h" #include "params.h" #include "alias.h" +#include "diagnostic.h" /* This file implements dead store elimination. @@ -742,7 +743,22 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi) } if (store_status == DSE_STORE_DEAD) - delete_dead_call (gsi); + { + tree ptr = gimple_call_arg (stmt, 0); + if (TREE_CODE (ptr) == SSA_NAME + || TREE_CODE (ptr) == ADDR_EXPR) + { + tree base = (TREE_CODE (ptr) == SSA_NAME) + ? SSA_NAME_VAR (ptr) + : TREE_OPERAND (ptr, 0); + + if (base && VAR_P (base)) + warning_at (gimple_location (stmt), + OPT_Wunused_but_set_variable, + "%qD set but not used", base); + } + delete_dead_call (gsi); + } return; }