home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: gnu.gcc.bug
- Path: sparky!uunet!charon.amdahl.com!pacbell.com!sgiblab!zaphod.mps.ohio-state.edu!cis.ohio-state.edu!runx.oz.AU!bde
- From: bde@runx.oz.AU (Bruce Evans)
- Subject: 386 gcc-2.3.1: sin (x) wrong for large x
- Message-ID: <1992Nov17.171303.19178@runx.oz.au>
- Sender: gnulists@ai.mit.edu
- Organization: RUNX Un*x Timeshare. Sydney, Australia.
- Distribution: gnu
- Date: Tue, 17 Nov 1992 17:13:03 GMT
- Approved: bug-gcc@prep.ai.mit.edu
- Lines: 106
-
- gcc-2.3.1 for the 386 generates incorrect code for sin (x). It is necessary to
- check the C2 bit in the FP status word to handle the case abs (x) >= 2**64.
- cos (x) requires the same treatment.
-
- I think that the C2 bit should be checked even for -ffast-math. It does not
- cause an exception (the arg is not changed) so the error will be discarded
- silently if C2 is not checked.
-
- I don't think it is worth inlining the transcendental functions for 486's
- (and probably not for 386/387's). The speedup is only 10-20% compared
- with an extern function and zero compared with an inline function. There
- is another correctness issue. The inline code will trap if the arg is a
- NaN or infinity and the exception masks say to trap. I think the ANSI
- standard says that sin () should not trap. The function implementation
- could easily change the exception masks to avoid the trap (or better
- keep track of the exception masks and change them only when necessary).
- This is a bit much for automatically inlined versions.
-
- See the comments in the assembler output for more remarks. The comment
- starting with a single / shows suitable correct code. Comments starting
- with // are about side issues.
-
- ---
- command
- ---
- gcc -v -S -O -m80387 -mfp-ret-in-387 -mieee-fp z.c
- ---
-
- ---
- error output
- ---
- Reading specs from /usr/gnu/gcc/lib/gcc-lib/i386-minix/2.3.1/specs
- gcc version 2.3.1
- /usr/gnu/gcc/lib/gcc-lib/i386-minix/2.3.1/cpp -lang-c -v -undef -D__GNUC__=2 -D__OPTIMIZE__ z.c /usr/tmp/cca02026.i
- GNU CPP version 2.3.1 (80386, BSD syntax)
- /usr/gnu/gcc/lib/gcc-lib/i386-minix/2.3.1/cc1 /usr/tmp/cca02026.i -quiet -dumpbase z.c -m80387 -mfp-ret-in-387 -mieee-fp -O -version -o z.s
- GNU C version 2.3.1 (80386, BSD syntax) compiled by GNU C version 2.3.1.
-
- ---
- input file z.c
- ---
- double sin(double x);
-
- extern double x;
-
- double g(void)
- {
- return sin(x);
- }
- ---
-
- ---
- commented output file
- ---
- .file "z.c"
- gcc2_compiled.:
- .text
- .align 2 // I want .align 2,0x90 - need to use a macro
- // more like ASM_OUTPUT_ALIGN_CODE than
- // ASM_OUTPUT_ALIGN at the start of a function
- .globl _g
- _g:
- pushl %ebp
- movl %esp,%ebp
- fldl _x
- fld %st(0) // inefficient
- fsin
- / Must test C2 set by fsin now since fucom will clobber it.
- / Add this:
- / fnstsw %ax
- / testb $4,%ah / 4 = C2
- / jne Lnew
- / Or delete the old 5 instructions starting at fucom and
- / add this:
- / fnstsw %ax
- / testl $0x4zz,%eax / 0x400 = C2, zz = relevant exceptions
- / jne Lnew
- / The second version calls the sin () function if the fsin
- / set an exception bit or if an exception bit was already
- / set. This version is better unless there are a lot of
- / (masked) exceptions and the sin () function is much slower.
- fucom %st(0)
- fnstsw %ax
- andb $69,%ah
- cmpb $64,%ah
- je L3 // inefficient - branch usually taken
- / Lnew:
- fstp %st(0)
- subl $8,%esp // inefficient
- fstpl (%esp) // inefficient
- // It was not good to dup the value of x in
- // loaded into %st for fsin, since we want
- // it on the x86 and not the x87 stack for
- // the function call.
- call _sin
- leave
- ret
- .align 2,0x90
- L3:
- fstp %st(1)
- leave
- ret
- ---
- --
- Bruce Evans (bde@runx.oz.au)
-
-