Simple test: --- struct U { unsigned s: 1; };
struct V { unsigned short o: 7; unsigned short u: 1; }; extern struct U t[]; extern struct V d[]; unsigned foo () { struct V descr = d[0]; unsigned osize = descr.o; if ( descr.u ) { struct U udata = t[osize]; if (udata.s) osize++; } return osize; } --- Compiled with specified gcc: >gcc -v Using built-in specs. COLLECT_GCC=/tools/local/gcc-5.2.0/bin/gcc COLLECT_LTO_WRAPPER=/tools/local/gcc-5.2.0/libexec/gcc/x86_64-unknown-linux-gnu/5.2.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../gcc-5.2.0/configure --prefix=/tools/local/gcc-5.2.0 --program-suffix=-5.2.0 --with-as=/tools/local/binutils-2.24/bin/as --with-ld=/tools/local/binutils-2.24/bin/ld Thread model: posix gcc version 5.2.0 (GCC) --- with options: -02 -S --- Yields assembler: --- foo: movzbl d(%rip), %eax andl $127, %eax cmpb $0, d(%rip) movzbl %al, %eax // <----- why this is here? jns .L2 movl %eax, %edx movl t(,%rdx,4), %edx andl $1, %edx cmpb $1, %dl sbbl $-1, %eax .L2: rep ret --- I can not understand why second movzbl is here? andl already bitwise and register eax with 127, why do someone need to zero-extend it one more time? May be some optimization missed here and it makes sense to file a ticket in bugzilla? Or maybe I do not understand something? Problem go away if I change unsigned short to unsigned int in bitfield type inside structure V.