Bug 24969 - tmpdir-gcc.dg-struct-layout-1/t026 fails execution
Summary: tmpdir-gcc.dg-struct-layout-1/t026 fails execution
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.1.0
: P3 critical
Target Milestone: 4.1.0
Assignee: Not yet assigned to anyone
URL:
Keywords: ABI, wrong-code
Depends on:
Blocks:
 
Reported: 2005-11-21 12:20 UTC by Richard Biener
Modified: 2005-12-15 16:24 UTC (History)
3 users (show)

See Also:
Host:
Target: x86_64-*-linux-gnu
Build:
Known to work:
Known to fail: 3.3.3 4.0.2 4.1.0 4.2.0 3.2.3
Last reconfirmed: 2005-11-21 14:35:35


Attachments
testcase (1.45 KB, application/octet-stream)
2005-11-21 12:22 UTC, Richard Biener
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2005-11-21 12:20:29 UTC
FAIL: tmpdir-gcc.dg-struct-layout-1/t026 c_compat_x_tst.o-c_compat_y_tst.o execute

(more specifically, test2495 fails)
Comment 1 Richard Biener 2005-11-21 12:22:19 UTC
Created attachment 10306 [details]
testcase

Compile and link the three files in the tar with -O0.
Comment 2 Richard Biener 2005-11-21 12:26:27 UTC
works on i686 with 4.1.0 and 4.0.2
Comment 3 Richard Biener 2005-11-21 12:29:33 UTC
4.0.2 seems to fail also, maybe a testsuite bug?  Still somebody needs to investigate closer.
Comment 4 Richard Biener 2005-11-21 13:40:23 UTC
Old value = 0
New value = 1
check2495 (arg0={a = 27121, b = {c = {d = true, e = 359101392}}}, 
    arg1=0x5019ec, arg2={a = 30216, b = {c = {d = true, e = 1}}})
    at t026_y.min.i:71
71       if (arg2.b.c.e != a2495[2].b.c.e) ++fails;

Reduced testcase:

void abort(void);
struct S2495 {
    short int a;
    union{
        struct{
            _Bool d;
            int e:31;
        } c;
    } b;
};
struct S2495 x;
void foo(struct S2495 a) __attribute__((noinline));
void foo(struct S2495 a)
{
  if (a.a != x.a)
    abort();
  if (a.b.c.d != x.b.c.d)
    abort();
  if (a.b.c.e != x.b.c.e)
    abort();
}
int main()
{
  x.a = 30216;
  x.b.c.d = 1;
  x.b.c.e = 32766;
  foo(x);
  return 0;
}
Comment 5 Richard Biener 2005-11-21 14:06:54 UTC
Disassembly with the first two checks removed (only the third aborts):

foo:
.LFB2:
        subq    $24, %rsp       #,
.LCFI0:
        movl    x+8(%rip), %eax #, tmp62
        movl    16(%rsp), %edx  #, tmp60
        movq    %rdi, 8(%rsp)   # a, a
        andl    $2147483647, %eax       #, tmp62
        andl    $2147483647, %edx       #, tmp60
        cmpl    %eax, %edx      # tmp62, tmp60
        jne     .L6     #,
        addq    $24, %rsp       #,
        ret
.L6:
        call    abort   #

main:
.LFB3:
        subq    $8, %rsp        #,
.LCFI1:
        movl    x+8(%rip), %eax #, tmp62
        movw    $30216, x(%rip) #, x.a
        movb    $1, x+4(%rip)   #, x.b.c.d
        movq    x(%rip), %rdi   # x, x
        andl    $-2147483648, %eax      #, tmp62
        orl     $32766, %eax    #, tmp62
        movl    %eax, x+8(%rip) # tmp62,
        call    foo     #
        xorl    %eax, %eax      # <result>
        addq    $8, %rsp        #,
        ret


it looks like we are confused on where we passed the structure by value.
It's in %rdi and %eax, while we think it got passed on stack(!?) in foo.

Someone with more x86_64 ABI knowledge has to look into this.
Comment 6 Michael Matz 2005-11-21 14:25:46 UTC
Something is fishy.  Iff registers are used for passing then it would have to
be %rdi and %rsi (not %rax)!  So the high part of this struct (where the
bitfield lies) is not passed at all here.  Per ABI this whole struct
should be passed in registers (it's not larger than two eightbytes, and
both eightbytes have class INTEGER (they contain no unaligned fields or
other fancy stuff)).
Comment 7 Richard Biener 2005-11-21 14:35:35 UTC
More reduced/simplified:

