[2/2] MIPS: Hard-float rounding instructions support

Message ID 20231225103548.1615-4-zhujunxian@oss.cipunited.com
State Dropped
Headers
Series Add hard-float rounding instructions support for MIPS architecture |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Testing passed

Commit Message

Junxian Zhu Dec. 25, 2023, 10:35 a.m. UTC
  From: Junxian Zhu <zhujunxian@oss.cipunited.com>

Use hardware floating-point rounding instructions to implement roundeven, trunc, ceil and floor.

* sysdeps/mips/mips32/Implies: Add source path.
* sysdeps/mips/mips64/Implies: Likewise.
* sysdeps/mips/fpu/Makefile: Newfile.
* sysdeps/mips/fpu/s_ceil.c: Likewise.
* sysdeps/mips/fpu/s_ceil_fpu.S: Likewise.
* sysdeps/mips/fpu/s_ceilf.c: Likewise.
* sysdeps/mips/fpu/s_ceilf_fpu.S: Likewise.
* sysdeps/mips/fpu/s_floor.c: Likewise.
* sysdeps/mips/fpu/s_floor_fpu.S: Likewise.
* sysdeps/mips/fpu/s_floorf.c: Likewise.
* sysdeps/mips/fpu/s_floorf_fpu.S: Likewise.
* sysdeps/mips/fpu/s_roundeven.c: Likewise.
* sysdeps/mips/fpu/s_roundeven_fpu.S: Likewise.
* sysdeps/mips/fpu/s_roundevenf.c: Likewise.
* sysdeps/mips/fpu/s_roundevenf_fpu.S: Likewise.
* sysdeps/mips/fpu/s_trunc.c: Likewise.
* sysdeps/mips/fpu/s_trunc_fpu.S: Likewise.
* sysdeps/mips/fpu/s_truncf.c: Likewise.
* sysdeps/mips/fpu/s_truncf_fpu.S: Likewise.

Signed-off-by: Rong Zhang <rongrong@oss.cipunited.com>
Signed-off-by: Junxian Zhu <zhujunxian@oss.cipunited.com>
---
 sysdeps/mips/fpu/Makefile           | 12 ++++
 sysdeps/mips/fpu/s_ceil.c           | 30 ++++++++++
 sysdeps/mips/fpu/s_ceil_fpu.S       | 90 +++++++++++++++++++++++++++++
 sysdeps/mips/fpu/s_ceilf.c          | 30 ++++++++++
 sysdeps/mips/fpu/s_ceilf_fpu.S      | 82 ++++++++++++++++++++++++++
 sysdeps/mips/fpu/s_floor.c          | 24 ++++++++
 sysdeps/mips/fpu/s_floor_fpu.S      | 88 ++++++++++++++++++++++++++++
 sysdeps/mips/fpu/s_floorf.c         | 24 ++++++++
 sysdeps/mips/fpu/s_floorf_fpu.S     | 80 +++++++++++++++++++++++++
 sysdeps/mips/fpu/s_roundeven.c      | 24 ++++++++
 sysdeps/mips/fpu/s_roundeven_fpu.S  | 87 ++++++++++++++++++++++++++++
 sysdeps/mips/fpu/s_roundevenf.c     | 24 ++++++++
 sysdeps/mips/fpu/s_roundevenf_fpu.S | 79 +++++++++++++++++++++++++
 sysdeps/mips/fpu/s_trunc.c          | 24 ++++++++
 sysdeps/mips/fpu/s_trunc_fpu.S      | 84 +++++++++++++++++++++++++++
 sysdeps/mips/fpu/s_truncf.c         | 24 ++++++++
 sysdeps/mips/fpu/s_truncf_fpu.S     | 76 ++++++++++++++++++++++++
 sysdeps/mips/mips32/Implies         |  1 +
 sysdeps/mips/mips64/Implies         |  1 +
 19 files changed, 884 insertions(+)
 create mode 100644 sysdeps/mips/fpu/Makefile
 create mode 100644 sysdeps/mips/fpu/s_ceil.c
 create mode 100644 sysdeps/mips/fpu/s_ceil_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_ceilf.c
 create mode 100644 sysdeps/mips/fpu/s_ceilf_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_floor.c
 create mode 100644 sysdeps/mips/fpu/s_floor_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_floorf.c
 create mode 100644 sysdeps/mips/fpu/s_floorf_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_roundeven.c
 create mode 100644 sysdeps/mips/fpu/s_roundeven_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_roundevenf.c
 create mode 100644 sysdeps/mips/fpu/s_roundevenf_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_trunc.c
 create mode 100644 sysdeps/mips/fpu/s_trunc_fpu.S
 create mode 100644 sysdeps/mips/fpu/s_truncf.c
 create mode 100644 sysdeps/mips/fpu/s_truncf_fpu.S
  

Comments

Xi Ruoyao Dec. 25, 2023, 10:51 a.m. UTC | #1
On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:

/* snip */

> +/*
> + * ceil(x)
> + * Return x rounded toward -inf to integral value
> + * Method:
> + *	Bit twiddling.
> + */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-double.h>
> +
> +ENTRY(__ceil)
> +	.set push
> +	.set noreorder
> +	.set noat
> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> +#if __mips == 64
> +	dmfc1   a0, $f12 # assign int64
> +#else
> +	mfhc1   a0, $f12 # assign int64
> +#endif
> +	cfc1    t0, $f26
> +	ceil.l.d    $f0, $f12

No, C23 does not allow this function to raise an INEXACT exception, but
ceil.l.d will do so.

Such optimizations should be performed in GCC which can be controlled by
the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
in Glibc where we cannot know if the programmer wants to deviate from
C23.
  
YunQiang Su Dec. 25, 2023, 12:36 p.m. UTC | #2
Junxian Zhu <zhujunxian@oss.cipunited.com> 于 2023年12月25日周一 18:38写道:

> From: Junxian Zhu <zhujunxian@oss.cipunited.com>
>
> Use hardware floating-point rounding instructions to implement roundeven,
> trunc, ceil and floor.
>
> * sysdeps/mips/mips32/Implies: Add source path.
> * sysdeps/mips/mips64/Implies: Likewise.
> * sysdeps/mips/fpu/Makefile: Newfile.
> * sysdeps/mips/fpu/s_ceil.c: Likewise.
> * sysdeps/mips/fpu/s_ceil_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_ceilf.c: Likewise.
> * sysdeps/mips/fpu/s_ceilf_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_floor.c: Likewise.
> * sysdeps/mips/fpu/s_floor_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_floorf.c: Likewise.
> * sysdeps/mips/fpu/s_floorf_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_roundeven.c: Likewise.
> * sysdeps/mips/fpu/s_roundeven_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_roundevenf.c: Likewise.
> * sysdeps/mips/fpu/s_roundevenf_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_trunc.c: Likewise.
> * sysdeps/mips/fpu/s_trunc_fpu.S: Likewise.
> * sysdeps/mips/fpu/s_truncf.c: Likewise.
> * sysdeps/mips/fpu/s_truncf_fpu.S: Likewise.
>
> Signed-off-by: Rong Zhang <rongrong@oss.cipunited.com>
> Signed-off-by: Junxian Zhu <zhujunxian@oss.cipunited.com>
> ---
>  sysdeps/mips/fpu/Makefile           | 12 ++++
>  sysdeps/mips/fpu/s_ceil.c           | 30 ++++++++++
>  sysdeps/mips/fpu/s_ceil_fpu.S       | 90 +++++++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_ceilf.c          | 30 ++++++++++
>  sysdeps/mips/fpu/s_ceilf_fpu.S      | 82 ++++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_floor.c          | 24 ++++++++
>  sysdeps/mips/fpu/s_floor_fpu.S      | 88 ++++++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_floorf.c         | 24 ++++++++
>  sysdeps/mips/fpu/s_floorf_fpu.S     | 80 +++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_roundeven.c      | 24 ++++++++
>  sysdeps/mips/fpu/s_roundeven_fpu.S  | 87 ++++++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_roundevenf.c     | 24 ++++++++
>  sysdeps/mips/fpu/s_roundevenf_fpu.S | 79 +++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_trunc.c          | 24 ++++++++
>  sysdeps/mips/fpu/s_trunc_fpu.S      | 84 +++++++++++++++++++++++++++
>  sysdeps/mips/fpu/s_truncf.c         | 24 ++++++++
>  sysdeps/mips/fpu/s_truncf_fpu.S     | 76 ++++++++++++++++++++++++
>  sysdeps/mips/mips32/Implies         |  1 +
>  sysdeps/mips/mips64/Implies         |  1 +
>  19 files changed, 884 insertions(+)
>  create mode 100644 sysdeps/mips/fpu/Makefile
>  create mode 100644 sysdeps/mips/fpu/s_ceil.c
>  create mode 100644 sysdeps/mips/fpu/s_ceil_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_ceilf.c
>  create mode 100644 sysdeps/mips/fpu/s_ceilf_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_floor.c
>  create mode 100644 sysdeps/mips/fpu/s_floor_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_floorf.c
>  create mode 100644 sysdeps/mips/fpu/s_floorf_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_roundeven.c
>  create mode 100644 sysdeps/mips/fpu/s_roundeven_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_roundevenf.c
>  create mode 100644 sysdeps/mips/fpu/s_roundevenf_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_trunc.c
>  create mode 100644 sysdeps/mips/fpu/s_trunc_fpu.S
>  create mode 100644 sysdeps/mips/fpu/s_truncf.c
>  create mode 100644 sysdeps/mips/fpu/s_truncf_fpu.S
>
> diff --git a/sysdeps/mips/fpu/Makefile b/sysdeps/mips/fpu/Makefile
> new file mode 100644
> index 0000000000..ad537d6bf1
> --- /dev/null
> +++ b/sysdeps/mips/fpu/Makefile
> @@ -0,0 +1,12 @@
> +ifeq ($(subdir),math)
> +sysdep_routines += s_floor_fpu s_floorf_fpu \
> +                       s_ceil_fpu s_ceilf_fpu \
> +                       s_trunc_fpu s_truncf_fpu \
> +                       s_roundeven_fpu s_roundevenf_fpu
> +
> +libm-sysdep_routines += s_floor_fpu s_floorf_fpu \
> +                       s_ceil_fpu s_ceilf_fpu \
> +                       s_trunc_fpu s_truncf_fpu \
> +                       s_roundeven_fpu s_roundevenf_fpu
> +
> +endif
> diff --git a/sysdeps/mips/fpu/s_ceil.c b/sysdeps/mips/fpu/s_ceil.c
> new file mode 100644
> index 0000000000..91a90a70c5
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_ceil.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/*
> + * ceil(x)
> + * Return x rounded toward -inf to integral value
> + * Method:
> + *     Bit twiddling.
> + */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
>

__mips_fpr == 64
this condition should not be here.
it means fp64.
In fact your code should also support fp32 and fpxx.

