Bug 23324 - [4.0/4.1 Regression] unsigned bitfield in struct not accessed correctly at -O2 and above
Summary: [4.0/4.1 Regression] unsigned bitfield in struct not accessed correctly at -O...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.1.0
: P2 critical
Target Milestone: 4.0.3
Assignee: Richard Henderson
URL:
Keywords: alias, wrong-code
Depends on:
Blocks:
 
Reported: 2005-08-11 08:08 UTC by Christian Lindig
Modified: 2005-10-12 16:35 UTC (History)
3 users (show)

See Also:
Host:
Target: powerpc-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2005-10-12 00:19:22


Attachments
Test case to reproduce the bug. (1.63 KB, text/plain)
2005-08-11 08:10 UTC, Christian Lindig
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Christian Lindig 2005-08-11 08:08:38 UTC
The following (generated) code fails an assertion that checks that values passed to a function are 
received correctly. This fails for one value: 

./gcc-4.1.1-ppc-cpp 
gcc-4.1.1-ppc.c:140: failed assertion `yv7.mv7 == dp7.mv7'
Abort trap

The particular value is an unsigned bitfield as part of a struct. The bug is likely to be related to inlining. 
The bug is detected in caller_bf7 but does not occur when the call to caller_bf6 is removed.

int main( int argc, char **argv )
{
    caller_bf6 ();
    caller_bf7 ();
    return errors;
}

To reproduce the bug compile and run the attached code:

: tmp; /scratch/lindig/bin/gcc -O2 -o gcc-4.1.1-ppc-cpp gcc-4.1.1-ppc-cpp.c
: tmp; ./gcc-4.1.1-ppc-cpp 
gcc-4.1.1-ppc.c:140: failed assertion `yv7.mv7 == dp7.mv7'
Abort trap

: tmp; /scratch/lindig/bin/gcc -v
Using built-in specs.
Target: powerpc-apple-darwin7.9.0
Configured with: ../gcc/configure --prefix=/scratch/lindig --enable-languages=c : (reconfigured) ../
gcc/configure --prefix=/scratch/lindig --enable-languages=c : (reconfigured) ../gcc/configure --
prefix=/scratch/lindig --enable-languages=c --no-create --no-recursion
Thread model: posix
gcc version 4.1.0 20050810 (experimental)

The code was generated by my test-code generator Quest: 
http://www.st.cs.uni-sb.de/~lindig/src/quest/index.html

I have reported the bug yesterday using gccbug but did not receive an email confirming the report. 
Therefore I'm filing it here again because I did not find it in the bug database.

# 1 "gcc-4.1.1-ppc.c"
# 0 "<built-in>"
# 1 "<command line>"
# 1 "gcc-4.1.1-ppc.c"
# 15 "gcc-4.1.1-ppc.c"
# 1 "/usr/include/assert.h" 1 3 4
# 45 "/usr/include/assert.h" 3 4
extern void __eprintf (const char *, const char *, unsigned, const char *)
    __attribute__ ((noreturn));
# 16 "gcc-4.1.1-ppc.c" 2





# 1 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.9.0/4.1.0/include/stdarg.h" 1 3 4
# 43 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.9.0/4.1.0/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 105 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.9.0/4.1.0/include/stdarg.h" 3 4
typedef __gnuc_va_list va_list;
# 22 "gcc-4.1.1-ppc.c" 2

extern int printf (char *, ...);
static int errors = 0;
static void failed( int line )
{ printf ("failed in %s: %d\n", "gcc-4.1.1-ppc.c", line); errors++; }
static union at6 { } vv6 = { };
static
struct et6
{
    struct bt6
    {
        signed av6:6;
        signed bv6:7;
        signed cv6:6;
        signed dv6:5;
        unsigned char ev6;
        unsigned int fv6;
        long int gv6;
    }
    mv6;
    unsigned long int nv6;
    signed ov6:12;
    signed pv6:3;
    signed qv6:2;
    signed rv6:10;
    union ct6 { long int hv6; float iv6; float jv6; } sv6;
    int *tv6;
    union dt6 { double kv6; float lv6; } uv6;
}
wv6
=
    {
        { 8, 9, 2, 4, '\x10', 67426805U, 1047191860L },
        1366022414UL,
        858,
        1,
        1,
        305,
        { 1069379046L },
        (int *) 358273621U,
        { 3318.041978 }
    };
