1const builtin = @import("builtin");
2const std = @import("std");
3const math = std.math;
4
5const compiler_rt = @import("../compiler_rt.zig");
6const symbol = compiler_rt.symbol;
7
8comptime {
9 symbol(&__floatsihf, "__floatsihf");
10 symbol(&__floatdihf, "__floatdihf");
11 symbol(&__floattihf, "__floattihf");
12 symbol(&__floateihf, "__floateihf");
13
14 if (compiler_rt.want_aeabi) {
15 symbol(&__aeabi_i2f, "__aeabi_i2f");
16 symbol(&__aeabi_l2f, "__aeabi_l2f");
17 } else {
18 symbol(&__floatsisf, "__floatsisf");
19 symbol(&__floatdisf, "__floatdisf");
20 if (compiler_rt.want_windows_arm_abi) symbol(&__floatdisf, "__i64tos");
21 }
22 symbol(&__floattisf, "__floattisf");
23 symbol(&__floateisf, "__floateisf");
24
25 if (compiler_rt.want_aeabi) {
26 symbol(&__aeabi_i2d, "__aeabi_i2d");
27 symbol(&__aeabi_l2d, "__aeabi_l2d");
28 } else {
29 symbol(&__floatsidf, "__floatsidf");
30 symbol(&__floatdidf, "__floatdidf");
31 if (compiler_rt.want_windows_arm_abi) symbol(&__floatdidf, "__i64tod");
32 }
33 symbol(&__floattidf, "__floattidf");
34 symbol(&__floateidf, "__floateidf");
35
36 symbol(&__floatsixf, "__floatsixf");
37 symbol(&__floatdixf, "__floatdixf");
38 symbol(&__floattixf, "__floattixf");
39 symbol(&__floateixf, "__floateixf");
40
41 if (compiler_rt.want_ppc_abi) {
42 symbol(&__floatsitf, "__floatsikf");
43 symbol(&__floatditf, "__floatdikf");
44 } else if (compiler_rt.want_sparc64_abi) {
45 symbol(&_Qp_itoq, "_Qp_itoq");
46 symbol(&_Qp_xtoq, "_Qp_xtoq");
47 } else if (compiler_rt.want_sparc32_abi) {
48 symbol(&__floatsitf, "_Q_itoq");
49 symbol(&__floatditf, "_Q_lltoq");
50 } else {
51 symbol(&__floatsitf, "__floatsitf");
52 symbol(&__floatditf, "__floatditf");
53 }
54 if (compiler_rt.want_ppc_abi) {
55 symbol(&__floattitf, "__floattikf");
56 symbol(&__floateitf, "__floateikf");
57 } else {
58 if (builtin.cpu.arch == .x86) {
59 symbol(&__floattitf_x86, "__floattitf");
60 } else {
61 symbol(&__floattitf, "__floattitf");
62 }
63 symbol(&__floateitf, "__floateitf");
64 }
65}
66
67fn __floatsihf(a: i32) callconv(.c) compiler_rt.f16.Abi {
68 return compiler_rt.f16.toAbi(f16_floatFromInt_i32(a));
69}
70pub fn f16_floatFromInt_i32(a: i32) f16 {
71 return floatFromInt(f16, a);
72}
73
74fn __floatdihf(a: i64) callconv(.c) compiler_rt.f16.Abi {
75 return compiler_rt.f16.toAbi(f16_floatFromInt_i64(a));
76}
77pub fn f16_floatFromInt_i64(a: i64) f16 {
78 return floatFromInt(f16, a);
79}
80
81fn __floattihf(a: i128) callconv(.c) compiler_rt.f16.Abi {
82 return compiler_rt.f16.toAbi(f16_floatFromInt_i128(a));
83}
84pub fn f16_floatFromInt_i128(a: i128) f16 {
85 return floatFromInt(f16, a);
86}
87
88fn __floateihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi {
89 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
90 return compiler_rt.f16.toAbi(f16_floatFromInt_signed(a[0..byte_size]));
91}
92pub fn f16_floatFromInt_signed(a: []const u8) f16 {
93 return floatFromBigInt(f16, .signed, @ptrCast(@alignCast(a)));
94}
95
96fn __floatsisf(a: i32) callconv(.c) compiler_rt.f32.Abi {
97 return compiler_rt.f32.toAbi(f32_floatFromInt_i32(a));
98}
99fn __aeabi_i2f(a: i32) callconv(.{ .arm_aapcs = .{} }) f32 {
100 return f32_floatFromInt_i32(a);
101}
102pub fn f32_floatFromInt_i32(a: i32) f32 {
103 return floatFromInt(f32, a);
104}
105
106fn __floatdisf(a: i64) callconv(.c) compiler_rt.f32.Abi {
107 return compiler_rt.f32.toAbi(f32_floatFromInt_i64(a));
108}
109fn __aeabi_l2f(a: i64) callconv(.{ .arm_aapcs = .{} }) f32 {
110 return f32_floatFromInt_i64(a);
111}
112pub fn f32_floatFromInt_i64(a: i64) f32 {
113 return floatFromInt(f32, a);
114}
115
116fn __floattisf(a: i128) callconv(.c) compiler_rt.f32.Abi {
117 return compiler_rt.f32.toAbi(f32_floatFromInt_i128(a));
118}
119pub fn f32_floatFromInt_i128(a: i128) f32 {
120 return floatFromInt(f32, a);
121}
122
123fn __floateisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi {
124 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
125 return compiler_rt.f32.toAbi(f32_floatFromInt_signed(a[0..byte_size]));
126}
127pub fn f32_floatFromInt_signed(a: []const u8) f32 {
128 return floatFromBigInt(f32, .signed, @ptrCast(@alignCast(a)));
129}
130
131fn __floatsidf(a: i32) callconv(.c) compiler_rt.f64.Abi {
132 return compiler_rt.f64.toAbi(f64_floatFromInt_i32(a));
133}
134fn __aeabi_i2d(a: i32) callconv(.{ .arm_aapcs = .{} }) f64 {
135 return f64_floatFromInt_i32(a);
136}
137pub fn f64_floatFromInt_i32(a: i32) f64 {
138 return floatFromInt(f64, a);
139}
140
141fn __floatdidf(a: i64) callconv(.c) compiler_rt.f64.Abi {
142 return compiler_rt.f64.toAbi(f64_floatFromInt_i64(a));
143}
144fn __aeabi_l2d(a: i64) callconv(.{ .arm_aapcs = .{} }) f64 {
145 return f64_floatFromInt_i64(a);
146}
147pub fn f64_floatFromInt_i64(a: i64) f64 {
148 return floatFromInt(f64, a);
149}
150
151fn __floattidf(a: i128) callconv(.c) compiler_rt.f64.Abi {
152 return compiler_rt.f64.toAbi(f64_floatFromInt_i128(a));
153}
154pub fn f64_floatFromInt_i128(a: i128) f64 {
155 return floatFromInt(f64, a);
156}
157
158fn __floateidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi {
159 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
160 return compiler_rt.f64.toAbi(f64_floatFromInt_signed(a[0..byte_size]));
161}
162pub fn f64_floatFromInt_signed(a: []const u8) f64 {
163 return floatFromBigInt(f64, .signed, @ptrCast(@alignCast(a)));
164}
165
166fn __floatsixf(a: i32) callconv(.c) compiler_rt.f80.Abi {
167 return compiler_rt.f80.toAbi(f80_floatFromInt_i32(a));
168}
169pub fn f80_floatFromInt_i32(a: i32) f80 {
170 return floatFromInt(f80, a);
171}
172
173fn __floatdixf(a: i64) callconv(.c) compiler_rt.f80.Abi {
174 return compiler_rt.f80.toAbi(f80_floatFromInt_i64(a));
175}
176pub fn f80_floatFromInt_i64(a: i64) f80 {
177 return floatFromInt(f80, a);
178}
179
180fn __floattixf(a: i128) callconv(.c) compiler_rt.f80.Abi {
181 return compiler_rt.f80.toAbi(f80_floatFromInt_i128(a));
182}
183pub fn f80_floatFromInt_i128(a: i128) f80 {
184 return floatFromInt(f80, a);
185}
186
187fn __floateixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi {
188 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
189 return compiler_rt.f80.toAbi(f80_floatFromInt_signed(a[0..byte_size]));
190}
191pub fn f80_floatFromInt_signed(a: []const u8) f80 {
192 return floatFromBigInt(f80, .signed, @ptrCast(@alignCast(a)));
193}
194
195fn __floatsitf(a: i32) callconv(.c) compiler_rt.f128.Abi {
196 return compiler_rt.f128.toAbi(f128_floatFromInt_i32(a));
197}
198fn _Qp_itoq(c: *f128, a: i32) callconv(.c) void {
199 c.* = f128_floatFromInt_i32(a);
200}
201pub fn f128_floatFromInt_i32(a: i32) f128 {
202 return floatFromInt(f128, a);
203}
204
205fn __floatditf(a: i64) callconv(.c) compiler_rt.f128.Abi {
206 return compiler_rt.f128.toAbi(f128_floatFromInt_i64(a));
207}
208fn _Qp_xtoq(c: *f128, a: i64) callconv(.c) void {
209 c.* = f128_floatFromInt_i64(a);
210}
211pub fn f128_floatFromInt_i64(a: i64) f128 {
212 return floatFromInt(f128, a);
213}
214
215fn __floattitf(a: i128) callconv(.c) compiler_rt.f128.Abi {
216 return compiler_rt.f128.toAbi(f128_floatFromInt_i128(a));
217}
218fn __floattitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi {
219 return compiler_rt.f128.toAbi(f128_floatFromInt_i128(@bitCast(a)));
220}
221pub fn f128_floatFromInt_i128(a: i128) f128 {
222 return floatFromInt(f128, a);
223}
224
225fn __floateitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi {
226 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
227 return compiler_rt.f128.toAbi(f128_floatFromInt_signed(a[0..byte_size]));
228}
229pub fn f128_floatFromInt_signed(a: []const u8) f128 {
230 return floatFromBigInt(f128, .signed, @ptrCast(@alignCast(a)));
231}
232
233comptime {
234 symbol(&__floatunsihf, "__floatunsihf");
235 symbol(&__floatundihf, "__floatundihf");
236 symbol(&__floatuntihf, "__floatuntihf");
237 symbol(&__floatuneihf, "__floatuneihf");
238
239 if (compiler_rt.want_aeabi) {
240 symbol(&__aeabi_ui2f, "__aeabi_ui2f");
241 symbol(&__aeabi_ul2f, "__aeabi_ul2f");
242 } else {
243 symbol(&__floatunsisf, "__floatunsisf");
244 symbol(&__floatundisf, "__floatundisf");
245 if (compiler_rt.want_windows_arm_abi) symbol(&__floatundisf, "__u64tos");
246 }
247 symbol(&__floatuntisf, "__floatuntisf");
248 symbol(&__floatuneisf, "__floatuneisf");
249
250 if (compiler_rt.want_aeabi) {
251 symbol(&__aeabi_ui2d, "__aeabi_ui2d");
252 } else {
253 symbol(&__floatunsidf, "__floatunsidf");
254 }
255 if (compiler_rt.want_aeabi) {
256 symbol(&__aeabi_ul2d, "__aeabi_ul2d");
257 } else {
258 if (compiler_rt.want_windows_arm_abi) {
259 symbol(&__floatundidf, "__u64tod");
260 }
261 symbol(&__floatundidf, "__floatundidf");
262 }
263 symbol(&__floatuntidf, "__floatuntidf");
264 symbol(&__floatuneidf, "__floatuneidf");
265
266 symbol(&__floatunsixf, "__floatunsixf");
267 symbol(&__floatundixf, "__floatundixf");
268 symbol(&__floatuntixf, "__floatuntixf");
269 symbol(&__floatuneixf, "__floatuneixf");
270
271 if (compiler_rt.want_ppc_abi) {
272 symbol(&__floatunsitf, "__floatunsikf");
273 symbol(&__floatunditf, "__floatundikf");
274 } else if (compiler_rt.want_sparc64_abi) {
275 symbol(&_Qp_uitoq, "_Qp_uitoq");
276 symbol(&_Qp_uxtoq, "_Qp_uxtoq");
277 } else if (compiler_rt.want_sparc32_abi) {
278 symbol(&__floatunsitf, "_Q_utoq");
279 symbol(&__floatunditf, "_Q_ulltoq");
280 } else {
281 symbol(&__floatunsitf, "__floatunsitf");
282 symbol(&__floatunditf, "__floatunditf");
283 }
284 if (compiler_rt.want_ppc_abi) {
285 symbol(&__floatuntitf, "__floatuntikf");
286 symbol(&__floatuneitf, "__floatuneikf");
287 } else {
288 if (builtin.cpu.arch == .x86) {
289 symbol(&__floatuntitf_x86, "__floatuntitf");
290 } else if (builtin.cpu.arch == .x86_64 and
291 (builtin.os.tag == .windows or builtin.os.tag == .uefi))
292 {
293 symbol(&__floatuntitf_x86_64_windows, "__floatuntitf");
294 } else {
295 symbol(&__floatuntitf, "__floatuntitf");
296 }
297 symbol(&__floatuneitf, "__floatuneitf");
298 }
299}
300
301fn __floatunsihf(a: u32) callconv(.c) compiler_rt.f16.Abi {
302 return compiler_rt.f16.toAbi(f16_floatFromInt_u32(a));
303}
304pub fn f16_floatFromInt_u32(a: u32) f16 {
305 return floatFromInt(f16, a);
306}
307
308fn __floatundihf(a: u64) callconv(.c) compiler_rt.f16.Abi {
309 return compiler_rt.f16.toAbi(f16_floatFromInt_u64(a));
310}
311pub fn f16_floatFromInt_u64(a: u64) f16 {
312 return floatFromInt(f16, a);
313}
314
315fn __floatuntihf(a: u128) callconv(.c) compiler_rt.f16.Abi {
316 return compiler_rt.f16.toAbi(f16_floatFromInt_u128(a));
317}
318pub fn f16_floatFromInt_u128(a: u128) f16 {
319 return floatFromInt(f16, a);
320}
321
322fn __floatuneihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi {
323 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
324 return compiler_rt.f16.toAbi(f16_floatFromInt_unsigned(a[0..byte_size]));
325}
326pub fn f16_floatFromInt_unsigned(a: []const u8) f16 {
327 return floatFromBigInt(f16, .unsigned, @ptrCast(@alignCast(a)));
328}
329
330fn __floatunsisf(a: u32) callconv(.c) compiler_rt.f32.Abi {
331 return compiler_rt.f32.toAbi(f32_floatFromInt_u32(a));
332}
333fn __aeabi_ui2f(a: u32) callconv(.{ .arm_aapcs = .{} }) f32 {
334 return f32_floatFromInt_u32(a);
335}
336pub fn f32_floatFromInt_u32(a: u32) f32 {
337 return floatFromInt(f32, a);
338}
339
340fn __floatundisf(a: u64) callconv(.c) compiler_rt.f32.Abi {
341 return compiler_rt.f32.toAbi(f32_floatFromInt_u64(a));
342}
343fn __aeabi_ul2f(a: u64) callconv(.{ .arm_aapcs = .{} }) f32 {
344 return f32_floatFromInt_u64(a);
345}
346pub fn f32_floatFromInt_u64(a: u64) f32 {
347 return floatFromInt(f32, a);
348}
349
350fn __floatuntisf(a: u128) callconv(.c) compiler_rt.f32.Abi {
351 return compiler_rt.f32.toAbi(f32_floatFromInt_u128(a));
352}
353pub fn f32_floatFromInt_u128(a: u128) f32 {
354 return floatFromInt(f32, a);
355}
356
357fn __floatuneisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi {
358 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
359 return compiler_rt.f32.toAbi(f32_floatFromInt_unsigned(a[0..byte_size]));
360}
361pub fn f32_floatFromInt_unsigned(a: []const u8) f32 {
362 return floatFromBigInt(f32, .unsigned, @ptrCast(@alignCast(a)));
363}
364
365fn __floatunsidf(a: u32) callconv(.c) compiler_rt.f64.Abi {
366 return compiler_rt.f64.toAbi(f64_floatFromInt_u32(a));
367}
368fn __aeabi_ui2d(a: u32) callconv(.{ .arm_aapcs = .{} }) f64 {
369 return f64_floatFromInt_u32(a);
370}
371pub fn f64_floatFromInt_u32(a: u32) f64 {
372 return floatFromInt(f64, a);
373}
374
375fn __floatundidf(a: u64) callconv(.c) compiler_rt.f64.Abi {
376 return compiler_rt.f64.toAbi(f64_floatFromInt_u64(a));
377}
378fn __aeabi_ul2d(a: u64) callconv(.{ .arm_aapcs = .{} }) f64 {
379 return f64_floatFromInt_u64(a);
380}
381pub fn f64_floatFromInt_u64(a: u64) f64 {
382 return floatFromInt(f64, a);
383}
384
385fn __floatuntidf(a: u128) callconv(.c) compiler_rt.f64.Abi {
386 return compiler_rt.f64.toAbi(f64_floatFromInt_u128(a));
387}
388pub fn f64_floatFromInt_u128(a: u128) f64 {
389 return floatFromInt(f64, a);
390}
391
392fn __floatuneidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi {
393 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
394 return compiler_rt.f64.toAbi(f64_floatFromInt_unsigned(a[0..byte_size]));
395}
396pub fn f64_floatFromInt_unsigned(a: []const u8) f64 {
397 return floatFromBigInt(f64, .unsigned, @ptrCast(@alignCast(a)));
398}
399
400fn __floatunsixf(a: u32) callconv(.c) compiler_rt.f80.Abi {
401 return compiler_rt.f80.toAbi(f80_floatFromInt_u32(a));
402}
403pub fn f80_floatFromInt_u32(a: u32) f80 {
404 return floatFromInt(f80, a);
405}
406
407fn __floatundixf(a: u64) callconv(.c) compiler_rt.f80.Abi {
408 return compiler_rt.f80.toAbi(f80_floatFromInt_u64(a));
409}
410pub fn f80_floatFromInt_u64(a: u64) f80 {
411 return floatFromInt(f80, a);
412}
413
414fn __floatuntixf(a: u128) callconv(.c) compiler_rt.f80.Abi {
415 return compiler_rt.f80.toAbi(f80_floatFromInt_u128(a));
416}
417pub fn f80_floatFromInt_u128(a: u128) f80 {
418 return floatFromInt(f80, a);
419}
420
421fn __floatuneixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi {
422 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
423 return compiler_rt.f80.toAbi(f80_floatFromInt_unsigned(a[0..byte_size]));
424}
425pub fn f80_floatFromInt_unsigned(a: []const u8) f80 {
426 return floatFromBigInt(f80, .unsigned, @ptrCast(@alignCast(a)));
427}
428
429fn __floatunsitf(a: u32) callconv(.c) compiler_rt.f128.Abi {
430 return compiler_rt.f128.toAbi(f128_floatFromInt_u32(a));
431}
432fn _Qp_uitoq(c: *f128, a: u32) callconv(.c) void {
433 c.* = f128_floatFromInt_u32(a);
434}
435pub fn f128_floatFromInt_u32(a: u32) f128 {
436 return floatFromInt(f128, a);
437}
438
439fn __floatunditf(a: u64) callconv(.c) compiler_rt.f128.Abi {
440 return compiler_rt.f128.toAbi(f128_floatFromInt_u64(a));
441}
442fn _Qp_uxtoq(c: *f128, a: u64) callconv(.c) void {
443 c.* = f128_floatFromInt_u64(a);
444}
445pub fn f128_floatFromInt_u64(a: u64) f128 {
446 return floatFromInt(f128, a);
447}
448
449fn __floatuntitf(a: u128) callconv(.c) compiler_rt.f128.Abi {
450 return compiler_rt.f128.toAbi(f128_floatFromInt_u128(a));
451}
452fn __floatuntitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi {
453 return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast(a)));
454}
455fn __floatuntitf_x86_64_windows(a_lo: u64, a_hi: u64) callconv(.c) compiler_rt.f128.Abi {
456 return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast(
457 packed struct { lo: u64, hi: u64 }{ .lo = a_lo, .hi = a_hi },
458 )));
459}
460pub fn f128_floatFromInt_u128(a: u128) f128 {
461 return floatFromInt(f128, a);
462}
463
464fn __floatuneitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi {
465 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
466 return compiler_rt.f128.toAbi(f128_floatFromInt_unsigned(a[0..byte_size]));
467}
468pub fn f128_floatFromInt_unsigned(a: []const u8) f128 {
469 return floatFromBigInt(f128, .unsigned, @ptrCast(@alignCast(a)));
470}
471
472inline fn floatFromInt(comptime T: type, x: anytype) T {
473 if (x == 0) return 0;
474
475 // Various constants whose values follow from the type parameters.
476 // Any reasonable optimizer will fold and propagate all of these.
477 const Z = @Int(.unsigned, @bitSizeOf(@TypeOf(x)));
478 const uT = @Int(.unsigned, @bitSizeOf(T));
479 const inf = math.inf(T);
480 const float_bits = @bitSizeOf(T);
481 const int_bits = @bitSizeOf(@TypeOf(x));
482 const exp_bits = math.floatExponentBits(T);
483 const fractional_bits = math.floatFractionalBits(T);
484 const exp_bias = math.maxInt(@Int(.unsigned, exp_bits - 1));
485 const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0;
486 const max_exp = exp_bias;
487
488 // Sign
489 const abs_val = @abs(x);
490 const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
491 var result: uT = sign_bit;
492
493 // Compute significand
494 const exp = int_bits - @clz(abs_val) - 1;
495 if (int_bits <= fractional_bits or exp <= fractional_bits) {
496 const shift_amt = fractional_bits - @as(math.Log2Int(uT), @intCast(exp));
497
498 // Shift up result to line up with the significand - no rounding required
499 result = @as(uT, @intCast(abs_val)) << shift_amt;
500 result ^= implicit_bit; // Remove implicit integer bit
501 } else {
502 const shift_amt: math.Log2Int(Z) = @intCast(exp - fractional_bits);
503 const exact_tie: bool = @ctz(abs_val) == shift_amt - 1;
504
505 // Shift down result and remove implicit integer bit
506 result = @as(uT, @intCast((abs_val >> (shift_amt - 1)))) ^ (implicit_bit << 1);
507
508 // Round result, including round-to-even for exact ties
509 result = ((result + 1) >> 1) & ~@as(uT, @intFromBool(exact_tie));
510 }
511
512 // Compute exponent
513 if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity
514 return @bitCast(sign_bit | @as(uT, @bitCast(inf)));
515
516 result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T);
517
518 // If the result included a carry, we need to restore the explicit integer bit
519 if (T == f80) result |= 1 << fractional_bits;
520
521 return @bitCast(sign_bit | result);
522}
523
524const endian = builtin.cpu.arch.endian();
525inline fn limb(limbs: []const u32, index: usize) u32 {
526 return switch (endian) {
527 .little => limbs[index],
528 .big => limbs[limbs.len - 1 - index],
529 };
530}
531
532inline fn floatFromBigInt(comptime T: type, comptime signedness: std.lang.Signedness, x: []const u32) T {
533 switch (x.len) {
534 0 => return 0,
535 inline 1...4 => |limbs_len| {
536 const low_to_high: [limbs_len]u32 = switch (endian) {
537 .little => x[0..limbs_len].*,
538 .big => switch (limbs_len) {
539 1 => .{x[0]},
540 2 => .{ x[1], x[0] },
541 3 => .{ x[2], x[1], x[0] },
542 4 => .{ x[3], x[2], x[1], x[0] },
543 else => comptime unreachable,
544 },
545 };
546 const I = @Int(signedness, 32 * limbs_len);
547 const int: I = @bitCast(low_to_high);
548 return @floatFromInt(int);
549 },
550 else => {},
551 }
552
553 // sign implicit fraction round sticky
554 const I = comptime @Int(
555 signedness,
556 @as(u16, @intFromBool(signedness == .signed)) + 1 + math.floatFractionalBits(T) + 1 + 1,
557 );
558
559 const clrsb = clrsb: {
560 var clsb: usize = 0;
561 const sign_bits: u32 = switch (signedness) {
562 .signed => @bitCast(@as(i32, @bitCast(limb(x, x.len - 1))) >> 31),
563 .unsigned => 0,
564 };
565 for (0..x.len) |limb_index| {
566 const l = limb(x, x.len - 1 - limb_index) ^ sign_bits;
567 clsb += @clz(l);
568 if (l != 0) break;
569 }
570 break :clrsb clsb - @intFromBool(signedness == .signed);
571 };
572 const active_bits = 32 * x.len - clrsb;
573 const exponent = active_bits -| @bitSizeOf(I);
574 const exponent_limb = exponent / 32;
575 const sticky = for (0..exponent_limb) |limb_index| {
576 if (limb(x, limb_index) != 0) break true;
577 } else limb(x, exponent_limb) & ((@as(u32, 1) << @truncate(exponent)) - 1) != 0;
578 return math.ldexp(@as(T, @floatFromInt(
579 std.mem.readPackedInt(I, std.mem.sliceAsBytes(x), exponent, .native) | @intFromBool(sticky),
580 )), @intCast(exponent));
581}
582
583test {
584 _ = @import("float_from_int_test.zig");
585}