Summary: | vectorization breaks diagnostic for array out of bound detect. | ||
---|---|---|---|
Product: | gcc | Reporter: | Hongtao.liu <crazylht> |
Component: | tree-optimization | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | NEW --- | ||
Severity: | normal | CC: | msebor, rguenth, sjames |
Priority: | P3 | Keywords: | diagnostic |
Version: | 12.0 | ||
Target Milestone: | --- | ||
See Also: | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113026 | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2021-09-23 00:00:00 | |
Bug Depends on: | |||
Bug Blocks: | 88443, 102697 |
Description
Hongtao.liu
2021-09-23 03:07:49 UTC
The issue also exists for O3 Can you reproduce compilable small testcases for all three cases here? I can't find 'gali_1' and esp. how struct A1 is laid out. case3: struct A1 { char n; char a[1]; // { dg-message "destination object" "note" } }; void sink (void*); struct A1 a1i_1 = { 0, { 1 } }; void ga1i_1 (void) { a1i_1.a[0] = 0; a1i_1.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1i_1.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1 a = { 0, { 1 } }; a.a[0] = 1; a.a[1] = 2; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 3; // { dg-warning "\\\[-Wstringop-overflow" } sink (&a); } I think i was wrong, there's no case3, case3 is just case2, part of access inbound, part is not, now the warning message is from struct A1 a = { 0, { 1 } }; which is recorded as the vectorized stmt lineno [case3.c:15:13] MEM <vector(4) char> [(char *)&a] = { 0, 1, 2, 3 }; case1 struct A1 { char n; char a[1]; // { dg-message "destination object" "note" } }; struct A1 a1__ = { 0 }; void ga1__ (void) { a1__.a[0] = 0; a1__.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1__.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1 a = { 1 }; a.a[0] = 0; a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } sink (&a); } It looks like vectorized stmt is always marked as the first access lineno. Move pass_strlen before loop passes @@ -261,6 +261,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_tsan); NEXT_PASS (pass_dse); NEXT_PASS (pass_dce); + NEXT_PASS (pass_strlen); /* Pass group that runs when 1) enabled, 2) there are loops in the function. Make sure to run pass_fix_loops before to discover/remove loops before running the gate function @@ -334,7 +335,6 @@ along with GCC; see the file COPYING3. If not see form if possible. */ NEXT_PASS (pass_thread_jumps); NEXT_PASS (pass_dominator, false /* may_peel_loop_headers_p */); - NEXT_PASS (pass_strlen); NEXT_PASS (pass_thread_jumps); NEXT_PASS (pass_vrp, false /* warn_array_bounds_p */); /* Threading can leave many const/copy propagations in the IL. causes 54 new fails c-c++-common/Wstringop-overflow.c -Wc++-compat (test for warnings, line 93) c-c++-common/Wstringop-overflow.c -Wc++-compat (test for warnings, line 94) c-c++-common/Wstringop-overflow.c -std=gnu++14 (test for warnings, line 93) c-c++-common/Wstringop-overflow.c -std=gnu++14 (test for warnings, line 94) c-c++-common/Wstringop-overflow.c -std=gnu++17 (test for warnings, line 93) c-c++-common/Wstringop-overflow.c -std=gnu++17 (test for warnings, line 94) c-c++-common/Wstringop-overflow.c -std=gnu++2a (test for warnings, line 93) c-c++-common/Wstringop-overflow.c -std=gnu++2a (test for warnings, line 94) c-c++-common/Wstringop-overflow.c -std=gnu++98 (test for warnings, line 93) c-c++-common/Wstringop-overflow.c -std=gnu++98 (test for warnings, line 94) g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-not optimized "malloc" g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-not optimized "memset" g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-times optimized "calloc" 1 g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-not optimized "malloc" g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-not optimized "memset" g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-times optimized "calloc" 1 g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-not optimized "malloc" g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-not optimized "memset" g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-times optimized "calloc" 1 g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-not optimized "malloc" g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-not optimized "memset" g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-times optimized "calloc" 1 gcc.dg/Wstringop-overflow-17.c (test for warnings, line 16) gcc.dg/Wstringop-overflow-17.c (test for warnings, line 9) gcc.dg/Wstringop-overflow-70.c (test for warnings, line 22) gcc.dg/tree-ssa/pr95731.c scan-tree-dump-times optimized " >= 0| < 0" 6 gcc.dg/tree-ssa/pr96480.c scan-tree-dump optimized " = _[0-9]* <= 3;" unix/-m32: c-c++-common/Wstringop-overflow.c -Wc++-compat (test for warnings, line 93) unix/-m32: c-c++-common/Wstringop-overflow.c -Wc++-compat (test for warnings, line 94) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++14 (test for warnings, line 93) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++14 (test for warnings, line 94) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++17 (test for warnings, line 93) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++17 (test for warnings, line 94) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++2a (test for warnings, line 93) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++2a (test for warnings, line 94) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++98 (test for warnings, line 93) unix/-m32: c-c++-common/Wstringop-overflow.c -std=gnu++98 (test for warnings, line 94) unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-not optimized "malloc" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-not optimized "memset" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++14 scan-tree-dump-times optimized "calloc" 1 unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-not optimized "malloc" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-not optimized "memset" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++17 scan-tree-dump-times optimized "calloc" 1 unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-not optimized "malloc" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-not optimized "memset" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++2a scan-tree-dump-times optimized "calloc" 1 unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-not optimized "malloc" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-not optimized "memset" unix/-m32: g++.dg/tree-ssa/calloc.C -std=gnu++98 scan-tree-dump-times optimized "calloc" 1 unix/-m32: gcc.dg/Wstringop-overflow-17.c (test for warnings, line 16) unix/-m32: gcc.dg/Wstringop-overflow-17.c (test for warnings, line 9) unix/-m32: gcc.dg/Wstringop-overflow-70.c (test for warnings, line 22) unix/-m32: gcc.dg/tree-ssa/pr95731.c scan-tree-dump-times optimized " >= 0| < 0" 6 unix/-m32: gcc.dg/tree-ssa/pr96480.c scan-tree-dump optimized " = _[0-9]* <= 3;" One thing to note here is that the three Wstringop-overflow tests mentioned in comment #0 disable -Warray-bounds. With the warning enabled the affected cases will (should) continue to trigger the expected diagnostics on the expected lines (and not on the in bounds accesses). I.e., the default GCC invocation (with no special codegen or warning suppression options) should be unaffected by the -O2 -> -O3 change, and so the regression in the quality of these diagnostics can be viewed as only minor. That -Warray-bounds is issued on the correct lines for these cases also confirms the viability of the idea of moving the strlen subset -Wstringop-overflow warnings into the -Warray-bounds pass. (As comment #6 implies, moving the whole strlen pass would likely have bigger repercussions and is not a suitable change just to maintain warning locations). Alternatively, since -Wstringop-overflow is documented to "warn for calls to string manipulation functions" it might make sense to consider disabling the -Wstringop-overflow warnings issued from the strlen pass as long as they're all handled by -Warray-bounds. (I'm not sure they are at present: I think out-of-bounds subobject accesses are not detected.) I got a case3 from Wstringop-overflow-76.c #define MAX(p, q) ((p) > (q) ? (p) : (q)) struct B4_B6 { char b4[4]; char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } }; void max_B6_B4 (int i, struct B4_B6 *pb4_b6) { char *p = pb4_b6->b6 + i; char *q = pb4_b6->b4 + i; char *d = MAX (p, q); d[3] = 0; d[4] = 0; d[5] = 0; d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0 " } After vectorization, no warning message output, option: -O2 -Wno-array-bounds Expected output warning message test.c: In function ‘max_B6_B4’: test.c:17:8: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 17 | d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0 "" { xfail vect_int }" } | ~~~~~^~~ test.c:5:8: note: at offset 6 into destination object ‘b6’ of size 6 5 | char b6[6]; // { dg-message "at offset \[^a-zA-Z\n\r\]*6\[^a-zA-Z0-9\]* into destination object 'b6' of size 6" "note" { xfail vect_int } } | ^~ case 1: All accesses are out of bound, and after vectorization, there are some warnings missing.(Because there only 1 access after vectorization, 2 accesses w/o vectorization, and diagnostic is based on access). from c-c++-common/Wstringop-overflow-2.c struct A1 a1__ = { 0 }; void ga1__ (void) { a1__.a[0] = 0; a1__.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1__.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1 a = { 1 }; a.a[0] = 0; // After vectorization, below codes are optimized to // vector(2) char = { 1, 2}, there's only 1 access remained, so add xfail // to a.a[2] = 2, refer to pr102462. a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } } sink (&a); } struct A1 a1_0 = { 0, { } }; void ga1_0_ (void) { a1_0.a[0] = 0; a1_0.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1_0.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1 a = { 1, { } }; a.a[0] = 0; a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } } sink (&a); } struct A1i a1i__ = { 0 }; void ga1i__ (void) { a1i__.a[0] = 0; a1i__.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1i__.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1i a = { 0 }; a.a[0] = 0; a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } } sink (&a); } struct A1 a1i_0 = { 0, { } }; void ga1i_0_ (void) { a1i_0.a[0] = 0; a1i_0.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a1i_0.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" } struct A1 a = { 0, { } }; a.a[0] = 0; a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" } a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } } sink (&a); } The master branch has been updated by hongtao Liu <liuhongt@gcc.gnu.org>: https://gcc.gnu.org/g:3c8d8c0be95e99dc0cba7f6fad2429243582119f commit r12-4523-g3c8d8c0be95e99dc0cba7f6fad2429243582119f Author: liuhongt <hongtao.liu@intel.com> Date: Thu Oct 14 09:31:03 2021 +0800 Adjust testcase for O2 vectorization. As discussed in [1], this patch add xfail/target selector to those testcases, also make a copy of them so that they can be tested w/o vectorization. Newly added xfail/target selectors are used to check the vectorization capability of continuous byte/double bytes storage, these scenarios are exactly the part of the testcases that regressed after O2 vectorization. [1] https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581456.html. 2021-10-19 Hongtao Liu <hongtao.liu@intel.com> Kewen Lin <linkw@linux.ibm.com> gcc/ChangeLog * doc/sourcebuild.texi (Effective-Target Keywords): Document vect_slp_v2qi_store, vect_slp_v4qi_store, vect_slp_v8qi_store, vect_slp_v16qi_store, vect_slp_v2hi_store, vect_slp_v4hi_store, vect_slp_v2si_store, vect_slp_v4si_store. gcc/testsuite/ChangeLog PR middle-end/102722 PR middle-end/102697 PR middle-end/102462 PR middle-end/102706 PR middle-end/102744 * c-c++-common/Wstringop-overflow-2.c: Adjust testcase with new xfail/target selector. * gcc.dg/Warray-bounds-51.c: Ditto. * gcc.dg/Warray-parameter-3.c: Ditto. * gcc.dg/Wstringop-overflow-14.c: Ditto. * gcc.dg/Wstringop-overflow-21.c: Ditto. * gcc.dg/Wstringop-overflow-68.c: Ditto. * gcc.dg/Wstringop-overflow-76.c: Ditto. * gcc.dg/Warray-bounds-48.c: Ditto. * gcc.dg/Wzero-length-array-bounds-2.c: Ditto. * lib/target-supports.exp (check_vect_slp_aligned_store_usage): New function. (check_effective_target_vect_slp_v2qi_store): Ditto. (check_effective_target_vect_slp_v4qi_store): Ditto. (check_effective_target_vect_slp_v8qi_store): Ditto. (check_effective_target_vect_slp_v16qi_store): Ditto. (check_effective_target_vect_slp_v2hi_store): Ditto. (check_effective_target_vect_slp_v4hi_store): Ditto. (check_effective_target_vect_slp_v2si_store): Ditto. (check_effective_target_vect_slp_v4si_store): Ditto. * c-c++-common/Wstringop-overflow-2-novec.c: New test. * gcc.dg/Warray-bounds-51-novec.c: New test. * gcc.dg/Warray-bounds-48-novec.c: New test. * gcc.dg/Warray-parameter-3-novec.c: New test. * gcc.dg/Wstringop-overflow-14-novec.c: New test. * gcc.dg/Wstringop-overflow-21-novec.c: New test. * gcc.dg/Wstringop-overflow-76-novec.c: New test. * gcc.dg/Wzero-length-array-bounds-2-novec.c: New test. |