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