+#  include <sysdeps/ieee754/dbl-64/s_ceil.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_ceil_fpu.S b/sysdeps/mips/fpu/s_ceil_fpu.S
> new file mode 100644
> index 0000000000..13d4f85ad3
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_ceil_fpu.S
> @@ -0,0 +1,90 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/*
> + * ceil(x)
> + * Return x rounded toward -inf to integral value
> + * Method:
> + *     Bit twiddling.
> + */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-double.h>
> +
> +ENTRY(__ceil)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> +#if __mips == 64
> +       dmfc1   a0, $f12 # assign int64
> +#else
> +       mfhc1   a0, $f12 # assign int64
> +#endif
> +       cfc1    t0, $f26
> +       ceil.l.d    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 52, 11 # assign exp
> +#else
> +       dsrl    a3, a0, 52
> +       andi    a3, a3, 0x7ff
> +#endif
> +#else
> +       ext     a3, a0, 20, 11 # assign exp
> +#endif
> +       sltiu   AT, a3, 1023
> +       bnez    AT, SMALL # exp < 1023
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 1023+54
> +       beqz    AT, BIG # exp >= 1023+54
> +       li      AT, 0x7ff
> +
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.d   $f0, $f12, $f12 # return double + double
> +SMALL:
> +#if __mips == 64
> +       dsrl    a2, a0, 63
> +#else
> +       srl     a2, a0, 31
> +#endif
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE: # return -0.0
> +       jr      ra
> +       neg.d   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.d   $f0, $f12
> +       .set pop
> +
> +END (__ceil)
> +libm_alias_double (__ceil, ceil)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/fpu/s_ceilf.c b/sysdeps/mips/fpu/s_ceilf.c
> new file mode 100644
> index 0000000000..a7f81c7539
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_ceilf.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/*
> + * ceil(x)
> + * Return x rounded toward -inf to integral value
> + * Method:
> + *     Bit twiddling.
> + */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/flt-32/s_ceilf.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_ceilf_fpu.S
> b/sysdeps/mips/fpu/s_ceilf_fpu.S
> new file mode 100644
> index 0000000000..7952894f73
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_ceilf_fpu.S
> @@ -0,0 +1,82 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/*
> + * ceil(x)
> + * Return x rounded toward -inf to integral value
> + * Method:
> + *     Bit twiddling.
> + */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-float.h>
> +
> +ENTRY(__ceilf)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
> +       mfc1    a0, $f12 # assign int32
> +       cfc1    t0, $f26
> +       ceil.l.s    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 23, 8 # assign exp
> +#else
> +       dsrl    a3, a0, 23
> +       andi    a3, a3, 0x1ff
> +#endif
> +#else
> +       ext     a3, a0, 23, 8 # assign exp
> +#endif
> +       sltiu   AT, a3, 127
> +       bnez    AT, SMALL # exp < 127
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 127+25
> +       beqz    AT, BIG # exp >= 127+25
> +       li      AT, 0xff
> +
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.s   $f0, $f12, $f12 # return double + double
> +SMALL:
> +       srl     a2, a0, 31
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE: # return -0.0
> +       jr      ra
> +       neg.s   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.s   $f0, $f12
> +       .set pop
> +
> +END (__ceilf)
> +libm_alias_float (__ceil, ceil)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/fpu/s_floor.c b/sysdeps/mips/fpu/s_floor.c
> new file mode 100644
> index 0000000000..4b43dc9ad9
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_floor.c
> @@ -0,0 +1,24 @@
> +/* Round double to integer away from zero.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/dbl-64/s_floor.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_floor_fpu.S
> b/sysdeps/mips/fpu/s_floor_fpu.S
> new file mode 100644
> index 0000000000..fda661fd3a
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_floor_fpu.S
> @@ -0,0 +1,88 @@
> +/* Round double to integer away from zero.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-double.h>
> +
> +ENTRY(__floor)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> +#if __mips == 64
> +       dmfc1   a0, $f12 # assign int64
> +#else
> +       mfhc1   a0, $f12 # assign int64
> +#endif
> +       cfc1    t0, $f26
> +       floor.l.d    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 52, 11 # assign exp
> +#else
> +       dsrl    a3, a0, 52
> +       andi    a3, a3, 0x7ff
> +#endif
> +#else
> +       ext     a3, a0, 20, 11 # assign exp
> +#endif
> +       sltiu   AT, a3, 1023
> +       bnez    AT, SMALL # exp < 1023
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 1023+54
> +       beqz    AT, BIG # exp >= 1023+54
> +       li      AT, 0x7ff
> +
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.d   $f0, $f12, $f12 # return double + double
> +SMALL:
> +#if __mips == 64
> +       dsrl    a2, a0, 63
> +#else
> +       srl     a2, a0, 31
> +#endif
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       li      AT, 0xbff # used by SMALL_NEGATIVE
> +SMALL_NEGATIVE:
> +       mfhc1   t1, $f0
> +       bnez    t1, SMALL_POSITIVE # sign == 0
> +       nop
> +
> +       jr      ra
> +       neg.d   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.d   $f0, $f12
> +       .set pop
> +
> +END (__floor)
> +libm_alias_double (__floor, floor)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/fpu/s_floorf.c b/sysdeps/mips/fpu/s_floorf.c
> new file mode 100644
> index 0000000000..30cfda7820
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_floorf.c
> @@ -0,0 +1,24 @@
> +/* Round double to integer away from zero.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/flt-32/s_floorf.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_floorf_fpu.S
> b/sysdeps/mips/fpu/s_floorf_fpu.S
> new file mode 100644
> index 0000000000..8edd234dbc
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_floorf_fpu.S
> @@ -0,0 +1,80 @@
> +/* Round double to integer away from zero.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-float.h>
> +
> +ENTRY(__floorf)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
> +       mfc1    a0, $f12 # assign int32
> +       cfc1    t0, $f26
> +       floor.l.s    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 23, 8 # assign exp
> +#else
> +       dsrl    a3, a0, 23
> +       andi    a3, a3, 0x1ff
> +#endif
> +#else
> +       ext     a3, a0, 23, 8 # assign exp
> +#endif
> +       sltiu   AT, a3, 127
> +       bnez    AT, SMALL # exp < 127
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 127+25
> +       beqz    AT, BIG # exp >= 127+25
> +       li      AT, 0xff
> +
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.s   $f0, $f12, $f12 # return double + double
> +SMALL:
> +       srl     a2, a0, 31
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       li      AT, 0xbff # used by SMALL_NEGATIVE
> +SMALL_NEGATIVE:
> +       mfhc1   t1, $f0
> +       bnez    t1, SMALL_POSITIVE # sign == 0
> +       nop
> +
> +       jr      ra
> +       neg.s   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.s   $f0, $f12
> +       .set pop
> +
> +END (__floorf)
> +libm_alias_float (__floor, floor)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/fpu/s_roundeven.c
> b/sysdeps/mips/fpu/s_roundeven.c
> new file mode 100644
> index 0000000000..dace85a70b
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_roundeven.c
> @@ -0,0 +1,24 @@
> +/* Round to nearest integer value, rounding halfway cases to even.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/dbl-64/s_roundeven.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_roundeven_fpu.S
> b/sysdeps/mips/fpu/s_roundeven_fpu.S
> new file mode 100644
> index 0000000000..aef6434886
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_roundeven_fpu.S
> @@ -0,0 +1,87 @@
> +/* Round to nearest integer value, rounding halfway cases to even.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-double.h>
> +
> +ENTRY(__roundeven)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> +#if __mips == 64
> +       dmfc1   a0, $f12 # assign int64
> +#else
> +       mfhc1   a0, $f12 # assign int64
> +#endif
> +       cfc1    t0, $f26
> +       round.l.d       $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 52, 11 # assign exp
> +#else
> +       dsrl    a3, a0, 52
> +       andi    a3, a3, 0x7ff
> +#endif
> +#else
> +       ext     a3, a0, 20, 11 # assign exp
> +#endif
> +       sltiu   AT, a3, 1023
> +       bnez    AT, SMALL # exp < 1023
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 1023+54
> +       beqz    AT, BIG # exp >= 1023+54
> +       li      AT, 0x7ff
> +
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.d   $f0, $f12, $f12 # return double + double
> +SMALL:
> +#if __mips == 64
> +       dsrl    a2, a0, 63
> +#else
> +       srl     a2, a0, 31
> +#endif
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE:
> +       mfhc1   t1, $f0
> +       bnez    t1, SMALL_POSITIVE # sign == 0
> +       nop
> +
> +       jr      ra
> +       neg.d   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.d   $f0, $f12
> +       .set pop
> +
> +END (__roundeven)
> +libm_alias_double (__roundeven, roundeven)
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_roundevenf.c
> b/sysdeps/mips/fpu/s_roundevenf.c
> new file mode 100644
> index 0000000000..5bb35901db
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_roundevenf.c
> @@ -0,0 +1,24 @@
> +/* Round to nearest integer value, rounding halfway cases to even.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/flt-32/s_roundevenf.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_roundevenf_fpu.S
> b/sysdeps/mips/fpu/s_roundevenf_fpu.S
> new file mode 100644
> index 0000000000..e946e50d8f
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_roundevenf_fpu.S
> @@ -0,0 +1,79 @@
> +/* Round to nearest integer value, rounding halfway cases to even.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-float.h>
> +
> +ENTRY(__roundevenf)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
> +       mfc1    a0, $f12 # assign int32
> +       cfc1    t0, $f26
> +       round.l.s       $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 23, 8 # assign exp
> +#else
> +       dsrl    a3, a0, 23
> +       andi    a3, a3, 0x1ff
> +#endif
> +#else
> +       ext     a3, a0, 23, 8 # assign exp
> +#endif
> +       sltiu   AT, a3, 127
> +       bnez    AT, SMALL # exp < 127
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 127+25
> +       beqz    AT, BIG # exp >= 127+25
> +       li      AT, 0xff
> +
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.s   $f0, $f12, $f12 # return double + double
> +SMALL:
> +       srl     a2, a0, 31
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE:
> +       mfhc1   t1, $f0
> +       bnez    t1, SMALL_POSITIVE # sign == 0
> +       nop
> +
> +       jr      ra
> +       neg.s   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +RETURN_AS_IS:
> +       jr ra
> +       mov.s   $f0, $f12
> +       .set pop
> +
> +END (__roundevenf)
> +libm_alias_float (__roundeven, roundeven)
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_trunc.c b/sysdeps/mips/fpu/s_trunc.c
> new file mode 100644
> index 0000000000..3865026c70
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_trunc.c
> @@ -0,0 +1,24 @@
> +/* Truncate argument to nearest integral value not larger than the
> argument.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/dbl-64/s_trunc.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_trunc_fpu.S
> b/sysdeps/mips/fpu/s_trunc_fpu.S
> new file mode 100644
> index 0000000000..3a7947507f
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_trunc_fpu.S
> @@ -0,0 +1,84 @@
> +/* Truncate argument to nearest integral value not larger than the
> argument.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-double.h>
> +
> +ENTRY(__trunc)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> +#if __mips == 64
> +       dmfc1   a0, $f12 # assign int64
> +#else
> +       mfhc1   a0, $f12 # assign int64
> +#endif
> +       cfc1    t0, $f26
> +       trunc.l.d    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 52, 11 # assign exp
> +#else
> +       dsrl    a3, a0, 52
> +       andi    a3, a3, 0x7ff
> +#endif
> +#else
> +       ext     a3, a0, 20, 11 # assign exp
> +#endif
> +       sltiu   AT, a3, 1023
> +       bnez    AT, SMALL # exp < 1023
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 1023+54
> +       beqz    AT, BIG # exp >= 1023+54
> +       li      AT, 0x7ff
> +
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.d   $f0, $f12, $f12 # return double + double
> +SMALL:
> +#if __mips == 64
> +       dsrl    a2, a0, 63
> +#else
> +       srl     a2, a0, 31
> +#endif
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE: # return -0.0
> +       jr      ra
> +       neg.d   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.d.l $f0, $f0
> +RETURN_AS_IS:
> +       jr      ra
> +       mov.d   $f0, $f12
> +       .set pop
> +
> +END (__trunc)
> +libm_alias_double (__trunc, trunc)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/fpu/s_truncf.c b/sysdeps/mips/fpu/s_truncf.c
> new file mode 100644
> index 0000000000..59ef17bf74
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_truncf.c
> @@ -0,0 +1,24 @@
> +/* Truncate argument to nearest integral value not larger than the
> argument.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)
>     \
> +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> +
> +#  include <sysdeps/ieee754/flt-32/s_truncf.c>
> +
> +#endif
> diff --git a/sysdeps/mips/fpu/s_truncf_fpu.S
> b/sysdeps/mips/fpu/s_truncf_fpu.S
> new file mode 100644
> index 0000000000..1878d88e3c
> --- /dev/null
> +++ b/sysdeps/mips/fpu/s_truncf_fpu.S
> @@ -0,0 +1,76 @@
> +/* Truncate argument to nearest integral value not larger than the
> argument.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 &&
> __mips_isa_rev > 1) || __mips == 64))
> +#include <sys/regdef.h>
> +#include <sysdep.h>
> +#include <libm-alias-float.h>
> +
> +ENTRY(__truncf)
> +       .set push
> +       .set noreorder
> +       .set noat
> +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
> +       mfc1    a0, $f12 # assign int32
> +       cfc1    t0, $f26
> +       trunc.l.s    $f0, $f12
> +#if __mips == 64
> +#if __mips_isa_rev > 1
> +       dext    a3, a0, 23, 8 # assign exp
> +#else
> +       dsrl    a3, a0, 23
> +       andi    a3, a3, 0x1ff
> +#endif
> +#else
> +       ext     a3, a0, 23, 8 # assign exp
> +#endif
> +       sltiu   AT, a3, 127
> +       bnez    AT, SMALL # exp < 127
> +       ctc1    t0, $f26
> +       sltiu   AT, a3, 127+25
> +       beqz    AT, BIG # exp >= 127+25
> +       li      AT, 0xff
> +
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +BIG:
> +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
> +       nop
> +NAN_INF:
> +       jr      ra
> +       add.s   $f0, $f12, $f12 # return double + double
> +SMALL:
> +       srl     a2, a0, 31
> +       beqz    a2, SMALL_POSITIVE # sign == 0
> +       nop
> +SMALL_NEGATIVE: # return -0.0
> +       jr      ra
> +       neg.s   $f0, $f0
> +SMALL_POSITIVE:
> +       jr      ra
> +       cvt.s.l $f0, $f0
> +RETURN_AS_IS:
> +       jr      ra
> +       mov.s   $f0, $f12
> +       .set pop
> +
> +END (__truncf)
> +libm_alias_float (__trunc, trunc)
> +
> +#endif
> +
> diff --git a/sysdeps/mips/mips32/Implies b/sysdeps/mips/mips32/Implies
> index 6473f2517c..71b3678c6c 100644
> --- a/sysdeps/mips/mips32/Implies
> +++ b/sysdeps/mips/mips32/Implies
> @@ -1,3 +1,4 @@
> +mips/fpu
>  mips/ieee754
>  mips
>  wordsize-32
> diff --git a/sysdeps/mips/mips64/Implies b/sysdeps/mips/mips64/Implies
> index 826ff1541f..8885ebd564 100644
> --- a/sysdeps/mips/mips64/Implies
> +++ b/sysdeps/mips/mips64/Implies
> @@ -1,4 +1,5 @@
>  # MIPS uses IEEE 754 floating point.
> +mips/fpu
>  mips/ieee754
>  ieee754/flt-32
>  ieee754/dbl-64
> --
> 2.43.0.windows.1
>
  
Junxian Zhu Dec. 26, 2023, 2:37 a.m. UTC | #3
在 2023/12/25 18:51, Xi Ruoyao 写道:
> On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
>
> /* snip */
>
>> +/*
>> + * ceil(x)
>> + * Return x rounded toward -inf to integral value
>> + * Method:
>> + *	Bit twiddling.
>> + */
>> +
>> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>> +#include <sys/regdef.h>
>> +#include <sysdep.h>
>> +#include <libm-alias-double.h>
>> +
>> +ENTRY(__ceil)
>> +	.set push
>> +	.set noreorder
>> +	.set noat
>> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>> +#if __mips == 64
>> +	dmfc1   a0, $f12 # assign int64
>> +#else
>> +	mfhc1   a0, $f12 # assign int64
>> +#endif
>> +	cfc1    t0, $f26
>> +	ceil.l.d    $f0, $f12
> No, C23 does not allow this function to raise an INEXACT exception, but
> ceil.l.d will do so.
>
> Such optimizations should be performed in GCC which can be controlled by
> the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
> in Glibc where we cannot know if the programmer wants to deviate from
> C23.

