[v3,13/19] RISC-V: Add the RV32 libm-test-ulps
Commit Message
Add a libm-test-ulps for RV32, this is the same as the RV64 one.
This dosn't match what is generated by running `make regen-ulps` on RV32
QEMU, but the current in tree RV64 doesn't match that either.
---
sysdeps/riscv/rv32/rvd/libm-test-ulps | 1402 ++++++++++++++++++++
sysdeps/riscv/rv32/rvd/libm-test-ulps-name | 1 +
2 files changed, 1403 insertions(+)
create mode 100644 sysdeps/riscv/rv32/rvd/libm-test-ulps
create mode 100644 sysdeps/riscv/rv32/rvd/libm-test-ulps-name
Comments
On Sun, 12 Jul 2020, Alistair Francis via Libc-alpha wrote:
> Add a libm-test-ulps for RV32, this is the same as the RV64 one.
>
> This dosn't match what is generated by running `make regen-ulps` on RV32
> QEMU, but the current in tree RV64 doesn't match that either.
For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
user emulation mode) match each other in my setup. However those don't
match RV64 results obtained with my HiFive Unleashed hardware, and then
those don't match our existing RV64 results, so I guess they will have to
be regenerated for the upcoming release.
I'll leave this change up to Joseph to ack, as he's the expert in this
area.
Maciej
On Mon, Jul 13, 2020 at 10:23 AM Maciej W. Rozycki via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
> On Sun, 12 Jul 2020, Alistair Francis via Libc-alpha wrote:
>
> > Add a libm-test-ulps for RV32, this is the same as the RV64 one.
> >
> > This dosn't match what is generated by running `make regen-ulps` on RV32
> > QEMU, but the current in tree RV64 doesn't match that either.
>
> For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
> user emulation mode) match each other in my setup. However those don't
> match RV64 results obtained with my HiFive Unleashed hardware, and then
> those don't match our existing RV64 results, so I guess they will have to
> be regenerated for the upcoming release.
Yep, so the current RV64 in tree doesn't match what I generate in QEMU
softmmu (full system) emulation for RV64.
I kind of assumed that what is in tree matches the Unleased.
>
> I'll leave this change up to Joseph to ack, as he's the expert in this
> area.
Let me know if you want it re-generated. I was assuming that what is
in tree works as it has been in a few releases now.
Alistair
>
> Maciej
On Mon, 13 Jul 2020, Alistair Francis wrote:
> > For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
> > user emulation mode) match each other in my setup. However those don't
> > match RV64 results obtained with my HiFive Unleashed hardware, and then
> > those don't match our existing RV64 results, so I guess they will have to
> > be regenerated for the upcoming release.
>
> Yep, so the current RV64 in tree doesn't match what I generate in QEMU
> softmmu (full system) emulation for RV64.
>
> I kind of assumed that what is in tree matches the Unleased.
For the record here's my RV64 diff to the Unleashed.
Maciej
Automatic regeneration of ULPs complete.
Difference between the current baseline and the new baseline is:
--- ../sysdeps/riscv/rv64/rvd/libm-test-ulps 2020-06-24 19:09:06.149618620 +0100
+++ .../obj/glibc/lp64d/math/NewUlps 2020-07-13 17:38:39.366490448 +0100
@@ -61,7 +61,7 @@
Function: "asinh":
double: 1
-float: 1
+float: 2
ldouble: 3
Function: "asinh_downward":
@@ -633,6 +633,7 @@
Function: "cos":
double: 1
+float: 1
ldouble: 1
Function: "cos_downward":
@@ -652,7 +653,7 @@
Function: "cosh":
double: 1
-float: 1
+float: 2
ldouble: 1
Function: "cosh_downward":
@@ -947,6 +948,7 @@
ldouble: 5
Function: "exp":
+float: 1
ldouble: 1
Function: "exp10":
@@ -1055,7 +1057,7 @@
Function: "j0":
double: 2
-float: 2
+float: 8
ldouble: 2
Function: "j0_downward":
@@ -1064,23 +1066,23 @@
ldouble: 4
Function: "j0_towardzero":
-double: 2
-float: 1
+double: 5
+float: 6
ldouble: 2
Function: "j0_upward":
-double: 3
-float: 2
+double: 4
+float: 5
ldouble: 5
Function: "j1":
-double: 1
-float: 2
+double: 2
+float: 8
ldouble: 4
Function: "j1_downward":
double: 3
-float: 2
+float: 5
ldouble: 4
Function: "j1_towardzero":
@@ -1224,6 +1226,7 @@
Function: "sin":
double: 1
+float: 1
ldouble: 1
Function: "sin_downward":
@@ -1321,27 +1324,27 @@
Function: "tgamma":
double: 5
-float: 4
+float: 8
ldouble: 4
Function: "tgamma_downward":
double: 5
-float: 5
+float: 7
ldouble: 5
Function: "tgamma_towardzero":
double: 5
-float: 4
+float: 7
ldouble: 5
Function: "tgamma_upward":
double: 4
-float: 4
+float: 8
ldouble: 4
Function: "y0":
double: 2
-float: 1
+float: 6
ldouble: 3
Function: "y0_downward":
Copy .../obj/glibc/lp64d/math/NewUlps to ../sysdeps/riscv/rv64/rvd/libm-test-ulps (relative to source).
Maciej
On 7/13/20 3:19 PM, Maciej W. Rozycki via Libc-alpha wrote:
> On Mon, 13 Jul 2020, Alistair Francis wrote:
>
>>> For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
>>> user emulation mode) match each other in my setup. However those don't
>>> match RV64 results obtained with my HiFive Unleashed hardware, and then
>>> those don't match our existing RV64 results, so I guess they will have to
>>> be regenerated for the upcoming release.
>>
>> Yep, so the current RV64 in tree doesn't match what I generate in QEMU
>> softmmu (full system) emulation for RV64.
>>
>> I kind of assumed that what is in tree matches the Unleased.
>
> For the record here's my RV64 diff to the Unleashed.
>
> Maciej
That's close enough that you should commit this blind to the
development branch that way developers don't get build failures.
We do this routinely for i686 and older hardware being used Fedora Koji
builders.
> Automatic regeneration of ULPs complete.
> Difference between the current baseline and the new baseline is:
> --- ../sysdeps/riscv/rv64/rvd/libm-test-ulps 2020-06-24 19:09:06.149618620 +0100
> +++ .../obj/glibc/lp64d/math/NewUlps 2020-07-13 17:38:39.366490448 +0100
> @@ -61,7 +61,7 @@
>
> Function: "asinh":
> double: 1
> -float: 1
> +float: 2
> ldouble: 3
>
> Function: "asinh_downward":
> @@ -633,6 +633,7 @@
>
> Function: "cos":
> double: 1
> +float: 1
> ldouble: 1
>
> Function: "cos_downward":
> @@ -652,7 +653,7 @@
>
> Function: "cosh":
> double: 1
> -float: 1
> +float: 2
> ldouble: 1
>
> Function: "cosh_downward":
> @@ -947,6 +948,7 @@
> ldouble: 5
>
> Function: "exp":
> +float: 1
> ldouble: 1
>
> Function: "exp10":
> @@ -1055,7 +1057,7 @@
>
> Function: "j0":
> double: 2
> -float: 2
> +float: 8
> ldouble: 2
>
> Function: "j0_downward":
> @@ -1064,23 +1066,23 @@
> ldouble: 4
>
> Function: "j0_towardzero":
> -double: 2
> -float: 1
> +double: 5
> +float: 6
> ldouble: 2
>
> Function: "j0_upward":
> -double: 3
> -float: 2
> +double: 4
> +float: 5
> ldouble: 5
>
> Function: "j1":
> -double: 1
> -float: 2
> +double: 2
> +float: 8
> ldouble: 4
>
> Function: "j1_downward":
> double: 3
> -float: 2
> +float: 5
> ldouble: 4
>
> Function: "j1_towardzero":
> @@ -1224,6 +1226,7 @@
>
> Function: "sin":
> double: 1
> +float: 1
> ldouble: 1
>
> Function: "sin_downward":
> @@ -1321,27 +1324,27 @@
>
> Function: "tgamma":
> double: 5
> -float: 4
> +float: 8
> ldouble: 4
>
> Function: "tgamma_downward":
> double: 5
> -float: 5
> +float: 7
> ldouble: 5
>
> Function: "tgamma_towardzero":
> double: 5
> -float: 4
> +float: 7
> ldouble: 5
>
> Function: "tgamma_upward":
> double: 4
> -float: 4
> +float: 8
> ldouble: 4
>
> Function: "y0":
> double: 2
> -float: 1
> +float: 6
> ldouble: 3
>
> Function: "y0_downward":
> Copy .../obj/glibc/lp64d/math/NewUlps to ../sysdeps/riscv/rv64/rvd/libm-test-ulps (relative to source).
>
> Maciej
>
On Mon, 13 Jul 2020, Maciej W. Rozycki via Libc-alpha wrote:
> On Sun, 12 Jul 2020, Alistair Francis via Libc-alpha wrote:
>
> > Add a libm-test-ulps for RV32, this is the same as the RV64 one.
> >
> > This dosn't match what is generated by running `make regen-ulps` on RV32
> > QEMU, but the current in tree RV64 doesn't match that either.
>
> For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
> user emulation mode) match each other in my setup. However those don't
> match RV64 results obtained with my HiFive Unleashed hardware, and then
> those don't match our existing RV64 results, so I guess they will have to
> be regenerated for the upcoming release.
If results on QEMU and on hardware (for the same binaries) don't match,
that indicates a bug in one or the other, which you could find by
identifying the exact instruction at which different floating-point values
first appear. (You can get different results from compilation with
different options or compiler versions, however, without any such bug,
because of e.g. changes in when the compiler chose to contract an
expression to use fused multiply-add.)
On 7/13/20 5:26 PM, Joseph Myers wrote:
> On Mon, 13 Jul 2020, Maciej W. Rozycki via Libc-alpha wrote:
>
>> On Sun, 12 Jul 2020, Alistair Francis via Libc-alpha wrote:
>>
>>> Add a libm-test-ulps for RV32, this is the same as the RV64 one.
>>>
>>> This dosn't match what is generated by running `make regen-ulps` on RV32
>>> QEMU, but the current in tree RV64 doesn't match that either.
>>
>> For the record RV32 and RV64 QEMU ULPS results (obtained in the Linux
>> user emulation mode) match each other in my setup. However those don't
>> match RV64 results obtained with my HiFive Unleashed hardware, and then
>> those don't match our existing RV64 results, so I guess they will have to
>> be regenerated for the upcoming release.
>
> If results on QEMU and on hardware (for the same binaries) don't match,
> that indicates a bug in one or the other, which you could find by
> identifying the exact instruction at which different floating-point values
> first appear. (You can get different results from compilation with
> different options or compiler versions, however, without any such bug,
> because of e.g. changes in when the compiler chose to contract an
> expression to use fused multiply-add.)
Is it really a "bug?" QEMU as an emulator could be taking liberties that
the hardware does not for the express purpose of improving emulated
performance? Is it ever QEMU's contract that it will operate identically
to hardware given the same software configuration?
On Mon, 13 Jul 2020, Carlos O'Donell via Libc-alpha wrote:
> > If results on QEMU and on hardware (for the same binaries) don't match,
> > that indicates a bug in one or the other, which you could find by
> > identifying the exact instruction at which different floating-point values
> > first appear. (You can get different results from compilation with
> > different options or compiler versions, however, without any such bug,
> > because of e.g. changes in when the compiler chose to contract an
> > expression to use fused multiply-add.)
>
> Is it really a "bug?" QEMU as an emulator could be taking liberties that
> the hardware does not for the express purpose of improving emulated
> performance? Is it ever QEMU's contract that it will operate identically
> to hardware given the same software configuration?
I believe the semantics of the RISC-V floating-point instructions are
fully specified (including details such as choice of NaN results) and so
it's a bug for either hardware or emulator to produce results other than
those in the architecture specification.
Sometimes architecture specifications do not fully specify results for all
floating-point instructions. For example, the Power instructions to
estimate reciprocal or reciprocal square root have accuracy bounds in the
architecture specification, but the exact result is not specified, so it
would be legitimate for hardware and emulation to produce different
results for those instructions. But AArch64 has an instruction to
estimate reciprocal square root whose exact semantics are fully specified
in the architecture specification, meaning it's a bug if emulation fails
to produce a result with exactly the same bit-pattern as hardware. My
understanding is that all the RISC-V floating-point instructions are fully
specified, as on AArch64.
On Mon, Jul 13, 2020 at 2:59 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Mon, 13 Jul 2020, Carlos O'Donell via Libc-alpha wrote:
>
> > > If results on QEMU and on hardware (for the same binaries) don't match,
> > > that indicates a bug in one or the other, which you could find by
> > > identifying the exact instruction at which different floating-point values
> > > first appear. (You can get different results from compilation with
> > > different options or compiler versions, however, without any such bug,
> > > because of e.g. changes in when the compiler chose to contract an
> > > expression to use fused multiply-add.)
> >
> > Is it really a "bug?" QEMU as an emulator could be taking liberties that
> > the hardware does not for the express purpose of improving emulated
> > performance? Is it ever QEMU's contract that it will operate identically
> > to hardware given the same software configuration?
>
> I believe the semantics of the RISC-V floating-point instructions are
> fully specified (including details such as choice of NaN results) and so
> it's a bug for either hardware or emulator to produce results other than
> those in the architecture specification.
>
> Sometimes architecture specifications do not fully specify results for all
> floating-point instructions. For example, the Power instructions to
> estimate reciprocal or reciprocal square root have accuracy bounds in the
> architecture specification, but the exact result is not specified, so it
> would be legitimate for hardware and emulation to produce different
> results for those instructions. But AArch64 has an instruction to
> estimate reciprocal square root whose exact semantics are fully specified
> in the architecture specification, meaning it's a bug if emulation fails
> to produce a result with exactly the same bit-pattern as hardware. My
> understanding is that all the RISC-V floating-point instructions are fully
> specified, as on AArch64.
This is indeed the case (at least for now; the forthcoming vector
extension adds an unordered sum reduction whose result can vary by
implementation). I think it would be good to confirm whether the
exact same binaries were used for the QEMU and Unleashed experiments,
and if not, whether the disparity remains when that's rectified.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
On Mon, 13 Jul 2020, Andrew Waterman wrote:
> > Sometimes architecture specifications do not fully specify results for all
> > floating-point instructions. For example, the Power instructions to
> > estimate reciprocal or reciprocal square root have accuracy bounds in the
> > architecture specification, but the exact result is not specified, so it
> > would be legitimate for hardware and emulation to produce different
> > results for those instructions. But AArch64 has an instruction to
> > estimate reciprocal square root whose exact semantics are fully specified
> > in the architecture specification, meaning it's a bug if emulation fails
> > to produce a result with exactly the same bit-pattern as hardware. My
> > understanding is that all the RISC-V floating-point instructions are fully
> > specified, as on AArch64.
>
> This is indeed the case (at least for now; the forthcoming vector
> extension adds an unordered sum reduction whose result can vary by
> implementation). I think it would be good to confirm whether the
> exact same binaries were used for the QEMU and Unleashed experiments,
> and if not, whether the disparity remains when that's rectified.
Well, yes. I just ran `make regen-ulps' consecutively with different
`test-wrapper*' variables each time so as to redirect execution either to
my HiFive Unleashed board or (user-mode) QEMU. I have double-checked the
logs now and no rebuild was made for subsequent runs, so the very same
executables and DSOs were used.
I tend to trust hardware with these matters and only use QEMU for quick
comparative verification where hardware is slow, or where hardware is
unavailable. A silicon erratum cannot be excluded in this case of course,
but I would check QEMU first.
Maciej
On Tue, 14 Jul 2020, Maciej W. Rozycki via Libc-alpha wrote:
> Well, yes. I just ran `make regen-ulps' consecutively with different
> `test-wrapper*' variables each time so as to redirect execution either to
> my HiFive Unleashed board or (user-mode) QEMU. I have double-checked the
> logs now and no rebuild was made for subsequent runs, so the very same
> executables and DSOs were used.
So picking one function and setting its ulps back to the lower value, then
rerunning the test on whichever of hardware and QEMU gave the higher
value, should result in a test log showing a specific input to a specific
function (in a specific rounding mode) for which the results on hardware
and QEMU differ. After confirming the difference with a minimal test just
making that one function call, it should be possible to trace the
execution of the function, whether in a debugger or inserting printf
calls, to find the exact instruction for which hardware and QEMU produce
different results with the same inputs.
new file mode 100644
@@ -0,0 +1,1402 @@
+# Begin of automatic generation
+
+# Maximal error of functions:
+Function: "acos":
+float: 1
+ldouble: 1
+
+Function: "acos_downward":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "acos_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "acos_upward":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "acosh":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "acosh_downward":
+double: 2
+float: 2
+ldouble: 3
+
+Function: "acosh_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "acosh_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "asin":
+float: 1
+ldouble: 1
+
+Function: "asin_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "asin_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "asin_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "asinh":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "asinh_downward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "asinh_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "asinh_upward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "atan":
+float: 1
+ldouble: 1
+
+Function: "atan2":
+float: 1
+ldouble: 1
+
+Function: "atan2_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: "atan2_towardzero":
+double: 1
+float: 2
+ldouble: 3
+
+Function: "atan2_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "atan_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: "atan_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "atan_upward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: "atanh":
+double: 2
+float: 2
+ldouble: 3
+
+Function: "atanh_downward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "atanh_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "atanh_upward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "cabs":
+double: 1
+ldouble: 1
+
+Function: "cabs_downward":
+double: 1
+ldouble: 1
+
+Function: "cabs_towardzero":
+double: 1
+ldouble: 1
+
+Function: "cabs_upward":
+double: 1
+ldouble: 1
+
+Function: Real part of "cacos":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "cacos":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "cacos_downward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "cacos_downward":
+double: 5
+float: 3
+ldouble: 6
+
+Function: Real part of "cacos_towardzero":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "cacos_towardzero":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Real part of "cacos_upward":
+double: 2
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "cacos_upward":
+double: 5
+float: 5
+ldouble: 7
+
+Function: Real part of "cacosh":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "cacosh":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "cacosh_downward":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "cacosh_downward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: Real part of "cacosh_towardzero":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "cacosh_towardzero":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Real part of "cacosh_upward":
+double: 4
+float: 3
+ldouble: 6
+
+Function: Imaginary part of "cacosh_upward":
+double: 3
+float: 2
+ldouble: 4
+
+Function: "carg":
+float: 1
+ldouble: 2
+
+Function: "carg_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: "carg_towardzero":
+double: 1
+float: 2
+ldouble: 3
+
+Function: "carg_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Real part of "casin":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Imaginary part of "casin":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "casin_downward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "casin_downward":
+double: 5
+float: 3
+ldouble: 6
+
+Function: Real part of "casin_towardzero":
+double: 3
+float: 1
+ldouble: 3
+
+Function: Imaginary part of "casin_towardzero":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Real part of "casin_upward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "casin_upward":
+double: 5
+float: 5
+ldouble: 7
+
+Function: Real part of "casinh":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "casinh":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Real part of "casinh_downward":
+double: 5
+float: 3
+ldouble: 6
+
+Function: Imaginary part of "casinh_downward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Real part of "casinh_towardzero":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "casinh_towardzero":
+double: 3
+float: 1
+ldouble: 3
+
+Function: Real part of "casinh_upward":
+double: 5
+float: 5
+ldouble: 7
+
+Function: Imaginary part of "casinh_upward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Real part of "catan":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "catan":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Real part of "catan_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "catan_downward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "catan_towardzero":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "catan_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "catan_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Imaginary part of "catan_upward":
+double: 2
+float: 2
+ldouble: 3
+
+Function: Real part of "catanh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "catanh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Real part of "catanh_downward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "catanh_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "catanh_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "catanh_towardzero":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "catanh_upward":
+double: 4
+float: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "cbrt":
+double: 3
+float: 1
+ldouble: 1
+
+Function: "cbrt_downward":
+double: 4
+float: 1
+ldouble: 1
+
+Function: "cbrt_towardzero":
+double: 3
+float: 1
+ldouble: 1
+
+Function: "cbrt_upward":
+double: 5
+float: 1
+ldouble: 1
+
+Function: Real part of "ccos":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "ccos":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Real part of "ccos_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Imaginary part of "ccos_downward":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "ccos_towardzero":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "ccos_towardzero":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "ccos_upward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "ccos_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "ccosh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "ccosh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Real part of "ccosh_downward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "ccosh_downward":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "ccosh_towardzero":
+double: 2
+float: 3
+ldouble: 2
+
+Function: Imaginary part of "ccosh_towardzero":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "ccosh_upward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "ccosh_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "cexp":
+double: 2
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "cexp":
+double: 1
+float: 2
+ldouble: 1
+
+Function: Real part of "cexp_downward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "cexp_downward":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "cexp_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "cexp_towardzero":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "cexp_upward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "cexp_upward":
+double: 3
+float: 2
+ldouble: 3
+
+Function: Real part of "clog":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Imaginary part of "clog":
+float: 1
+ldouble: 1
+
+Function: Real part of "clog10":
+double: 3
+float: 4
+ldouble: 2
+
+Function: Imaginary part of "clog10":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "clog10_downward":
+double: 5
+float: 5
+ldouble: 3
+
+Function: Imaginary part of "clog10_downward":
+double: 2
+float: 4
+ldouble: 3
+
+Function: Real part of "clog10_towardzero":
+double: 5
+float: 5
+ldouble: 4
+
+Function: Imaginary part of "clog10_towardzero":
+double: 2
+float: 4
+ldouble: 3
+
+Function: Real part of "clog10_upward":
+double: 6
+float: 5
+ldouble: 4
+
+Function: Imaginary part of "clog10_upward":
+double: 2
+float: 4
+ldouble: 3
+
+Function: Real part of "clog_downward":
+double: 4
+float: 3
+ldouble: 3
+
+Function: Imaginary part of "clog_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "clog_towardzero":
+double: 4
+float: 4
+ldouble: 3
+
+Function: Imaginary part of "clog_towardzero":
+double: 1
+float: 3
+ldouble: 2
+
+Function: Real part of "clog_upward":
+double: 4
+float: 3
+ldouble: 4
+
+Function: Imaginary part of "clog_upward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: "cos":
+double: 1
+ldouble: 1
+
+Function: "cos_downward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "cos_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "cos_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "cosh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "cosh_downward":
+double: 2
+float: 1
+ldouble: 2
+
+Function: "cosh_towardzero":
+double: 2
+float: 1
+ldouble: 2
+
+Function: "cosh_upward":
+double: 2
+float: 2
+ldouble: 3
+
+Function: Real part of "cpow":
+double: 2
+float: 5
+ldouble: 4
+
+Function: Imaginary part of "cpow":
+float: 2
+ldouble: 1
+
+Function: Real part of "cpow_downward":
+double: 5
+float: 8
+ldouble: 6
+
+Function: Imaginary part of "cpow_downward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "cpow_towardzero":
+double: 5
+float: 8
+ldouble: 6
+
+Function: Imaginary part of "cpow_towardzero":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "cpow_upward":
+double: 4
+float: 1
+ldouble: 3
+
+Function: Imaginary part of "cpow_upward":
+double: 1
+float: 2
+ldouble: 2
+
+Function: Real part of "csin":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "csin":
+ldouble: 1
+
+Function: Real part of "csin_downward":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Imaginary part of "csin_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Real part of "csin_towardzero":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Imaginary part of "csin_towardzero":
+double: 1
+float: 1
+ldouble: 2
+
+Function: Real part of "csin_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "csin_upward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: Real part of "csinh":
+float: 1
+ldouble: 1
+
+Function: Imaginary part of "csinh":
+double: 1
+float: 1
+ldouble: 1
+
+Function: Real part of "csinh_downward":
+double: 2
+float: 1
+ldouble: 2
+
+Function: Imaginary part of "csinh_downward":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "csinh_towardzero":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "csinh_towardzero":
+double: 3
+float: 3
+ldouble: 2
+
+Function: Real part of "csinh_upward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "csinh_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "csqrt":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Imaginary part of "csqrt":
+double: 2
+float: 2
+ldouble: 2
+
+Function: Real part of "csqrt_downward":
+double: 5
+float: 4
+ldouble: 4
+
+Function: Imaginary part of "csqrt_downward":
+double: 4
+float: 3
+ldouble: 3
+
+Function: Real part of "csqrt_towardzero":
+double: 4
+float: 3
+ldouble: 3
+
+Function: Imaginary part of "csqrt_towardzero":
+double: 4
+float: 3
+ldouble: 3
+
+Function: Real part of "csqrt_upward":
+double: 5
+float: 4
+ldouble: 4
+
+Function: Imaginary part of "csqrt_upward":
+double: 3
+float: 3
+ldouble: 3
+
+Function: Real part of "ctan":
+double: 1
+float: 1
+ldouble: 3
+
+Function: Imaginary part of "ctan":
+double: 2
+float: 2
+ldouble: 3
+
+Function: Real part of "ctan_downward":
+double: 6
+float: 5
+ldouble: 4
+
+Function: Imaginary part of "ctan_downward":
+double: 2
+float: 2
+ldouble: 5
+
+Function: Real part of "ctan_towardzero":
+double: 5
+float: 2
+ldouble: 4
+
+Function: Imaginary part of "ctan_towardzero":
+double: 2
+float: 2
+ldouble: 5
+
+Function: Real part of "ctan_upward":
+double: 2
+float: 4
+ldouble: 5
+
+Function: Imaginary part of "ctan_upward":
+double: 2
+float: 2
+ldouble: 5
+
+Function: Real part of "ctanh":
+double: 2
+float: 2
+ldouble: 3
+
+Function: Imaginary part of "ctanh":
+double: 2
+float: 1
+ldouble: 3
+
+Function: Real part of "ctanh_downward":
+double: 4
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "ctanh_downward":
+double: 6
+float: 5
+ldouble: 4
+
+Function: Real part of "ctanh_towardzero":
+double: 2
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "ctanh_towardzero":
+double: 5
+float: 2
+ldouble: 3
+
+Function: Real part of "ctanh_upward":
+double: 2
+float: 2
+ldouble: 5
+
+Function: Imaginary part of "ctanh_upward":
+double: 2
+float: 3
+ldouble: 5
+
+Function: "erf":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "erf_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "erf_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "erf_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "erfc":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "erfc_downward":
+double: 4
+float: 4
+ldouble: 5
+
+Function: "erfc_towardzero":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "erfc_upward":
+double: 4
+float: 4
+ldouble: 5
+
+Function: "exp":
+ldouble: 1
+
+Function: "exp10":
+double: 2
+ldouble: 2
+
+Function: "exp10_downward":
+double: 3
+float: 1
+ldouble: 3
+
+Function: "exp10_towardzero":
+double: 3
+float: 1
+ldouble: 3
+
+Function: "exp10_upward":
+double: 2
+float: 1
+ldouble: 3
+
+Function: "exp2":
+double: 1
+ldouble: 1
+
+Function: "exp2_downward":
+double: 1
+ldouble: 1
+
+Function: "exp2_towardzero":
+double: 1
+ldouble: 1
+
+Function: "exp2_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "exp_downward":
+double: 1
+float: 1
+
+Function: "exp_towardzero":
+double: 1
+float: 1
+
+Function: "exp_upward":
+double: 1
+float: 1
+
+Function: "expm1":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "expm1_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "expm1_towardzero":
+double: 1
+float: 2
+ldouble: 4
+
+Function: "expm1_upward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "gamma":
+double: 3
+float: 3
+ldouble: 5
+
+Function: "gamma_downward":
+double: 4
+float: 4
+ldouble: 8
+
+Function: "gamma_towardzero":
+double: 4
+float: 3
+ldouble: 5
+
+Function: "gamma_upward":
+double: 4
+float: 5
+ldouble: 8
+
+Function: "hypot":
+double: 1
+ldouble: 1
+
+Function: "hypot_downward":
+double: 1
+ldouble: 1
+
+Function: "hypot_towardzero":
+double: 1
+ldouble: 1
+
+Function: "hypot_upward":
+double: 1
+ldouble: 1
+
+Function: "j0":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "j0_downward":
+double: 2
+float: 4
+ldouble: 4
+
+Function: "j0_towardzero":
+double: 2
+float: 1
+ldouble: 2
+
+Function: "j0_upward":
+double: 3
+float: 2
+ldouble: 5
+
+Function: "j1":
+double: 1
+float: 2
+ldouble: 4
+
+Function: "j1_downward":
+double: 3
+float: 2
+ldouble: 4
+
+Function: "j1_towardzero":
+double: 3
+float: 2
+ldouble: 4
+
+Function: "j1_upward":
+double: 3
+float: 4
+ldouble: 3
+
+Function: "jn":
+double: 4
+float: 4
+ldouble: 7
+
+Function: "jn_downward":
+double: 4
+float: 5
+ldouble: 8
+
+Function: "jn_towardzero":
+double: 4
+float: 5
+ldouble: 8
+
+Function: "jn_upward":
+double: 5
+float: 4
+ldouble: 7
+
+Function: "lgamma":
+double: 3
+float: 3
+ldouble: 5
+
+Function: "lgamma_downward":
+double: 4
+float: 4
+ldouble: 8
+
+Function: "lgamma_towardzero":
+double: 4
+float: 3
+ldouble: 5
+
+Function: "lgamma_upward":
+double: 4
+float: 5
+ldouble: 8
+
+Function: "log":
+ldouble: 1
+
+Function: "log10":
+double: 2
+float: 2
+ldouble: 1
+
+Function: "log10_downward":
+double: 2
+float: 3
+ldouble: 1
+
+Function: "log10_towardzero":
+double: 2
+float: 1
+ldouble: 1
+
+Function: "log10_upward":
+double: 2
+float: 2
+ldouble: 1
+
+Function: "log1p":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "log1p_downward":
+double: 1
+float: 2
+ldouble: 3
+
+Function: "log1p_towardzero":
+double: 2
+float: 2
+ldouble: 3
+
+Function: "log1p_upward":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "log2":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "log2_downward":
+double: 3
+ldouble: 3
+
+Function: "log2_towardzero":
+double: 2
+ldouble: 1
+
+Function: "log2_upward":
+double: 3
+ldouble: 1
+
+Function: "log_downward":
+ldouble: 1
+
+Function: "log_towardzero":
+ldouble: 2
+
+Function: "log_upward":
+double: 1
+ldouble: 2
+
+Function: "pow":
+double: 1
+ldouble: 2
+
+Function: "pow_downward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "pow_towardzero":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "pow_upward":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "sin":
+double: 1
+ldouble: 1
+
+Function: "sin_downward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "sin_towardzero":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "sin_upward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "sincos":
+double: 1
+ldouble: 1
+
+Function: "sincos_downward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "sincos_towardzero":
+double: 1
+float: 1
+ldouble: 2
+
+Function: "sincos_upward":
+double: 1
+float: 1
+ldouble: 3
+
+Function: "sinh":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "sinh_downward":
+double: 3
+float: 3
+ldouble: 3
+
+Function: "sinh_towardzero":
+double: 2
+float: 2
+ldouble: 3
+
+Function: "sinh_upward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "tan":
+float: 1
+ldouble: 1
+
+Function: "tan_downward":
+double: 1
+float: 2
+ldouble: 1
+
+Function: "tan_towardzero":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "tan_upward":
+double: 1
+float: 1
+ldouble: 1
+
+Function: "tanh":
+double: 2
+float: 2
+ldouble: 2
+
+Function: "tanh_downward":
+double: 3
+float: 3
+ldouble: 4
+
+Function: "tanh_towardzero":
+double: 2
+float: 2
+ldouble: 3
+
+Function: "tanh_upward":
+double: 3
+float: 3
+ldouble: 3
+
+Function: "tgamma":
+double: 5
+float: 4
+ldouble: 4
+
+Function: "tgamma_downward":
+double: 5
+float: 5
+ldouble: 5
+
+Function: "tgamma_towardzero":
+double: 5
+float: 4
+ldouble: 5
+
+Function: "tgamma_upward":
+double: 4
+float: 4
+ldouble: 4
+
+Function: "y0":
+double: 2
+float: 1
+ldouble: 3
+
+Function: "y0_downward":
+double: 3
+float: 4
+ldouble: 4
+
+Function: "y0_towardzero":
+double: 3
+float: 3
+ldouble: 3
+
+Function: "y0_upward":
+double: 2
+float: 5
+ldouble: 3
+
+Function: "y1":
+double: 3
+float: 2
+ldouble: 2
+
+Function: "y1_downward":
+double: 3
+float: 2
+ldouble: 4
+
+Function: "y1_towardzero":
+double: 3
+float: 2
+ldouble: 2
+
+Function: "y1_upward":
+double: 5
+float: 2
+ldouble: 5
+
+Function: "yn":
+double: 3
+float: 3
+ldouble: 5
+
+Function: "yn_downward":
+double: 3
+float: 4
+ldouble: 5
+
+Function: "yn_towardzero":
+double: 3
+float: 3
+ldouble: 5
+
+Function: "yn_upward":
+double: 4
+float: 5
+ldouble: 5
+
+# end of automatic generation
new file mode 100644
@@ -0,0 +1 @@
+RISC-V