static double xv6 = 19239.101269;
static long long int yv6 = 1207859169L;
static int zv6 = 660195606;
static
union at6
callee_af6( struct et6 ap6, double bp6, long long int cp6, int dp6 )
{

    ((void) ((wv6.mv6.av6 == ap6.mv6.av6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 72, "wv6.mv6.av6 == ap6.mv6.av6"), 0)));
    ((void) ((wv6.mv6.bv6 == ap6.mv6.bv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 73, "wv6.mv6.bv6 == ap6.mv6.bv6"), 0)));
    ((void) ((wv6.mv6.cv6 == ap6.mv6.cv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 74, "wv6.mv6.cv6 == ap6.mv6.cv6"), 0)));
    ((void) ((wv6.mv6.dv6 == ap6.mv6.dv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 75, "wv6.mv6.dv6 == ap6.mv6.dv6"), 0)));
    ((void) ((wv6.mv6.ev6 == ap6.mv6.ev6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 76, "wv6.mv6.ev6 == ap6.mv6.ev6"), 0)));
    ((void) ((wv6.mv6.fv6 == ap6.mv6.fv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 77, "wv6.mv6.fv6 == ap6.mv6.fv6"), 0)));
    ((void) ((wv6.mv6.gv6 == ap6.mv6.gv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 78, "wv6.mv6.gv6 == ap6.mv6.gv6"), 0)));
    ((void) ((wv6.nv6 == ap6.nv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 79, 
"wv6.nv6 == ap6.nv6"), 0)));
    ((void) ((wv6.ov6 == ap6.ov6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 80, 
"wv6.ov6 == ap6.ov6"), 0)));
    ((void) ((wv6.pv6 == ap6.pv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 81, 
"wv6.pv6 == ap6.pv6"), 0)));
    ((void) ((wv6.qv6 == ap6.qv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 82, 
"wv6.qv6 == ap6.qv6"), 0)));
    ((void) ((wv6.rv6 == ap6.rv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 83, 
"wv6.rv6 == ap6.rv6"), 0)));
    ((void) ((wv6.sv6.hv6 == ap6.sv6.hv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 84, "wv6.sv6.hv6 == ap6.sv6.hv6"), 0)));
    ((void) ((wv6.tv6 == ap6.tv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 85, 
"wv6.tv6 == ap6.tv6"), 0)));
    ((void) ((wv6.uv6.kv6 == ap6.uv6.kv6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 86, "wv6.uv6.kv6 == ap6.uv6.kv6"), 0)));
    ((void) ((xv6 == bp6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 87, "xv6 == 
bp6"), 0)));
    ((void) ((yv6 == cp6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 88, "yv6 == 
cp6"), 0)));
    ((void) ((zv6 == dp6) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 89, "zv6 == 
dp6"), 0)));
    return vv6;
}
static void caller_bf6( )
{
    union at6 bav6;
                           bav6 = callee_af6 (wv6, xv6, yv6, zv6);
}
static unsigned char uv7 = '\x46';
static float vv7 = 96636.982442;
static double wv7 = 28450.711801;
static union ct7 { } xv7 = { };
static
struct et7
{
    struct dt7 { float iv7; unsigned short int jv7; } kv7;
    float lv7[0];
    signed mv7:9;
    short int nv7;
    double ov7;
    float pv7;
}
yv7
=
    { { 30135.996213, 42435 }, { }, 170, 22116, 26479.628148, 4082.960685 };
static
union ft7 { float qv7; float *rv7; unsigned int *sv7; } zv7 =
    { 5042.227886 };
static int bav7 = 1345451862;
static struct gt7 { double tv7; } bbv7 = { 47875.491954 };
static long int bcv7[1] = { 1732133482L };
static long long int bdv7 = 381678602L;
static
unsigned char
callee_af7(
    float ap7,
    double bp7,
    union ct7 cp7,
    struct et7 dp7,
    union ft7 ep7,
    int fp7,
    struct gt7 gp7,
    long int hp7[1],
    long long int ip7
)
{

    ((void) ((vv7 == ap7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 136, "vv7 
== ap7"), 0)));
    ((void) ((wv7 == bp7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 137, "wv7 
== bp7"), 0)));
    ((void) ((yv7.kv7.iv7 == dp7.kv7.iv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 138, "yv7.kv7.iv7 == dp7.kv7.iv7"), 0)));
    ((void) ((yv7.kv7.jv7 == dp7.kv7.jv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-
ppc.c", 139, "yv7.kv7.jv7 == dp7.kv7.jv7"), 0)));
    ((void) ((yv7.mv7 == dp7.mv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 
140, "yv7.mv7 == dp7.mv7"), 0)));
    ((void) ((yv7.nv7 == dp7.nv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 
141, "yv7.nv7 == dp7.nv7"), 0)));
    ((void) ((yv7.ov7 == dp7.ov7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 142, 
"yv7.ov7 == dp7.ov7"), 0)));
    ((void) ((yv7.pv7 == dp7.pv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 
143, "yv7.pv7 == dp7.pv7"), 0)));
    ((void) ((zv7.qv7 == ep7.qv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 144, 
"zv7.qv7 == ep7.qv7"), 0)));
    ((void) ((bav7 == fp7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 145, "bav7 
== fp7"), 0)));
    ((void) ((bbv7.tv7 == gp7.tv7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 
146, "bbv7.tv7 == gp7.tv7"), 0)));
    ((void) ((bcv7[0] == hp7[0]) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 147, 
"bcv7[0] == hp7[0]"), 0)));
    ((void) ((bdv7 == ip7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 148, "bdv7 
== ip7"), 0)));
    return uv7;
}
static void caller_bf7( )
{
    unsigned char bev7;

    bev7 = callee_af7 (vv7, wv7, xv7, yv7, zv7, bav7, bbv7, bcv7, bdv7);
    ((void) ((uv7 == bev7) ? 0 : (__eprintf ("%s:%u: failed assertion `%s'\n", "gcc-4.1.1-ppc.c", 156, "uv7 
== bev7"), 0)));
}

int main( int argc, char **argv )
{
    caller_bf6 ();
    caller_bf7 ();
    return errors;
}
Comment 1 Christian Lindig 2005-08-11 08:10:53 UTC
Created attachment 9468 [details]
Test case to reproduce the bug.

This is the same code that I included in the bug description.
Comment 2 Christian Lindig 2005-08-11 08:15:24 UTC
The bitfield mv7 is actually signed, not unsigned:

struct et7
{
    struct dt7 { float iv7; unsigned short int jv7; } kv7;
    float lv7[0];
    signed mv7:9;
    short int nv7;
    double ov7;
    float pv7;
}
yv7
Comment 3 Andrew Pinski 2005-08-11 12:22:53 UTC
Confirmed,  This looks like an aliasing issue on the rtl level as -O2 -fno-strict-aliasing works.

This also worked on the 4.0 branch.
Comment 4 Andrew Pinski 2005-08-11 12:24:08 UTC
Oh, and this is related to how we inline and then also inline the values of the static const variables (with 
-ftree-store-ccp).
Comment 5 Andrew Pinski 2005-08-11 12:34:33 UTC
CSE1 is where the differenet is between -O2 and -O2 -fno-strict-aliasing.
Comment 6 Alan Modra 2005-09-01 03:47:58 UTC
Fails on powerpc-linux -m32 -O2 too.  Passes with -m64 -O2.
Comment 7 Jakub Jelinek 2005-09-07 18:58:29 UTC
Looking into it.
Comment 8 Jakub Jelinek 2005-09-08 14:03:29 UTC
This seems to be a serious problem introduced by PR middle-end/9997 fix,
at least if I understand it right.

The testcase I'm looking at is, on ppc64-linux -m32 -O2:
extern void abort (void);
#define A(x) if (!(x)) abort ()

static union at6 {} vv6 = {};
static struct et6
{
  struct bt6
  {
    signed av6:6;
    signed bv6:7;
    signed cv6:6;
    signed dv6:5;
    unsigned char ev6;
    unsigned int fv6;
    long int gv6;
  } mv6;
  unsigned long int nv6;
  signed ov6:12;
  signed pv6:3;
  signed qv6:2;
  signed rv6:10;
  union ct6 { long int hv6; float iv6; float jv6; } sv6;
  int *tv6;
  union dt6 { double kv6; float lv6; } uv6;
} wv6 = {
  { 8, 9, 2, 4, '\x10', 67426805U, 1047191860L },
  1366022414UL, 858, 1, 1, 305,
  { 1069379046L }, (int *) 358273621U,
  { 3318.041978 }
};
static double xv6 = 19239.101269;
static long long int yv6 = 1207859169L;
static int zv6 = 660195606;

static union at6
callee_af6 (struct et6 ap6, double bp6, long long int cp6, int dp6)
{
  A (wv6.mv6.av6 == ap6.mv6.av6);
  A (wv6.mv6.bv6 == ap6.mv6.bv6);
  A (wv6.mv6.cv6 == ap6.mv6.cv6);
  A (wv6.mv6.dv6 == ap6.mv6.dv6);
  A (wv6.mv6.ev6 == ap6.mv6.ev6);
  A (wv6.mv6.fv6 == ap6.mv6.fv6);
  A (wv6.mv6.gv6 == ap6.mv6.gv6);
  A (wv6.nv6 == ap6.nv6);
  A (wv6.ov6 == ap6.ov6);
  A (wv6.pv6 == ap6.pv6);
  A (wv6.qv6 == ap6.qv6);
  A (wv6.rv6 == ap6.rv6);
  A (wv6.sv6.hv6 == ap6.sv6.hv6);
  A (wv6.tv6 == ap6.tv6);
  A (wv6.uv6.kv6 == ap6.uv6.kv6);
  A (xv6 == bp6);
  A (yv6 == cp6);
  A (zv6 == dp6);
  return vv6;
}

static void
caller_bf6 (void)
{
  union at6 bav6;
  bav6 = callee_af6 (wv6, xv6, yv6, zv6);
}

static unsigned char uv7 = '\x46';
static float vv7 = 96636.982442;
static double wv7 = 28450.711801;
static union ct7 {} xv7 = {};
static struct et7
{
  struct dt7
  {
    float iv7;
    unsigned short int jv7;
  } kv7;
  float lv7[0];
  signed mv7:9;
  short int nv7;
  double ov7;
  float pv7;
} yv7 = {
  { 30135.996213, 42435 },
  {}, 170, 22116, 26479.628148, 4082.960685
};
static union ft7
{
  float qv7;
  float *rv7;
  unsigned int *sv7;
} zv7 = { 5042.227886 };
static int bav7 = 1345451862;
static struct gt7 { double tv7; } bbv7 = { 47875.491954 };
static long int bcv7[1] = { 1732133482L };
static long long int bdv7 = 381678602L;

static unsigned char
callee_af7 (float ap7, double bp7, union ct7 cp7, struct et7 dp7,
            union ft7 ep7, int fp7, struct gt7 gp7, long int hp7[1],
            long long int ip7)
{
  A (vv7 == ap7);
  A (wv7 == bp7);
  A (yv7.kv7.iv7 == dp7.kv7.iv7);
  A (yv7.kv7.jv7 == dp7.kv7.jv7);
  A (yv7.mv7 == dp7.mv7);
  A (yv7.nv7 == dp7.nv7);
  A (yv7.ov7 == dp7.ov7);
  A (yv7.pv7 == dp7.pv7);
  A (zv7.qv7 == ep7.qv7);
  A (bav7 == fp7);
  A (bbv7.tv7 == gp7.tv7);
  A (bcv7[0] == hp7[0]);
  A (bdv7 == ip7);
  return uv7;
}

static void
caller_bf7 (void)
{
  unsigned char bev7;

  bev7 = callee_af7 (vv7, wv7, xv7, yv7, zv7, bav7, bbv7, bcv7, bdv7);
  A (uv7 == bev7);
}

int
main ()
{
  caller_bf6 ();
  caller_bf7 ();
  return 0;
}

expand_used_vars is assigning stack slots just to 2 variables, ap6 and dp7.
ap6's alias set (5) has has_zero_child set to 1, as it contains an unsigned char
field (ap6.mv6.ev6), dp7's alias set (13) does not.
But one has_zero_child is enough for alias_sets_conflict_p (5, 13) == 1.
The problem is that add_alias_set_conflicts uses just !alias_sets_conflict_p
and not something stronger to find which variables can't overlap.
ap6 and dp7 MAY conflict (which is correct), but that is not enough to
guarantee the two variables can overlap (they IMHO can't).

When CSE uses later the alias info, it sees a read from ap6.mv6.gv6 field
(long int type, alias set 4) and write, part of initializing whole dp7,
using alias set 13 (dp7's alias set).  But there are no long int fields in
dp7, so alias_sets_conflict_p (4, 13) == 0 and thus CSE decides the write
couldn't possibly invalidate av6.mv6.gv6 value at that location.

Now the question is what add_alias_set_conflicts should check if both vars are
aggregates instead of alias_sets_conflict_p (or better yet in addition to, if
!alias_sets_conflict_p, we know the variables can't overlap quickly).
Certainly for all fields (recursively) of one aggregate it needs to ensure they
may conflict with the other aggregate's alias set and vice versa.
That will handle the case of a MEM reading/writing a field and another MEM
reading/writing the other variable as whole (well, at least using whole
variable's alias set).  Plus if there are fields which themselves are aggregates,
we would I think need to ensure that aggregate subfield may conflict with all
fields in the other variable that might overlap it (i.e. look at field offsets
etc.).

Comment 9 CVS Commits 2005-10-12 16:29:41 UTC
Subject: Bug 23324

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	rth@gcc.gnu.org	2005-10-12 16:29:35

Modified files:
	gcc            : ChangeLog cfgexpand.c 
Added files:
	gcc/testsuite/gcc.c-torture/execute: pr23324.c 

Log message:
	PR rtl-opt/23324
	* cfgexpand.c (add_alias_set_conflicts): Use objects_must_conflict_p.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.10146&r2=2.10147
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cfgexpand.c.diff?cvsroot=gcc&r1=2.51&r2=2.52
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/gcc.c-torture/execute/pr23324.c.diff?cvsroot=gcc&r1=NONE&r2=1.1

Comment 10 CVS Commits 2005-10-12 16:34:38 UTC
Subject: Bug 23324

CVSROOT:	/cvs/gcc
Module name:	gcc
Branch: 	gcc-4_0-branch
Changes by:	rth@gcc.gnu.org	2005-10-12 16:34:33

Modified files:
	gcc            : ChangeLog cfgexpand.c 
Added files:
	gcc/testsuite/gcc.c-torture/execute: pr23324.c 

Log message:
	PR rtl-opt/23324
	* cfgexpand.c (add_alias_set_conflicts): Use objects_must_conflict_p.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.7592.2.461&r2=2.7592.2.462
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cfgexpand.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.33.2.1&r2=2.33.2.2
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/gcc.c-torture/execute/pr23324.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.2.1

Comment 11 Richard Henderson 2005-10-12 16:35:11 UTC
Fixed.