The cfc1 instruction will backup float point exception status before 
running ceil.l.d, and the following ctc1 will restore float point 
exception status to avoid INEXACT exception raised by ceil.l.d. It's the 
same way like what have been done in s_ceil.S for i386.
  
Junxian Zhu Dec. 26, 2023, 2:48 a.m. UTC | #4
在 2023/12/25 20:36, YunQiang Su 写道:
>
>
> Junxian Zhu <zhujunxian@oss.cipunited.com> 于 2023年12月25日周一 
> 18:38写道:
>
>     From: Junxian Zhu <zhujunxian@oss.cipunited.com>
>
>     Use hardware floating-point rounding instructions to implement
>     roundeven, trunc, ceil and floor.
>
>     * sysdeps/mips/mips32/Implies: Add source path.
>     * sysdeps/mips/mips64/Implies: Likewise.
>     * sysdeps/mips/fpu/Makefile: Newfile.
>     * sysdeps/mips/fpu/s_ceil.c: Likewise.
>     * sysdeps/mips/fpu/s_ceil_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_ceilf.c: Likewise.
>     * sysdeps/mips/fpu/s_ceilf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_floor.c: Likewise.
>     * sysdeps/mips/fpu/s_floor_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_floorf.c: Likewise.
>     * sysdeps/mips/fpu/s_floorf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_roundeven.c: Likewise.
>     * sysdeps/mips/fpu/s_roundeven_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_roundevenf.c: Likewise.
>     * sysdeps/mips/fpu/s_roundevenf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_trunc.c: Likewise.
>     * sysdeps/mips/fpu/s_trunc_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_truncf.c: Likewise.
>     * sysdeps/mips/fpu/s_truncf_fpu.S: Likewise.
>
>     Signed-off-by: Rong Zhang <rongrong@oss.cipunited.com>
>     Signed-off-by: Junxian Zhu <zhujunxian@oss.cipunited.com>
>     ---
>      sysdeps/mips/fpu/Makefile           | 12 ++++
>      sysdeps/mips/fpu/s_ceil.c           | 30 ++++++++++
>      sysdeps/mips/fpu/s_ceil_fpu.S       | 90
>     +++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_ceilf.c          | 30 ++++++++++
>      sysdeps/mips/fpu/s_ceilf_fpu.S      | 82 ++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_floor.c          | 24 ++++++++
>      sysdeps/mips/fpu/s_floor_fpu.S      | 88 ++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_floorf.c         | 24 ++++++++
>      sysdeps/mips/fpu/s_floorf_fpu.S     | 80 +++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_roundeven.c      | 24 ++++++++
>      sysdeps/mips/fpu/s_roundeven_fpu.S  | 87 ++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_roundevenf.c     | 24 ++++++++
>      sysdeps/mips/fpu/s_roundevenf_fpu.S | 79 +++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_trunc.c          | 24 ++++++++
>      sysdeps/mips/fpu/s_trunc_fpu.S      | 84 +++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_truncf.c         | 24 ++++++++
>      sysdeps/mips/fpu/s_truncf_fpu.S     | 76 ++++++++++++++++++++++++
>      sysdeps/mips/mips32/Implies         |  1 +
>      sysdeps/mips/mips64/Implies         |  1 +
>      19 files changed, 884 insertions(+)
>      create mode 100644 sysdeps/mips/fpu/Makefile
>      create mode 100644 sysdeps/mips/fpu/s_ceil.c
>      create mode 100644 sysdeps/mips/fpu/s_ceil_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_ceilf.c
>      create mode 100644 sysdeps/mips/fpu/s_ceilf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_floor.c
>      create mode 100644 sysdeps/mips/fpu/s_floor_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_floorf.c
>      create mode 100644 sysdeps/mips/fpu/s_floorf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_roundeven.c
>      create mode 100644 sysdeps/mips/fpu/s_roundeven_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_roundevenf.c
>      create mode 100644 sysdeps/mips/fpu/s_roundevenf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_trunc.c
>      create mode 100644 sysdeps/mips/fpu/s_trunc_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_truncf.c
>      create mode 100644 sysdeps/mips/fpu/s_truncf_fpu.S
>
>     diff --git a/sysdeps/mips/fpu/Makefile b/sysdeps/mips/fpu/Makefile
>     new file mode 100644
>     index 0000000000..ad537d6bf1
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/Makefile
>     @@ -0,0 +1,12 @@
>     +ifeq ($(subdir),math)
>     +sysdep_routines += s_floor_fpu s_floorf_fpu \
>     +                       s_ceil_fpu s_ceilf_fpu \
>     +                       s_trunc_fpu s_truncf_fpu \
>     +                       s_roundeven_fpu s_roundevenf_fpu
>     +
>     +libm-sysdep_routines += s_floor_fpu s_floorf_fpu \
>     +                       s_ceil_fpu s_ceilf_fpu \
>     +                       s_trunc_fpu s_truncf_fpu \
>     +                       s_roundeven_fpu s_roundevenf_fpu
>     +
>     +endif
>     diff --git a/sysdeps/mips/fpu/s_ceil.c b/sysdeps/mips/fpu/s_ceil.c
>     new file mode 100644
>     index 0000000000..91a90a70c5
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_ceil.c
>     @@ -0,0 +1,30 @@
>     +/* Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library.  If not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +/*
>     + * ceil(x)
>     + * Return x rounded toward -inf to integral value
>     + * Method:
>     + *     Bit twiddling.
>     + */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>
>
> __mips_fpr == 64
> this condition should not be here.
> it means fp64.
> In fact your code should also support fp32 and fpxx.
>
>     +#  include <sysdeps/ieee754/dbl-64/s_ceil.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_ceil_fpu.S
>     b/sysdeps/mips/fpu/s_ceil_fpu.S
>     new file mode 100644
>     index 0000000000..13d4f85ad3
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_ceil_fpu.S
>     @@ -0,0 +1,90 @@
>     +/* Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library.  If not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +/*
>     + * ceil(x)
>     + * Return x rounded toward -inf to integral value
>     + * Method:
>     + *     Bit twiddling.
>     + */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-double.h>
>     +
>     +ENTRY(__ceil)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>     +#if __mips == 64
>     +       dmfc1   a0, $f12 # assign int64
>     +#else
>     +       mfhc1   a0, $f12 # assign int64
>     +#endif
>     +       cfc1    t0, $f26
>     +       ceil.l.d    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 52, 11 # assign exp
>     +#else
>     +       dsrl    a3, a0, 52
>     +       andi    a3, a3, 0x7ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 20, 11 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 1023
>     +       bnez    AT, SMALL # exp < 1023
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 1023+54
>     +       beqz    AT, BIG # exp >= 1023+54
>     +       li      AT, 0x7ff
>     +
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.d   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +#if __mips == 64
>     +       dsrl    a2, a0, 63
>     +#else
>     +       srl     a2, a0, 31
>     +#endif
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE: # return -0.0
>     +       jr      ra
>     +       neg.d   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.d   $f0, $f12
>     +       .set pop
>     +
>     +END (__ceil)
>     +libm_alias_double (__ceil, ceil)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/fpu/s_ceilf.c b/sysdeps/mips/fpu/s_ceilf.c
>     new file mode 100644
>     index 0000000000..a7f81c7539
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_ceilf.c
>     @@ -0,0 +1,30 @@
>     +/* Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library.  If not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +/*
>     + * ceil(x)
>     + * Return x rounded toward -inf to integral value
>     + * Method:
>     + *     Bit twiddling.
>     + */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/flt-32/s_ceilf.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_ceilf_fpu.S
>     b/sysdeps/mips/fpu/s_ceilf_fpu.S
>     new file mode 100644
>     index 0000000000..7952894f73
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_ceilf_fpu.S
>     @@ -0,0 +1,82 @@
>     +/* Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library.  If not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +/*
>     + * ceil(x)
>     + * Return x rounded toward -inf to integral value
>     + * Method:
>     + *     Bit twiddling.
>     + */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-float.h>
>     +
>     +ENTRY(__ceilf)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
>     +       mfc1    a0, $f12 # assign int32
>     +       cfc1    t0, $f26
>     +       ceil.l.s    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 23, 8 # assign exp
>     +#else
>     +       dsrl    a3, a0, 23
>     +       andi    a3, a3, 0x1ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 23, 8 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 127
>     +       bnez    AT, SMALL # exp < 127
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 127+25
>     +       beqz    AT, BIG # exp >= 127+25
>     +       li      AT, 0xff
>     +
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.s   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +       srl     a2, a0, 31
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE: # return -0.0
>     +       jr      ra
>     +       neg.s   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.s   $f0, $f12
>     +       .set pop
>     +
>     +END (__ceilf)
>     +libm_alias_float (__ceil, ceil)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/fpu/s_floor.c b/sysdeps/mips/fpu/s_floor.c
>     new file mode 100644
>     index 0000000000..4b43dc9ad9
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_floor.c
>     @@ -0,0 +1,24 @@
>     +/* Round double to integer away from zero.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/dbl-64/s_floor.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_floor_fpu.S
>     b/sysdeps/mips/fpu/s_floor_fpu.S
>     new file mode 100644
>     index 0000000000..fda661fd3a
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_floor_fpu.S
>     @@ -0,0 +1,88 @@
>     +/* Round double to integer away from zero.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-double.h>
>     +
>     +ENTRY(__floor)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>     +#if __mips == 64
>     +       dmfc1   a0, $f12 # assign int64
>     +#else
>     +       mfhc1   a0, $f12 # assign int64
>     +#endif
>     +       cfc1    t0, $f26
>     +       floor.l.d    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 52, 11 # assign exp
>     +#else
>     +       dsrl    a3, a0, 52
>     +       andi    a3, a3, 0x7ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 20, 11 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 1023
>     +       bnez    AT, SMALL # exp < 1023
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 1023+54
>     +       beqz    AT, BIG # exp >= 1023+54
>     +       li      AT, 0x7ff
>     +
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.d   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +#if __mips == 64
>     +       dsrl    a2, a0, 63
>     +#else
>     +       srl     a2, a0, 31
>     +#endif
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       li      AT, 0xbff # used by SMALL_NEGATIVE
>     +SMALL_NEGATIVE:
>     +       mfhc1   t1, $f0
>     +       bnez    t1, SMALL_POSITIVE # sign == 0
>     +       nop
>     +
>     +       jr      ra
>     +       neg.d   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.d   $f0, $f12
>     +       .set pop
>     +
>     +END (__floor)
>     +libm_alias_double (__floor, floor)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/fpu/s_floorf.c b/sysdeps/mips/fpu/s_floorf.c
>     new file mode 100644
>     index 0000000000..30cfda7820
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_floorf.c
>     @@ -0,0 +1,24 @@
>     +/* Round double to integer away from zero.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/flt-32/s_floorf.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_floorf_fpu.S
>     b/sysdeps/mips/fpu/s_floorf_fpu.S
>     new file mode 100644
>     index 0000000000..8edd234dbc
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_floorf_fpu.S
>     @@ -0,0 +1,80 @@
>     +/* Round double to integer away from zero.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-float.h>
>     +
>     +ENTRY(__floorf)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
>     +       mfc1    a0, $f12 # assign int32
>     +       cfc1    t0, $f26
>     +       floor.l.s    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 23, 8 # assign exp
>     +#else
>     +       dsrl    a3, a0, 23
>     +       andi    a3, a3, 0x1ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 23, 8 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 127
>     +       bnez    AT, SMALL # exp < 127
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 127+25
>     +       beqz    AT, BIG # exp >= 127+25
>     +       li      AT, 0xff
>     +
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.s   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +       srl     a2, a0, 31
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       li      AT, 0xbff # used by SMALL_NEGATIVE
>     +SMALL_NEGATIVE:
>     +       mfhc1   t1, $f0
>     +       bnez    t1, SMALL_POSITIVE # sign == 0
>     +       nop
>     +
>     +       jr      ra
>     +       neg.s   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.s   $f0, $f12
>     +       .set pop
>     +
>     +END (__floorf)
>     +libm_alias_float (__floor, floor)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/fpu/s_roundeven.c
>     b/sysdeps/mips/fpu/s_roundeven.c
>     new file mode 100644
>     index 0000000000..dace85a70b
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_roundeven.c
>     @@ -0,0 +1,24 @@
>     +/* Round to nearest integer value, rounding halfway cases to even.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/dbl-64/s_roundeven.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_roundeven_fpu.S
>     b/sysdeps/mips/fpu/s_roundeven_fpu.S
>     new file mode 100644
>     index 0000000000..aef6434886
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_roundeven_fpu.S
>     @@ -0,0 +1,87 @@
>     +/* Round to nearest integer value, rounding halfway cases to even.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-double.h>
>     +
>     +ENTRY(__roundeven)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>     +#if __mips == 64
>     +       dmfc1   a0, $f12 # assign int64
>     +#else
>     +       mfhc1   a0, $f12 # assign int64
>     +#endif
>     +       cfc1    t0, $f26
>     +       round.l.d       $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 52, 11 # assign exp
>     +#else
>     +       dsrl    a3, a0, 52
>     +       andi    a3, a3, 0x7ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 20, 11 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 1023
>     +       bnez    AT, SMALL # exp < 1023
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 1023+54
>     +       beqz    AT, BIG # exp >= 1023+54
>     +       li      AT, 0x7ff
>     +
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.d   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +#if __mips == 64
>     +       dsrl    a2, a0, 63
>     +#else
>     +       srl     a2, a0, 31
>     +#endif
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE:
>     +       mfhc1   t1, $f0
>     +       bnez    t1, SMALL_POSITIVE # sign == 0
>     +       nop
>     +
>     +       jr      ra
>     +       neg.d   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.d   $f0, $f12
>     +       .set pop
>     +
>     +END (__roundeven)
>     +libm_alias_double (__roundeven, roundeven)
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_roundevenf.c
>     b/sysdeps/mips/fpu/s_roundevenf.c
>     new file mode 100644
>     index 0000000000..5bb35901db
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_roundevenf.c
>     @@ -0,0 +1,24 @@
>     +/* Round to nearest integer value, rounding halfway cases to even.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/flt-32/s_roundevenf.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_roundevenf_fpu.S
>     b/sysdeps/mips/fpu/s_roundevenf_fpu.S
>     new file mode 100644
>     index 0000000000..e946e50d8f
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_roundevenf_fpu.S
>     @@ -0,0 +1,79 @@
>     +/* Round to nearest integer value, rounding halfway cases to even.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-float.h>
>     +
>     +ENTRY(__roundevenf)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
>     +       mfc1    a0, $f12 # assign int32
>     +       cfc1    t0, $f26
>     +       round.l.s       $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 23, 8 # assign exp
>     +#else
>     +       dsrl    a3, a0, 23
>     +       andi    a3, a3, 0x1ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 23, 8 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 127
>     +       bnez    AT, SMALL # exp < 127
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 127+25
>     +       beqz    AT, BIG # exp >= 127+25
>     +       li      AT, 0xff
>     +
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.s   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +       srl     a2, a0, 31
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE:
>     +       mfhc1   t1, $f0
>     +       bnez    t1, SMALL_POSITIVE # sign == 0
>     +       nop
>     +
>     +       jr      ra
>     +       neg.s   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr ra
>     +       mov.s   $f0, $f12
>     +       .set pop
>     +
>     +END (__roundevenf)
>     +libm_alias_float (__roundeven, roundeven)
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_trunc.c b/sysdeps/mips/fpu/s_trunc.c
>     new file mode 100644
>     index 0000000000..3865026c70
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_trunc.c
>     @@ -0,0 +1,24 @@
>     +/* Truncate argument to nearest integral value not larger than
>     the argument.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/dbl-64/s_trunc.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_trunc_fpu.S
>     b/sysdeps/mips/fpu/s_trunc_fpu.S
>     new file mode 100644
>     index 0000000000..3a7947507f
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_trunc_fpu.S
>     @@ -0,0 +1,84 @@
>     +/* Truncate argument to nearest integral value not larger than
>     the argument.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-double.h>
>     +
>     +ENTRY(__trunc)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>     +#if __mips == 64
>     +       dmfc1   a0, $f12 # assign int64
>     +#else
>     +       mfhc1   a0, $f12 # assign int64
>     +#endif
>     +       cfc1    t0, $f26
>     +       trunc.l.d    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 52, 11 # assign exp
>     +#else
>     +       dsrl    a3, a0, 52
>     +       andi    a3, a3, 0x7ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 20, 11 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 1023
>     +       bnez    AT, SMALL # exp < 1023
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 1023+54
>     +       beqz    AT, BIG # exp >= 1023+54
>     +       li      AT, 0x7ff
>     +
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.d   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +#if __mips == 64
>     +       dsrl    a2, a0, 63
>     +#else
>     +       srl     a2, a0, 31
>     +#endif
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE: # return -0.0
>     +       jr      ra
>     +       neg.d   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.d.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr      ra
>     +       mov.d   $f0, $f12
>     +       .set pop
>     +
>     +END (__trunc)
>     +libm_alias_double (__trunc, trunc)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/fpu/s_truncf.c b/sysdeps/mips/fpu/s_truncf.c
>     new file mode 100644
>     index 0000000000..59ef17bf74
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_truncf.c
>     @@ -0,0 +1,24 @@
>     +/* Truncate argument to nearest integral value not larger than
>     the argument.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>     +#  include <sysdeps/ieee754/flt-32/s_truncf.c>
>     +
>     +#endif
>     diff --git a/sysdeps/mips/fpu/s_truncf_fpu.S
>     b/sysdeps/mips/fpu/s_truncf_fpu.S
>     new file mode 100644
>     index 0000000000..1878d88e3c
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_truncf_fpu.S
>     @@ -0,0 +1,76 @@
>     +/* Truncate argument to nearest integral value not larger than
>     the argument.
>     +   Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library; if not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips
>     == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +#include <sys/regdef.h>
>     +#include <sysdep.h>
>     +#include <libm-alias-float.h>
>     +
>     +ENTRY(__truncf)
>     +       .set push
>     +       .set noreorder
>     +       .set noat
>     +# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
>     +       mfc1    a0, $f12 # assign int32
>     +       cfc1    t0, $f26
>     +       trunc.l.s    $f0, $f12
>     +#if __mips == 64
>     +#if __mips_isa_rev > 1
>     +       dext    a3, a0, 23, 8 # assign exp
>     +#else
>     +       dsrl    a3, a0, 23
>     +       andi    a3, a3, 0x1ff
>     +#endif
>     +#else
>     +       ext     a3, a0, 23, 8 # assign exp
>     +#endif
>     +       sltiu   AT, a3, 127
>     +       bnez    AT, SMALL # exp < 127
>     +       ctc1    t0, $f26
>     +       sltiu   AT, a3, 127+25
>     +       beqz    AT, BIG # exp >= 127+25
>     +       li      AT, 0xff
>     +
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +BIG:
>     +       bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
>     +       nop
>     +NAN_INF:
>     +       jr      ra
>     +       add.s   $f0, $f12, $f12 # return double + double
>     +SMALL:
>     +       srl     a2, a0, 31
>     +       beqz    a2, SMALL_POSITIVE # sign == 0
>     +       nop
>     +SMALL_NEGATIVE: # return -0.0
>     +       jr      ra
>     +       neg.s   $f0, $f0
>     +SMALL_POSITIVE:
>     +       jr      ra
>     +       cvt.s.l $f0, $f0
>     +RETURN_AS_IS:
>     +       jr      ra
>     +       mov.s   $f0, $f12
>     +       .set pop
>     +
>     +END (__truncf)
>     +libm_alias_float (__trunc, trunc)
>     +
>     +#endif
>     +
>     diff --git a/sysdeps/mips/mips32/Implies b/sysdeps/mips/mips32/Implies
>     index 6473f2517c..71b3678c6c 100644
>     --- a/sysdeps/mips/mips32/Implies
>     +++ b/sysdeps/mips/mips32/Implies
>     @@ -1,3 +1,4 @@
>     +mips/fpu
>      mips/ieee754
>      mips
>      wordsize-32
>     diff --git a/sysdeps/mips/mips64/Implies b/sysdeps/mips/mips64/Implies
>     index 826ff1541f..8885ebd564 100644
>     --- a/sysdeps/mips/mips64/Implies
>     +++ b/sysdeps/mips/mips64/Implies
>     @@ -1,4 +1,5 @@
>      # MIPS uses IEEE 754 floating point.
>     +mips/fpu
>      mips/ieee754
>      ieee754/flt-32
>      ieee754/dbl-64
>     -- 
>     2.43.0.windows.1
>

According to restrictions about rounding instructions in MIPS 
instructions manual, "The result of this instruction is UNPREDICTABLE if 
the processor is executing in the FR=0 32-bit FPU register model; it is 
predictable if executing on a 64-bit FPU in the FR=1 mode, but not with 
FR=0, and not on a 32-bit FPU.".

It means that such MIPS rounding instruction could only work correct in 
the FR=1 mode, and fp64 is the only ABI can make sure MIPS FPU running 
at FR=1 mode. If we support fp32 or fpxx, the result will be UNPREDICTABLE.
  
Xi Ruoyao Dec. 26, 2023, 8:29 a.m. UTC | #5
On Tue, 2023-12-26 at 10:37 +0800, Junxian Zhu wrote:
> 在 2023/12/25 18:51, Xi Ruoyao 写道:
> > On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
> > 
> > /* snip */
> > 
> > > +/*
> > > + * ceil(x)
> > > + * Return x rounded toward -inf to integral value
> > > + * Method:
> > > + *	Bit twiddling.
> > > + */
> > > +
> > > +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> > > +#include <sys/regdef.h>
> > > +#include <sysdep.h>
> > > +#include <libm-alias-double.h>
> > > +
> > > +ENTRY(__ceil)
> > > +	.set push
> > > +	.set noreorder
> > > +	.set noat
> > > +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> > > +#if __mips == 64
> > > +	dmfc1   a0, $f12 # assign int64
> > > +#else
> > > +	mfhc1   a0, $f12 # assign int64
> > > +#endif
> > > +	cfc1    t0, $f26
> > > +	ceil.l.d    $f0, $f12
> > No, C23 does not allow this function to raise an INEXACT exception, but
> > ceil.l.d will do so.
> > 
> > Such optimizations should be performed in GCC which can be controlled by
> > the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
> > in Glibc where we cannot know if the programmer wants to deviate from
> > C23.
> 
> The cfc1 instruction will backup float point exception status before 
> running ceil.l.d, and the following ctc1 will restore float point 
> exception status to avoid INEXACT exception raised by ceil.l.d. It's the 
> same way like what have been done in s_ceil.S for i386.

