Package: gnat-3.2 Version: 1:3.2.1-0pre2 Operating system kernel version: Linux 2.4.17 CPU: Intel i686
The program gnat_bug3, shown below, contains two consecutive comparisons of Guess and Guess_Low. As can be seen from the program output, the first comparison indicates that the two variables are not equal, while the second indicates that they are equal. Both comparisons should produce the same result. The problem only occurs if optimization is turned on. Without the -O option both comparisons indicate that the two variables are equal. Based on my rather hazy understanding of Intel assembly code, it appears that the code between L35 and L36 computes the value of Guess and stores it in memory. The GNAT documentation states that code generated by the compiler assumes that the Intel FPU is in 80 bit mode. Thus the store operation converts an 80 bit value to a 64 bit value. The code then compares the value in the register (the 80 bit value) to Guess_Low. This is incorrect, since the 80 bit value in the register is not equal to the value of Guess. The second comparison reads the value of Guess from memory, so it uses the 64 bit value. Note that the generated code would be correct if the FPU was set to 64 bit mode, so whether the bug is in the GCC back end or the GNAT front end would seem to depend on whether the back end optimizations are justified in assuming that the FPU is in 64 bit mode. Kenneth Almquist ------------------------------ gnat_bug3.adb ------------------------------ with Ada.Text_IO; use Ada.Text_IO; with Ada.Long_Float_Text_IO; use Ada.Long_Float_Text_IO; procedure Gnat_Bug3 is function Next_Value(Guess_Low, Guess_High : Long_Float; Error_Low, Error_High : Long_Float) return Long_Float is Ratio : Long_Float; Guess : Long_Float; begin Ratio := -Error_Low / (Error_High - Error_Low); if Ratio > 1.0 or Ratio < 0.0 then Put("bad ratio "); Put(Ratio, 1, 10, 0); Put(", error_high = "); Put(Error_High, 1, 10, 0); Put(", error_low = "); Put(Error_Low, 1, 10, 0); New_Line; end if; Ratio := Ratio * 0.99 + 0.005; Guess := Guess_Low + Ratio * (Guess_High - Guess_Low); if Guess = Guess_Low then Put_Line("First test: Guess = Guess_Low"); else Put_Line("First test: Guess /= Guess_Low"); end if; if Guess = Guess_Low then Put_Line("Second test: Guess = Guess_Low"); else Put_Line("Second test: Guess /= Guess_Low"); end if; return Guess; end Next_Value; Guess : Long_Float; begin -- Gnat_Bug3 Guess := Next_Value(9.07611839107694429, 9.07611839107696916, -2.22044604925031308E-16, 1.96231919602496419E-14); end Gnat_Bug3; -------------- output from gnatmake gnat_bug3 -cargs -gnatv -O -------------- gcc-3.2 -c -gnatv -O gnat_bug3.adb GNAT 3.2.1 20020912 (prerelease) Copyright 1992-2001 Free Software Foundation, Inc. Compiling: gnat_bug3.adb (source file time stamp: 2002-10-23 17:53:11) 43 lines: No errors gnatbind -x gnat_bug3.ali gnatlink gnat_bug3.ali ------------------------------ program output ------------------------------ First test: Guess /= Guess_Low Second test: Guess = Guess_Low ----------------------- compiler output (gnat_bug3.s) ----------------------- .file "gnat_bug3.adb" .section .rodata .align 4 LC3: .long 1 .long 10 .align 4 LC5: .long 1 .long 15 .align 4 LC7: .long 1 .long 14 .align 4 LC11: .long 1 .long 31 .align 4 LC13: .long 1 .long 32 LC2: .ascii "bad ratio " LC4: .ascii ", error_high = " LC6: .ascii ", error_low = " .align 32 LC10: .ascii "First test: Guess = Guess_Low" .align 32 LC12: .ascii "First test: Guess /= Guess_Low" .align 32 LC14: .ascii "Second test: Guess = Guess_Low" .align 32 LC15: .ascii "Second test: Guess /= Guess_Low" .section .rodata.cst8,"aM",@progbits,8 .align 8 LC8: .long 2061584302 .long 1072672276 .align 8 LC9: .long 1202590843 .long 1064598241 .text .align 2 .type gnat_bug3__next_value.0,@function gnat_bug3__next_value.0: pushl %ebp movl %esp, %ebp subl $24, %esp movl %ecx, -4(%ebp) fldl 32(%ebp) fsubl 24(%ebp) fdivrl 24(%ebp) fstpl -16(%ebp) xorb $-128, -9(%ebp) fld1 fldl -16(%ebp) fucom %st(1) fnstsw %ax fstp %st(1) testb $69, %ah sete %dl fldz fucompp fnstsw %ax testb $69, %ah sete %al orb %al, %dl je .L35 subl $8, %esp movl $.LC2, %eax movl $.LC3, %edx pushl %edx pushl %eax call ada__text_io__put__4 movl $0, (%esp) pushl $10 pushl $1 pushl -12(%ebp) pushl -16(%ebp) call ada__long_float_text_io__put__2 addl $24, %esp movl $.LC4, %eax movl $.LC5, %edx pushl %edx pushl %eax call ada__text_io__put__4 movl $0, (%esp) pushl $10 pushl $1 pushl 36(%ebp) pushl 32(%ebp) call ada__long_float_text_io__put__2 addl $24, %esp movl $.LC6, %eax movl $.LC7, %edx pushl %edx pushl %eax call ada__text_io__put__4 movl $0, (%esp) pushl $10 pushl $1 pushl 28(%ebp) pushl 24(%ebp) call ada__long_float_text_io__put__2 addl $20, %esp pushl $1 call ada__text_io__new_line__2 addl $16, %esp L35: fldl -16(%ebp) fmull .LC8 faddl .LC9 fstpl -16(%ebp) fldl 8(%ebp) fsubrl 16(%ebp) fmull -16(%ebp) faddl 8(%ebp) fstl -24(%ebp) fldl 8(%ebp) fxch %st(1) fucompp fnstsw %ax andb $69, %ah xorb $64, %ah jne .L36 subl $8, %esp movl $.LC10, %eax movl $.LC11, %edx jmp .L42 L36: subl $8, %esp movl $.LC12, %eax movl $.LC13, %edx L42: pushl %edx pushl %eax call ada__text_io__put_line__2 addl $16, %esp fldl -24(%ebp) fldl 8(%ebp) fxch %st(1) fucompp fnstsw %ax andb $69, %ah xorb $64, %ah jne .L39 subl $8, %esp movl $.LC14, %eax movl $.LC11, %edx jmp .L43 L39: subl $8, %esp movl $.LC15, %eax movl $.LC13, %edx L43: pushl %edx pushl %eax call ada__text_io__put_line__2 addl $16, %esp fldl -24(%ebp) leave ret Lfe1: .size gnat_bug3__next_value.0,.Lfe1-gnat_bug3__next_value.0 .align 2 globl _ada_gnat_bug3 .type _ada_gnat_bug3,@function _ada_gnat_bug3: pushl %ebp movl %esp, %ebp subl $8, %esp pushl $1024858112 pushl $0 pushl $-1129316352 pushl $0 pushl $1075980024 pushl $-44000907 pushl $1075980024 pushl $-44000921 movl %ebp, %ecx call gnat_bug3__next_value.0 fstp %st(0) leave ret Lfe2: .size _ada_gnat_bug3,.Lfe2-_ada_gnat_bug3 .ident "GCC: (GNU) 3.2.1 20020912 (Debian prerelease)" --------------------------------------------------------------------------