void abort(void);
struct S2495 {
    int a;
    struct{
       int d;
       int e:31;
    } c;
};
struct S2495 x;
void foo(struct S2495 a) __attribute__((noinline));
void foo(struct S2495 a)
{
  if (a.c.e != x.c.e)
    abort();
}
int main()
{
  x.c.e = 32766;
  foo(x);
  return 0;
}
Comment 8 Andrew Pinski 2005-11-21 15:29:13 UTC
3.2.3 also gets this wrong the same way.

The callee side says the struct comes on the stack.
The caller side says the struct goes in via %rdi.

Which one is correct?
Comment 9 Andrew Pinski 2005-11-21 15:35:57 UTC
Here is the rtl which is produced by expanding foo(x):
(insn 15 13 16 (set (reg/f:DI 63)
        (symbol_ref:DI ("x") <var_decl 0x2aaaab15eb00 x>)) -1 (nil)
    (nil))

(insn 16 15 17 (set (reg:DI 62)
        (mem/s/c:DI (reg/f:DI 63) [4 x+0 S8 A32])) -1 (nil)
    (nil))

(insn 17 16 18 (set (reg:DI 5 di)
        (reg:DI 62)) -1 (nil)
    (nil))

(call_insn 18 17 0 (call (mem:QI (symbol_ref:DI ("foo") [flags 0x3] <function_decl 0x2aaaab15fb00 foo>) [0 S1 A8])
        (const_int 0 [0x0])) -1 (nil)
    (expr_list:REG_EH_REGION (const_int 0 [0x0])
        (nil))
    (expr_list:REG_DEP_TRUE (use (reg:DI 5 di))
        (nil)))

Obviously this is wrong as it only passes one half of the struct.
Comment 10 Jan Hubicka 2005-12-02 18:14:24 UTC
Testing patch:
2005-12-02  Jan Hubicka  <jh@suse.cz>
        PR target/24969
        * i386.c (classify_argument): Properly adjust offset of bitfield for
        substructures.
Index: config/i386/i386.c
===================================================================
*** config/i386/i386.c  (revision 107909)
--- config/i386/i386.c  (working copy)
*************** classify_argument (enum machine_mode mod
*** 2652,2659 ****
                     misaligned integers.  */
                  if (DECL_BIT_FIELD (field))
                    {
!                     for (i = int_bit_position (field) / 8 / 8;
!                          i < (int_bit_position (field)
                                + tree_low_cst (DECL_SIZE (field), 0)
                                + 63) / 8 / 8; i++)
                        classes[i] =
--- 2652,2659 ----
                     misaligned integers.  */
                  if (DECL_BIT_FIELD (field))
                    {
!                     for (i = (int_bit_position (field) + (bit_offset % 64)) / 8 / 8;
!                          i < ((int_bit_position (field) + (bit_offset % 64))
                                + tree_low_cst (DECL_SIZE (field), 0)
                                + 63) / 8 / 8; i++)
                        classes[i] =
Comment 11 Richard Biener 2005-12-09 10:09:29 UTC
Honza, how went the patch testing?
Comment 12 Jan Hubicka 2005-12-15 12:49:21 UTC
Subject: Bug 24969

Author: hubicka
Date: Thu Dec 15 12:49:10 2005
New Revision: 108573

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=108573
Log:
	PR target/24969
	* i386.c (classify_argument): Properly adjust offset of bitfield for
	substructures.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/i386.c

Comment 13 Jan Hubicka 2005-12-15 13:48:33 UTC
Subject: Bug 24969

Author: hubicka
Date: Thu Dec 15 13:48:22 2005
New Revision: 108577

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=108577
Log:
	PR target/24969
	* i386.c (classify_argument): Properly adjust offset of bitfield for
	substructures.

Modified:
    branches/gcc-4_1-branch/gcc/ChangeLog
    branches/gcc-4_1-branch/gcc/config/i386/i386.c

Comment 14 Andrew Pinski 2005-12-15 16:24:17 UTC
Fixed.
Comment 15 Jan Hubicka 2005-12-15 19:04:09 UTC
Subject: Bug 24969

Author: hubicka
Date: Thu Dec 15 19:04:04 2005
New Revision: 108592

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=108592
Log:
	PR target/24969
	* i386.c (classify_argument): Properly adjust offset of bitfield for
	substructures.

Modified:
    branches/gcc-4_0-branch/gcc/ChangeLog
    branches/gcc-4_0-branch/gcc/config/i386/i386.c