Still incorrect because when the Enable field of FCSR contains INEXACT a
SIGFPE will be immediately delivered and there is no way to recover.  A
demonstration:

#define _GNU_SOURCE
#include <stdio.h>
#include <fenv.h>

int main()
{
  printf("%d\n", feenableexcept(FE_INEXACT));

  double data = 114.514;
  long control;
  asm("cfc1\t%1,$f26\n\t"
      "ceil.l.d\t%0,%0\n\t"
      "cvt.d.l\t%0,%0\n\t"
      "ctc1\t%1,$f26": "+f"(data), "=r"(control));
  printf("%.15f\n", data);
  return 0;
}

On i386 the fnstenv instruction also masks out all the FP exceptions so
this is not a problem.  See commit 26b0bf96000a.
  
Adhemerval Zanella Netto Dec. 26, 2023, 8:12 p.m. UTC | #6
On 26/12/23 05:29, Xi Ruoyao wrote:
> On Tue, 2023-12-26 at 10:37 +0800, Junxian Zhu wrote:
>> 在 2023/12/25 18:51, Xi Ruoyao 写道:
>>> On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
>>>
>>> /* snip */
>>>
>>>> +/*
>>>> + * ceil(x)
>>>> + * Return x rounded toward -inf to integral value
>>>> + * Method:
>>>> + *	Bit twiddling.
>>>> + */
>>>> +
>>>> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>>>> +#include <sys/regdef.h>
>>>> +#include <sysdep.h>
>>>> +#include <libm-alias-double.h>
>>>> +
>>>> +ENTRY(__ceil)
>>>> +	.set push
>>>> +	.set noreorder
>>>> +	.set noat
>>>> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>>>> +#if __mips == 64
>>>> +	dmfc1   a0, $f12 # assign int64
>>>> +#else
>>>> +	mfhc1   a0, $f12 # assign int64
>>>> +#endif
>>>> +	cfc1    t0, $f26
>>>> +	ceil.l.d    $f0, $f12
>>> No, C23 does not allow this function to raise an INEXACT exception, but
>>> ceil.l.d will do so.
>>>
>>> Such optimizations should be performed in GCC which can be controlled by
>>> the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
>>> in Glibc where we cannot know if the programmer wants to deviate from
>>> C23.
>>
>> The cfc1 instruction will backup float point exception status before 
>> running ceil.l.d, and the following ctc1 will restore float point 
>> exception status to avoid INEXACT exception raised by ceil.l.d. It's the 
>> same way like what have been done in s_ceil.S for i386.
> 
> Still incorrect because when the Enable field of FCSR contains INEXACT a
> SIGFPE will be immediately delivered and there is no way to recover.  A
> demonstration:
> 
> #define _GNU_SOURCE
> #include <stdio.h>
> #include <fenv.h>
> 
> int main()
> {
>   printf("%d\n", feenableexcept(FE_INEXACT));
> 
>   double data = 114.514;
>   long control;
>   asm("cfc1\t%1,$f26\n\t"
>       "ceil.l.d\t%0,%0\n\t"
>       "cvt.d.l\t%0,%0\n\t"
>       "ctc1\t%1,$f26": "+f"(data), "=r"(control));
>   printf("%.15f\n", data);
>   return 0;
> }
> 
> On i386 the fnstenv instruction also masks out all the FP exceptions so
> this is not a problem.  See commit 26b0bf96000a.
> 

