This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
shift+test optimization error
- From: Bob Rorschach <rfr at franz dot com>
- To: gcc-help at gcc dot gnu dot org, rfr at franz dot com
- Date: Wed, 18 Jan 2017 15:38:21 -0800
- Subject: shift+test optimization error
- Authentication-results: sourceware.org; auth=none
I have what looks to me like a flawed optimization by the
6.3.1 gcc.
This is the program:
/* bug24192 test case */
#include <stdio.h>
/* whatever the shift in badexample does,
* the function should never return 1
*/
long
badexample(unsigned long iv)
{
long ov = ((long)(1)) << ((iv & 0x3f) + 1);
if (ov == 1)
ov = 0;
return ov;
}
int
main()
{
int i;
for(i=60;i<65;i++)
printf("%d=>0x%lx\n",i&63,badexample(i&63));
}
/* end bug24192 test case */
The "if (ov==1)..." test is failing when the compilation is optimized,
but not when compiled without optimization, as shown below.
The 63=>0x1 line should be 63=>0x0.
$ gcc -O -Wall -Wextra bug24192.c
$ ./a.out
60=>0x2000000000000000
61=>0x4000000000000000
62=>0x8000000000000000
63=>0x1
0=>0x2
$ gcc -Wall -Wextra bug24192.c
$ ./a.out
60=>0x2000000000000000
61=>0x4000000000000000
62=>0x8000000000000000
63=>0x0
0=>0x2
The reason is that the optimized code isn't looking at the value of
ov, but at the value of the shift argument, as seen in the assembly
code below. The shift argument is 64, which acts like an argument of
0 on the 64-bit x86, but the test is only looking for a shift
argument of 0. Shouldn't a programmer be able to expect that
whatever the shift operation puts into ov, the subsequent test
will ensure that the function cannot return 1?
$ gcc -S -O -o bug24192.s bug24192.c
$ cat bug24192.s
.file "bug24192.c"
.text
.globl badexample
.type badexample, @function
badexample:
.LFB11:
.cfi_startproc
andl $63, %edi
movl %edi, %ecx
addl $1, %ecx
movl $1, %eax
salq %cl, %rax
testl %ecx, %ecx
movl $0, %edx
cmove %rdx, %rax
ret
.cfi_endproc
.LFE11:
.size badexample, .-badexample
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d=>0x%lx\n"
.text
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
pushq %rbx
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
subq $8, %rsp
.cfi_def_cfa_offset 32
movl $60, %ebx
.L5:
movl %ebx, %ebp
andl $63, %ebp
movslq %ebp, %rdi
call badexample
movq %rax, %rdx
movl %ebp, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
addl $1, %ebx
cmpl $65, %ebx
jne .L5
movl $0, %eax
addq $8, %rsp
.cfi_def_cfa_offset 24
popq %rbx
.cfi_def_cfa_offset 16
popq %rbp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE12:
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20161221 (Red Hat 6.3.1-1)"
.section .note.GNU-stack,"",@progbits
Here's the gcc info:
$ gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/6.3.1/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 6.3.1 20161221 (Red Hat 6.3.1-1) (GCC)