1 | /* $Id: IEMGenFpuConstants.c 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * IEMGenFpuConstants - Generates FPU constants for IEMAllAImplC.cpp.
|
---|
4 | *
|
---|
5 | * Compile on linux: gcc -I../../../../include -DIN_RING3 IEMGenFpuConstants.c -lmpfr -g -o IEMGenFpuConstants
|
---|
6 | */
|
---|
7 |
|
---|
8 | /*
|
---|
9 | * Copyright (C) 2022-2024 Oracle and/or its affiliates.
|
---|
10 | *
|
---|
11 | * This file is part of VirtualBox base platform packages, as
|
---|
12 | * available from https://www.virtualbox.org.
|
---|
13 | *
|
---|
14 | * This program is free software; you can redistribute it and/or
|
---|
15 | * modify it under the terms of the GNU General Public License
|
---|
16 | * as published by the Free Software Foundation, in version 3 of the
|
---|
17 | * License.
|
---|
18 | *
|
---|
19 | * This program is distributed in the hope that it will be useful, but
|
---|
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
22 | * General Public License for more details.
|
---|
23 | *
|
---|
24 | * You should have received a copy of the GNU General Public License
|
---|
25 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
26 | *
|
---|
27 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
28 | */
|
---|
29 |
|
---|
30 |
|
---|
31 | /*********************************************************************************************************************************
|
---|
32 | * Header Files *
|
---|
33 | *********************************************************************************************************************************/
|
---|
34 | #include <iprt/types.h>
|
---|
35 | #include <iprt/assertcompile.h>
|
---|
36 | #include <stdio.h>
|
---|
37 | #define MPFR_WANT_FLOAT128
|
---|
38 | #include <gmp.h>
|
---|
39 | #include <mpfr.h>
|
---|
40 |
|
---|
41 |
|
---|
42 | void PrintComment(const char *pszComment, va_list va, mpfr_srcptr pVal, bool fList)
|
---|
43 | {
|
---|
44 | const char * const pszIndent = fList ? " " : "";
|
---|
45 | printf(fList ? " /* " : "/** ");
|
---|
46 | vprintf(pszComment, va);
|
---|
47 | printf("\n%s * base-10: ", pszIndent);
|
---|
48 | mpfr_out_str(stdout, 10, 0, pVal, MPFR_RNDD);
|
---|
49 | printf("\n%s * base-16: ", pszIndent);
|
---|
50 | mpfr_out_str(stdout, 16, 0, pVal, MPFR_RNDD);
|
---|
51 | printf("\n%s * base-2 : ", pszIndent);
|
---|
52 | mpfr_out_str(stdout, 2, 0, pVal, MPFR_RNDD);
|
---|
53 | printf(" */\n");
|
---|
54 | }
|
---|
55 |
|
---|
56 |
|
---|
57 | uint64_t BinStrToU64(const char *psz, size_t cch)
|
---|
58 | {
|
---|
59 | uint64_t u = 0;
|
---|
60 | while (cch-- > 0)
|
---|
61 | {
|
---|
62 | u <<= 1;
|
---|
63 | u |= *psz++ == '1';
|
---|
64 | }
|
---|
65 | return u;
|
---|
66 | }
|
---|
67 |
|
---|
68 |
|
---|
69 | void PrintU128(mpfr_srcptr pVal, const char *pszVariable, const char *pszComment, ...)
|
---|
70 | {
|
---|
71 | va_list va;
|
---|
72 | va_start(va, pszComment);
|
---|
73 | PrintComment(pszComment, va, pVal, !pszVariable);
|
---|
74 | va_end(va);
|
---|
75 | if (pszVariable)
|
---|
76 | printf("const RTUINT128U %s = ", pszVariable);
|
---|
77 | else
|
---|
78 | printf(" ");
|
---|
79 | mpfr_exp_t iExpBinary;
|
---|
80 | char *pszBinary = mpfr_get_str(NULL, &iExpBinary, 2, 0, pVal, MPFR_RNDD);
|
---|
81 | printf("RTUINT128_INIT_C(%#llx, %#llx)%s\n",
|
---|
82 | BinStrToU64(pszBinary, 64), BinStrToU64(&pszBinary[64], 64), pszVariable ? ";" : ",");
|
---|
83 | mpfr_free_str(pszBinary);
|
---|
84 | }
|
---|
85 |
|
---|
86 |
|
---|
87 | void PrintF128(mpfr_srcptr pVal, const char *pszVariable, const char *pszComment, ...)
|
---|
88 | {
|
---|
89 | RTFLOAT128U r128;
|
---|
90 | *(_Float128 *)&r128 = mpfr_get_float128(pVal, MPFR_RNDD);
|
---|
91 |
|
---|
92 | va_list va;
|
---|
93 | va_start(va, pszComment);
|
---|
94 | PrintComment(pszComment, va, pVal, !pszVariable);
|
---|
95 | va_end(va);
|
---|
96 | if (pszVariable)
|
---|
97 | printf("const RTFLOAT128U %s = ", pszVariable);
|
---|
98 | else
|
---|
99 | printf(" ");
|
---|
100 | printf("RTFLOAT128U_INIT_C(%d, 0x%012llx, 0x%016llx, 0x%04x)%s\n",
|
---|
101 | r128.s.fSign, r128.s64.uFractionHi, r128.s64.uFractionLo, r128.s64.uExponent, pszVariable ? ";" : ",");
|
---|
102 | }
|
---|
103 |
|
---|
104 |
|
---|
105 | int main(void)
|
---|
106 | {
|
---|
107 | mpfr_t Val;
|
---|
108 |
|
---|
109 | mpfr_init2(Val, 112 + 1);
|
---|
110 | mpfr_const_log2(Val, MPFR_RNDN);
|
---|
111 | PrintF128(Val, "g_r128Ln2", "The ln2 constant as 128-bit floating point value.");
|
---|
112 |
|
---|
113 | mpfr_init2(Val, 128);
|
---|
114 | mpfr_const_log2(Val, MPFR_RNDN);
|
---|
115 | PrintU128(Val, "g_u128Ln2Mantissa", "High precision ln2 value.");
|
---|
116 |
|
---|
117 | mpfr_t Val2;
|
---|
118 | mpfr_init2(Val2, 67);
|
---|
119 | mpfr_const_log2(Val2, MPFR_RNDN);
|
---|
120 | mpfr_set(Val, Val2, MPFR_RNDN);
|
---|
121 | PrintU128(Val, "g_u128Ln2MantissaIntel", "High precision ln2 value, compatible with f2xm1 results on intel 10980XE.");
|
---|
122 |
|
---|
123 | /** @todo emit constants with 68-bit precision (1+67 bits), as that's what we
|
---|
124 | * use for intel now. */
|
---|
125 | printf("\n"
|
---|
126 | "/** Horner constants for f2xm1 */\n"
|
---|
127 | "const RTFLOAT128U g_ar128F2xm1HornerConsts[] =\n"
|
---|
128 | "{\n");
|
---|
129 | mpfr_t One;
|
---|
130 | mpfr_init2(One, 112 + 1);
|
---|
131 | mpfr_set_ui(One, 1, MPFR_RNDD);
|
---|
132 | PrintF128(One, NULL, "a0");
|
---|
133 |
|
---|
134 | mpfr_init2(Val, 112 + 1);
|
---|
135 | mpfr_set_ui(Val, 1, MPFR_RNDD);
|
---|
136 | for (unsigned a = 1; a < 22; a++)
|
---|
137 | {
|
---|
138 | mpfr_div_ui(Val, Val, a + 1, MPFR_RNDD);
|
---|
139 | PrintF128(Val, NULL, "a%u", a);
|
---|
140 | }
|
---|
141 |
|
---|
142 | printf("};\n");
|
---|
143 |
|
---|
144 | mpfr_init2(Val, 112 + 1);
|
---|
145 | mpfr_const_pi(Val, MPFR_RNDN);
|
---|
146 | PrintF128(Val, "g_r128pi", "The pi constant as 128-bit floating point value.");
|
---|
147 | mpfr_div_ui(Val, Val, 2, MPFR_RNDD);
|
---|
148 | PrintF128(Val, "g_r128pi2", "The pi/2 constant as 128-bit floating point value.");
|
---|
149 |
|
---|
150 | printf("\n"
|
---|
151 | "/** CORDIC constants for fsin and fcos, defined by c(i)=atan(2^(-i)) */\n"
|
---|
152 | "const RTFLOAT128U g_ar128FsincosCORDICConsts[] =\n"
|
---|
153 | "{\n");
|
---|
154 | mpfr_init2(Val, 112 + 1);
|
---|
155 | signed kmax = 68;
|
---|
156 |
|
---|
157 | for (signed k = 0; k < kmax; k++)
|
---|
158 | {
|
---|
159 | // mpfr_mul_2si ?
|
---|
160 | mpfr_set_si_2exp(Val, 1, -k, MPFR_RNDD);
|
---|
161 | mpfr_atan(Val, Val, MPFR_RNDD);
|
---|
162 | PrintF128(Val, NULL, "c%u", k);
|
---|
163 | }
|
---|
164 |
|
---|
165 | printf("};\n");
|
---|
166 |
|
---|
167 | printf("\n"
|
---|
168 | "/** CORDIC multipliers for fsin and fcos, defined by K(i)=1/sqrt(1+2^(-2i)) */\n"
|
---|
169 | "const RTFLOAT128U g_ar128FsincosCORDICConsts2[] =\n"
|
---|
170 | "{\n");
|
---|
171 |
|
---|
172 | mpfr_init2(Val, 112 + 1);
|
---|
173 | mpfr_init2(Val2, 112 + 1);
|
---|
174 |
|
---|
175 | mpfr_set_ui(Val, 2, MPFR_RNDD);
|
---|
176 | mpfr_sqrt(Val, Val, MPFR_RNDD);
|
---|
177 | mpfr_ui_div(Val2, 1, Val, MPFR_RNDD);
|
---|
178 | PrintF128(Val2, NULL, "K_%u", 0);
|
---|
179 |
|
---|
180 | for (signed k = 1; k < kmax; k++)
|
---|
181 | {
|
---|
182 | mpfr_set_si_2exp(Val, 1, -2 * k, MPFR_RNDD);
|
---|
183 | mpfr_add_ui(Val, Val, 1, MPFR_RNDD);
|
---|
184 | mpfr_sqrt(Val, Val, MPFR_RNDD);
|
---|
185 | mpfr_div(Val2, Val2, Val, MPFR_RNDD);
|
---|
186 | PrintF128(Val2, NULL, "K_%u", k);
|
---|
187 | }
|
---|
188 |
|
---|
189 | printf("};\n");
|
---|
190 |
|
---|
191 | printf("\n"
|
---|
192 | "/** Chebyshev coeffs for log2 function in [1, 2] interval */\n"
|
---|
193 | "const RTFLOAT128U g_ar128ChebLog2Consts[] =\n"
|
---|
194 | "{\n");
|
---|
195 | signed j, d, dmax = 22;
|
---|
196 | mpfr_t ValX, ValXX, ValA, ValB, ValBmA, ValCos, ValSum;
|
---|
197 | mpfr_init2(Val, 112 + 1);
|
---|
198 | mpfr_init2(Val2, 112 + 1);
|
---|
199 | mpfr_init2(ValX, 112 + 1);
|
---|
200 | mpfr_init2(ValXX, 112 + 1);
|
---|
201 | mpfr_init2(ValA, 112 + 1);
|
---|
202 | mpfr_init2(ValB, 112 + 1);
|
---|
203 | mpfr_init2(ValBmA, 112 + 1);
|
---|
204 | mpfr_init2(ValCos, 112 + 1);
|
---|
205 | mpfr_init2(ValSum, 112 + 1);
|
---|
206 |
|
---|
207 | /* Setting the desired interpolation range [1.0, 2.0] */
|
---|
208 | mpfr_set_d(ValA, 1.0, MPFR_RNDD);
|
---|
209 | mpfr_set_d(ValB, 2.0, MPFR_RNDD);
|
---|
210 | mpfr_sub(ValBmA, ValB, ValA, MPFR_RNDD);
|
---|
211 |
|
---|
212 | for (signed d = 0; d < dmax; d++)
|
---|
213 | {
|
---|
214 | mpfr_set_si(ValSum, 0, MPFR_RNDD);
|
---|
215 |
|
---|
216 | for(j = 0; j < dmax; j++)
|
---|
217 | {
|
---|
218 | mpfr_set_si_2exp(Val, 1, -1, MPFR_RNDD);
|
---|
219 | mpfr_add_ui(Val, Val, j, MPFR_RNDD);
|
---|
220 | mpfr_const_pi(Val2, MPFR_RNDN);
|
---|
221 | mpfr_mul(Val, Val2, Val, MPFR_RNDN);
|
---|
222 | mpfr_div_si(Val, Val, dmax, MPFR_RNDN);
|
---|
223 | /* Val = M_PIq * (j + 0.5Q) / N */
|
---|
224 |
|
---|
225 | mpfr_cos(ValX, Val, MPFR_RNDN);
|
---|
226 | /* ValX = cos(M_PIq * (j + 0.5Q) / N) */
|
---|
227 |
|
---|
228 | mpfr_mul_si(Val, Val, d, MPFR_RNDN);
|
---|
229 | mpfr_cos(ValCos, Val, MPFR_RNDN);
|
---|
230 | /* ValCos = cos(M_PIq * d * (j + 0.5Q) / N) */
|
---|
231 |
|
---|
232 | mpfr_add_si(Val, ValX, 1, MPFR_RNDN);
|
---|
233 | mpfr_div_si(Val, Val, 2, MPFR_RNDN);
|
---|
234 | mpfr_mul(Val, ValBmA, Val, MPFR_RNDN);
|
---|
235 | mpfr_add(ValXX, ValA, Val, MPFR_RNDN);
|
---|
236 | /* ValXX = a + (b - a) * (x + 1.0Q) / 2.0Q */
|
---|
237 |
|
---|
238 | mpfr_sub_si(Val, ValXX, 1, MPFR_RNDN);
|
---|
239 | mpfr_log2(Val2, ValXX, MPFR_RNDN);
|
---|
240 | mpfr_div(Val, Val2, Val, MPFR_RNDN);
|
---|
241 | mpfr_mul(Val, Val, ValCos, MPFR_RNDN);
|
---|
242 | mpfr_add(ValSum, ValSum, Val, MPFR_RNDN);
|
---|
243 | }
|
---|
244 |
|
---|
245 | mpfr_div_si(ValSum, ValSum, dmax, MPFR_RNDN);
|
---|
246 |
|
---|
247 | if (d != 0)
|
---|
248 | mpfr_mul_si(ValSum, ValSum, 2, MPFR_RNDN);
|
---|
249 |
|
---|
250 | PrintF128(ValSum, NULL, "c%u", d);
|
---|
251 | }
|
---|
252 |
|
---|
253 | printf("};\n");
|
---|
254 |
|
---|
255 | mpfr_init2(One, 112 + 1);
|
---|
256 | mpfr_set_ui(One, 1, MPFR_RNDD);
|
---|
257 |
|
---|
258 | mpfr_init2(Val, 112 + 1);
|
---|
259 | mpfr_exp(Val, One, MPFR_RNDD);
|
---|
260 | mpfr_log2(Val, Val, MPFR_RNDD);
|
---|
261 |
|
---|
262 | PrintF128(Val, "g_r128Log2e", "The log2e constant as 128-bit floating point value.");
|
---|
263 |
|
---|
264 | mpfr_clear(ValXX);
|
---|
265 | mpfr_clear(ValX);
|
---|
266 | mpfr_clear(Val);
|
---|
267 | mpfr_clear(Val2);
|
---|
268 | mpfr_clear(One);
|
---|
269 | mpfr_free_cache();
|
---|
270 | return 0;
|
---|
271 | }
|
---|
272 |
|
---|