And we lack proper tests for ceil, floor, round and trunc similar to 
test-nearbyint-except2.c to check if the implementation does not wrongly 
raise inexact floating point exception.

Also, I see no point in implementing this optimizations with assembly where
a C implementation would be way simpler and generate similar code. Similar 
to what I did for powerpc with sysdeps/powerpc/fpu/round_to_integer.h, I 
implemented a similar approach for MIPS [1].  The resulting code should be 
similar to the assembly implementation, taking in consideration the correct 
fix to save/restore floating-point exceptions. I did see no math regression 
on cfarm23 with a glibc built with -mabi=64 -mips64r2.

As a side note, it seems that x86 long double implementation are not fully c23
conformant (as they are wrongly raising inexact exception if the exception is
already set).

[1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/mips-hw-fp-round
  
Xi Ruoyao Dec. 26, 2023, 9:50 p.m. UTC | #7
On Tue, 2023-12-26 at 17:12 -0300, Adhemerval Zanella Netto wrote:
> Also, I see no point in implementing this optimizations with assembly where
> a C implementation would be way simpler and generate similar code. Similar 
> to what I did for powerpc with sysdeps/powerpc/fpu/round_to_integer.h, I 
> implemented a similar approach for MIPS [1].  The resulting code should be 
> similar to the assembly implementation, taking in consideration the correct 
> fix to save/restore floating-point exceptions. I did see no math regression 
> on cfarm23 with a glibc built with -mabi=64 -mips64r2.

Is there a micro-benchmark result on the cfarm machine?  AFAIK the FCSR
setting instruction may be much more slower than normal instructions, so
I'm not sure if this is really a win.
  
Xi Ruoyao Dec. 26, 2023, 10:50 p.m. UTC | #8
On Wed, 2023-12-27 at 05:50 +0800, Xi Ruoyao wrote:
> On Tue, 2023-12-26 at 17:12 -0300, Adhemerval Zanella Netto wrote:
> > Also, I see no point in implementing this optimizations with assembly where
> > a C implementation would be way simpler and generate similar code. Similar 
> > to what I did for powerpc with sysdeps/powerpc/fpu/round_to_integer.h, I 
> > implemented a similar approach for MIPS [1].  The resulting code should be 
> > similar to the assembly implementation, taking in consideration the correct 
> > fix to save/restore floating-point exceptions. I did see no math regression 
> > on cfarm23 with a glibc built with -mabi=64 -mips64r2.
> 
> Is there a micro-benchmark result on the cfarm machine?  AFAIK the FCSR
> setting instruction may be much more slower than normal instructions, so
> I'm not sure if this is really a win.

Add Jiaxun who knows MIPS much better than me.
  
Adhemerval Zanella Netto Dec. 27, 2023, 1:25 p.m. UTC | #9
On 26/12/23 19:50, Xi Ruoyao wrote:
> On Wed, 2023-12-27 at 05:50 +0800, Xi Ruoyao wrote:
>> On Tue, 2023-12-26 at 17:12 -0300, Adhemerval Zanella Netto wrote:
>>> Also, I see no point in implementing this optimizations with assembly where
>>> a C implementation would be way simpler and generate similar code. Similar 
>>> to what I did for powerpc with sysdeps/powerpc/fpu/round_to_integer.h, I 
>>> implemented a similar approach for MIPS [1].  The resulting code should be 
>>> similar to the assembly implementation, taking in consideration the correct 
>>> fix to save/restore floating-point exceptions. I did see no math regression 
>>> on cfarm23 with a glibc built with -mabi=64 -mips64r2.
>>
>> Is there a micro-benchmark result on the cfarm machine?  AFAIK the FCSR
>> setting instruction may be much more slower than normal instructions, so
>> I'm not sure if this is really a win.
> 
> Add Jiaxun who knows MIPS much better than me.
> 

This is a good question, we do have a trunc one which should give us a hint
whether this strategy might shows any performance gain.  At least with 
cfarm230 (Cavium Octeon III V0.2  FPU V0.0) my version is actually worse 
than the generic one:

- Using master/generic:
$ ./ld.so --library-path . ./bench-trunc
  "trunc": {
   "": {
    "duration": 9.83902e+08,
    "iterations": 4.2864e+07,
    "max": 10027.9,
    "min": 21.329,
    "mean": 22.954
   }
  }

- Using trunc.l.d:
$ ./ld.so --library-path . ./bench-trunc
  "trunc": {
   "": {
    "duration": 9.91892e+08,
    "iterations": 2.2458e+07,
    "max": 10048.9,
    "min": 38.326,
    "mean": 44.1666
   }
  }

The system does not have perf, but I guess that libc_fesetenv_mips is really
bad performance-wise since it requires to read the current state to flush the
fpu pipeline and the set the previous one (which is ends up being two cfc1).

In any case I updated my branch [1] with single float implementation, if any
wants to experiment with it.

At least this experiment raised the issue that some ceil, floor, round, and/or
trunc implementation might still raising inexact floating point exceptions due
lacking of proper testing.

PS: I had to disable the vDSO on this system since clock_gettime was returning
bogus value that make the bench tests unusable.

[1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/mips-hw-fp-round
  
Joseph Myers Dec. 29, 2023, 1 a.m. UTC | #10
On Mon, 25 Dec 2023, Junxian Zhu wrote:

> diff --git a/sysdeps/mips/mips32/Implies b/sysdeps/mips/mips32/Implies
> index 6473f2517c..71b3678c6c 100644
> --- a/sysdeps/mips/mips32/Implies
> +++ b/sysdeps/mips/mips32/Implies
> @@ -1,3 +1,4 @@
> +mips/fpu
>  mips/ieee754
>  mips
>  wordsize-32
> diff --git a/sysdeps/mips/mips64/Implies b/sysdeps/mips/mips64/Implies
> index 826ff1541f..8885ebd564 100644
> --- a/sysdeps/mips/mips64/Implies
> +++ b/sysdeps/mips/mips64/Implies
> @@ -1,4 +1,5 @@
>  # MIPS uses IEEE 754 floating point.
> +mips/fpu
>  mips/ieee754
>  ieee754/flt-32
>  ieee754/dbl-64

These changes are clearly incorrect, as they would cause mips/fpu/ to be 
used for soft-float.  The fpu/ directories are selected automatically for 
hard-float, and must not be used for soft-float.

I'm guessing you're motivated by some ordering issue that results in the 
ieee754/ directories ending up being used before mips/fpu/.  I'm not sure 
of the best way to avoid such an ordering issue (noting that the ieee754/ 
directories go in Implies separately for mips32 and mips64 because only 
mips64 uses ldbl-128), but e.g. #includes like in 
sysdeps/mips/mips64/n32/fpu/s_fma.c should work if you can't get the 
preferred sysdeps directory ordering.
  
Junxian Zhu Jan. 2, 2024, 9:43 a.m. UTC | #11
在 2023/12/26 16:29, Xi Ruoyao 写道:
> On Tue, 2023-12-26 at 10:37 +0800, Junxian Zhu wrote:
>> 在 2023/12/25 18:51, Xi Ruoyao 写道:
>>> On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
>>>
>>> /* snip */
>>>
>>>> +/*
>>>> + * ceil(x)
>>>> + * Return x rounded toward -inf to integral value
>>>> + * Method:
>>>> + *	Bit twiddling.
>>>> + */
>>>> +
>>>> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>>>> +#include <sys/regdef.h>
>>>> +#include <sysdep.h>
>>>> +#include <libm-alias-double.h>
>>>> +
>>>> +ENTRY(__ceil)
>>>> +	.set push
>>>> +	.set noreorder
>>>> +	.set noat
>>>> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>>>> +#if __mips == 64
>>>> +	dmfc1   a0, $f12 # assign int64
>>>> +#else
>>>> +	mfhc1   a0, $f12 # assign int64
>>>> +#endif
>>>> +	cfc1    t0, $f26
>>>> +	ceil.l.d    $f0, $f12
>>> No, C23 does not allow this function to raise an INEXACT exception, but
>>> ceil.l.d will do so.
>>>
>>> Such optimizations should be performed in GCC which can be controlled by
>>> the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
>>> in Glibc where we cannot know if the programmer wants to deviate from
>>> C23.
>> The cfc1 instruction will backup float point exception status before
>> running ceil.l.d, and the following ctc1 will restore float point
>> exception status to avoid INEXACT exception raised by ceil.l.d. It's the
>> same way like what have been done in s_ceil.S for i386.
> Still incorrect because when the Enable field of FCSR contains INEXACT a
> SIGFPE will be immediately delivered and there is no way to recover.  A
> demonstration:
>
> #define _GNU_SOURCE
> #include <stdio.h>
> #include <fenv.h>
>
> int main()
> {
>    printf("%d\n", feenableexcept(FE_INEXACT));
>
>    double data = 114.514;
>    long control;
>    asm("cfc1\t%1,$f26\n\t"
>        "ceil.l.d\t%0,%0\n\t"
>        "cvt.d.l\t%0,%0\n\t"
>        "ctc1\t%1,$f26": "+f"(data), "=r"(control));
>    printf("%.15f\n", data);
>    return 0;
> }
>
> On i386 the fnstenv instruction also masks out all the FP exceptions so
> this is not a problem.  See commit 26b0bf96000a.

I can use "ctc1 $0, $28" to disable all float point exception to ensure 
no FP exceptions occur at here. But it will introduce additional 
consumption.
  
Junxian Zhu Jan. 2, 2024, 9:51 a.m. UTC | #12
在 2023/12/25 20:36, YunQiang Su 写道:
>
> Junxian Zhu <zhujunxian@oss.cipunited.com> 于 2023年12月25日周一 
> 18:38写道:
>
>     From: Junxian Zhu <zhujunxian@oss.cipunited.com>
>
>     Use hardware floating-point rounding instructions to implement
>     roundeven, trunc, ceil and floor.
>
>     * sysdeps/mips/mips32/Implies: Add source path.
>     * sysdeps/mips/mips64/Implies: Likewise.
>     * sysdeps/mips/fpu/Makefile: Newfile.
>     * sysdeps/mips/fpu/s_ceil.c: Likewise.
>     * sysdeps/mips/fpu/s_ceil_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_ceilf.c: Likewise.
>     * sysdeps/mips/fpu/s_ceilf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_floor.c: Likewise.
>     * sysdeps/mips/fpu/s_floor_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_floorf.c: Likewise.
>     * sysdeps/mips/fpu/s_floorf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_roundeven.c: Likewise.
>     * sysdeps/mips/fpu/s_roundeven_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_roundevenf.c: Likewise.
>     * sysdeps/mips/fpu/s_roundevenf_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_trunc.c: Likewise.
>     * sysdeps/mips/fpu/s_trunc_fpu.S: Likewise.
>     * sysdeps/mips/fpu/s_truncf.c: Likewise.
>     * sysdeps/mips/fpu/s_truncf_fpu.S: Likewise.
>
>     Signed-off-by: Rong Zhang <rongrong@oss.cipunited.com>
>     Signed-off-by: Junxian Zhu <zhujunxian@oss.cipunited.com>
>     ---
>      sysdeps/mips/fpu/Makefile           | 12 ++++
>      sysdeps/mips/fpu/s_ceil.c           | 30 ++++++++++
>      sysdeps/mips/fpu/s_ceil_fpu.S       | 90
>     +++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_ceilf.c          | 30 ++++++++++
>      sysdeps/mips/fpu/s_ceilf_fpu.S      | 82 ++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_floor.c          | 24 ++++++++
>      sysdeps/mips/fpu/s_floor_fpu.S      | 88 ++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_floorf.c         | 24 ++++++++
>      sysdeps/mips/fpu/s_floorf_fpu.S     | 80 +++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_roundeven.c      | 24 ++++++++
>      sysdeps/mips/fpu/s_roundeven_fpu.S  | 87 ++++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_roundevenf.c     | 24 ++++++++
>      sysdeps/mips/fpu/s_roundevenf_fpu.S | 79 +++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_trunc.c          | 24 ++++++++
>      sysdeps/mips/fpu/s_trunc_fpu.S      | 84 +++++++++++++++++++++++++++
>      sysdeps/mips/fpu/s_truncf.c         | 24 ++++++++
>      sysdeps/mips/fpu/s_truncf_fpu.S     | 76 ++++++++++++++++++++++++
>      sysdeps/mips/mips32/Implies         |  1 +
>      sysdeps/mips/mips64/Implies         |  1 +
>      19 files changed, 884 insertions(+)
>      create mode 100644 sysdeps/mips/fpu/Makefile
>      create mode 100644 sysdeps/mips/fpu/s_ceil.c
>      create mode 100644 sysdeps/mips/fpu/s_ceil_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_ceilf.c
>      create mode 100644 sysdeps/mips/fpu/s_ceilf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_floor.c
>      create mode 100644 sysdeps/mips/fpu/s_floor_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_floorf.c
>      create mode 100644 sysdeps/mips/fpu/s_floorf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_roundeven.c
>      create mode 100644 sysdeps/mips/fpu/s_roundeven_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_roundevenf.c
>      create mode 100644 sysdeps/mips/fpu/s_roundevenf_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_trunc.c
>      create mode 100644 sysdeps/mips/fpu/s_trunc_fpu.S
>      create mode 100644 sysdeps/mips/fpu/s_truncf.c
>      create mode 100644 sysdeps/mips/fpu/s_truncf_fpu.S
>
>     diff --git a/sysdeps/mips/fpu/Makefile b/sysdeps/mips/fpu/Makefile
>     new file mode 100644
>     index 0000000000..ad537d6bf1
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/Makefile
>     @@ -0,0 +1,12 @@
>     +ifeq ($(subdir),math)
>     +sysdep_routines += s_floor_fpu s_floorf_fpu \
>     +                       s_ceil_fpu s_ceilf_fpu \
>     +                       s_trunc_fpu s_truncf_fpu \
>     +                       s_roundeven_fpu s_roundevenf_fpu
>     +
>     +libm-sysdep_routines += s_floor_fpu s_floorf_fpu \
>     +                       s_ceil_fpu s_ceilf_fpu \
>     +                       s_trunc_fpu s_truncf_fpu \
>     +                       s_roundeven_fpu s_roundevenf_fpu
>     +
>     +endif
>     diff --git a/sysdeps/mips/fpu/s_ceil.c b/sysdeps/mips/fpu/s_ceil.c
>     new file mode 100644
>     index 0000000000..91a90a70c5
>     --- /dev/null
>     +++ b/sysdeps/mips/fpu/s_ceil.c
>     @@ -0,0 +1,30 @@
>     +/* Copyright (C) 2023 Free Software Foundation, Inc.
>     +   This file is part of the GNU C Library.
>     +
>     +   The GNU C Library is free software; you can redistribute it and/or
>     +   modify it under the terms of the GNU Lesser General Public
>     +   License as published by the Free Software Foundation; either
>     +   version 2.1 of the License, or (at your option) any later version.
>     +
>     +   The GNU C Library is distributed in the hope that it will be
>     useful,
>     +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>     +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     +   Lesser General Public License for more details.
>     +
>     +   You should have received a copy of the GNU Lesser General Public
>     +   License along with the GNU C Library.  If not, see
>     +   <https://www.gnu.org/licenses/>. */
>     +
>     +/*
>     + * ceil(x)
>     + * Return x rounded toward -inf to integral value
>     + * Method:
>     + *     Bit twiddling.
>     + */
>     +
>     +#if !((__mips_fpr == 64) && (__mips_hard_float == 1)             
>                 \
>     +      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>     +
>
>
> __mips_fpr == 64
> this condition should not be here.
> it means fp64.
> In fact your code should also support fp32 and fpxx.
>

The MIPS instruction documentation has specifies restrictions for the 
ceil, round, floor and trunc. "The result of this instruction is 
UNPREDICTABLE if the processor is executing in the FR=0 32-bit FPU 
register model; it is predictable if executing on a 64-bit FPU in the 
FR=1 mode, but not with FR=0, and not on a 32-bit FPU."

And fp64 ABI is the only configuration that restricts FPU work in FR=1 
mode.
  
Xi Ruoyao Jan. 2, 2024, 9:57 a.m. UTC | #13
On Tue, 2024-01-02 at 17:43 +0800, Junxian Zhu wrote:
> 在 2023/12/26 16:29, Xi Ruoyao 写道:
> > On Tue, 2023-12-26 at 10:37 +0800, Junxian Zhu wrote:
> > > 在 2023/12/25 18:51, Xi Ruoyao 写道:
> > > > On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
> > > > 
> > > > /* snip */
> > > > 
> > > > > +/*
> > > > > + * ceil(x)
> > > > > + * Return x rounded toward -inf to integral value
> > > > > + * Method:
> > > > > + *	Bit twiddling.
> > > > > + */
> > > > > +
> > > > > +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> > > > > +#include <sys/regdef.h>
> > > > > +#include <sysdep.h>
> > > > > +#include <libm-alias-double.h>
> > > > > +
> > > > > +ENTRY(__ceil)
> > > > > +	.set push
> > > > > +	.set noreorder
> > > > > +	.set noat
> > > > > +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
> > > > > +#if __mips == 64
> > > > > +	dmfc1   a0, $f12 # assign int64
> > > > > +#else
> > > > > +	mfhc1   a0, $f12 # assign int64
> > > > > +#endif
> > > > > +	cfc1    t0, $f26
> > > > > +	ceil.l.d    $f0, $f12
> > > > No, C23 does not allow this function to raise an INEXACT exception, but
> > > > ceil.l.d will do so.
> > > > 
> > > > Such optimizations should be performed in GCC which can be controlled by
> > > > the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
> > > > in Glibc where we cannot know if the programmer wants to deviate from
> > > > C23.
> > > The cfc1 instruction will backup float point exception status before
> > > running ceil.l.d, and the following ctc1 will restore float point
> > > exception status to avoid INEXACT exception raised by ceil.l.d. It's the
> > > same way like what have been done in s_ceil.S for i386.
> > Still incorrect because when the Enable field of FCSR contains INEXACT a
> > SIGFPE will be immediately delivered and there is no way to recover.  A
> > demonstration:
> > 
> > #define _GNU_SOURCE
> > #include <stdio.h>
> > #include <fenv.h>
> > 
> > int main()
> > {
> >    printf("%d\n", feenableexcept(FE_INEXACT));
> > 
> >    double data = 114.514;
> >    long control;
> >    asm("cfc1\t%1,$f26\n\t"
> >        "ceil.l.d\t%0,%0\n\t"
> >        "cvt.d.l\t%0,%0\n\t"
> >        "ctc1\t%1,$f26": "+f"(data), "=r"(control));
> >    printf("%.15f\n", data);
> >    return 0;
> > }
> > 
> > On i386 the fnstenv instruction also masks out all the FP exceptions so
> > this is not a problem.  See commit 26b0bf96000a.
> 
> I can use "ctc1 $0, $28" to disable all float point exception to ensure 
> no FP exceptions occur at here. But it will introduce additional 
> consumption.

And then it will likely be even slower than the generic implementation
like Adhemerval already tested on the cfarm machine.  Frankly I'm even
unsure if your (incorrect) implementation is really faster than the
generic implementation: if the uarch just handles all ctc1 instructions
equally (i.e. always stalling the FP unit or even the entire CPU for a
dozen of cycles) it would be already slower.

Have you benchmarked this on real hardware?  Note that benchmarking on
things like QEMU can be completely misleading.
  
Junxian Zhu Jan. 2, 2024, 10:08 a.m. UTC | #14
在 2023/12/27 6:50, Xi Ruoyao 写道:
> On Wed, 2023-12-27 at 05:50 +0800, Xi Ruoyao wrote:
>> On Tue, 2023-12-26 at 17:12 -0300, Adhemerval Zanella Netto wrote:
>>> Also, I see no point in implementing this optimizations with assembly where
>>> a C implementation would be way simpler and generate similar code. Similar
>>> to what I did for powerpc with sysdeps/powerpc/fpu/round_to_integer.h, I
>>> implemented a similar approach for MIPS [1].  The resulting code should be
>>> similar to the assembly implementation, taking in consideration the correct
>>> fix to save/restore floating-point exceptions. I did see no math regression
>>> on cfarm23 with a glibc built with -mabi=64 -mips64r2.
>> Is there a micro-benchmark result on the cfarm machine?  AFAIK the FCSR
>> setting instruction may be much more slower than normal instructions, so
>> I'm not sure if this is really a win.
> Add Jiaxun who knows MIPS much better than me.

After disscussion with Jiaxun, we guess that the consuming of switching 
mode in FCSR is the cause of FPU implements slower than generic 
implements. If we don't change or switching mode in FCSR, the FPU 
implements will be faster than generic implements. Tested on Imagination 
Ci40 (MIPS interAptiv (multi) V2.0  FPU V0.0)and loogson 3A2000.

So it's enough to use generic C implements for rounding on MIPS.......
  
Junxian Zhu Jan. 25, 2024, 1:58 p.m. UTC | #15
在 2023/12/25 18:51, Xi Ruoyao 写道:
> On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
>
> /* snip */
>
>> +/*
>> + * ceil(x)
>> + * Return x rounded toward -inf to integral value
>> + * Method:
>> + *	Bit twiddling.
>> + */
>> +
>> +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
>> +#include <sys/regdef.h>
>> +#include <sysdep.h>
>> +#include <libm-alias-double.h>
>> +
>> +ENTRY(__ceil)
>> +	.set push
>> +	.set noreorder
>> +	.set noat
>> +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
>> +#if __mips == 64
>> +	dmfc1   a0, $f12 # assign int64
>> +#else
>> +	mfhc1   a0, $f12 # assign int64
>> +#endif
>> +	cfc1    t0, $f26
>> +	ceil.l.d    $f0, $f12
> No, C23 does not allow this function to raise an INEXACT exception, but
> ceil.l.d will do so.
>
> Such optimizations should be performed in GCC which can be controlled by
> the programmer with -std=c23 and/or -f[no-]fp-int-builtin-inexact, not
> in Glibc where we cannot know if the programmer wants to deviate from
> C23.


Recently, I'm still trying to do some optimization for MIPS. I want to 
know if I use rounding instructions on MIPS, like |round.l.d|, in 
functions with parameters input in FPR and results in GPR, like 
|llrint|or |lrint|, will we still face the INEXACT exception and 
potentially violate C23?
  
Xi Ruoyao Jan. 25, 2024, 2:37 p.m. UTC | #16
On Thu, 2024-01-25 at 21:58 +0800, Junxian Zhu wrote:

> Recently, I'm still trying to do some optimization for MIPS. I want to
> know if I use rounding instructions on MIPS, like |round.l.d|, in 
> functions with parameters input in FPR and results in GPR, like 
> > llrint|or |lrint|, will we still face the INEXACT exception and 
> potentially violate C23?

C23 explicitly says llrint and lrint *raises* FE_INEXACT exception when
they raise no other floating-point exception and the result differs from
the argument.

But you should still do the optimization in GCC, then define
USE_LRINT_BUILTIN etc. in Glibc if GCC is recent enough to support it. 
By doing this in the compiler, users can avoid an overhead to do a
function call (esp. on MIPS with all the "abicall" stuff the overhead is
very large).
  
Xi Ruoyao Jan. 31, 2024, 9:08 a.m. UTC | #17
On Wed, 2024-01-31 at 11:28 +0800, Junxian Zhu wrote:
> 在 2023/12/26 16:29, Xi Ruoyao 写道:
> > On Tue, 2023-12-26 at 10:37 +0800, Junxian Zhu wrote:
> > > 在 2023/12/25 18:51, Xi Ruoyao 写道:
> > > > On Mon, 2023-12-25 at 18:35 +0800, Junxian Zhu wrote:
> > > > 
> > > > /* snip */
> > > > 
> > > > > +/*
> > > > > + * ceil(x)
> > > > > + * Return x rounded toward -inf to integral value
> > > > > + * Method:
> > > > > + *	Bit twiddling.
> > > > > + */
> > > > > +
> > > > > +#if ((__mips_fpr == 64) && (__mips_hard_float == 1) &&
> > > > > ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
> > > > > +#include <sys/regdef.h>
> > > > > +#include <sysdep.h>
> > > > > +#include <libm-alias-double.h>
> > > > > +
> > > > > +ENTRY(__ceil)
> > > > > +	.set push
> > > > > +	.set noreorder
> > > > > +	.set noat
> > > > > +# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l,
> > > > > a2=sign, a3=exp
> > > > > +#if __mips == 64
> > > > > +	dmfc1   a0, $f12 # assign int64
> > > > > +#else
> > > > > +	mfhc1   a0, $f12 # assign int64
> > > > > +#endif
> > > > > +	cfc1    t0, $f26
> > > > > +	ceil.l.d    $f0, $f12
> > > > No, C23 does not allow this function to raise an INEXACT
> > > > exception, but
> > > > ceil.l.d will do so.
> > > > 
> > > > Such optimizations should be performed in GCC which can be
> > > > controlled by
> > > > the programmer with -std=c23 and/or -f[no-]fp-int-builtin-
> > > > inexact, not
> > > > in Glibc where we cannot know if the programmer wants to deviate
> > > > from
> > > > C23.
> > > The cfc1 instruction will backup float point exception status
> > > before
> > > running ceil.l.d, and the following ctc1 will restore float point
> > > exception status to avoid INEXACT exception raised by ceil.l.d.
> > > It's the
> > > same way like what have been done in s_ceil.S for i386.
> > Still incorrect because when the Enable field of FCSR contains
> > INEXACT a
> > SIGFPE will be immediately delivered and there is no way to
> > recover.  A
> > demonstration:
> > 
> > #define _GNU_SOURCE
> > #include <stdio.h>
> > #include <fenv.h>
> > 
> > int main()
> > {
> >    printf("%d\n", feenableexcept(FE_INEXACT));
> > 
> >    double data = 114.514;
> >    long control;
> >    asm("cfc1\t%1,$f26\n\t"
> >        "ceil.l.d\t%0,%0\n\t"
> >        "cvt.d.l\t%0,%0\n\t"
> >        "ctc1\t%1,$f26": "+f"(data), "=r"(control));
> >    printf("%.15f\n", data);
> >    return 0;
> > }
> > 
> > On i386 the fnstenv instruction also masks out all the FP exceptions
> > so
> > this is not a problem.  See commit 26b0bf96000a.
> 
> I made some similar code to test and found that sqrt.fmt on MIPS will 
> raise INEXACT exception too.
> 
> So should we mask all the FP exceptions while compiling MIPS 
> SQRT{F}_BUILTIN in GCC ? (for C23)

Why?

    volatile double x = 2;
    sqrt(x); 

should definitely raise an INEXACT exception.  Unless explicitly stated
otherwise, all operations producing a result different than the
"infinite precision operation" should do it.  For the conversion
operations they are just "explicitly stated otherwise."

But if sqrt.fmt is raising it for

    volatile double x = 4;
    sqrt(x); 

it's obviously wrong, and I'd say such an exception is nonsense even
regardless of the standard so we should just not use this instruction.

Something not so obvious is: the standard explicitly says

    volatile double x = __builtin_inf();
    sqrt(x); 

should **not** raise an INEXACT exception.  So if you are raising
INEXACT for this you should only use sqrt.fmt when you can prove the
operand is finite (for example when -ffinite-math-only, or using some
information from the VRP pass).
  

Patch

diff --git a/sysdeps/mips/fpu/Makefile b/sysdeps/mips/fpu/Makefile
new file mode 100644
index 0000000000..ad537d6bf1
--- /dev/null
+++ b/sysdeps/mips/fpu/Makefile
@@ -0,0 +1,12 @@ 
+ifeq ($(subdir),math)
+sysdep_routines += s_floor_fpu s_floorf_fpu \
+			s_ceil_fpu s_ceilf_fpu \
+			s_trunc_fpu s_truncf_fpu \
+			s_roundeven_fpu s_roundevenf_fpu 
+
+libm-sysdep_routines += s_floor_fpu s_floorf_fpu \
+			s_ceil_fpu s_ceilf_fpu \
+			s_trunc_fpu s_truncf_fpu \
+			s_roundeven_fpu s_roundevenf_fpu 
+
+endif
diff --git a/sysdeps/mips/fpu/s_ceil.c b/sysdeps/mips/fpu/s_ceil.c
new file mode 100644
index 0000000000..91a90a70c5
--- /dev/null
+++ b/sysdeps/mips/fpu/s_ceil.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/dbl-64/s_ceil.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_ceil_fpu.S b/sysdeps/mips/fpu/s_ceil_fpu.S
new file mode 100644
index 0000000000..13d4f85ad3
--- /dev/null
+++ b/sysdeps/mips/fpu/s_ceil_fpu.S
@@ -0,0 +1,90 @@ 
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-double.h>
+
+ENTRY(__ceil)
+	.set push
+	.set noreorder
+	.set noat
+# $f0=ret, $f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
+#if __mips == 64
+	dmfc1   a0, $f12 # assign int64
+#else
+	mfhc1   a0, $f12 # assign int64
+#endif
+	cfc1    t0, $f26
+	ceil.l.d    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 52, 11 # assign exp
+#else
+	dsrl    a3, a0, 52
+	andi    a3, a3, 0x7ff
+#endif
+#else
+	ext     a3, a0, 20, 11 # assign exp
+#endif
+	sltiu   AT, a3, 1023
+	bnez    AT, SMALL # exp < 1023
+	ctc1    t0, $f26
+	sltiu   AT, a3, 1023+54
+	beqz    AT, BIG # exp >= 1023+54
+	li      AT, 0x7ff
+
+	jr      ra
+	cvt.d.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.d   $f0, $f12, $f12 # return double + double
+SMALL:
+#if __mips == 64
+	dsrl    a2, a0, 63
+#else
+	srl     a2, a0, 31
+#endif
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE: # return -0.0
+	jr      ra
+	neg.d   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.d.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.d   $f0, $f12
+	.set pop
+
+END (__ceil)
+libm_alias_double (__ceil, ceil)
+
+#endif
+
diff --git a/sysdeps/mips/fpu/s_ceilf.c b/sysdeps/mips/fpu/s_ceilf.c
new file mode 100644
index 0000000000..a7f81c7539
--- /dev/null
+++ b/sysdeps/mips/fpu/s_ceilf.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/flt-32/s_ceilf.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_ceilf_fpu.S b/sysdeps/mips/fpu/s_ceilf_fpu.S
new file mode 100644
index 0000000000..7952894f73
--- /dev/null
+++ b/sysdeps/mips/fpu/s_ceilf_fpu.S
@@ -0,0 +1,82 @@ 
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-float.h>
+
+ENTRY(__ceilf)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
+	mfc1    a0, $f12 # assign int32
+	cfc1    t0, $f26
+	ceil.l.s    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 23, 8 # assign exp
+#else
+	dsrl    a3, a0, 23
+	andi    a3, a3, 0x1ff
+#endif
+#else
+	ext     a3, a0, 23, 8 # assign exp
+#endif
+	sltiu   AT, a3, 127
+	bnez    AT, SMALL # exp < 127
+	ctc1    t0, $f26
+	sltiu   AT, a3, 127+25
+	beqz    AT, BIG # exp >= 127+25
+	li      AT, 0xff
+
+	jr      ra
+	cvt.s.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.s   $f0, $f12, $f12 # return double + double
+SMALL:
+	srl     a2, a0, 31
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE: # return -0.0
+	jr      ra
+	neg.s   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.s.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.s   $f0, $f12
+	.set pop
+
+END (__ceilf)
+libm_alias_float (__ceil, ceil)
+
+#endif
+
diff --git a/sysdeps/mips/fpu/s_floor.c b/sysdeps/mips/fpu/s_floor.c
new file mode 100644
index 0000000000..4b43dc9ad9
--- /dev/null
+++ b/sysdeps/mips/fpu/s_floor.c
@@ -0,0 +1,24 @@ 
+/* Round double to integer away from zero.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/dbl-64/s_floor.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_floor_fpu.S b/sysdeps/mips/fpu/s_floor_fpu.S
new file mode 100644
index 0000000000..fda661fd3a
--- /dev/null
+++ b/sysdeps/mips/fpu/s_floor_fpu.S
@@ -0,0 +1,88 @@ 
+/* Round double to integer away from zero.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-double.h>
+
+ENTRY(__floor)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
+#if __mips == 64
+	dmfc1   a0, $f12 # assign int64
+#else
+	mfhc1   a0, $f12 # assign int64
+#endif
+	cfc1    t0, $f26
+	floor.l.d    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 52, 11 # assign exp
+#else
+	dsrl    a3, a0, 52
+	andi    a3, a3, 0x7ff
+#endif
+#else
+	ext     a3, a0, 20, 11 # assign exp
+#endif
+	sltiu   AT, a3, 1023
+	bnez    AT, SMALL # exp < 1023
+	ctc1    t0, $f26
+	sltiu   AT, a3, 1023+54
+	beqz    AT, BIG # exp >= 1023+54
+	li      AT, 0x7ff
+
+	jr      ra
+	cvt.d.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.d   $f0, $f12, $f12 # return double + double
+SMALL:
+#if __mips == 64
+	dsrl    a2, a0, 63
+#else
+	srl     a2, a0, 31
+#endif
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	li      AT, 0xbff # used by SMALL_NEGATIVE
+SMALL_NEGATIVE:
+	mfhc1   t1, $f0
+	bnez    t1, SMALL_POSITIVE # sign == 0
+	nop
+
+	jr      ra
+	neg.d   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.d.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.d   $f0, $f12
+	.set pop
+
+END (__floor)
+libm_alias_double (__floor, floor)
+
+#endif
+
diff --git a/sysdeps/mips/fpu/s_floorf.c b/sysdeps/mips/fpu/s_floorf.c
new file mode 100644
index 0000000000..30cfda7820
--- /dev/null
+++ b/sysdeps/mips/fpu/s_floorf.c
@@ -0,0 +1,24 @@ 
+/* Round double to integer away from zero.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/flt-32/s_floorf.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_floorf_fpu.S b/sysdeps/mips/fpu/s_floorf_fpu.S
new file mode 100644
index 0000000000..8edd234dbc
--- /dev/null
+++ b/sysdeps/mips/fpu/s_floorf_fpu.S
@@ -0,0 +1,80 @@ 
+/* Round double to integer away from zero.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-float.h>
+
+ENTRY(__floorf)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
+	mfc1    a0, $f12 # assign int32
+	cfc1    t0, $f26
+	floor.l.s    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 23, 8 # assign exp
+#else
+	dsrl    a3, a0, 23
+	andi    a3, a3, 0x1ff
+#endif
+#else
+	ext     a3, a0, 23, 8 # assign exp
+#endif
+	sltiu   AT, a3, 127
+	bnez    AT, SMALL # exp < 127
+	ctc1    t0, $f26
+	sltiu   AT, a3, 127+25
+	beqz    AT, BIG # exp >= 127+25
+	li      AT, 0xff
+
+	jr      ra
+	cvt.s.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.s   $f0, $f12, $f12 # return double + double
+SMALL:
+	srl     a2, a0, 31
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	li      AT, 0xbff # used by SMALL_NEGATIVE
+SMALL_NEGATIVE:
+	mfhc1   t1, $f0
+	bnez    t1, SMALL_POSITIVE # sign == 0
+	nop
+
+	jr      ra
+	neg.s   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.s.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.s   $f0, $f12
+	.set pop
+
+END (__floorf)
+libm_alias_float (__floor, floor)
+
+#endif
+
diff --git a/sysdeps/mips/fpu/s_roundeven.c b/sysdeps/mips/fpu/s_roundeven.c
new file mode 100644
index 0000000000..dace85a70b
--- /dev/null
+++ b/sysdeps/mips/fpu/s_roundeven.c
@@ -0,0 +1,24 @@ 
+/* Round to nearest integer value, rounding halfway cases to even.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/dbl-64/s_roundeven.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_roundeven_fpu.S b/sysdeps/mips/fpu/s_roundeven_fpu.S
new file mode 100644
index 0000000000..aef6434886
--- /dev/null
+++ b/sysdeps/mips/fpu/s_roundeven_fpu.S
@@ -0,0 +1,87 @@ 
+/* Round to nearest integer value, rounding halfway cases to even.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-double.h>
+
+ENTRY(__roundeven)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
+#if __mips == 64
+	dmfc1   a0, $f12 # assign int64
+#else
+	mfhc1   a0, $f12 # assign int64
+#endif
+	cfc1    t0, $f26
+	round.l.d       $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 52, 11 # assign exp
+#else
+	dsrl    a3, a0, 52
+	andi    a3, a3, 0x7ff
+#endif
+#else
+	ext     a3, a0, 20, 11 # assign exp
+#endif
+	sltiu   AT, a3, 1023
+	bnez    AT, SMALL # exp < 1023
+	ctc1    t0, $f26
+	sltiu   AT, a3, 1023+54
+	beqz    AT, BIG # exp >= 1023+54
+	li      AT, 0x7ff
+
+	jr      ra
+	cvt.d.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.d   $f0, $f12, $f12 # return double + double
+SMALL:
+#if __mips == 64
+	dsrl    a2, a0, 63
+#else
+	srl     a2, a0, 31
+#endif
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE:
+	mfhc1   t1, $f0
+	bnez    t1, SMALL_POSITIVE # sign == 0
+	nop
+
+	jr      ra
+	neg.d   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.d.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.d   $f0, $f12
+	.set pop
+
+END (__roundeven)
+libm_alias_double (__roundeven, roundeven)
+
+#endif
diff --git a/sysdeps/mips/fpu/s_roundevenf.c b/sysdeps/mips/fpu/s_roundevenf.c
new file mode 100644
index 0000000000..5bb35901db
--- /dev/null
+++ b/sysdeps/mips/fpu/s_roundevenf.c
@@ -0,0 +1,24 @@ 
+/* Round to nearest integer value, rounding halfway cases to even.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/flt-32/s_roundevenf.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_roundevenf_fpu.S b/sysdeps/mips/fpu/s_roundevenf_fpu.S
new file mode 100644
index 0000000000..e946e50d8f
--- /dev/null
+++ b/sysdeps/mips/fpu/s_roundevenf_fpu.S
@@ -0,0 +1,79 @@ 
+/* Round to nearest integer value, rounding halfway cases to even.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-float.h>
+
+ENTRY(__roundevenf)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
+	mfc1    a0, $f12 # assign int32
+	cfc1    t0, $f26
+	round.l.s       $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 23, 8 # assign exp
+#else
+	dsrl    a3, a0, 23
+	andi    a3, a3, 0x1ff
+#endif
+#else
+	ext     a3, a0, 23, 8 # assign exp
+#endif
+	sltiu   AT, a3, 127
+	bnez    AT, SMALL # exp < 127
+	ctc1    t0, $f26
+	sltiu   AT, a3, 127+25
+	beqz    AT, BIG # exp >= 127+25
+	li      AT, 0xff
+
+	jr      ra
+	cvt.s.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.s   $f0, $f12, $f12 # return double + double
+SMALL:
+	srl     a2, a0, 31
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE:
+	mfhc1   t1, $f0
+	bnez    t1, SMALL_POSITIVE # sign == 0
+	nop
+
+	jr      ra
+	neg.s   $f0, $f0
+SMALL_POSITIVE:
+	jr      ra
+	cvt.s.l $f0, $f0
+RETURN_AS_IS:
+	jr ra
+	mov.s   $f0, $f12
+	.set pop
+
+END (__roundevenf)
+libm_alias_float (__roundeven, roundeven)
+
+#endif
diff --git a/sysdeps/mips/fpu/s_trunc.c b/sysdeps/mips/fpu/s_trunc.c
new file mode 100644
index 0000000000..3865026c70
--- /dev/null
+++ b/sysdeps/mips/fpu/s_trunc.c
@@ -0,0 +1,24 @@ 
+/* Truncate argument to nearest integral value not larger than the argument.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/dbl-64/s_trunc.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_trunc_fpu.S b/sysdeps/mips/fpu/s_trunc_fpu.S
new file mode 100644
index 0000000000..3a7947507f
--- /dev/null
+++ b/sysdeps/mips/fpu/s_trunc_fpu.S
@@ -0,0 +1,84 @@ 
+/* Truncate argument to nearest integral value not larger than the argument.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-double.h>
+
+ENTRY(__trunc)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=double, a0=int64/int32_h, a1=int32_l, a2=sign, a3=exp
+#if __mips == 64
+	dmfc1   a0, $f12 # assign int64
+#else
+	mfhc1   a0, $f12 # assign int64
+#endif
+	cfc1    t0, $f26
+	trunc.l.d    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 52, 11 # assign exp
+#else
+	dsrl    a3, a0, 52
+	andi    a3, a3, 0x7ff
+#endif
+#else
+	ext     a3, a0, 20, 11 # assign exp
+#endif
+	sltiu   AT, a3, 1023
+	bnez    AT, SMALL # exp < 1023
+	ctc1    t0, $f26
+	sltiu   AT, a3, 1023+54
+	beqz    AT, BIG # exp >= 1023+54
+	li      AT, 0x7ff
+
+	jr      ra
+	cvt.d.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0x7ff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.d   $f0, $f12, $f12 # return double + double
+SMALL:
+#if __mips == 64
+	dsrl    a2, a0, 63
+#else
+	srl     a2, a0, 31
+#endif
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE: # return -0.0
+	jr	ra
+	neg.d	$f0, $f0
+SMALL_POSITIVE:
+	jr	ra
+	cvt.d.l	$f0, $f0
+RETURN_AS_IS:
+	jr	ra
+	mov.d	$f0, $f12
+	.set pop
+
+END (__trunc)
+libm_alias_double (__trunc, trunc)
+
+#endif
+
diff --git a/sysdeps/mips/fpu/s_truncf.c b/sysdeps/mips/fpu/s_truncf.c
new file mode 100644
index 0000000000..59ef17bf74
--- /dev/null
+++ b/sysdeps/mips/fpu/s_truncf.c
@@ -0,0 +1,24 @@ 
+/* Truncate argument to nearest integral value not larger than the argument.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if !((__mips_fpr == 64) && (__mips_hard_float == 1)                          \
+      && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+
+#  include <sysdeps/ieee754/flt-32/s_truncf.c>
+
+#endif
diff --git a/sysdeps/mips/fpu/s_truncf_fpu.S b/sysdeps/mips/fpu/s_truncf_fpu.S
new file mode 100644
index 0000000000..1878d88e3c
--- /dev/null
+++ b/sysdeps/mips/fpu/s_truncf_fpu.S
@@ -0,0 +1,76 @@ 
+/* Truncate argument to nearest integral value not larger than the argument.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if ((__mips_fpr == 64) && (__mips_hard_float == 1) && ((__mips == 32 && __mips_isa_rev > 1) || __mips == 64))
+#include <sys/regdef.h>
+#include <sysdep.h>
+#include <libm-alias-float.h>
+
+ENTRY(__truncf)
+	.set push
+	.set noreorder
+	.set noat
+# f0=ret, f12=float, a0=int32, a2=sign, a3=exp
+	mfc1    a0, $f12 # assign int32
+	cfc1    t0, $f26
+	trunc.l.s    $f0, $f12
+#if __mips == 64
+#if __mips_isa_rev > 1
+	dext    a3, a0, 23, 8 # assign exp
+#else
+	dsrl    a3, a0, 23
+	andi    a3, a3, 0x1ff
+#endif
+#else
+	ext     a3, a0, 23, 8 # assign exp
+#endif
+	sltiu   AT, a3, 127
+	bnez    AT, SMALL # exp < 127
+	ctc1    t0, $f26
+	sltiu   AT, a3, 127+25
+	beqz    AT, BIG # exp >= 127+25
+	li      AT, 0xff
+
+	jr      ra
+	cvt.s.l $f0, $f0
+BIG:
+	bne     AT, a3, RETURN_AS_IS # exp != 0xff, no frac
+	nop
+NAN_INF:
+	jr      ra
+	add.s   $f0, $f12, $f12 # return double + double
+SMALL:
+	srl     a2, a0, 31
+	beqz    a2, SMALL_POSITIVE # sign == 0
+	nop
+SMALL_NEGATIVE: # return -0.0
+	jr	ra
+	neg.s	$f0, $f0
+SMALL_POSITIVE:
+	jr	ra
+	cvt.s.l	$f0, $f0
+RETURN_AS_IS:
+	jr	ra
+	mov.s	$f0, $f12
+	.set pop
+
+END (__truncf)
+libm_alias_float (__trunc, trunc)
+
+#endif
+
diff --git a/sysdeps/mips/mips32/Implies b/sysdeps/mips/mips32/Implies
index 6473f2517c..71b3678c6c 100644
--- a/sysdeps/mips/mips32/Implies
+++ b/sysdeps/mips/mips32/Implies
@@ -1,3 +1,4 @@ 
+mips/fpu
 mips/ieee754
 mips
 wordsize-32
diff --git a/sysdeps/mips/mips64/Implies b/sysdeps/mips/mips64/Implies
index 826ff1541f..8885ebd564 100644
--- a/sysdeps/mips/mips64/Implies
+++ b/sysdeps/mips/mips64/Implies
@@ -1,4 +1,5 @@ 
 # MIPS uses IEEE 754 floating point.
+mips/fpu
 mips/ieee754
 ieee754/flt-32
 ieee754/dbl-64