Bug 102706 - [12 regression] -O2 vectorization causes regression in Warray-bounds-48.c on many targets
Summary: [12 regression] -O2 vectorization causes regression in Warray-bounds-48.c on ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: 12.0
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on: 102744
Blocks: Warray-bounds
  Show dependency treegraph
 
Reported: 2021-10-12 14:29 UTC by Jeffrey A. Law
Modified: 2022-12-08 10:58 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-10-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jeffrey A. Law 2021-10-12 14:29:03 UTC
More fallout from enabling auto-vectorization at -O2.

gcc.dg/Warray-bonds-48.c is regressing on most (but not all) of the embedded targets.

Just picking one semi-randomly, iq2000-elf:



Running target iq2000-sim
Using /usr/share/dejagnu/baseboards/iq2000-sim.exp as board description file for target.
Using /usr/share/dejagnu/config/sim.exp as generic interface file for target.
Using /usr/share/dejagnu/baseboards/basic-sim.exp as board description file for target.
Using /home/jlaw/jenkins/workspace/iq2000-elf/gcc/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /home/jlaw/jenkins/workspace/iq2000-elf/gcc/gcc/testsuite/gcc.dg/dg.exp ...
FAIL: gcc.dg/Warray-bounds-48.c (test for excess errors)

                === gcc Summary ===

# of expected passes            38
# of unexpected failures        1
/home/jlaw/jenkins/workspace/iq2000-elf/iq2000-elf-obj/gcc/gcc/xgcc  version 12.0.0 20211008 (experimental) (GCC)

From the log file we see:

FAIL: gcc.dg/Warray-bounds-48.c (test for excess errors)
Excess errors:
/home/jlaw/jenkins/workspace/iq2000-elf/gcc/gcc/testsuite/gcc.dg/Warray-bounds-48.c:33:12: warning: writing 4 bytes into a region of size 0 [-Wstringop-overflow=]
/home/jlaw/jenkins/workspace/iq2000-elf/gcc/gcc/testsuite/gcc.dg/Warray-bounds-48.c:133:12: warning: writing 4 bytes into a region of size 0 [-Wstringop-overflow=]


My very cursory examination of the test tells me this is a bogus warning.  In both cases we have allocated enough space to reference array index 0 and 1.


You should be able to reproduce this with a cross compiler without needing a cross assembler, library, etc.
Comment 1 Martin Sebor 2021-10-12 16:35:53 UTC
Confirmed.  The root cause is similar as in the test case in pr102462 comment 4.  Here, in addition to the expected -Warray-bounds (from the vrp1 pass) for the invalid subscripts (before vectorization) the code also triggers -Wstringop-overflow (from the strlen pass) for the two valid stores to p->ax at indices 0 and 1 vectorized with the subsequent two stores.  See the dumps below.

Hongtao and I have been discussing the fallout of the autovectorization change in the context of the following review:
https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581371.html

Hongtao, we could use this bug to track case (2)  that you described in your reply this morning in the thread above.

$ cat pr102706.c && /build/iq2000-elf/gcc-master/gcc/xgcc -B /build/iq200f/gcc-master/gcc -O2 -S -Wall -fdump-tree-vrp1=/dev/stdout -fdump-tree-strlen=/dev/stdout pr102706.c
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;

void sink (void*);

/* Exercise a true flexible member.  */

struct AX
{
  int32_t n;
  int16_t ax[];     // { dg-message "while referencing 'ax'" "member" }
};

static void warn_ax_local_buf (struct AX *p)
{
  p->ax[0] = 4; p->ax[1] = 5;

  p->ax[2] = 6;     // { dg-warning "\\\[-Warray-bounds" }
  p->ax[3] = 7;     // { dg-warning "\\\[-Warray-bounds" }
  p->ax[4] = 8;     // { dg-warning "\\\[-Warray-bounds" }
}


void g (void)
{
  /* Verify out-of-bounds access to the local BUF is diagnosed.  */
  char ax_buf_p2[sizeof (struct AX) + 2 * sizeof (int16_t)];
  warn_ax_local_buf ((struct AX*) ax_buf_p2);
  sink (ax_buf_p2);
}

;; Function g (g, funcdef_no=1, decl_uid=1438, cgraph_uid=2, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }

Value ranges after VRP:



In function 'warn_ax_local_buf',
    inlined from 'g' at pr102706.c:28:3:
pr102706.c:18:8: warning: array subscript 2 is above array bounds of 'int16_t[]' {aka 'short int[]'} [-Warray-bounds]
   18 |   p->ax[2] = 6;     // { dg-warning "\\\[-Warray-bounds" }
      |   ~~~~~^~~
pr102706.c: In function 'g':
pr102706.c:11:11: note: while referencing 'ax'
   11 |   int16_t ax[];     // { dg-message "while referencing 'ax'" "member" }
      |           ^~
In function 'warn_ax_local_buf',
    inlined from 'g' at pr102706.c:28:3:
