This program: #include <stdio.h>
struct tree_type { unsigned int precision : 9; }; void *bork(const void *Ty, unsigned Subpart) { printf("Subpart == %08x\n", Subpart); return 0; } const void *TConvertType(tree_type* type) { asm("movl $1104150528, 4(%%esp)" : : ); const void *Ty = 0; return bork(Ty, type->precision); } const void *foo(tree_type* type) { asm("movl $1104150528, 4(%%esp)" : : ); const void *Ty = 0; unsigned S = type->precision; return bork(Ty, S); } int main() { struct tree_type t; t.precision = 1; TConvertType(&t); foo(&t); return 0; } Compiled with "c++ t.c" Should print out: Subpart == 00000001 Subpart == 00000001 But instead prints out: Subpart == 41d00001 Subpart == 00000001 (on my iMac). The problem seems to be that, in the TConvertType function passes "type->precision" as an HI instead of SI to the "bork" function. The asm code is: movl $1104150528, 4(%esp) movl $0, -4(%ebp) movl 8(%ebp), %eax movzwl (%eax), %eax andw $511, %ax movw %ax, 4(%esp) movl -4(%ebp), %eax movl %eax, (%esp) call __Z4borkPKvj for TConvertType, so the %ax isn't putting a full SI onto the stack, leaving garbage in the MSBs of 4(%esp), which "bork" expects to be 0, of course. (See http://gcc.gnu.org/ml/gcc/2007-04/msg00237.html) Dave Korn confirmed this miscompilation: (See http://gcc.gnu.org/ml/gcc/2007-04/msg00239.html) Confirmed on x86/cygwin. I removed the asms just in case they were somehow confusing the compiler but the generated code is still clearly incorrect. 004010a2 <__Z12TConvertTypeP9tree_type>: 4010a2: 55 push %ebp 4010a3: 89 e5 mov %esp,%ebp 4010a5: 83 ec 18 sub $0x18,%esp 4010a8: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp) 4010af: 8b 45 08 mov 0x8(%ebp),%eax 4010b2: 0f b7 00 movzwl (%eax),%eax 4010b5: 66 25 ff 01 and $0x1ff,%ax 4010b9: 66 89 44 24 04 mov %ax,0x4(%esp) 4010be: 8b 45 fc mov 0xfffffffc(%ebp),%eax 4010c1: 89 04 24 mov %eax,(%esp) 4010c4: e8 87 ff ff ff call 401050 <__Z4borkPKvj> 4010c9: c9 leave 4010ca: c3 ret 4010cb: 90 nop Looking at tree dumps for the two functions ConvertType and foo, ;; Function const void* foo(tree_type*) (_Z3fooP9tree_type) const void* foo(tree_type*) (type) { unsigned int S; const void * Ty; void * D.2934; const void * D.2933; <unnamed type> D.2932; # BLOCK 2 # PRED: ENTRY (fallthru) Ty = 0B; D.2932 = type->precision; S = (unsigned int) D.2932; D.2934 = bork (Ty, S); D.2933 = D.2934; return D.2933; # SUCC: EXIT } ;; Function const void* TConvertType(tree_type*) (_Z12TConvertTypeP9tree_type) const void* TConvertType(tree_type*) (type) { const void * Ty; void * D.2926; <unnamed type> D.2925; const void * D.2924; # BLOCK 2 # PRED: ENTRY (fallthru) Ty = 0B; D.2925 = type->precision; D.2926 = bork (Ty, D.2925); D.2924 = D.2926; return D.2924; # SUCC: EXIT } the difference is just in whether the <unnamed type> representing the bitfield is passed directly to bork as a parameter; when forcibly cast via an unsigned, it gets it right. The generated RTL appears to then select a minimal size for <unsigned type> and not take account of argument promotion: ;; Function const void* TConvertType(tree_type*) (_Z12TConvertTypeP9tree_type) ;; Generating RTL for tree basic block 2 ;; Ty = 0B (insn 7 5 0 (set (mem/f/c/i:SI (plus:SI (reg/f:SI 54 virtual-stack-vars) (const_int -4 [0xfffffffc])) [0 Ty+0 S4 A32]) (const_int 0 [0x0])) -1 (nil) (nil)) ;; D.2925 = type->precision (insn 9 7 11 (set (reg/f:SI 62) (mem/f/c/i:SI (reg/f:SI 53 virtual-incoming-args) [0 type+0 S4 A32])) -1 (nil) (nil)) (insn 11 9 0 (parallel [ (set (reg:HI 59 [ D.2925 ]) (and:HI (mem/s:HI (reg/f:SI 62) [0 S2 A32]) (const_int 511 [0x1ff]))) (clobber (reg:CC 17 flags)) ]) -1 (nil) (nil)) ;; D.2926 = bork (Ty, D.2925) (insn 12 11 13 (set (mem:HI (plus:SI (reg/f:SI 56 virtual-outgoing-args) (const_int 4 [0x4])) [0 S2 A32]) (reg:HI 59 [ D.2925 ])) -1 (nil) (nil)) -- Summary: Miscompilation of Function Passing Bit Field Value to Function Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: isanbard at gmail dot com http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31513