Created attachment 36842 [details] u.c gcc -Wmaybe-uninitialized wrongly warns about data0 being uninitialized in the attached test case. This may be a duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42145
(In reply to Matt Turner from comment #0) > Created attachment 36842 [details] > u.c > > gcc -Wmaybe-uninitialized wrongly warns about data0 being uninitialized in > the attached test case. > > This may be a duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42145 No, it is not. This is just that the uninit predicate analysis is not powerful enough. It sees that the DEF is guarded by writemask_3(D) & 1, but it sees that the use is guarded by remaining_8 == 0, and it doesn't seem to analyse further than that.
True that tree-ssa-uninit.c is now powerful enough to grok this case. But my first preference for any kind of Wuninitialized false positive is to first think of it as a missed optimization. Fix the missed optimization and the false positive goes away for free. In this particular case there's a couple potential approaches. ;; basic block 2, loop depth 0, count 0, freq 10000, maybe hot ;; prev block 0, next block 3, flags: (NEW, REACHABLE, VISITED) ;; pred: ENTRY [100.0%] (FALLTHRU,EXECUTABLE) _1 = writemask_5(D) & 1; if (_1 != 0) goto <bb 4>; else goto <bb 3>; ;; succ: 4 [50.0%] (TRUE_VALUE,EXECUTABLE) ;; 3 [50.0%] (FALSE_VALUE,EXECUTABLE) ;; basic block 3, loop depth 0, count 0, freq 5000, maybe hot ;; prev block 2, next block 4, flags: (NEW, VISITED) ;; pred: 2 [50.0%] (FALSE_VALUE,EXECUTABLE) ;; succ: 4 [100.0%] (FALLTHRU,EXECUTABLE) ;; basic block 4, loop depth 0, count 0, freq 10000, maybe hot ;; prev block 3, next block 5, flags: (NEW, REACHABLE, VISITED) ;; pred: 3 [100.0%] (FALLTHRU,EXECUTABLE) ;; 2 [50.0%] (TRUE_VALUE,EXECUTABLE) # data0_3 = PHI <data0_6(D)(3), data_7(D)(2)> _2 = ~writemask_5(D); remaining_8 = _2 & 1; if (remaining_8 == 0) goto <bb 5>; else goto <bb 6>; One would be to realize that remaining_8 can be expressed in terms of _1. If that's done we expose the redundant test and we end up with the only path to bar() being the one where data0 is initialized. This can be modeled in DOM and is about ~20 lines of code. Not sure how often it'd trigger in the real world. Another would be to utilize bitwise inference in jump threading in conjunction with the ASSERT_EXPRs from VRP. That essentially allows us to construct jump threads 2->3->4->6 and 2->4->5 which result in the only path to bar() being one were data0 is initialized. This is probably more effective, but requires extending the VRP related jump threading bits whereas I'd rather be relying upon those less. But it might be the most tractable for gcc-7. A third approach would be to extend the backward jump threader to walk through some binary and unary ops. I've got some prototype code to do that, but it's not gcc-7 material. A fourth approach would be to take the bitwise inference stuff and do it in the DOM threader instead (which will likely last longer than the VRP threader). My worry in this case is that we won't have the ASSERT_EXPRs or range information on the appropriate edges that would allow us to identify the jump threads. A fifth approach would be to extend tree-ssa-uninit.c. But I'd really prefer to explore opportunities to remove the useless test and unexecutable paths through the CFG first.
Reconfirmed with GCC 11. It's not a regression. With a patch I'm working with GCC issues the following warning and notes confirming the analysis from comment #1 and #2. pr68548.c: In function ‘foo’: pr68548.c:14:17: warning: ‘data0’ may be used uninitialized in this function [-Wmaybe-uninitialized] 14 | bar(data0); | ^~~~~~~~~~ pr68548.c:7:18: note: when ‘(writemask & 1) == 0’ 7 | unsigned data0; | ^~~~~ pr68548.c:7:18: note: used when ‘(writemask & 1) == 0’ pr68548.c:7:18: note: ‘data0’ was declared here EVRP knows to fold the test for data0 != data to false but nothing substitutes data for data0 when the value is passed to another function or returned. So the following, for instance, doesn't trigger a warning because the data0 - data subtraction is folded into zero. int x; void baz (unsigned writemask, unsigned data) { unsigned remaining = X; unsigned data0; if (writemask & X) data0 = data; remaining &= ~writemask; if (remaining == 0) x = data0 - data; }
Fixed on the trunk. A jump threading improvement fixed it.