pr102706.c:19:8: warning: array subscript 3 is above array bounds of 'int16_t[]' {aka 'short int[]'} [-Warray-bounds]
   19 |   p->ax[3] = 7;     // { dg-warning "\\\[-Warray-bounds" }
      |   ~~~~~^~~
pr102706.c: In function 'g':
pr102706.c:11:11: note: while referencing 'ax'
   11 |   int16_t ax[];     // { dg-message "while referencing 'ax'" "member" }
      |           ^~
In function 'warn_ax_local_buf',
    inlined from 'g' at pr102706.c:28:3:
pr102706.c:20:8: warning: array subscript 4 is above array bounds of 'int16_t[]' {aka 'short int[]'} [-Warray-bounds]
   20 |   p->ax[4] = 8;     // { dg-warning "\\\[-Warray-bounds" }
      |   ~~~~~^~~
pr102706.c: In function 'g':
pr102706.c:11:11: note: while referencing 'ax'
   11 |   int16_t ax[];     // { dg-message "while referencing 'ax'" "member" }
      |           ^~
void g ()
{
  char ax_buf_p2[8];

  <bb 2> [local count: 1073741824]:
  MEM[(struct AX *)&ax_buf_p2].ax[0] = 4;
  MEM[(struct AX *)&ax_buf_p2].ax[1] = 5;
  MEM[(struct AX *)&ax_buf_p2].ax[2] = 6;
  MEM[(struct AX *)&ax_buf_p2].ax[3] = 7;
  MEM[(struct AX *)&ax_buf_p2].ax[4] = 8;
  sink (&ax_buf_p2);
  ax_buf_p2 ={v} {CLOBBER};
  return;

}



;; Function g (g, funcdef_no=1, decl_uid=1438, cgraph_uid=2, symbol_order=1)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
In function 'warn_ax_local_buf',
    inlined from 'g' at pr102706.c:28:3:
pr102706.c:16:12: warning: writing 4 bytes into a region of size 0 [-Wstringop-overflow=]
   16 |   p->ax[0] = 4; p->ax[1] = 5;
      |   ~~~~~~~~~^~~
pr102706.c: In function 'g':
pr102706.c:27:8: note: at offset 8 into destination object 'ax_buf_p2' of size 8
   27 |   char ax_buf_p2[sizeof (struct AX) + 2 * sizeof (int16_t)];
      |        ^~~~~~~~~
void g ()
{
  int16_t * vectp.5;
  vector(2) short int * vectp_ax_buf_p2.4;
  char ax_buf_p2[8];

  <bb 2> [local count: 1073741824]:
  MEM <vector(2) short int> [(short int *)&ax_buf_p2 + 4B] = { 4, 5 };
  MEM <vector(2) short int> [(short int *)&ax_buf_p2 + 8B] = { 6, 7 };
  MEM[(struct AX *)&ax_buf_p2].ax[4] = 8;
  sink (&ax_buf_p2);
  ax_buf_p2 ={v} {CLOBBER};
  return;

}
Comment 2 Hongtao.liu 2021-10-13 02:19:28 UTC
case (2): Part of accesses are inbound, part of accesses are out of bound,
and after vectorization, the warning goes from out of bound line to
inbound line.

From Wstringop-overflow-2.c:

struct A1 a1_1 = { 0, { 1 } };

void ga1_1 (void)
{
  a1_1.a[0] = 0;
  a1_1.a[1] = 1;                // { dg-warning "\\\[-Wstringop-overflow" }
  a1_1.a[2] = 2;                // { dg-warning "\\\[-Wstringop-overflow" }

  struct A1 a = { 0, { 1 } };   // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  a.a[0] = 0;
  a.a[1] = 1;                   // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  a.a[2] = 2;                   // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  sink (&a);
}

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" }

  // Refer to PR102462
  struct A1 a = { 0, { 1 } };   // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  a.a[0] = 1;
  a.a[1] = 2;                   // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  a.a[2] = 3;                   // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  sink (&a);
}
Comment 3 Hongtao.liu 2021-10-13 02:26:46 UTC
From gcc.dg/Warray-bounds-51.c

void test_struct_char_vla_location (void)
{
  unsigned nelts = 7;

  struct {
    char cvla[nelts]; // { dg-message "declared here|while referencing" }
  } s;

  s.cvla[0] = __LINE__;
  s.cvla[nelts - 1] = 0; // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  s.cvla[nelts] = 0;  // { dg-warning "\\\[-Warray-bounds" }

  sink (&s);
}

From gcc.dg/Warray-parameter-3.c

__attribute__ ((noipa)) void
gcas3 (char a[static 3])
{
  a[0] = 0; a[1] = 1; a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  a[3] = 3;                   // { dg-warning "\\\[-Warray-bounds" }
}

From gcc.dg/Wstringop-overflow-14.c

