http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46357
Summary: Unnecessary movzx instruction Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassig...@gcc.gnu.org ReportedBy: justin.lebar+...@gmail.com Originally reported to the gcc-help list. Tested with gcc Ubuntu/Linaro 4.5.1-7ubuntu2, but I get the same code with gcc 4.4. The following C code generates assembly code with what appears to be an unnecessary call to movzx: char skip[] = { /* ... */ }; int foo(const unsigned char *str, int len) { int result = 0; int i = 7; while (i < len) { if (str[i] == '_' && str[i-1] == 'D') { result |= 2; } i += skip[str[i]]; } return result; } 0000000000000000 <foo>: 0: 31 c0 xor eax,eax 2: 83 fe 07 cmp esi,0x7 5: ba 07 00 00 00 mov edx,0x7 a: 7f 14 jg 20 <foo+0x20> c: eb 32 jmp 40 <foo+0x40> e: 66 90 xchg ax,ax // Beginning of loop 10: 0f b6 c9 movzx ecx,cl 13: 0f be 89 00 00 00 00 movsx ecx,BYTE PTR [rcx+0x0] 1a: 01 ca add edx,ecx 1c: 39 d6 cmp esi,edx 1e: 7e 20 jle 40 <foo+0x40> 20: 4c 63 c2 movsxd r8,edx 23: 42 0f b6 0c 07 movzx ecx,BYTE PTR [rdi+r8*1] 28: 80 f9 5f cmp cl,0x5f 2b: 75 e3 jne 10 <foo+0x10> // Likely end of loop (i.e. branch above is likely taken) 2d: 41 89 c1 mov r9d,eax 30: 41 83 c9 02 or r9d,0x2 34: 41 80 7c 38 ff 44 cmp BYTE PTR [r8+rdi*1-0x1],0x44 3a: 41 0f 44 c1 cmove eax,r9d 3e: eb d0 jmp 10 <foo+0x10> 40: f3 c3 repz ret The movzx on line 10 sets everything except the least-significant bit of ecx to zero. This is unnecessary since line 23 dominates line 10, so we're guaranteed that ecx contains zeros everywhere except in its least-significant bit by the time we get to line 10. If I change |str| in the C code to a signed char, then line 10 becomes movsx (now a necessary instruction). Perhaps this gives a hint as to where the errant instruction is coming from.