NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-mips/57680: printf("%.1f") shows wrong resultsonR3000mipseb



The following reply was made to PR port-mips/57680; it has been noted by GNATS.

From: Izumi Tsutsui <tsutsui%ceres.dti.ne.jp@localhost>
To: riastradh%NetBSD.org@localhost
Cc: gnats-bugs%netbsd.org@localhost, tsutsui%ceres.dti.ne.jp@localhost
Subject: Re: port-mips/57680: printf("%.1f") shows wrong resultsonR3000mipseb
Date: Sun, 5 Nov 2023 17:01:44 +0900

 I wrote:
 
 > riastradh@ wrote:
 > 
 > > Perhaps on these CPUs, the kernel is setting the default rounding mode
 > > wrong when it enters a new userland process.  You could test this by
 > > writing a program that just queries fegetround and prints the value:
 > > 
 > > #include <fenv.h>
 > > #include <stdio.h>
 > > 
 > > int
 > > main(void)
 > > {
 > > 	printf("FE_TONEAREST = %d\n", (int)FE_TONEAREST);
 > > 	printf("fegetround() = %d\n", (int)fegetround());
 > > 	fflush(stdout);
 > > 	return ferror(stdout);
 > > }
 > 
 > This shows:
 > ---
 
  :
 
 > news3470-% cc -o fetest fetest.c
 > news3470-% ./fetest
 > FE_TONEAREST = 0
 > fegetround() = 0
 > news3470-% 
 > ---
 
 It looks dtoa.c alsos use __flt_rounds() defined in
 <sys/float_ieee754.h> via FLT_ROUNDS:
 
 ---
 #ifndef _SYS_FLOAT_IEEE754_H_
 #define _SYS_FLOAT_IEEE754_H_
 
 #include <sys/cdefs.h>
 #include <sys/featuretest.h>
 
 /*
  * feature macro to test for IEEE754
  */
 #define _FLOAT_IEEE754  1
 
 #if !defined(__ASSEMBLER__) && !defined(FLT_ROUNDS)
 __BEGIN_DECLS
 extern int __flt_rounds(void);
 __END_DECLS
 #define FLT_ROUNDS      __flt_rounds()
 #endif
 
  :
 ---
 
 On mips, __flt_round() is a real function in
 src/lib/libc/arch/mips/gen/flt_rounds.c:
 ---
 static const int map[] = {
         1,      /* round to nearest */
         0,      /* round to zero */
         2,      /* round to positive infinity */
         3       /* round to negative infinity */
 };
 
 int
 __flt_rounds(void)
 {
 #ifdef SOFTFLOAT_FOR_GCC
         return map[fpgetround()];
 #else
         int x;
 
         __asm(".set push; .set noat; cfc1 %0,$31; .set pop" : "=r" (x));
         return map[x & 0x03];
 #endif
 }
 ---
 
 On the other hand, fegetround() is defined as static inline
 in <mips/fenv.h>:
 
 ---
 static inline fpu_control_t
 __rfs(void)
 {
         fpu_control_t __fpsr;
 
         __asm __volatile("cfc1 %0,$31" : "=r" (__fpsr));
         return __fpsr;
 }
 
  :
 
 __fenv_static inline int
 fegetround(void)
 {
         fexcept_t __fpsr;
 
         __fpsr = __rfs();
         return __fpsr & _ROUND_MASK;
 }
 ---
 
 It looks these inline functions make gcc optimization confused,
 but now I have one question:
 
   Is there any reason why we don't use -DTrust_FLT_ROUNDS that
   just uses __flt_round() in libc, rather hacked fegetround() in libm?
   (it looks most ports have flt_round in libc/arch/${MACHINE_CPU}/gen)
 
 src/lib/libc/gdtoaimpl.h has:
 
 ---
 #ifndef Flt_Rounds
 #ifdef FLT_ROUNDS
 #define Flt_Rounds FLT_ROUNDS
 #else
 #define Flt_Rounds 1
 #endif
 #endif /*Flt_Rounds*/
 ---
 
 and src/lib/libc/gdtoa/dtoa.c has:
 
 ---
 #ifdef Honor_FLT_ROUNDS /*{*/
         int Rounding;
 #ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
         Rounding = Flt_Rounds;
 #else /*}{*/
         Rounding = 1;
         switch(fegetround()) {
           case FE_TOWARDZERO:   Rounding = 0; break;
           case FE_UPWARD:       Rounding = 2; break;
           case FE_DOWNWARD:     Rounding = 3;
           }
 #endif /*}}*/
 #endif /*}*/
 ---
 
 and actually following patch also make dtoa work on NWS-3470 (MIPS1)
 even with the default DBG=-O2:
 
 ---
 Index: gdtoa/Makefile.inc
 ===================================================================
 RCS file: /cvsroot/src/lib/libc/gdtoa/Makefile.inc,v
 retrieving revision 1.10.28.1
 diff -u -p -d -r1.10.28.1 Makefile.inc
 --- gdtoa/Makefile.inc	8 Dec 2019 13:35:51 -0000	1.10.28.1
 +++ gdtoa/Makefile.inc	5 Nov 2023 07:54:36 -0000
 @@ -8,6 +8,9 @@ CPPFLAGS+=-I${.CURDIR}/gdtoa -I${.CURDIR
  CPPFLAGS+=-DNO_FENV_H
  .else
  CPPFLAGS+=-DHonor_FLT_ROUNDS
 +.if ${MACHINE_CPU} == "mips"
 +CPPFLAGS+=-DTrust_FLT_ROUNDS
 +.endif
  .endif
  
  # machine-dependent directory must provide the following:
 
 ---
 Izumi Tsutsui
 


Home | Main Index | Thread Index | Old Index