void test_int16 (void)
{
  char *p = a4 + 1;

  *(int16_t*)p = 0;    // { dg-warning "writing 4 bytes into a region of size 3" "" { target { i?86-*-* x86_64-*-* } } }
  *(int16_t*)(p + 2) = 0;   // { dg-warning "writing 2 bytes into a region of size 1" "" { xfail { i?86-*-* x86_64-*-* } } }
}

From gcc.dg/Wstringop-overflow-21.c

void test_store_zero_length (int i)
{
  char a[3];
  struct S0 *p = (struct S0*)a;
  p->a = 0;                         // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  p->b[0] = 0;
  p->b[1] = 1;                      // { dg-bogus "\\\[-Wstringop-overflow" }
  p->b[2] = 2;                      // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  p->b[i] = 2;
  sink (p);
}


void test_store_flexarray (int i)
{
  char a[3];
  struct Sx *p = (struct Sx*)a;
  p->a = 0;                         // { dg-warning "\\\[-Wstringop-overflow" "" { target { i?86-*-* x86_64-*-* } } }
  p->b[0] = 0;
  p->b[1] = 1;                      // { dg-bogus "\\\[-Wstringop-overflow" }
  p->b[2] = 1;                      // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { i?86-*-* x86_64-*-* } } }
  p->b[i] = 2;
  sink (p);
}

From gcc.dg/Wstringop-overflow-76.c:

extern char a3[3];
extern char a5[5];  // { dg-message "at offset \[^a-zA-Z\n\r\]*5\[^a-zA-Z0-9\]* into destination object 'a5' of size 5" "note" }

void max_a3_a5 (int i)
{
  char *p = a3 + i;
  char *q = a5 + i;

  /* The relational expression below is invalid and should be diagnosed
     by its own warning independently of -Wstringop-overflow.  */
  char *d = MAX (p, q);
  d[2] = 0;         // { dg-warning "writing 4 bytes into a region of size 3" "" { target { i?86-*-* x86_64-*-* } } }
  d[3] = 0;
  d[4] = 0;
  d[5] = 0;         // { dg-warning "writing 1 byte into a region of size 0" "" { xfail { i?86-*-* x86_64-*-* } } }
}


// Same as above but with the larger array as the first MAX_EXPR operand.
extern char b4[4];
extern 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" }

void max_b6_b4 (int i)
{
  char *p = b6 + i;
  char *q = b4 + i;
  char *d = MAX (p, q);
  d[3] = 0;         // { dg-warning "writing 4 bytes into a region of size 3" "" { target { i?86-*-* x86_64-*-* } } }
  d[4] = 0;
  d[5] = 0;
  d[6] = 0;         // { dg-warning "writing 1 byte into a region of size 0" "" { xfail { i?86-*-* x86_64-*-* } } }
}
Comment 4 GCC Commits 2021-10-20 02:13:36 UTC
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.
Comment 5 Richard Biener 2022-01-19 08:55:43 UTC
The testsuite fails have been resolved.
Comment 6 GCC Commits 2022-12-08 10:58:04 UTC
The master branch has been updated by Alexandre Oliva <aoliva@gcc.gnu.org>:

https://gcc.gnu.org/g:4505270128ef70538ea345f292e3eb85a5369eaf

commit r13-4554-g4505270128ef70538ea345f292e3eb85a5369eaf
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Thu Dec 8 07:50:33 2022 -0300

    [PR102706] [testsuite] -Wno-stringop-overflow vs Warray-bounds
    
    The bogus Wstringop-overflow warnings conditionally issued for
    Warray-bounds-48.c and -Wzero-length-array-bounds-2.c are expected
    under conditions that depend on the availability of certain vector
    patterns, but that don't seem to model the conditions under which the
    warnings are expected.
    
    On riscv64-elf and arm-eabi/-mcpu=cortex-r5, for example, though the
    Warray-bounds-48.c condition passes, we don't issue warnings.  On
    riscv64-elf, we decide not to vectorize the assignments; on cortex-r5,
    we do vectorize pairs of assignments, but that doesn't yield the
    expected warning, even though assignments that should trigger the
    bogus warning are vectorized and associated with the earlier line
    where the bogus warning would be expected.
    
    On riscv64, for Wzero-length-array-bounds-2.c, we issue the expected
    warning in test_C_global_buf, but we also issue a warning for
    test_C_local_buf under the same conditions, that would be expected on
    other platforms but that is not issued on them.  On
    arm-eabi/-mcpu=cortex-r5, the condition passes so we'd expect the
    warning in both functions, but we don't warn on either.
    
    Instead of further extending the effective target tests, introduced to
    temporarily tolerate these expected bogus warnings, so as to capture
    the vectorizer analyses that lead to the mismatched decisions, I'm
    disabling the undesired warnings for these two tests.
    
    
    for  gcc/testsuite/ChangeLog
    
            PR tree-optimization/102706
            * gcc.dg/Warray-bounds-48.c: Disable -Wstringop-overflow.
            * gcc.dg/Wzero-length-array-bounds-2.c: Likewise.