| author | |
| committer | |
| log | c99c085d70c9347ec9a15d9a4f73c19e628912b7 |
| tree | 877b2d98b2611f8b4a1598f3c7b28e62f20ddd90 |
| parent | 47c834e477657113bccaaad32e91148ff837f1a4 |
The purpose of this branch is to switch to using an object file for each
independent function, in order to make linking simpler - instead of
relying on `-ffunction-sections` and `--gc-sections`, which involves the
linker doing the work of linking everything and then undoing work via
garbage collection, this will allow the linker to only include the
compilation units that are depended on in the first place.
This commit makes progress towards that goal.135 files changed, 4791 insertions(+), 4008 deletions(-)
CMakeLists.txt+92-9| ... | @@ -480,7 +480,14 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -480,7 +480,14 @@ set(ZIG_STAGE2_SOURCES |
| 480 | "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" | 480 | "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" |
| 481 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig" | 481 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig" |
| 482 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absv.zig" | 482 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absv.zig" |
| 483 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addXf3.zig" | 483 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addf3.zig" |
| 484 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addsf3.zig" | ||
| 485 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addtf3.zig" | ||
| 486 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addxf3.zig" | ||
| 487 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig" | ||
| 488 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig" | ||
| 489 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig" | ||
| 490 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig" | ||
| 484 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addo.zig" | 491 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addo.zig" |
| 485 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/arm.zig" | 492 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/arm.zig" |
| 486 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/atomics.zig" | 493 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/atomics.zig" |
| ... | @@ -491,7 +498,18 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -491,7 +498,18 @@ set(ZIG_STAGE2_SOURCES |
| 491 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/clear_cache.zig" | 498 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/clear_cache.zig" |
| 492 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmp.zig" | 499 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmp.zig" |
| 493 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/common.zig" | 500 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/common.zig" |
| 494 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/compareXf2.zig" | 501 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/comparef.zig" |
| 502 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpsf2.zig" | ||
| 503 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpdf2.zig" | ||
| 504 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmptf2.zig" | ||
| 505 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpxf2.zig" | ||
| 506 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gesf2.zig" | ||
| 507 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gedf2.zig" | ||
| 508 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/getf2.zig" | ||
| 509 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gexf2.zig" | ||
| 510 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordsf2.zig" | ||
| 511 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unorddf2.zig" | ||
| 512 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordtf2.zig" | ||
| 495 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cos.zig" | 513 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cos.zig" |
| 496 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/count0bits.zig" | 514 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/count0bits.zig" |
| 497 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/divdf3.zig" | 515 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/divdf3.zig" |
| ... | @@ -502,11 +520,79 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -502,11 +520,79 @@ set(ZIG_STAGE2_SOURCES |
| 502 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/emutls.zig" | 520 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/emutls.zig" |
| 503 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp.zig" | 521 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp.zig" |
| 504 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp2.zig" | 522 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp2.zig" |
| 505 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendXfYf2.zig" | 523 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendf.zig" |
| 506 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extend_f80.zig" | 524 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddftf2.zig" |
| 525 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddfxf2.zig" | ||
| 526 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfsf2.zig" | ||
| 527 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhftf2.zig" | ||
| 528 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfxf2.zig" | ||
| 529 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfdf2.zig" | ||
| 530 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsftf2.zig" | ||
| 531 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfxf2.zig" | ||
| 532 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendxftf2.zig" | ||
| 507 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fabs.zig" | 533 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fabs.zig" |
| 508 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixXfYi.zig" | 534 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/int_to_float.zig" |
| 509 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatXiYf.zig" | 535 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsihf.zig" |
| 536 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsisf.zig" | ||
| 537 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsidf.zig" | ||
| 538 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsitf.zig" | ||
| 539 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsixf.zig" | ||
| 540 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdihf.zig" | ||
| 541 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdisf.zig" | ||
| 542 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdidf.zig" | ||
| 543 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatditf.zig" | ||
| 544 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdixf.zig" | ||
| 545 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattihf.zig" | ||
| 546 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattisf.zig" | ||
| 547 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattidf.zig" | ||
| 548 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattitf.zig" | ||
| 549 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattixf.zig" | ||
| 550 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundihf.zig" | ||
| 551 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundisf.zig" | ||
| 552 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundidf.zig" | ||
| 553 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunditf.zig" | ||
| 554 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundixf.zig" | ||
| 555 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsihf.zig" | ||
| 556 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsisf.zig" | ||
| 557 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsidf.zig" | ||
| 558 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsitf.zig" | ||
| 559 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsixf.zig" | ||
| 560 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntihf.zig" | ||
| 561 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntisf.zig" | ||
| 562 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntidf.zig" | ||
| 563 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntitf.zig" | ||
| 564 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntixf.zig" | ||
| 565 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/float_to_int.zig" | ||
| 566 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfsi.zig" | ||
| 567 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfdi.zig" | ||
| 568 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfti.zig" | ||
| 569 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfsi.zig" | ||
| 570 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfdi.zig" | ||
| 571 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfti.zig" | ||
| 572 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfsi.zig" | ||
| 573 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfdi.zig" | ||
| 574 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfti.zig" | ||
| 575 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfsi.zig" | ||
| 576 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfdi.zig" | ||
| 577 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfti.zig" | ||
| 578 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfsi.zig" | ||
| 579 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfdi.zig" | ||
| 580 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfti.zig" | ||
| 581 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfsi.zig" | ||
| 582 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfdi.zig" | ||
| 583 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfti.zig" | ||
| 584 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfsi.zig" | ||
| 585 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfdi.zig" | ||
| 586 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfti.zig" | ||
| 587 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfsi.zig" | ||
| 588 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfdi.zig" | ||
| 589 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfti.zig" | ||
| 590 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfsi.zig" | ||
| 591 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfdi.zig" | ||
| 592 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfti.zig" | ||
| 593 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfsi.zig" | ||
| 594 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfdi.zig" | ||
| 595 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfti.zig" | ||
| 510 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floor.zig" | 596 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floor.zig" |
| 511 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fma.zig" | 597 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fma.zig" |
| 512 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmax.zig" | 598 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmax.zig" |
| ... | @@ -517,7 +603,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -517,7 +603,6 @@ set(ZIG_STAGE2_SOURCES |
| 517 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig" | 603 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig" |
| 518 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig" | 604 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig" |
| 519 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig" | 605 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig" |
| 520 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulXf3.zig" | ||
| 521 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig" | 606 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig" |
| 522 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig" | 607 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig" |
| 523 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig" | 608 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig" |
| ... | @@ -541,8 +626,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -541,8 +626,6 @@ set(ZIG_STAGE2_SOURCES |
| 541 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig" | 626 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig" |
| 542 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig" | 627 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig" |
| 543 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig" | 628 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig" |
| 544 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncXfYf2.zig" | ||
| 545 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc_f80.zig" | ||
| 546 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmod.zig" | 629 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmod.zig" |
| 547 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmodti4.zig" | 630 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmodti4.zig" |
| 548 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivti3.zig" | 631 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivti3.zig" |
lib/compiler_rt.zig+127-20| ... | @@ -1,18 +1,59 @@ | ... | @@ -1,18 +1,59 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | pub const panic = @import("compiler_rt/common.zig").panic; | 1 | pub const panic = @import("compiler_rt/common.zig").panic; |
| 3 | 2 | ||
| 4 | comptime { | 3 | comptime { |
| 5 | // TODO moving these around makes or breaks compilation of zig1.o for some reason | ||
| 6 | // Perhaps, until we switch to stage2, exports should be duplicated between this file | ||
| 7 | // and files included as a standalone units? | ||
| 8 | _ = @import("compiler_rt/atomics.zig"); | 4 | _ = @import("compiler_rt/atomics.zig"); |
| 9 | _ = @import("compiler_rt/addXf3.zig"); | 5 | |
| 10 | _ = @import("compiler_rt/mulXf3.zig"); | 6 | _ = @import("compiler_rt/addf3.zig"); |
| 11 | _ = @import("compiler_rt/compareXf2.zig"); | 7 | _ = @import("compiler_rt/addsf3.zig"); |
| 12 | _ = @import("compiler_rt/extendXfYf2.zig"); | 8 | _ = @import("compiler_rt/addtf3.zig"); |
| 13 | _ = @import("compiler_rt/extend_f80.zig"); | 9 | _ = @import("compiler_rt/addxf3.zig"); |
| 14 | _ = @import("compiler_rt/truncXfYf2.zig"); | 10 | _ = @import("compiler_rt/subdf3.zig"); |
| 15 | _ = @import("compiler_rt/trunc_f80.zig"); | 11 | _ = @import("compiler_rt/subsf3.zig"); |
| 12 | _ = @import("compiler_rt/subtf3.zig"); | ||
| 13 | _ = @import("compiler_rt/subxf3.zig"); | ||
| 14 | |||
| 15 | _ = @import("compiler_rt/mulf3.zig"); | ||
| 16 | _ = @import("compiler_rt/muldf3.zig"); | ||
| 17 | _ = @import("compiler_rt/mulsf3.zig"); | ||
| 18 | _ = @import("compiler_rt/multf3.zig"); | ||
| 19 | _ = @import("compiler_rt/mulxf3.zig"); | ||
| 20 | |||
| 21 | _ = @import("compiler_rt/comparef.zig"); | ||
| 22 | _ = @import("compiler_rt/cmpsf2.zig"); | ||
| 23 | _ = @import("compiler_rt/cmpdf2.zig"); | ||
| 24 | _ = @import("compiler_rt/cmptf2.zig"); | ||
| 25 | _ = @import("compiler_rt/cmpxf2.zig"); | ||
| 26 | _ = @import("compiler_rt/gesf2.zig"); | ||
| 27 | _ = @import("compiler_rt/gedf2.zig"); | ||
| 28 | _ = @import("compiler_rt/getf2.zig"); | ||
| 29 | _ = @import("compiler_rt/gexf2.zig"); | ||
| 30 | _ = @import("compiler_rt/unordsf2.zig"); | ||
| 31 | _ = @import("compiler_rt/unorddf2.zig"); | ||
| 32 | _ = @import("compiler_rt/unordtf2.zig"); | ||
| 33 | |||
| 34 | _ = @import("compiler_rt/extendf.zig"); | ||
| 35 | _ = @import("compiler_rt/extenddftf2.zig"); | ||
| 36 | _ = @import("compiler_rt/extenddfxf2.zig"); | ||
| 37 | _ = @import("compiler_rt/extendhfsf2.zig"); | ||
| 38 | _ = @import("compiler_rt/extendhftf2.zig"); | ||
| 39 | _ = @import("compiler_rt/extendhfxf2.zig"); | ||
| 40 | _ = @import("compiler_rt/extendsfdf2.zig"); | ||
| 41 | _ = @import("compiler_rt/extendsftf2.zig"); | ||
| 42 | _ = @import("compiler_rt/extendsfxf2.zig"); | ||
| 43 | _ = @import("compiler_rt/extendxftf2.zig"); | ||
| 44 | |||
| 45 | _ = @import("compiler_rt/truncf.zig"); | ||
| 46 | _ = @import("compiler_rt/truncsfhf2.zig"); | ||
| 47 | _ = @import("compiler_rt/truncdfhf2.zig"); | ||
| 48 | _ = @import("compiler_rt/truncdfsf2.zig"); | ||
| 49 | _ = @import("compiler_rt/trunctfhf2.zig"); | ||
| 50 | _ = @import("compiler_rt/trunctfsf2.zig"); | ||
| 51 | _ = @import("compiler_rt/trunctfdf2.zig"); | ||
| 52 | _ = @import("compiler_rt/trunctfxf2.zig"); | ||
| 53 | _ = @import("compiler_rt/truncxfhf2.zig"); | ||
| 54 | _ = @import("compiler_rt/truncxfsf2.zig"); | ||
| 55 | _ = @import("compiler_rt/truncxfdf2.zig"); | ||
| 56 | |||
| 16 | _ = @import("compiler_rt/divtf3.zig"); | 57 | _ = @import("compiler_rt/divtf3.zig"); |
| 17 | _ = @import("compiler_rt/divsf3.zig"); | 58 | _ = @import("compiler_rt/divsf3.zig"); |
| 18 | _ = @import("compiler_rt/divdf3.zig"); | 59 | _ = @import("compiler_rt/divdf3.zig"); |
| ... | @@ -43,35 +84,101 @@ comptime { | ... | @@ -43,35 +84,101 @@ comptime { |
| 43 | _ = @import("compiler_rt/udivti3.zig"); | 84 | _ = @import("compiler_rt/udivti3.zig"); |
| 44 | _ = @import("compiler_rt/udivmodti4.zig"); | 85 | _ = @import("compiler_rt/udivmodti4.zig"); |
| 45 | _ = @import("compiler_rt/umodti3.zig"); | 86 | _ = @import("compiler_rt/umodti3.zig"); |
| 46 | _ = @import("compiler_rt/floatXiYf.zig"); | 87 | |
| 47 | _ = @import("compiler_rt/fixXfYi.zig"); | 88 | _ = @import("compiler_rt/int_to_float.zig"); |
| 89 | _ = @import("compiler_rt/floatsihf.zig"); | ||
| 90 | _ = @import("compiler_rt/floatsisf.zig"); | ||
| 91 | _ = @import("compiler_rt/floatsidf.zig"); | ||
| 92 | _ = @import("compiler_rt/floatsitf.zig"); | ||
| 93 | _ = @import("compiler_rt/floatsixf.zig"); | ||
| 94 | _ = @import("compiler_rt/floatdihf.zig"); | ||
| 95 | _ = @import("compiler_rt/floatdisf.zig"); | ||
| 96 | _ = @import("compiler_rt/floatdidf.zig"); | ||
| 97 | _ = @import("compiler_rt/floatditf.zig"); | ||
| 98 | _ = @import("compiler_rt/floatdixf.zig"); | ||
| 99 | _ = @import("compiler_rt/floattihf.zig"); | ||
| 100 | _ = @import("compiler_rt/floattisf.zig"); | ||
| 101 | _ = @import("compiler_rt/floattidf.zig"); | ||
| 102 | _ = @import("compiler_rt/floattitf.zig"); | ||
| 103 | _ = @import("compiler_rt/floattixf.zig"); | ||
| 104 | _ = @import("compiler_rt/floatundihf.zig"); | ||
| 105 | _ = @import("compiler_rt/floatundisf.zig"); | ||
| 106 | _ = @import("compiler_rt/floatundidf.zig"); | ||
| 107 | _ = @import("compiler_rt/floatunditf.zig"); | ||
| 108 | _ = @import("compiler_rt/floatundixf.zig"); | ||
| 109 | _ = @import("compiler_rt/floatunsihf.zig"); | ||
| 110 | _ = @import("compiler_rt/floatunsisf.zig"); | ||
| 111 | _ = @import("compiler_rt/floatunsidf.zig"); | ||
| 112 | _ = @import("compiler_rt/floatunsitf.zig"); | ||
| 113 | _ = @import("compiler_rt/floatunsixf.zig"); | ||
| 114 | _ = @import("compiler_rt/floatuntihf.zig"); | ||
| 115 | _ = @import("compiler_rt/floatuntisf.zig"); | ||
| 116 | _ = @import("compiler_rt/floatuntidf.zig"); | ||
| 117 | _ = @import("compiler_rt/floatuntitf.zig"); | ||
| 118 | _ = @import("compiler_rt/floatuntixf.zig"); | ||
| 119 | |||
| 120 | _ = @import("compiler_rt/float_to_int.zig"); | ||
| 121 | _ = @import("compiler_rt/fixhfsi.zig"); | ||
| 122 | _ = @import("compiler_rt/fixhfdi.zig"); | ||
| 123 | _ = @import("compiler_rt/fixhfti.zig"); | ||
| 124 | _ = @import("compiler_rt/fixsfsi.zig"); | ||
| 125 | _ = @import("compiler_rt/fixsfdi.zig"); | ||
| 126 | _ = @import("compiler_rt/fixsfti.zig"); | ||
| 127 | _ = @import("compiler_rt/fixdfsi.zig"); | ||
| 128 | _ = @import("compiler_rt/fixdfdi.zig"); | ||
| 129 | _ = @import("compiler_rt/fixdfti.zig"); | ||
| 130 | _ = @import("compiler_rt/fixtfsi.zig"); | ||
| 131 | _ = @import("compiler_rt/fixtfdi.zig"); | ||
| 132 | _ = @import("compiler_rt/fixtfti.zig"); | ||
| 133 | _ = @import("compiler_rt/fixxfsi.zig"); | ||
| 134 | _ = @import("compiler_rt/fixxfdi.zig"); | ||
| 135 | _ = @import("compiler_rt/fixxfti.zig"); | ||
| 136 | _ = @import("compiler_rt/fixunshfsi.zig"); | ||
| 137 | _ = @import("compiler_rt/fixunshfdi.zig"); | ||
| 138 | _ = @import("compiler_rt/fixunshfti.zig"); | ||
| 139 | _ = @import("compiler_rt/fixunssfsi.zig"); | ||
| 140 | _ = @import("compiler_rt/fixunssfdi.zig"); | ||
| 141 | _ = @import("compiler_rt/fixunssfti.zig"); | ||
| 142 | _ = @import("compiler_rt/fixunsdfsi.zig"); | ||
| 143 | _ = @import("compiler_rt/fixunsdfdi.zig"); | ||
| 144 | _ = @import("compiler_rt/fixunsdfti.zig"); | ||
| 145 | _ = @import("compiler_rt/fixunstfsi.zig"); | ||
| 146 | _ = @import("compiler_rt/fixunstfdi.zig"); | ||
| 147 | _ = @import("compiler_rt/fixunstfti.zig"); | ||
| 148 | _ = @import("compiler_rt/fixunsxfsi.zig"); | ||
| 149 | _ = @import("compiler_rt/fixunsxfdi.zig"); | ||
| 150 | _ = @import("compiler_rt/fixunsxfti.zig"); | ||
| 151 | |||
| 48 | _ = @import("compiler_rt/count0bits.zig"); | 152 | _ = @import("compiler_rt/count0bits.zig"); |
| 49 | _ = @import("compiler_rt/parity.zig"); | 153 | _ = @import("compiler_rt/parity.zig"); |
| 50 | _ = @import("compiler_rt/popcount.zig"); | 154 | _ = @import("compiler_rt/popcount.zig"); |
| 51 | _ = @import("compiler_rt/bswap.zig"); | 155 | _ = @import("compiler_rt/bswap.zig"); |
| 52 | _ = @import("compiler_rt/int.zig"); | 156 | _ = @import("compiler_rt/int.zig"); |
| 53 | _ = @import("compiler_rt/shift.zig"); | 157 | _ = @import("compiler_rt/shift.zig"); |
| 158 | |||
| 54 | _ = @import("compiler_rt/negXi2.zig"); | 159 | _ = @import("compiler_rt/negXi2.zig"); |
| 160 | |||
| 55 | _ = @import("compiler_rt/muldi3.zig"); | 161 | _ = @import("compiler_rt/muldi3.zig"); |
| 162 | |||
| 56 | _ = @import("compiler_rt/absv.zig"); | 163 | _ = @import("compiler_rt/absv.zig"); |
| 164 | _ = @import("compiler_rt/absvsi2.zig"); | ||
| 165 | _ = @import("compiler_rt/absvdi2.zig"); | ||
| 166 | _ = @import("compiler_rt/absvti2.zig"); | ||
| 167 | |||
| 57 | _ = @import("compiler_rt/negv.zig"); | 168 | _ = @import("compiler_rt/negv.zig"); |
| 58 | _ = @import("compiler_rt/addo.zig"); | 169 | _ = @import("compiler_rt/addo.zig"); |
| 59 | _ = @import("compiler_rt/subo.zig"); | 170 | _ = @import("compiler_rt/subo.zig"); |
| 60 | _ = @import("compiler_rt/mulo.zig"); | 171 | _ = @import("compiler_rt/mulo.zig"); |
| 61 | _ = @import("compiler_rt/cmp.zig"); | 172 | _ = @import("compiler_rt/cmp.zig"); |
| 173 | |||
| 62 | _ = @import("compiler_rt/negXf2.zig"); | 174 | _ = @import("compiler_rt/negXf2.zig"); |
| 175 | |||
| 63 | _ = @import("compiler_rt/os_version_check.zig"); | 176 | _ = @import("compiler_rt/os_version_check.zig"); |
| 64 | _ = @import("compiler_rt/emutls.zig"); | 177 | _ = @import("compiler_rt/emutls.zig"); |
| 65 | _ = @import("compiler_rt/arm.zig"); | 178 | _ = @import("compiler_rt/arm.zig"); |
| 66 | _ = @import("compiler_rt/aulldiv.zig"); | 179 | _ = @import("compiler_rt/aulldiv.zig"); |
| 67 | _ = @import("compiler_rt/aullrem.zig"); | 180 | _ = @import("compiler_rt/aullrem.zig"); |
| 68 | _ = @import("compiler_rt/sparc.zig"); | ||
| 69 | _ = @import("compiler_rt/clear_cache.zig"); | 181 | _ = @import("compiler_rt/clear_cache.zig"); |
| 70 | 182 | ||
| 71 | // missing: Floating point raised to integer power | 183 | _ = @import("compiler_rt/sparc.zig"); |
| 72 | |||
| 73 | // missing: Complex arithmetic | ||
| 74 | // (a + ib) * (c + id) | ||
| 75 | // (a + ib) / (c + id) | ||
| 76 | |||
| 77 | } | 184 | } |
lib/compiler_rt/absv.zig+3-27| ... | @@ -1,18 +1,6 @@ | ... | @@ -1,18 +1,6 @@ |
| 1 | // absv - absolute oVerflow | 1 | /// absv - absolute oVerflow |
| 2 | // * @panic, if value can not be represented | 2 | /// * @panic if value can not be represented |
| 3 | // - absvXi4_generic for unoptimized version | 3 | pub inline fn absv(comptime ST: type, a: ST) ST { |
| 4 | const std = @import("std"); | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 7 | pub const panic = @import("common.zig").panic; | ||
| 8 | |||
| 9 | comptime { | ||
| 10 | @export(__absvsi2, .{ .name = "__absvsi2", .linkage = linkage }); | ||
| 11 | @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); | ||
| 12 | @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); | ||
| 13 | } | ||
| 14 | |||
| 15 | inline fn absvXi(comptime ST: type, a: ST) ST { | ||
| 16 | const UT = switch (ST) { | 4 | const UT = switch (ST) { |
| 17 | i32 => u32, | 5 | i32 => u32, |
| 18 | i64 => u64, | 6 | i64 => u64, |
| ... | @@ -31,18 +19,6 @@ inline fn absvXi(comptime ST: type, a: ST) ST { | ... | @@ -31,18 +19,6 @@ inline fn absvXi(comptime ST: type, a: ST) ST { |
| 31 | return x; | 19 | return x; |
| 32 | } | 20 | } |
| 33 | 21 | ||
| 34 | pub fn __absvsi2(a: i32) callconv(.C) i32 { | ||
| 35 | return absvXi(i32, a); | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn __absvdi2(a: i64) callconv(.C) i64 { | ||
| 39 | return absvXi(i64, a); | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn __absvti2(a: i128) callconv(.C) i128 { | ||
| 43 | return absvXi(i128, a); | ||
| 44 | } | ||
| 45 | |||
| 46 | test { | 22 | test { |
| 47 | _ = @import("absvsi2_test.zig"); | 23 | _ = @import("absvsi2_test.zig"); |
| 48 | _ = @import("absvdi2_test.zig"); | 24 | _ = @import("absvdi2_test.zig"); |
lib/compiler_rt/absvdi2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const absv = @import("./absv.zig").absv; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__absvdi2, .{ .name = "__absvdi2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __absvdi2(a: i64) callconv(.C) i64 { | ||
| 11 | return absv(i64, a); | ||
| 12 | } | ||
lib/compiler_rt/absvsi2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const absv = @import("./absv.zig").absv; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__absvsi2, .{ .name = "__absvsi2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __absvsi2(a: i32) callconv(.C) i32 { | ||
| 11 | return absv(i32, a); | ||
| 12 | } | ||
lib/compiler_rt/absvti2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const absv = @import("./absv.zig").absv; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__absvti2, .{ .name = "__absvti2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __absvti2(a: i128) callconv(.C) i128 { | ||
| 11 | return absv(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/addXf3.zig deleted-271| ... | @@ -1,271 +0,0 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc | ||
| 4 | |||
| 5 | const std = @import("std"); | ||
| 6 | const builtin = @import("builtin"); | ||
| 7 | const math = std.math; | ||
| 8 | const arch = builtin.cpu.arch; | ||
| 9 | const is_test = builtin.is_test; | ||
| 10 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 11 | |||
| 12 | const common = @import("common.zig"); | ||
| 13 | const normalize = common.normalize; | ||
| 14 | pub const panic = common.panic; | ||
| 15 | |||
| 16 | comptime { | ||
| 17 | @export(__addsf3, .{ .name = "__addsf3", .linkage = linkage }); | ||
| 18 | @export(__adddf3, .{ .name = "__adddf3", .linkage = linkage }); | ||
| 19 | @export(__addxf3, .{ .name = "__addxf3", .linkage = linkage }); | ||
| 20 | @export(__addtf3, .{ .name = "__addtf3", .linkage = linkage }); | ||
| 21 | |||
| 22 | @export(__subsf3, .{ .name = "__subsf3", .linkage = linkage }); | ||
| 23 | @export(__subdf3, .{ .name = "__subdf3", .linkage = linkage }); | ||
| 24 | @export(__subxf3, .{ .name = "__subxf3", .linkage = linkage }); | ||
| 25 | @export(__subtf3, .{ .name = "__subtf3", .linkage = linkage }); | ||
| 26 | |||
| 27 | if (!is_test) { | ||
| 28 | if (arch.isARM() or arch.isThumb()) { | ||
| 29 | @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = linkage }); | ||
| 30 | @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = linkage }); | ||
| 31 | @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = linkage }); | ||
| 32 | @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage }); | ||
| 33 | } | ||
| 34 | |||
| 35 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 36 | @export(__addkf3, .{ .name = "__addkf3", .linkage = linkage }); | ||
| 37 | @export(__subkf3, .{ .name = "__subkf3", .linkage = linkage }); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn __addsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 43 | return addXf3(f32, a, b); | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 47 | return addXf3(f64, a, b); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 51 | return addXf3(f80, a, b); | ||
| 52 | } | ||
| 53 | |||
| 54 | pub fn __subxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 55 | var b_rep = std.math.break_f80(b); | ||
| 56 | b_rep.exp ^= 0x8000; | ||
| 57 | return __addxf3(a, std.math.make_f80(b_rep)); | ||
| 58 | } | ||
| 59 | |||
| 60 | pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 61 | return addXf3(f128, a, b); | ||
| 62 | } | ||
| 63 | |||
| 64 | pub fn __addkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 65 | return @call(.{ .modifier = .always_inline }, __addtf3, .{ a, b }); | ||
| 66 | } | ||
| 67 | |||
| 68 | pub fn __subsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 69 | const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); | ||
| 70 | return addXf3(f32, a, neg_b); | ||
| 71 | } | ||
| 72 | |||
| 73 | pub fn __subdf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 74 | const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); | ||
| 75 | return addXf3(f64, a, neg_b); | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn __subtf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 79 | const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); | ||
| 80 | return addXf3(f128, a, neg_b); | ||
| 81 | } | ||
| 82 | |||
| 83 | pub fn __subkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 84 | return @call(.{ .modifier = .always_inline }, __subtf3, .{ a, b }); | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { | ||
| 88 | @setRuntimeSafety(false); | ||
| 89 | return @call(.{ .modifier = .always_inline }, __addsf3, .{ a, b }); | ||
| 90 | } | ||
| 91 | |||
| 92 | pub fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { | ||
| 93 | @setRuntimeSafety(false); | ||
| 94 | return @call(.{ .modifier = .always_inline }, __adddf3, .{ a, b }); | ||
| 95 | } | ||
| 96 | |||
| 97 | pub fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { | ||
| 98 | @setRuntimeSafety(false); | ||
| 99 | return @call(.{ .modifier = .always_inline }, __subsf3, .{ a, b }); | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { | ||
| 103 | @setRuntimeSafety(false); | ||
| 104 | return @call(.{ .modifier = .always_inline }, __subdf3, .{ a, b }); | ||
| 105 | } | ||
| 106 | |||
| 107 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 | ||
| 108 | pub fn addXf3(comptime T: type, a: T, b: T) T { | ||
| 109 | const bits = @typeInfo(T).Float.bits; | ||
| 110 | const Z = std.meta.Int(.unsigned, bits); | ||
| 111 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 112 | |||
| 113 | const typeWidth = bits; | ||
| 114 | const significandBits = math.floatMantissaBits(T); | ||
| 115 | const fractionalBits = math.floatFractionalBits(T); | ||
| 116 | const exponentBits = math.floatExponentBits(T); | ||
| 117 | |||
| 118 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | ||
| 119 | const maxExponent = ((1 << exponentBits) - 1); | ||
| 120 | |||
| 121 | const integerBit = (@as(Z, 1) << fractionalBits); | ||
| 122 | const quietBit = integerBit >> 1; | ||
| 123 | const significandMask = (@as(Z, 1) << significandBits) - 1; | ||
| 124 | |||
| 125 | const absMask = signBit - 1; | ||
| 126 | const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; | ||
| 127 | |||
| 128 | var aRep = @bitCast(Z, a); | ||
| 129 | var bRep = @bitCast(Z, b); | ||
| 130 | const aAbs = aRep & absMask; | ||
| 131 | const bAbs = bRep & absMask; | ||
| 132 | |||
| 133 | const infRep = @bitCast(Z, math.inf(T)); | ||
| 134 | |||
| 135 | // Detect if a or b is zero, infinity, or NaN. | ||
| 136 | if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or | ||
| 137 | bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) | ||
| 138 | { | ||
| 139 | // NaN + anything = qNaN | ||
| 140 | if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); | ||
| 141 | // anything + NaN = qNaN | ||
| 142 | if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); | ||
| 143 | |||
| 144 | if (aAbs == infRep) { | ||
| 145 | // +/-infinity + -/+infinity = qNaN | ||
| 146 | if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { | ||
| 147 | return @bitCast(T, qnanRep); | ||
| 148 | } | ||
| 149 | // +/-infinity + anything remaining = +/- infinity | ||
| 150 | else { | ||
| 151 | return a; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | // anything remaining + +/-infinity = +/-infinity | ||
| 156 | if (bAbs == infRep) return b; | ||
| 157 | |||
| 158 | // zero + anything = anything | ||
| 159 | if (aAbs == 0) { | ||
| 160 | // but we need to get the sign right for zero + zero | ||
| 161 | if (bAbs == 0) { | ||
| 162 | return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); | ||
| 163 | } else { | ||
| 164 | return b; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | // anything + zero = anything | ||
| 169 | if (bAbs == 0) return a; | ||
| 170 | } | ||
| 171 | |||
| 172 | // Swap a and b if necessary so that a has the larger absolute value. | ||
| 173 | if (bAbs > aAbs) { | ||
| 174 | const temp = aRep; | ||
| 175 | aRep = bRep; | ||
| 176 | bRep = temp; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Extract the exponent and significand from the (possibly swapped) a and b. | ||
| 180 | var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); | ||
| 181 | var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); | ||
| 182 | var aSignificand = aRep & significandMask; | ||
| 183 | var bSignificand = bRep & significandMask; | ||
| 184 | |||
| 185 | // Normalize any denormals, and adjust the exponent accordingly. | ||
| 186 | if (aExponent == 0) aExponent = normalize(T, &aSignificand); | ||
| 187 | if (bExponent == 0) bExponent = normalize(T, &bSignificand); | ||
| 188 | |||
| 189 | // The sign of the result is the sign of the larger operand, a. If they | ||
| 190 | // have opposite signs, we are performing a subtraction; otherwise addition. | ||
| 191 | const resultSign = aRep & signBit; | ||
| 192 | const subtraction = (aRep ^ bRep) & signBit != 0; | ||
| 193 | |||
| 194 | // Shift the significands to give us round, guard and sticky, and or in the | ||
| 195 | // implicit significand bit. (If we fell through from the denormal path it | ||
| 196 | // was already set by normalize( ), but setting it twice won't hurt | ||
| 197 | // anything.) | ||
| 198 | aSignificand = (aSignificand | integerBit) << 3; | ||
| 199 | bSignificand = (bSignificand | integerBit) << 3; | ||
| 200 | |||
| 201 | // Shift the significand of b by the difference in exponents, with a sticky | ||
| 202 | // bottom bit to get rounding correct. | ||
| 203 | const @"align" = @intCast(u32, aExponent - bExponent); | ||
| 204 | if (@"align" != 0) { | ||
| 205 | if (@"align" < typeWidth) { | ||
| 206 | const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; | ||
| 207 | bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; | ||
| 208 | } else { | ||
| 209 | bSignificand = 1; // sticky; b is known to be non-zero. | ||
| 210 | } | ||
| 211 | } | ||
| 212 | if (subtraction) { | ||
| 213 | aSignificand -= bSignificand; | ||
| 214 | // If a == -b, return +zero. | ||
| 215 | if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); | ||
| 216 | |||
| 217 | // If partial cancellation occured, we need to left-shift the result | ||
| 218 | // and adjust the exponent: | ||
| 219 | if (aSignificand < integerBit << 3) { | ||
| 220 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); | ||
| 221 | aSignificand <<= @intCast(S, shift); | ||
| 222 | aExponent -= shift; | ||
| 223 | } | ||
| 224 | } else { // addition | ||
| 225 | aSignificand += bSignificand; | ||
| 226 | |||
| 227 | // If the addition carried up, we need to right-shift the result and | ||
| 228 | // adjust the exponent: | ||
| 229 | if (aSignificand & (integerBit << 4) != 0) { | ||
| 230 | const sticky = aSignificand & 1; | ||
| 231 | aSignificand = aSignificand >> 1 | sticky; | ||
| 232 | aExponent += 1; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | // If we have overflowed the type, return +/- infinity: | ||
| 237 | if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); | ||
| 238 | |||
| 239 | if (aExponent <= 0) { | ||
| 240 | // Result is denormal; the exponent and round/sticky bits are zero. | ||
| 241 | // All we need to do is shift the significand and apply the correct sign. | ||
| 242 | aSignificand >>= @intCast(S, 4 - aExponent); | ||
| 243 | return @bitCast(T, resultSign | aSignificand); | ||
| 244 | } | ||
| 245 | |||
| 246 | // Low three bits are round, guard, and sticky. | ||
| 247 | const roundGuardSticky = aSignificand & 0x7; | ||
| 248 | |||
| 249 | // Shift the significand into place, and mask off the integer bit, if it's implicit. | ||
| 250 | var result = (aSignificand >> 3) & significandMask; | ||
| 251 | |||
| 252 | // Insert the exponent and sign. | ||
| 253 | result |= @intCast(Z, aExponent) << significandBits; | ||
| 254 | result |= resultSign; | ||
| 255 | |||
| 256 | // Final rounding. The result may overflow to infinity, but that is the | ||
| 257 | // correct result in that case. | ||
| 258 | if (roundGuardSticky > 0x4) result += 1; | ||
| 259 | if (roundGuardSticky == 0x4) result += result & 1; | ||
| 260 | |||
| 261 | // Restore any explicit integer bit, if it was rounded off | ||
| 262 | if (significandBits != fractionalBits) { | ||
| 263 | if ((result >> significandBits) != 0) result |= integerBit; | ||
| 264 | } | ||
| 265 | |||
| 266 | return @bitCast(T, result); | ||
| 267 | } | ||
| 268 | |||
| 269 | test { | ||
| 270 | _ = @import("addXf3_test.zig"); | ||
| 271 | } | ||
lib/compiler_rt/addXf3_test.zig deleted-157| ... | @@ -1,157 +0,0 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c | ||
| 4 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c | ||
| 5 | |||
| 6 | const std = @import("std"); | ||
| 7 | const math = std.math; | ||
| 8 | const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); | ||
| 9 | |||
| 10 | const __addtf3 = @import("addXf3.zig").__addtf3; | ||
| 11 | |||
| 12 | fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 13 | const x = __addtf3(a, b); | ||
| 14 | |||
| 15 | const rep = @bitCast(u128, x); | ||
| 16 | const hi = @intCast(u64, rep >> 64); | ||
| 17 | const lo = @truncate(u64, rep); | ||
| 18 | |||
| 19 | if (hi == expected_hi and lo == expected_lo) { | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | // test other possible NaN representation (signal NaN) | ||
| 23 | else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { | ||
| 24 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 25 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 26 | { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | return error.TestFailed; | ||
| 32 | } | ||
| 33 | |||
| 34 | test "addtf3" { | ||
| 35 | try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 36 | |||
| 37 | // NaN + any = NaN | ||
| 38 | try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 39 | |||
| 40 | // inf + inf = inf | ||
| 41 | try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); | ||
| 42 | |||
| 43 | // inf + any = inf | ||
| 44 | try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 45 | |||
| 46 | // any + any | ||
| 47 | try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); | ||
| 48 | try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); | ||
| 49 | } | ||
| 50 | |||
| 51 | const __subtf3 = @import("addXf3.zig").__subtf3; | ||
| 52 | |||
| 53 | fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 54 | const x = __subtf3(a, b); | ||
| 55 | |||
| 56 | const rep = @bitCast(u128, x); | ||
| 57 | const hi = @intCast(u64, rep >> 64); | ||
| 58 | const lo = @truncate(u64, rep); | ||
| 59 | |||
| 60 | if (hi == expected_hi and lo == expected_lo) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | // test other possible NaN representation (signal NaN) | ||
| 64 | else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { | ||
| 65 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 66 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 67 | { | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | return error.TestFailed; | ||
| 73 | } | ||
| 74 | |||
| 75 | test "subtf3" { | ||
| 76 | // qNaN - any = qNaN | ||
| 77 | try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 78 | |||
| 79 | // NaN + any = NaN | ||
| 80 | try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 81 | |||
| 82 | // inf - any = inf | ||
| 83 | try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 84 | |||
| 85 | // any + any | ||
| 86 | try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); | ||
| 87 | try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); | ||
| 88 | } | ||
| 89 | |||
| 90 | const __addxf3 = @import("addXf3.zig").__addxf3; | ||
| 91 | const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); | ||
| 92 | |||
| 93 | fn test__addxf3(a: f80, b: f80, expected: u80) !void { | ||
| 94 | const x = __addxf3(a, b); | ||
| 95 | const rep = @bitCast(u80, x); | ||
| 96 | |||
| 97 | if (rep == expected) | ||
| 98 | return; | ||
| 99 | |||
| 100 | if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) | ||
| 101 | return; // We don't currently test NaN payload propagation | ||
| 102 | |||
| 103 | return error.TestFailed; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "addxf3" { | ||
| 107 | // NaN + any = NaN | ||
| 108 | try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 109 | try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 110 | |||
| 111 | // any + NaN = NaN | ||
| 112 | try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); | ||
| 113 | try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); | ||
| 114 | |||
| 115 | // NaN + inf = NaN | ||
| 116 | try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); | ||
| 117 | |||
| 118 | // inf + NaN = NaN | ||
| 119 | try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); | ||
| 120 | |||
| 121 | // inf + inf = inf | ||
| 122 | try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 123 | |||
| 124 | // inf + -inf = NaN | ||
| 125 | try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); | ||
| 126 | |||
| 127 | // -inf + inf = NaN | ||
| 128 | try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); | ||
| 129 | |||
| 130 | // inf + any = inf | ||
| 131 | try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); | ||
| 132 | |||
| 133 | // any + inf = inf | ||
| 134 | try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 135 | |||
| 136 | // any + any | ||
| 137 | try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); | ||
| 138 | try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); | ||
| 139 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact | ||
| 140 | try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact | ||
| 141 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down | ||
| 142 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even | ||
| 143 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up | ||
| 144 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact | ||
| 145 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down | ||
| 146 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even | ||
| 147 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up | ||
| 148 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact | ||
| 149 | |||
| 150 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact | ||
| 151 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down | ||
| 152 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even | ||
| 153 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up | ||
| 154 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact | ||
| 155 | try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact | ||
| 156 | try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact | ||
| 157 | } | ||
lib/compiler_rt/adddf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const addf3 = @import("./addf3.zig").addf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__adddf3, .{ .name = "__adddf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __adddf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 15 | return addf3(f64, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { | ||
| 19 | return addf3(f64, a, b); | ||
| 20 | } | ||
lib/compiler_rt/addf3.zig created+172| ... | @@ -0,0 +1,172 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const normalize = common.normalize; | ||
| 5 | |||
| 6 | /// Ported from: | ||
| 7 | /// | ||
| 8 | /// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc | ||
| 9 | pub inline fn addf3(comptime T: type, a: T, b: T) T { | ||
| 10 | const bits = @typeInfo(T).Float.bits; | ||
| 11 | const Z = std.meta.Int(.unsigned, bits); | ||
| 12 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 13 | |||
| 14 | const typeWidth = bits; | ||
| 15 | const significandBits = math.floatMantissaBits(T); | ||
| 16 | const fractionalBits = math.floatFractionalBits(T); | ||
| 17 | const exponentBits = math.floatExponentBits(T); | ||
| 18 | |||
| 19 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | ||
| 20 | const maxExponent = ((1 << exponentBits) - 1); | ||
| 21 | |||
| 22 | const integerBit = (@as(Z, 1) << fractionalBits); | ||
| 23 | const quietBit = integerBit >> 1; | ||
| 24 | const significandMask = (@as(Z, 1) << significandBits) - 1; | ||
| 25 | |||
| 26 | const absMask = signBit - 1; | ||
| 27 | const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; | ||
| 28 | |||
| 29 | var aRep = @bitCast(Z, a); | ||
| 30 | var bRep = @bitCast(Z, b); | ||
| 31 | const aAbs = aRep & absMask; | ||
| 32 | const bAbs = bRep & absMask; | ||
| 33 | |||
| 34 | const infRep = @bitCast(Z, math.inf(T)); | ||
| 35 | |||
| 36 | // Detect if a or b is zero, infinity, or NaN. | ||
| 37 | if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or | ||
| 38 | bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) | ||
| 39 | { | ||
| 40 | // NaN + anything = qNaN | ||
| 41 | if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); | ||
| 42 | // anything + NaN = qNaN | ||
| 43 | if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); | ||
| 44 | |||
| 45 | if (aAbs == infRep) { | ||
| 46 | // +/-infinity + -/+infinity = qNaN | ||
| 47 | if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { | ||
| 48 | return @bitCast(T, qnanRep); | ||
| 49 | } | ||
| 50 | // +/-infinity + anything remaining = +/- infinity | ||
| 51 | else { | ||
| 52 | return a; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | // anything remaining + +/-infinity = +/-infinity | ||
| 57 | if (bAbs == infRep) return b; | ||
| 58 | |||
| 59 | // zero + anything = anything | ||
| 60 | if (aAbs == 0) { | ||
| 61 | // but we need to get the sign right for zero + zero | ||
| 62 | if (bAbs == 0) { | ||
| 63 | return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); | ||
| 64 | } else { | ||
| 65 | return b; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | // anything + zero = anything | ||
| 70 | if (bAbs == 0) return a; | ||
| 71 | } | ||
| 72 | |||
| 73 | // Swap a and b if necessary so that a has the larger absolute value. | ||
| 74 | if (bAbs > aAbs) { | ||
| 75 | const temp = aRep; | ||
| 76 | aRep = bRep; | ||
| 77 | bRep = temp; | ||
| 78 | } | ||
| 79 | |||
| 80 | // Extract the exponent and significand from the (possibly swapped) a and b. | ||
| 81 | var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); | ||
| 82 | var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); | ||
| 83 | var aSignificand = aRep & significandMask; | ||
| 84 | var bSignificand = bRep & significandMask; | ||
| 85 | |||
| 86 | // Normalize any denormals, and adjust the exponent accordingly. | ||
| 87 | if (aExponent == 0) aExponent = normalize(T, &aSignificand); | ||
| 88 | if (bExponent == 0) bExponent = normalize(T, &bSignificand); | ||
| 89 | |||
| 90 | // The sign of the result is the sign of the larger operand, a. If they | ||
| 91 | // have opposite signs, we are performing a subtraction; otherwise addition. | ||
| 92 | const resultSign = aRep & signBit; | ||
| 93 | const subtraction = (aRep ^ bRep) & signBit != 0; | ||
| 94 | |||
| 95 | // Shift the significands to give us round, guard and sticky, and or in the | ||
| 96 | // implicit significand bit. (If we fell through from the denormal path it | ||
| 97 | // was already set by normalize( ), but setting it twice won't hurt | ||
| 98 | // anything.) | ||
| 99 | aSignificand = (aSignificand | integerBit) << 3; | ||
| 100 | bSignificand = (bSignificand | integerBit) << 3; | ||
| 101 | |||
| 102 | // Shift the significand of b by the difference in exponents, with a sticky | ||
| 103 | // bottom bit to get rounding correct. | ||
| 104 | const @"align" = @intCast(u32, aExponent - bExponent); | ||
| 105 | if (@"align" != 0) { | ||
| 106 | if (@"align" < typeWidth) { | ||
| 107 | const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; | ||
| 108 | bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; | ||
| 109 | } else { | ||
| 110 | bSignificand = 1; // sticky; b is known to be non-zero. | ||
| 111 | } | ||
| 112 | } | ||
| 113 | if (subtraction) { | ||
| 114 | aSignificand -= bSignificand; | ||
| 115 | // If a == -b, return +zero. | ||
| 116 | if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); | ||
| 117 | |||
| 118 | // If partial cancellation occured, we need to left-shift the result | ||
| 119 | // and adjust the exponent: | ||
| 120 | if (aSignificand < integerBit << 3) { | ||
| 121 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); | ||
| 122 | aSignificand <<= @intCast(S, shift); | ||
| 123 | aExponent -= shift; | ||
| 124 | } | ||
| 125 | } else { // addition | ||
| 126 | aSignificand += bSignificand; | ||
| 127 | |||
| 128 | // If the addition carried up, we need to right-shift the result and | ||
| 129 | // adjust the exponent: | ||
| 130 | if (aSignificand & (integerBit << 4) != 0) { | ||
| 131 | const sticky = aSignificand & 1; | ||
| 132 | aSignificand = aSignificand >> 1 | sticky; | ||
| 133 | aExponent += 1; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | // If we have overflowed the type, return +/- infinity: | ||
| 138 | if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); | ||
| 139 | |||
| 140 | if (aExponent <= 0) { | ||
| 141 | // Result is denormal; the exponent and round/sticky bits are zero. | ||
| 142 | // All we need to do is shift the significand and apply the correct sign. | ||
| 143 | aSignificand >>= @intCast(S, 4 - aExponent); | ||
| 144 | return @bitCast(T, resultSign | aSignificand); | ||
| 145 | } | ||
| 146 | |||
| 147 | // Low three bits are round, guard, and sticky. | ||
| 148 | const roundGuardSticky = aSignificand & 0x7; | ||
| 149 | |||
| 150 | // Shift the significand into place, and mask off the integer bit, if it's implicit. | ||
| 151 | var result = (aSignificand >> 3) & significandMask; | ||
| 152 | |||
| 153 | // Insert the exponent and sign. | ||
| 154 | result |= @intCast(Z, aExponent) << significandBits; | ||
| 155 | result |= resultSign; | ||
| 156 | |||
| 157 | // Final rounding. The result may overflow to infinity, but that is the | ||
| 158 | // correct result in that case. | ||
| 159 | if (roundGuardSticky > 0x4) result += 1; | ||
| 160 | if (roundGuardSticky == 0x4) result += result & 1; | ||
| 161 | |||
| 162 | // Restore any explicit integer bit, if it was rounded off | ||
| 163 | if (significandBits != fractionalBits) { | ||
| 164 | if ((result >> significandBits) != 0) result |= integerBit; | ||
| 165 | } | ||
| 166 | |||
| 167 | return @bitCast(T, result); | ||
| 168 | } | ||
| 169 | |||
| 170 | test { | ||
| 171 | _ = @import("addf3_test.zig"); | ||
| 172 | } | ||
lib/compiler_rt/addf3_test.zig created+157| ... | @@ -0,0 +1,157 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c | ||
| 4 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c | ||
| 5 | |||
| 6 | const std = @import("std"); | ||
| 7 | const math = std.math; | ||
| 8 | const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); | ||
| 9 | |||
| 10 | const __addtf3 = @import("addf3.zig").__addtf3; | ||
| 11 | |||
| 12 | fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 13 | const x = __addtf3(a, b); | ||
| 14 | |||
| 15 | const rep = @bitCast(u128, x); | ||
| 16 | const hi = @intCast(u64, rep >> 64); | ||
| 17 | const lo = @truncate(u64, rep); | ||
| 18 | |||
| 19 | if (hi == expected_hi and lo == expected_lo) { | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | // test other possible NaN representation (signal NaN) | ||
| 23 | else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { | ||
| 24 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 25 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 26 | { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | return error.TestFailed; | ||
| 32 | } | ||
| 33 | |||
| 34 | test "addtf3" { | ||
| 35 | try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 36 | |||
| 37 | // NaN + any = NaN | ||
| 38 | try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 39 | |||
| 40 | // inf + inf = inf | ||
| 41 | try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); | ||
| 42 | |||
| 43 | // inf + any = inf | ||
| 44 | try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 45 | |||
| 46 | // any + any | ||
| 47 | try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); | ||
| 48 | try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); | ||
| 49 | } | ||
| 50 | |||
| 51 | const __subtf3 = @import("addf3.zig").__subtf3; | ||
| 52 | |||
| 53 | fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 54 | const x = __subtf3(a, b); | ||
| 55 | |||
| 56 | const rep = @bitCast(u128, x); | ||
| 57 | const hi = @intCast(u64, rep >> 64); | ||
| 58 | const lo = @truncate(u64, rep); | ||
| 59 | |||
| 60 | if (hi == expected_hi and lo == expected_lo) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | // test other possible NaN representation (signal NaN) | ||
| 64 | else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { | ||
| 65 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 66 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 67 | { | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | return error.TestFailed; | ||
| 73 | } | ||
| 74 | |||
| 75 | test "subtf3" { | ||
| 76 | // qNaN - any = qNaN | ||
| 77 | try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 78 | |||
| 79 | // NaN + any = NaN | ||
| 80 | try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 81 | |||
| 82 | // inf - any = inf | ||
| 83 | try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 84 | |||
| 85 | // any + any | ||
| 86 | try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); | ||
| 87 | try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); | ||
| 88 | } | ||
| 89 | |||
| 90 | const __addxf3 = @import("addf3.zig").__addxf3; | ||
| 91 | const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); | ||
| 92 | |||
| 93 | fn test__addxf3(a: f80, b: f80, expected: u80) !void { | ||
| 94 | const x = __addxf3(a, b); | ||
| 95 | const rep = @bitCast(u80, x); | ||
| 96 | |||
| 97 | if (rep == expected) | ||
| 98 | return; | ||
| 99 | |||
| 100 | if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) | ||
| 101 | return; // We don't currently test NaN payload propagation | ||
| 102 | |||
| 103 | return error.TestFailed; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "addxf3" { | ||
| 107 | // NaN + any = NaN | ||
| 108 | try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 109 | try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 110 | |||
| 111 | // any + NaN = NaN | ||
| 112 | try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); | ||
| 113 | try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); | ||
| 114 | |||
| 115 | // NaN + inf = NaN | ||
| 116 | try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); | ||
| 117 | |||
| 118 | // inf + NaN = NaN | ||
| 119 | try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); | ||
| 120 | |||
| 121 | // inf + inf = inf | ||
| 122 | try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 123 | |||
| 124 | // inf + -inf = NaN | ||
| 125 | try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); | ||
| 126 | |||
| 127 | // -inf + inf = NaN | ||
| 128 | try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); | ||
| 129 | |||
| 130 | // inf + any = inf | ||
| 131 | try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); | ||
| 132 | |||
| 133 | // any + inf = inf | ||
| 134 | try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 135 | |||
| 136 | // any + any | ||
| 137 | try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); | ||
| 138 | try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); | ||
| 139 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact | ||
| 140 | try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact | ||
| 141 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down | ||
| 142 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even | ||
| 143 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up | ||
| 144 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact | ||
| 145 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down | ||
| 146 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even | ||
| 147 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up | ||
| 148 | try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact | ||
| 149 | |||
| 150 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact | ||
| 151 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down | ||
| 152 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even | ||
| 153 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up | ||
| 154 | try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact | ||
| 155 | try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact | ||
| 156 | try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact | ||
| 157 | } | ||
lib/compiler_rt/addsf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const addf3 = @import("./addf3.zig").addf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__addsf3, .{ .name = "__addsf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __addsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 15 | return addf3(f32, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { | ||
| 19 | return addf3(f32, a, b); | ||
| 20 | } | ||
lib/compiler_rt/addtf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const addf3 = @import("./addf3.zig").addf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__addkf3, .{ .name = "__addkf3", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__addtf3, .{ .name = "__addtf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __addtf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 15 | return addf3(f128, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __addkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 19 | return addf3(f128, a, b); | ||
| 20 | } | ||
lib/compiler_rt/addxf3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const addf3 = @import("./addf3.zig").addf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__addxf3, .{ .name = "__addxf3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __addxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 11 | return addf3(f80, a, b); | ||
| 12 | } | ||
lib/compiler_rt/cmpdf2.zig created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = common.linkage }); | ||
| 11 | @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = common.linkage }); | ||
| 12 | @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = common.linkage }); | ||
| 13 | } else { | ||
| 14 | @export(__eqdf2, .{ .name = "__eqdf2", .linkage = common.linkage }); | ||
| 15 | @export(__nedf2, .{ .name = "__nedf2", .linkage = common.linkage }); | ||
| 16 | @export(__ledf2, .{ .name = "__ledf2", .linkage = common.linkage }); | ||
| 17 | @export(__cmpdf2, .{ .name = "__cmpdf2", .linkage = common.linkage }); | ||
| 18 | @export(__ltdf2, .{ .name = "__ltdf2", .linkage = common.linkage }); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | /// "These functions calculate a <=> b. That is, if a is less than b, they return -1; | ||
| 23 | /// if a is greater than b, they return 1; and if a and b are equal they return 0. | ||
| 24 | /// If either argument is NaN they return 1..." | ||
| 25 | /// | ||
| 26 | /// Note that this matches the definition of `__ledf2`, `__eqdf2`, `__nedf2`, `__cmpdf2`, | ||
| 27 | /// and `__ltdf2`. | ||
| 28 | fn __cmpdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 29 | return @enumToInt(comparef.cmpf2(f64, comparef.LE, a, b)); | ||
| 30 | } | ||
| 31 | |||
| 32 | /// "These functions return a value less than or equal to zero if neither argument is NaN, | ||
| 33 | /// and a is less than or equal to b." | ||
| 34 | fn __ledf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 35 | return __cmpdf2(a, b); | ||
| 36 | } | ||
| 37 | |||
| 38 | /// "These functions return zero if neither argument is NaN, and a and b are equal." | ||
| 39 | /// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined | ||
| 40 | /// to have the same return value. | ||
| 41 | fn __eqdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 42 | return __cmpdf2(a, b); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." | ||
| 46 | /// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined | ||
| 47 | /// to have the same return value. | ||
| 48 | fn __nedf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 49 | return __cmpdf2(a, b); | ||
| 50 | } | ||
| 51 | |||
| 52 | /// "These functions return a value less than zero if neither argument is NaN, and a | ||
| 53 | /// is strictly less than b." | ||
| 54 | fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 55 | return __cmpdf2(a, b); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 59 | return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Equal); | ||
| 60 | } | ||
| 61 | |||
| 62 | fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 63 | return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Less); | ||
| 64 | } | ||
| 65 | |||
| 66 | fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 67 | return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater); | ||
| 68 | } | ||
lib/compiler_rt/cmpsf2.zig created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = common.linkage }); | ||
| 11 | @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = common.linkage }); | ||
| 12 | @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = common.linkage }); | ||
| 13 | } else { | ||
| 14 | @export(__eqsf2, .{ .name = "__eqsf2", .linkage = common.linkage }); | ||
| 15 | @export(__nesf2, .{ .name = "__nesf2", .linkage = common.linkage }); | ||
| 16 | @export(__lesf2, .{ .name = "__lesf2", .linkage = common.linkage }); | ||
| 17 | @export(__cmpsf2, .{ .name = "__cmpsf2", .linkage = common.linkage }); | ||
| 18 | @export(__ltsf2, .{ .name = "__ltsf2", .linkage = common.linkage }); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | /// "These functions calculate a <=> b. That is, if a is less than b, they return -1; | ||
| 23 | /// if a is greater than b, they return 1; and if a and b are equal they return 0. | ||
| 24 | /// If either argument is NaN they return 1..." | ||
| 25 | /// | ||
| 26 | /// Note that this matches the definition of `__lesf2`, `__eqsf2`, `__nesf2`, `__cmpsf2`, | ||
| 27 | /// and `__ltsf2`. | ||
| 28 | fn __cmpsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 29 | return @enumToInt(comparef.cmpf2(f32, comparef.LE, a, b)); | ||
| 30 | } | ||
| 31 | |||
| 32 | /// "These functions return a value less than or equal to zero if neither argument is NaN, | ||
| 33 | /// and a is less than or equal to b." | ||
| 34 | fn __lesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 35 | return __cmpsf2(a, b); | ||
| 36 | } | ||
| 37 | |||
| 38 | /// "These functions return zero if neither argument is NaN, and a and b are equal." | ||
| 39 | /// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined | ||
| 40 | /// to have the same return value. | ||
| 41 | fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 42 | return __cmpsf2(a, b); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." | ||
| 46 | /// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined | ||
| 47 | /// to have the same return value. | ||
| 48 | fn __nesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 49 | return __cmpsf2(a, b); | ||
| 50 | } | ||
| 51 | |||
| 52 | /// "These functions return a value less than zero if neither argument is NaN, and a | ||
| 53 | /// is strictly less than b." | ||
| 54 | fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 55 | return __cmpsf2(a, b); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 59 | return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Equal); | ||
| 60 | } | ||
| 61 | |||
| 62 | fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 63 | return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Less); | ||
| 64 | } | ||
| 65 | |||
| 66 | fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 67 | return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) != .Greater); | ||
| 68 | } | ||
lib/compiler_rt/cmptf2.zig created+73| ... | @@ -0,0 +1,73 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_ppc_abi) { | ||
| 10 | @export(__eqkf2, .{ .name = "__eqkf2", .linkage = common.linkage }); | ||
| 11 | @export(__nekf2, .{ .name = "__nekf2", .linkage = common.linkage }); | ||
| 12 | @export(__ltkf2, .{ .name = "__ltkf2", .linkage = common.linkage }); | ||
| 13 | @export(__lekf2, .{ .name = "__lekf2", .linkage = common.linkage }); | ||
| 14 | } else { | ||
| 15 | @export(__eqtf2, .{ .name = "__eqtf2", .linkage = common.linkage }); | ||
| 16 | @export(__netf2, .{ .name = "__netf2", .linkage = common.linkage }); | ||
| 17 | @export(__letf2, .{ .name = "__letf2", .linkage = common.linkage }); | ||
| 18 | @export(__cmptf2, .{ .name = "__cmptf2", .linkage = common.linkage }); | ||
| 19 | @export(__lttf2, .{ .name = "__lttf2", .linkage = common.linkage }); | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | /// "These functions calculate a <=> b. That is, if a is less than b, they return -1; | ||
| 24 | /// if a is greater than b, they return 1; and if a and b are equal they return 0. | ||
| 25 | /// If either argument is NaN they return 1..." | ||
| 26 | /// | ||
| 27 | /// Note that this matches the definition of `__letf2`, `__eqtf2`, `__netf2`, `__cmptf2`, | ||
| 28 | /// and `__lttf2`. | ||
| 29 | fn __cmptf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 30 | return @enumToInt(comparef.cmpf2(f128, comparef.LE, a, b)); | ||
| 31 | } | ||
| 32 | |||
| 33 | /// "These functions return a value less than or equal to zero if neither argument is NaN, | ||
| 34 | /// and a is less than or equal to b." | ||
| 35 | fn __letf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 36 | return __cmptf2(a, b); | ||
| 37 | } | ||
| 38 | |||
| 39 | /// "These functions return zero if neither argument is NaN, and a and b are equal." | ||
| 40 | /// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined | ||
| 41 | /// to have the same return value. | ||
| 42 | fn __eqtf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 43 | return __cmptf2(a, b); | ||
| 44 | } | ||
| 45 | |||
| 46 | /// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." | ||
| 47 | /// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined | ||
| 48 | /// to have the same return value. | ||
| 49 | fn __netf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 50 | return __cmptf2(a, b); | ||
| 51 | } | ||
| 52 | |||
| 53 | /// "These functions return a value less than zero if neither argument is NaN, and a | ||
| 54 | /// is strictly less than b." | ||
| 55 | fn __lttf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 56 | return __cmptf2(a, b); | ||
| 57 | } | ||
| 58 | |||
| 59 | fn __eqkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 60 | return __cmptf2(a, b); | ||
| 61 | } | ||
| 62 | |||
| 63 | fn __nekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 64 | return __cmptf2(a, b); | ||
| 65 | } | ||
| 66 | |||
| 67 | fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 68 | return __cmptf2(a, b); | ||
| 69 | } | ||
| 70 | |||
| 71 | fn __lekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 72 | return __cmptf2(a, b); | ||
| 73 | } | ||
lib/compiler_rt/cmpxf2.zig created+50| ... | @@ -0,0 +1,50 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | @export(__eqxf2, .{ .name = "__eqxf2", .linkage = common.linkage }); | ||
| 10 | @export(__nexf2, .{ .name = "__nexf2", .linkage = common.linkage }); | ||
| 11 | @export(__lexf2, .{ .name = "__lexf2", .linkage = common.linkage }); | ||
| 12 | @export(__cmpxf2, .{ .name = "__cmpxf2", .linkage = common.linkage }); | ||
| 13 | @export(__ltxf2, .{ .name = "__ltxf2", .linkage = common.linkage }); | ||
| 14 | } | ||
| 15 | |||
| 16 | /// "These functions calculate a <=> b. That is, if a is less than b, they return -1; | ||
| 17 | /// if a is greater than b, they return 1; and if a and b are equal they return 0. | ||
| 18 | /// If either argument is NaN they return 1..." | ||
| 19 | /// | ||
| 20 | /// Note that this matches the definition of `__lexf2`, `__eqxf2`, `__nexf2`, `__cmpxf2`, | ||
| 21 | /// and `__ltxf2`. | ||
| 22 | fn __cmpxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 23 | return @enumToInt(comparef.cmp_f80(comparef.LE, a, b)); | ||
| 24 | } | ||
| 25 | |||
| 26 | /// "These functions return a value less than or equal to zero if neither argument is NaN, | ||
| 27 | /// and a is less than or equal to b." | ||
| 28 | fn __lexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 29 | return __cmpxf2(a, b); | ||
| 30 | } | ||
| 31 | |||
| 32 | /// "These functions return zero if neither argument is NaN, and a and b are equal." | ||
| 33 | /// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined | ||
| 34 | /// to have the same return value. | ||
| 35 | fn __eqxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 36 | return __cmpxf2(a, b); | ||
| 37 | } | ||
| 38 | |||
| 39 | /// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." | ||
| 40 | /// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined | ||
| 41 | /// to have the same return value. | ||
| 42 | fn __nexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 43 | return __cmpxf2(a, b); | ||
| 44 | } | ||
| 45 | |||
| 46 | /// "These functions return a value less than zero if neither argument is NaN, and a | ||
| 47 | /// is strictly less than b." | ||
| 48 | fn __ltxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 49 | return __cmpxf2(a, b); | ||
| 50 | } | ||
lib/compiler_rt/common.zig+17-10| ... | @@ -3,8 +3,14 @@ const builtin = @import("builtin"); | ... | @@ -3,8 +3,14 @@ const builtin = @import("builtin"); |
| 3 | const math = std.math; | 3 | const math = std.math; |
| 4 | const is_test = builtin.is_test; | 4 | const is_test = builtin.is_test; |
| 5 | 5 | ||
| 6 | pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 7 | pub const want_aeabi = builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb(); | ||
| 8 | pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); | ||
| 9 | pub const want_msvc_abi = builtin.abi == .msvc; | ||
| 10 | pub const want_gnu_abi = builtin.abi.isGnu(); | ||
| 11 | |||
| 6 | // Avoid dragging in the runtime safety mechanisms into this .o file, | 12 | // Avoid dragging in the runtime safety mechanisms into this .o file, |
| 7 | // unless we're trying to test this file. | 13 | // unless we're trying to test compiler-rt. |
| 8 | pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { | 14 | pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { |
| 9 | _ = error_return_trace; | 15 | _ = error_return_trace; |
| 10 | @setCold(true); | 16 | @setCold(true); |
| ... | @@ -15,8 +21,13 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore | ... | @@ -15,8 +21,13 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore |
| 15 | } | 21 | } |
| 16 | } | 22 | } |
| 17 | 23 | ||
| 24 | /// AArch64 is the only ABI (at the moment) to support f16 arguments without the | ||
| 25 | /// need for extending them to wider fp types. | ||
| 26 | /// TODO remove this; do this type selection in the language rather than | ||
| 27 | /// here in compiler-rt. | ||
| 28 | pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16; | ||
| 29 | |||
| 18 | pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | 30 | pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { |
| 19 | @setRuntimeSafety(is_test); | ||
| 20 | switch (Z) { | 31 | switch (Z) { |
| 21 | u16 => { | 32 | u16 => { |
| 22 | // 16x16 --> 32 bit multiply | 33 | // 16x16 --> 32 bit multiply |
| ... | @@ -130,15 +141,11 @@ pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | ... | @@ -130,15 +141,11 @@ pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { |
| 130 | } | 141 | } |
| 131 | } | 142 | } |
| 132 | 143 | ||
| 133 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 | ||
| 134 | pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { | 144 | pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { |
| 135 | const bits = @typeInfo(T).Float.bits; | 145 | const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); |
| 136 | const Z = std.meta.Int(.unsigned, bits); | 146 | const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); |
| 137 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 138 | const fractionalBits = math.floatFractionalBits(T); | ||
| 139 | const integerBit = @as(Z, 1) << fractionalBits; | ||
| 140 | 147 | ||
| 141 | const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, integerBit); | 148 | const shift = @clz(Z, significand.*) - @clz(Z, integerBit); |
| 142 | significand.* <<= @intCast(S, shift); | 149 | significand.* <<= @intCast(std.math.Log2Int(Z), shift); |
| 143 | return @as(i32, 1) - shift; | 150 | return @as(i32, 1) - shift; |
| 144 | } | 151 | } |
lib/compiler_rt/compareXf2.zig deleted-440| ... | @@ -1,440 +0,0 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c | ||
| 4 | |||
| 5 | const std = @import("std"); | ||
| 6 | const builtin = @import("builtin"); | ||
| 7 | const is_test = builtin.is_test; | ||
| 8 | const arch = builtin.cpu.arch; | ||
| 9 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 10 | pub const panic = @import("common.zig").panic; | ||
| 11 | |||
| 12 | comptime { | ||
| 13 | @export(__lesf2, .{ .name = "__lesf2", .linkage = linkage }); | ||
| 14 | @export(__ledf2, .{ .name = "__ledf2", .linkage = linkage }); | ||
| 15 | @export(__letf2, .{ .name = "__letf2", .linkage = linkage }); | ||
| 16 | @export(__lexf2, .{ .name = "__lexf2", .linkage = linkage }); | ||
| 17 | |||
| 18 | @export(__gesf2, .{ .name = "__gesf2", .linkage = linkage }); | ||
| 19 | @export(__gedf2, .{ .name = "__gedf2", .linkage = linkage }); | ||
| 20 | @export(__getf2, .{ .name = "__getf2", .linkage = linkage }); | ||
| 21 | @export(__gexf2, .{ .name = "__gexf2", .linkage = linkage }); | ||
| 22 | |||
| 23 | @export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage }); | ||
| 24 | @export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage }); | ||
| 25 | @export(__eqxf2, .{ .name = "__eqxf2", .linkage = linkage }); | ||
| 26 | |||
| 27 | @export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage }); | ||
| 28 | @export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage }); | ||
| 29 | @export(__ltxf2, .{ .name = "__ltxf2", .linkage = linkage }); | ||
| 30 | |||
| 31 | @export(__nesf2, .{ .name = "__nesf2", .linkage = linkage }); | ||
| 32 | @export(__nedf2, .{ .name = "__nedf2", .linkage = linkage }); | ||
| 33 | @export(__nexf2, .{ .name = "__nexf2", .linkage = linkage }); | ||
| 34 | |||
| 35 | @export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage }); | ||
| 36 | @export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage }); | ||
| 37 | @export(__gtxf2, .{ .name = "__gtxf2", .linkage = linkage }); | ||
| 38 | |||
| 39 | @export(__unordsf2, .{ .name = "__unordsf2", .linkage = linkage }); | ||
| 40 | @export(__unorddf2, .{ .name = "__unorddf2", .linkage = linkage }); | ||
| 41 | @export(__unordtf2, .{ .name = "__unordtf2", .linkage = linkage }); | ||
| 42 | |||
| 43 | if (!is_test) { | ||
| 44 | @export(__cmpsf2, .{ .name = "__cmpsf2", .linkage = linkage }); | ||
| 45 | @export(__cmpdf2, .{ .name = "__cmpdf2", .linkage = linkage }); | ||
| 46 | @export(__cmptf2, .{ .name = "__cmptf2", .linkage = linkage }); | ||
| 47 | @export(__eqtf2, .{ .name = "__eqtf2", .linkage = linkage }); | ||
| 48 | @export(__lttf2, .{ .name = "__lttf2", .linkage = linkage }); | ||
| 49 | @export(__gttf2, .{ .name = "__gttf2", .linkage = linkage }); | ||
| 50 | @export(__netf2, .{ .name = "__netf2", .linkage = linkage }); | ||
| 51 | |||
| 52 | if (arch.isARM() or arch.isThumb()) { | ||
| 53 | @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage }); | ||
| 54 | @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage }); | ||
| 55 | @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage }); | ||
| 56 | @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage }); | ||
| 57 | @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage }); | ||
| 58 | @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage }); | ||
| 59 | |||
| 60 | @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage }); | ||
| 61 | @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage }); | ||
| 62 | @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage }); | ||
| 63 | @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage }); | ||
| 64 | @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage }); | ||
| 65 | @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage }); | ||
| 66 | } | ||
| 67 | |||
| 68 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 69 | @export(__eqkf2, .{ .name = "__eqkf2", .linkage = linkage }); | ||
| 70 | @export(__nekf2, .{ .name = "__nekf2", .linkage = linkage }); | ||
| 71 | @export(__gekf2, .{ .name = "__gekf2", .linkage = linkage }); | ||
| 72 | @export(__ltkf2, .{ .name = "__ltkf2", .linkage = linkage }); | ||
| 73 | @export(__lekf2, .{ .name = "__lekf2", .linkage = linkage }); | ||
| 74 | @export(__gtkf2, .{ .name = "__gtkf2", .linkage = linkage }); | ||
| 75 | @export(__unordkf2, .{ .name = "__unordkf2", .linkage = linkage }); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | const LE = enum(i32) { | ||
| 81 | Less = -1, | ||
| 82 | Equal = 0, | ||
| 83 | Greater = 1, | ||
| 84 | |||
| 85 | const Unordered: LE = .Greater; | ||
| 86 | }; | ||
| 87 | |||
| 88 | const GE = enum(i32) { | ||
| 89 | Less = -1, | ||
| 90 | Equal = 0, | ||
| 91 | Greater = 1, | ||
| 92 | |||
| 93 | const Unordered: GE = .Less; | ||
| 94 | }; | ||
| 95 | |||
| 96 | pub inline fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { | ||
| 97 | @setRuntimeSafety(builtin.is_test); | ||
| 98 | |||
| 99 | const bits = @typeInfo(T).Float.bits; | ||
| 100 | const srep_t = std.meta.Int(.signed, bits); | ||
| 101 | const rep_t = std.meta.Int(.unsigned, bits); | ||
| 102 | |||
| 103 | const significandBits = std.math.floatMantissaBits(T); | ||
| 104 | const exponentBits = std.math.floatExponentBits(T); | ||
| 105 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | ||
| 106 | const absMask = signBit - 1; | ||
| 107 | const infT = comptime std.math.inf(T); | ||
| 108 | const infRep = @bitCast(rep_t, infT); | ||
| 109 | |||
| 110 | const aInt = @bitCast(srep_t, a); | ||
| 111 | const bInt = @bitCast(srep_t, b); | ||
| 112 | const aAbs = @bitCast(rep_t, aInt) & absMask; | ||
| 113 | const bAbs = @bitCast(rep_t, bInt) & absMask; | ||
| 114 | |||
| 115 | // If either a or b is NaN, they are unordered. | ||
| 116 | if (aAbs > infRep or bAbs > infRep) return RT.Unordered; | ||
| 117 | |||
| 118 | // If a and b are both zeros, they are equal. | ||
| 119 | if ((aAbs | bAbs) == 0) return .Equal; | ||
| 120 | |||
| 121 | // If at least one of a and b is positive, we get the same result comparing | ||
| 122 | // a and b as signed integers as we would with a floating-point compare. | ||
| 123 | if ((aInt & bInt) >= 0) { | ||
| 124 | if (aInt < bInt) { | ||
| 125 | return .Less; | ||
| 126 | } else if (aInt == bInt) { | ||
| 127 | return .Equal; | ||
| 128 | } else return .Greater; | ||
| 129 | } else { | ||
| 130 | // Otherwise, both are negative, so we need to flip the sense of the | ||
| 131 | // comparison to get the correct result. (This assumes a twos- or ones- | ||
| 132 | // complement integer representation; if integers are represented in a | ||
| 133 | // sign-magnitude representation, then this flip is incorrect). | ||
| 134 | if (aInt > bInt) { | ||
| 135 | return .Less; | ||
| 136 | } else if (aInt == bInt) { | ||
| 137 | return .Equal; | ||
| 138 | } else return .Greater; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { | ||
| 143 | @setRuntimeSafety(builtin.is_test); | ||
| 144 | |||
| 145 | const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | ||
| 146 | |||
| 147 | const significandBits = std.math.floatMantissaBits(T); | ||
| 148 | const exponentBits = std.math.floatExponentBits(T); | ||
| 149 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | ||
| 150 | const absMask = signBit - 1; | ||
| 151 | const infRep = @bitCast(rep_t, std.math.inf(T)); | ||
| 152 | |||
| 153 | const aAbs: rep_t = @bitCast(rep_t, a) & absMask; | ||
| 154 | const bAbs: rep_t = @bitCast(rep_t, b) & absMask; | ||
| 155 | |||
| 156 | return @boolToInt(aAbs > infRep or bAbs > infRep); | ||
| 157 | } | ||
| 158 | |||
| 159 | // Comparison between f32 | ||
| 160 | |||
| 161 | pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 162 | @setRuntimeSafety(builtin.is_test); | ||
| 163 | const float = cmp(f32, LE, a, b); | ||
| 164 | return @bitCast(i32, float); | ||
| 165 | } | ||
| 166 | |||
| 167 | pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 168 | @setRuntimeSafety(builtin.is_test); | ||
| 169 | const float = cmp(f32, GE, a, b); | ||
| 170 | return @bitCast(i32, float); | ||
| 171 | } | ||
| 172 | |||
| 173 | pub fn __cmpsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 174 | return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); | ||
| 175 | } | ||
| 176 | |||
| 177 | pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 178 | return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); | ||
| 179 | } | ||
| 180 | |||
| 181 | pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 182 | return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); | ||
| 183 | } | ||
| 184 | |||
| 185 | pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 186 | return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); | ||
| 187 | } | ||
| 188 | |||
| 189 | pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 190 | return @call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }); | ||
| 191 | } | ||
| 192 | |||
| 193 | // Comparison between f64 | ||
| 194 | |||
| 195 | pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 196 | @setRuntimeSafety(builtin.is_test); | ||
| 197 | const float = cmp(f64, LE, a, b); | ||
| 198 | return @bitCast(i32, float); | ||
| 199 | } | ||
| 200 | |||
| 201 | pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 202 | @setRuntimeSafety(builtin.is_test); | ||
| 203 | const float = cmp(f64, GE, a, b); | ||
| 204 | return @bitCast(i32, float); | ||
| 205 | } | ||
| 206 | |||
| 207 | pub fn __cmpdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 208 | return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); | ||
| 209 | } | ||
| 210 | |||
| 211 | pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 212 | return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); | ||
| 213 | } | ||
| 214 | |||
| 215 | pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 216 | return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); | ||
| 217 | } | ||
| 218 | |||
| 219 | pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 220 | return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); | ||
| 221 | } | ||
| 222 | |||
| 223 | pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 224 | return @call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }); | ||
| 225 | } | ||
| 226 | |||
| 227 | // Comparison between f80 | ||
| 228 | |||
| 229 | pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { | ||
| 230 | const a_rep = std.math.break_f80(a); | ||
| 231 | const b_rep = std.math.break_f80(b); | ||
| 232 | const sig_bits = std.math.floatMantissaBits(f80); | ||
| 233 | const int_bit = 0x8000000000000000; | ||
| 234 | const sign_bit = 0x8000; | ||
| 235 | const special_exp = 0x7FFF; | ||
| 236 | |||
| 237 | // If either a or b is NaN, they are unordered. | ||
| 238 | if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or | ||
| 239 | (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) | ||
| 240 | return RT.Unordered; | ||
| 241 | |||
| 242 | // If a and b are both zeros, they are equal. | ||
| 243 | if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) | ||
| 244 | return .Equal; | ||
| 245 | |||
| 246 | if (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(a_rep.fraction == b_rep.fraction) != 0) { | ||
| 247 | return .Equal; | ||
| 248 | } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { | ||
| 249 | // signs are different | ||
| 250 | if (@bitCast(i16, a_rep.exp) < @bitCast(i16, b_rep.exp)) { | ||
| 251 | return .Less; | ||
| 252 | } else { | ||
| 253 | return .Greater; | ||
| 254 | } | ||
| 255 | } else { | ||
| 256 | const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); | ||
| 257 | const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); | ||
| 258 | if (a_fraction < b_fraction) { | ||
| 259 | return .Less; | ||
| 260 | } else { | ||
| 261 | return .Greater; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | pub fn __lexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 267 | @setRuntimeSafety(builtin.is_test); | ||
| 268 | const float = cmp_f80(LE, a, b); | ||
| 269 | return @bitCast(i32, float); | ||
| 270 | } | ||
| 271 | |||
| 272 | pub fn __gexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 273 | @setRuntimeSafety(builtin.is_test); | ||
| 274 | const float = cmp_f80(GE, a, b); | ||
| 275 | return @bitCast(i32, float); | ||
| 276 | } | ||
| 277 | |||
| 278 | pub fn __eqxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 279 | return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); | ||
| 280 | } | ||
| 281 | |||
| 282 | pub fn __ltxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 283 | return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); | ||
| 284 | } | ||
| 285 | |||
| 286 | pub fn __nexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 287 | return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); | ||
| 288 | } | ||
| 289 | |||
| 290 | pub fn __gtxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 291 | return @call(.{ .modifier = .always_inline }, __gexf2, .{ a, b }); | ||
| 292 | } | ||
| 293 | |||
| 294 | // Comparison between f128 | ||
| 295 | |||
| 296 | pub fn __letf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 297 | @setRuntimeSafety(builtin.is_test); | ||
| 298 | const float = cmp(f128, LE, a, b); | ||
| 299 | return @bitCast(i32, float); | ||
| 300 | } | ||
| 301 | |||
| 302 | pub fn __getf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 303 | @setRuntimeSafety(builtin.is_test); | ||
| 304 | const float = cmp(f128, GE, a, b); | ||
| 305 | return @bitCast(i32, float); | ||
| 306 | } | ||
| 307 | |||
| 308 | pub fn __cmptf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 309 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 310 | } | ||
| 311 | |||
| 312 | pub fn __eqtf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 313 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 314 | } | ||
| 315 | |||
| 316 | pub fn __lttf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 317 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 318 | } | ||
| 319 | |||
| 320 | pub fn __netf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 321 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 322 | } | ||
| 323 | |||
| 324 | pub fn __gttf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 325 | return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); | ||
| 326 | } | ||
| 327 | |||
| 328 | pub fn __eqkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 329 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 330 | } | ||
| 331 | |||
| 332 | pub fn __nekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 333 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 334 | } | ||
| 335 | |||
| 336 | pub fn __gekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 337 | return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); | ||
| 338 | } | ||
| 339 | |||
| 340 | pub fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 341 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 342 | } | ||
| 343 | |||
| 344 | pub fn __lekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 345 | return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); | ||
| 346 | } | ||
| 347 | |||
| 348 | pub fn __gtkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 349 | return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); | ||
| 350 | } | ||
| 351 | |||
| 352 | // Unordered comparison between f32/f64/f128 | ||
| 353 | |||
| 354 | pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 355 | @setRuntimeSafety(builtin.is_test); | ||
| 356 | return unordcmp(f32, a, b); | ||
| 357 | } | ||
| 358 | |||
| 359 | pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 360 | @setRuntimeSafety(builtin.is_test); | ||
| 361 | return unordcmp(f64, a, b); | ||
| 362 | } | ||
| 363 | |||
| 364 | pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 365 | @setRuntimeSafety(builtin.is_test); | ||
| 366 | return unordcmp(f128, a, b); | ||
| 367 | } | ||
| 368 | |||
| 369 | pub fn __unordkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 370 | return @call(.{ .modifier = .always_inline }, __unordtf2, .{ a, b }); | ||
| 371 | } | ||
| 372 | |||
| 373 | // ARM EABI intrinsics | ||
| 374 | |||
| 375 | pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 376 | @setRuntimeSafety(false); | ||
| 377 | return @boolToInt(@call(.{ .modifier = .always_inline }, __eqsf2, .{ a, b }) == 0); | ||
| 378 | } | ||
| 379 | |||
| 380 | pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 381 | @setRuntimeSafety(false); | ||
| 382 | return @boolToInt(@call(.{ .modifier = .always_inline }, __ltsf2, .{ a, b }) < 0); | ||
| 383 | } | ||
| 384 | |||
| 385 | pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 386 | @setRuntimeSafety(false); | ||
| 387 | return @boolToInt(@call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }) <= 0); | ||
| 388 | } | ||
| 389 | |||
| 390 | pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 391 | @setRuntimeSafety(false); | ||
| 392 | return @boolToInt(@call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }) >= 0); | ||
| 393 | } | ||
| 394 | |||
| 395 | pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 396 | @setRuntimeSafety(false); | ||
| 397 | return @boolToInt(@call(.{ .modifier = .always_inline }, __gtsf2, .{ a, b }) > 0); | ||
| 398 | } | ||
| 399 | |||
| 400 | pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 401 | @setRuntimeSafety(false); | ||
| 402 | return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b }); | ||
| 403 | } | ||
| 404 | |||
| 405 | pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 406 | @setRuntimeSafety(false); | ||
| 407 | return @boolToInt(@call(.{ .modifier = .always_inline }, __eqdf2, .{ a, b }) == 0); | ||
| 408 | } | ||
| 409 | |||
| 410 | pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 411 | @setRuntimeSafety(false); | ||
| 412 | return @boolToInt(@call(.{ .modifier = .always_inline }, __ltdf2, .{ a, b }) < 0); | ||
| 413 | } | ||
| 414 | |||
| 415 | pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 416 | @setRuntimeSafety(false); | ||
| 417 | return @boolToInt(@call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }) <= 0); | ||
| 418 | } | ||
| 419 | |||
| 420 | pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 421 | @setRuntimeSafety(false); | ||
| 422 | return @boolToInt(@call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }) >= 0); | ||
| 423 | } | ||
| 424 | |||
| 425 | pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 426 | @setRuntimeSafety(false); | ||
| 427 | return @boolToInt(@call(.{ .modifier = .always_inline }, __gtdf2, .{ a, b }) > 0); | ||
| 428 | } | ||
| 429 | |||
| 430 | pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 431 | @setRuntimeSafety(false); | ||
| 432 | return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b }); | ||
| 433 | } | ||
| 434 | |||
| 435 | test "comparesf2" { | ||
| 436 | _ = @import("comparesf2_test.zig"); | ||
| 437 | } | ||
| 438 | test "comparedf2" { | ||
| 439 | _ = @import("comparedf2_test.zig"); | ||
| 440 | } | ||
lib/compiler_rt/comparef.zig created+118| ... | @@ -0,0 +1,118 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub const LE = enum(i32) { | ||
| 4 | Less = -1, | ||
| 5 | Equal = 0, | ||
| 6 | Greater = 1, | ||
| 7 | |||
| 8 | const Unordered: LE = .Greater; | ||
| 9 | }; | ||
| 10 | |||
| 11 | pub const GE = enum(i32) { | ||
| 12 | Less = -1, | ||
| 13 | Equal = 0, | ||
| 14 | Greater = 1, | ||
| 15 | |||
| 16 | const Unordered: GE = .Less; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { | ||
| 20 | const bits = @typeInfo(T).Float.bits; | ||
| 21 | const srep_t = std.meta.Int(.signed, bits); | ||
| 22 | const rep_t = std.meta.Int(.unsigned, bits); | ||
| 23 | |||
| 24 | const significandBits = std.math.floatMantissaBits(T); | ||
| 25 | const exponentBits = std.math.floatExponentBits(T); | ||
| 26 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | ||
| 27 | const absMask = signBit - 1; | ||
| 28 | const infT = comptime std.math.inf(T); | ||
| 29 | const infRep = @bitCast(rep_t, infT); | ||
| 30 | |||
| 31 | const aInt = @bitCast(srep_t, a); | ||
| 32 | const bInt = @bitCast(srep_t, b); | ||
| 33 | const aAbs = @bitCast(rep_t, aInt) & absMask; | ||
| 34 | const bAbs = @bitCast(rep_t, bInt) & absMask; | ||
| 35 | |||
| 36 | // If either a or b is NaN, they are unordered. | ||
| 37 | if (aAbs > infRep or bAbs > infRep) return RT.Unordered; | ||
| 38 | |||
| 39 | // If a and b are both zeros, they are equal. | ||
| 40 | if ((aAbs | bAbs) == 0) return .Equal; | ||
| 41 | |||
| 42 | // If at least one of a and b is positive, we get the same result comparing | ||
| 43 | // a and b as signed integers as we would with a floating-point compare. | ||
| 44 | if ((aInt & bInt) >= 0) { | ||
| 45 | if (aInt < bInt) { | ||
| 46 | return .Less; | ||
| 47 | } else if (aInt == bInt) { | ||
| 48 | return .Equal; | ||
| 49 | } else return .Greater; | ||
| 50 | } else { | ||
| 51 | // Otherwise, both are negative, so we need to flip the sense of the | ||
| 52 | // comparison to get the correct result. (This assumes a twos- or ones- | ||
| 53 | // complement integer representation; if integers are represented in a | ||
| 54 | // sign-magnitude representation, then this flip is incorrect). | ||
| 55 | if (aInt > bInt) { | ||
| 56 | return .Less; | ||
| 57 | } else if (aInt == bInt) { | ||
| 58 | return .Equal; | ||
| 59 | } else return .Greater; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { | ||
| 64 | const a_rep = std.math.break_f80(a); | ||
| 65 | const b_rep = std.math.break_f80(b); | ||
| 66 | const sig_bits = std.math.floatMantissaBits(f80); | ||
| 67 | const int_bit = 0x8000000000000000; | ||
| 68 | const sign_bit = 0x8000; | ||
| 69 | const special_exp = 0x7FFF; | ||
| 70 | |||
| 71 | // If either a or b is NaN, they are unordered. | ||
| 72 | if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or | ||
| 73 | (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) | ||
| 74 | return RT.Unordered; | ||
| 75 | |||
| 76 | // If a and b are both zeros, they are equal. | ||
| 77 | if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) | ||
| 78 | return .Equal; | ||
| 79 | |||
| 80 | if (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(a_rep.fraction == b_rep.fraction) != 0) { | ||
| 81 | return .Equal; | ||
| 82 | } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { | ||
| 83 | // signs are different | ||
| 84 | if (@bitCast(i16, a_rep.exp) < @bitCast(i16, b_rep.exp)) { | ||
| 85 | return .Less; | ||
| 86 | } else { | ||
| 87 | return .Greater; | ||
| 88 | } | ||
| 89 | } else { | ||
| 90 | const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); | ||
| 91 | const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); | ||
| 92 | if (a_fraction < b_fraction) { | ||
| 93 | return .Less; | ||
| 94 | } else { | ||
| 95 | return .Greater; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { | ||
| 101 | const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | ||
| 102 | |||
| 103 | const significandBits = std.math.floatMantissaBits(T); | ||
| 104 | const exponentBits = std.math.floatExponentBits(T); | ||
| 105 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | ||
| 106 | const absMask = signBit - 1; | ||
| 107 | const infRep = @bitCast(rep_t, std.math.inf(T)); | ||
| 108 | |||
| 109 | const aAbs: rep_t = @bitCast(rep_t, a) & absMask; | ||
| 110 | const bAbs: rep_t = @bitCast(rep_t, b) & absMask; | ||
| 111 | |||
| 112 | return @boolToInt(aAbs > infRep or bAbs > infRep); | ||
| 113 | } | ||
| 114 | |||
| 115 | test { | ||
| 116 | _ = @import("comparesf2_test.zig"); | ||
| 117 | _ = @import("comparedf2_test.zig"); | ||
| 118 | } | ||
lib/compiler_rt/extendXfYf2.zig deleted-148| ... | @@ -1,148 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const is_test = builtin.is_test; | ||
| 4 | const arch = builtin.cpu.arch; | ||
| 5 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 6 | pub const panic = @import("common.zig").panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage }); | ||
| 10 | @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = linkage }); | ||
| 11 | @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = linkage }); | ||
| 12 | @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage }); | ||
| 13 | @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage }); | ||
| 14 | |||
| 15 | if (!is_test) { | ||
| 16 | @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = linkage }); | ||
| 17 | |||
| 18 | if (arch.isARM() or arch.isThumb()) { | ||
| 19 | @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage }); | ||
| 20 | @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = linkage }); | ||
| 21 | } | ||
| 22 | |||
| 23 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 24 | @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = linkage }); | ||
| 25 | @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = linkage }); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | pub fn __extendsfdf2(a: f32) callconv(.C) f64 { | ||
| 31 | return extendXfYf2(f64, f32, @bitCast(u32, a)); | ||
| 32 | } | ||
| 33 | |||
| 34 | pub fn __extenddftf2(a: f64) callconv(.C) f128 { | ||
| 35 | return extendXfYf2(f128, f64, @bitCast(u64, a)); | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn __extenddfkf2(a: f64) callconv(.C) f128 { | ||
| 39 | return @call(.{ .modifier = .always_inline }, __extenddftf2, .{a}); | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn __extendsftf2(a: f32) callconv(.C) f128 { | ||
| 43 | return extendXfYf2(f128, f32, @bitCast(u32, a)); | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn __extendsfkf2(a: f32) callconv(.C) f128 { | ||
| 47 | return @call(.{ .modifier = .always_inline }, __extendsftf2, .{a}); | ||
| 48 | } | ||
| 49 | |||
| 50 | // AArch64 is the only ABI (at the moment) to support f16 arguments without the | ||
| 51 | // need for extending them to wider fp types. | ||
| 52 | pub const F16T = if (arch.isAARCH64()) f16 else u16; | ||
| 53 | |||
| 54 | pub fn __extendhfsf2(a: F16T) callconv(.C) f32 { | ||
| 55 | return extendXfYf2(f32, f16, @bitCast(u16, a)); | ||
| 56 | } | ||
| 57 | |||
| 58 | pub fn __gnu_h2f_ieee(a: F16T) callconv(.C) f32 { | ||
| 59 | return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{a}); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn __extendhftf2(a: F16T) callconv(.C) f128 { | ||
| 63 | return extendXfYf2(f128, f16, @bitCast(u16, a)); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 { | ||
| 67 | @setRuntimeSafety(false); | ||
| 68 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg }); | ||
| 69 | } | ||
| 70 | |||
| 71 | pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 { | ||
| 72 | @setRuntimeSafety(false); | ||
| 73 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) }); | ||
| 74 | } | ||
| 75 | |||
| 76 | inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t { | ||
| 77 | @setRuntimeSafety(builtin.is_test); | ||
| 78 | |||
| 79 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 80 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 81 | const srcSigBits = std.math.floatMantissaBits(src_t); | ||
| 82 | const dstSigBits = std.math.floatMantissaBits(dst_t); | ||
| 83 | const DstShift = std.math.Log2Int(dst_rep_t); | ||
| 84 | |||
| 85 | // Various constants whose values follow from the type parameters. | ||
| 86 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 87 | const srcBits = @bitSizeOf(src_t); | ||
| 88 | const srcExpBits = srcBits - srcSigBits - 1; | ||
| 89 | const srcInfExp = (1 << srcExpBits) - 1; | ||
| 90 | const srcExpBias = srcInfExp >> 1; | ||
| 91 | |||
| 92 | const srcMinNormal = 1 << srcSigBits; | ||
| 93 | const srcInfinity = srcInfExp << srcSigBits; | ||
| 94 | const srcSignMask = 1 << (srcSigBits + srcExpBits); | ||
| 95 | const srcAbsMask = srcSignMask - 1; | ||
| 96 | const srcQNaN = 1 << (srcSigBits - 1); | ||
| 97 | const srcNaNCode = srcQNaN - 1; | ||
| 98 | |||
| 99 | const dstBits = @bitSizeOf(dst_t); | ||
| 100 | const dstExpBits = dstBits - dstSigBits - 1; | ||
| 101 | const dstInfExp = (1 << dstExpBits) - 1; | ||
| 102 | const dstExpBias = dstInfExp >> 1; | ||
| 103 | |||
| 104 | const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; | ||
| 105 | |||
| 106 | // Break a into a sign and representation of the absolute value | ||
| 107 | const aRep: src_rep_t = @bitCast(src_rep_t, a); | ||
| 108 | const aAbs: src_rep_t = aRep & srcAbsMask; | ||
| 109 | const sign: src_rep_t = aRep & srcSignMask; | ||
| 110 | var absResult: dst_rep_t = undefined; | ||
| 111 | |||
| 112 | if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { | ||
| 113 | // a is a normal number. | ||
| 114 | // Extend to the destination type by shifting the significand and | ||
| 115 | // exponent into the proper position and rebiasing the exponent. | ||
| 116 | absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); | ||
| 117 | absResult += (dstExpBias - srcExpBias) << dstSigBits; | ||
| 118 | } else if (aAbs >= srcInfinity) { | ||
| 119 | // a is NaN or infinity. | ||
| 120 | // Conjure the result by beginning with infinity, then setting the qNaN | ||
| 121 | // bit (if needed) and right-aligning the rest of the trailing NaN | ||
| 122 | // payload field. | ||
| 123 | absResult = dstInfExp << dstSigBits; | ||
| 124 | absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); | ||
| 125 | absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); | ||
| 126 | } else if (aAbs != 0) { | ||
| 127 | // a is denormal. | ||
| 128 | // renormalize the significand and clear the leading bit, then insert | ||
| 129 | // the correct adjusted exponent in the destination type. | ||
| 130 | const scale: u32 = @clz(src_rep_t, aAbs) - | ||
| 131 | @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); | ||
| 132 | absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); | ||
| 133 | absResult ^= dstMinNormal; | ||
| 134 | const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; | ||
| 135 | absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; | ||
| 136 | } else { | ||
| 137 | // a is zero. | ||
| 138 | absResult = 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | // Apply the signbit to (dst_t)abs(a). | ||
| 142 | const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); | ||
| 143 | return @bitCast(dst_t, result); | ||
| 144 | } | ||
| 145 | |||
| 146 | test { | ||
| 147 | _ = @import("extendXfYf2_test.zig"); | ||
| 148 | } | ||
lib/compiler_rt/extend_f80.zig deleted-140| ... | @@ -1,140 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const is_test = builtin.is_test; | ||
| 4 | const arch = builtin.cpu.arch; | ||
| 5 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 6 | pub const panic = @import("common.zig").panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = linkage }); | ||
| 10 | @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = linkage }); | ||
| 11 | @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = linkage }); | ||
| 12 | @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = linkage }); | ||
| 13 | } | ||
| 14 | |||
| 15 | // AArch64 is the only ABI (at the moment) to support f16 arguments without the | ||
| 16 | // need for extending them to wider fp types. | ||
| 17 | const F16T = if (arch.isAARCH64()) f16 else u16; | ||
| 18 | |||
| 19 | fn __extendhfxf2(a: F16T) callconv(.C) f80 { | ||
| 20 | return extendF80(f16, @bitCast(u16, a)); | ||
| 21 | } | ||
| 22 | |||
| 23 | fn __extendsfxf2(a: f32) callconv(.C) f80 { | ||
| 24 | return extendF80(f32, @bitCast(u32, a)); | ||
| 25 | } | ||
| 26 | |||
| 27 | fn __extenddfxf2(a: f64) callconv(.C) f80 { | ||
| 28 | return extendF80(f64, @bitCast(u64, a)); | ||
| 29 | } | ||
| 30 | |||
| 31 | inline fn extendF80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { | ||
| 32 | @setRuntimeSafety(builtin.is_test); | ||
| 33 | |||
| 34 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 35 | const src_sig_bits = std.math.floatMantissaBits(src_t); | ||
| 36 | const dst_int_bit = 0x8000000000000000; | ||
| 37 | const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 38 | |||
| 39 | const dst_exp_bias = 16383; | ||
| 40 | |||
| 41 | const src_bits = @bitSizeOf(src_t); | ||
| 42 | const src_exp_bits = src_bits - src_sig_bits - 1; | ||
| 43 | const src_inf_exp = (1 << src_exp_bits) - 1; | ||
| 44 | const src_exp_bias = src_inf_exp >> 1; | ||
| 45 | |||
| 46 | const src_min_normal = 1 << src_sig_bits; | ||
| 47 | const src_inf = src_inf_exp << src_sig_bits; | ||
| 48 | const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); | ||
| 49 | const src_abs_mask = src_sign_mask - 1; | ||
| 50 | const src_qnan = 1 << (src_sig_bits - 1); | ||
| 51 | const src_nan_code = src_qnan - 1; | ||
| 52 | |||
| 53 | var dst: std.math.F80 = undefined; | ||
| 54 | |||
| 55 | // Break a into a sign and representation of the absolute value | ||
| 56 | const a_abs = a & src_abs_mask; | ||
| 57 | const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; | ||
| 58 | |||
| 59 | if (a_abs -% src_min_normal < src_inf - src_min_normal) { | ||
| 60 | // a is a normal number. | ||
| 61 | // Extend to the destination type by shifting the significand and | ||
| 62 | // exponent into the proper position and rebiasing the exponent. | ||
| 63 | dst.exp = @intCast(u16, a_abs >> src_sig_bits); | ||
| 64 | dst.exp += dst_exp_bias - src_exp_bias; | ||
| 65 | dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); | ||
| 66 | dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers | ||
| 67 | } else if (a_abs >= src_inf) { | ||
| 68 | // a is NaN or infinity. | ||
| 69 | // Conjure the result by beginning with infinity, then setting the qNaN | ||
| 70 | // bit (if needed) and right-aligning the rest of the trailing NaN | ||
| 71 | // payload field. | ||
| 72 | dst.exp = 0x7fff; | ||
| 73 | dst.fraction = dst_int_bit; | ||
| 74 | dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); | ||
| 75 | dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); | ||
| 76 | } else if (a_abs != 0) { | ||
| 77 | // a is denormal. | ||
| 78 | // renormalize the significand and clear the leading bit, then insert | ||
| 79 | // the correct adjusted exponent in the destination type. | ||
| 80 | const scale: u16 = @clz(src_rep_t, a_abs) - | ||
| 81 | @clz(src_rep_t, @as(src_rep_t, src_min_normal)); | ||
| 82 | |||
| 83 | dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); | ||
| 84 | dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers | ||
| 85 | dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); | ||
| 86 | dst.exp ^= 1; | ||
| 87 | dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; | ||
| 88 | } else { | ||
| 89 | // a is zero. | ||
| 90 | dst.exp = 0; | ||
| 91 | dst.fraction = 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | dst.exp |= sign; | ||
| 95 | return std.math.make_f80(dst); | ||
| 96 | } | ||
| 97 | |||
| 98 | fn __extendxftf2(a: f80) callconv(.C) f128 { | ||
| 99 | @setRuntimeSafety(builtin.is_test); | ||
| 100 | |||
| 101 | const src_int_bit: u64 = 0x8000000000000000; | ||
| 102 | const src_sig_mask = ~src_int_bit; | ||
| 103 | const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 104 | const dst_sig_bits = std.math.floatMantissaBits(f128); | ||
| 105 | |||
| 106 | const dst_bits = @bitSizeOf(f128); | ||
| 107 | |||
| 108 | const dst_min_normal = @as(u128, 1) << dst_sig_bits; | ||
| 109 | |||
| 110 | // Break a into a sign and representation of the absolute value | ||
| 111 | var a_rep = std.math.break_f80(a); | ||
| 112 | const sign = a_rep.exp & 0x8000; | ||
| 113 | a_rep.exp &= 0x7FFF; | ||
| 114 | var abs_result: u128 = undefined; | ||
| 115 | |||
| 116 | if (a_rep.exp == 0 and a_rep.fraction == 0) { | ||
| 117 | // zero | ||
| 118 | abs_result = 0; | ||
| 119 | } else if (a_rep.exp == 0x7FFF) { | ||
| 120 | // a is nan or infinite | ||
| 121 | abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); | ||
| 122 | abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; | ||
| 123 | } else if (a_rep.fraction & src_int_bit != 0) { | ||
| 124 | // a is a normal value | ||
| 125 | abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); | ||
| 126 | abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; | ||
| 127 | } else { | ||
| 128 | // a is denormal | ||
| 129 | // renormalize the significand and clear the leading bit and integer part, | ||
| 130 | // then insert the correct adjusted exponent in the destination type. | ||
| 131 | const scale: u32 = @clz(u64, a_rep.fraction); | ||
| 132 | abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); | ||
| 133 | abs_result ^= dst_min_normal; | ||
| 134 | abs_result |= @as(u128, scale + 1) << dst_sig_bits; | ||
| 135 | } | ||
| 136 | |||
| 137 | // Apply the signbit to (dst_t)abs(a). | ||
| 138 | const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); | ||
| 139 | return @bitCast(f128, result); | ||
| 140 | } | ||
lib/compiler_rt/extenddftf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __extenddftf2(a: f64) callconv(.C) f128 { | ||
| 15 | return extendf(f128, f64, @bitCast(u64, a)); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __extenddfkf2(a: f64) callconv(.C) f128 { | ||
| 19 | return extendf(f128, f64, @bitCast(u64, a)); | ||
| 20 | } | ||
lib/compiler_rt/extenddfxf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extend_f80 = @import("./extendf.zig").extend_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __extenddfxf2(a: f64) callconv(.C) f80 { | ||
| 11 | return extend_f80(f64, @bitCast(u64, a)); | ||
| 12 | } | ||
lib/compiler_rt/extendf.zig created+142| ... | @@ -0,0 +1,142 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub inline fn extendf( | ||
| 4 | comptime dst_t: type, | ||
| 5 | comptime src_t: type, | ||
| 6 | a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits), | ||
| 7 | ) dst_t { | ||
| 8 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 9 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 10 | const srcSigBits = std.math.floatMantissaBits(src_t); | ||
| 11 | const dstSigBits = std.math.floatMantissaBits(dst_t); | ||
| 12 | const DstShift = std.math.Log2Int(dst_rep_t); | ||
| 13 | |||
| 14 | // Various constants whose values follow from the type parameters. | ||
| 15 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 16 | const srcBits = @bitSizeOf(src_t); | ||
| 17 | const srcExpBits = srcBits - srcSigBits - 1; | ||
| 18 | const srcInfExp = (1 << srcExpBits) - 1; | ||
| 19 | const srcExpBias = srcInfExp >> 1; | ||
| 20 | |||
| 21 | const srcMinNormal = 1 << srcSigBits; | ||
| 22 | const srcInfinity = srcInfExp << srcSigBits; | ||
| 23 | const srcSignMask = 1 << (srcSigBits + srcExpBits); | ||
| 24 | const srcAbsMask = srcSignMask - 1; | ||
| 25 | const srcQNaN = 1 << (srcSigBits - 1); | ||
| 26 | const srcNaNCode = srcQNaN - 1; | ||
| 27 | |||
| 28 | const dstBits = @bitSizeOf(dst_t); | ||
| 29 | const dstExpBits = dstBits - dstSigBits - 1; | ||
| 30 | const dstInfExp = (1 << dstExpBits) - 1; | ||
| 31 | const dstExpBias = dstInfExp >> 1; | ||
| 32 | |||
| 33 | const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; | ||
| 34 | |||
| 35 | // Break a into a sign and representation of the absolute value | ||
| 36 | const aRep: src_rep_t = @bitCast(src_rep_t, a); | ||
| 37 | const aAbs: src_rep_t = aRep & srcAbsMask; | ||
| 38 | const sign: src_rep_t = aRep & srcSignMask; | ||
| 39 | var absResult: dst_rep_t = undefined; | ||
| 40 | |||
| 41 | if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { | ||
| 42 | // a is a normal number. | ||
| 43 | // Extend to the destination type by shifting the significand and | ||
| 44 | // exponent into the proper position and rebiasing the exponent. | ||
| 45 | absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); | ||
| 46 | absResult += (dstExpBias - srcExpBias) << dstSigBits; | ||
| 47 | } else if (aAbs >= srcInfinity) { | ||
| 48 | // a is NaN or infinity. | ||
| 49 | // Conjure the result by beginning with infinity, then setting the qNaN | ||
| 50 | // bit (if needed) and right-aligning the rest of the trailing NaN | ||
| 51 | // payload field. | ||
| 52 | absResult = dstInfExp << dstSigBits; | ||
| 53 | absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); | ||
| 54 | absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); | ||
| 55 | } else if (aAbs != 0) { | ||
| 56 | // a is denormal. | ||
| 57 | // renormalize the significand and clear the leading bit, then insert | ||
| 58 | // the correct adjusted exponent in the destination type. | ||
| 59 | const scale: u32 = @clz(src_rep_t, aAbs) - | ||
| 60 | @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); | ||
| 61 | absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); | ||
| 62 | absResult ^= dstMinNormal; | ||
| 63 | const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; | ||
| 64 | absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; | ||
| 65 | } else { | ||
| 66 | // a is zero. | ||
| 67 | absResult = 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | // Apply the signbit to (dst_t)abs(a). | ||
| 71 | const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); | ||
| 72 | return @bitCast(dst_t, result); | ||
| 73 | } | ||
| 74 | |||
| 75 | pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { | ||
| 76 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 77 | const src_sig_bits = std.math.floatMantissaBits(src_t); | ||
| 78 | const dst_int_bit = 0x8000000000000000; | ||
| 79 | const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 80 | |||
| 81 | const dst_exp_bias = 16383; | ||
| 82 | |||
| 83 | const src_bits = @bitSizeOf(src_t); | ||
| 84 | const src_exp_bits = src_bits - src_sig_bits - 1; | ||
| 85 | const src_inf_exp = (1 << src_exp_bits) - 1; | ||
| 86 | const src_exp_bias = src_inf_exp >> 1; | ||
| 87 | |||
| 88 | const src_min_normal = 1 << src_sig_bits; | ||
| 89 | const src_inf = src_inf_exp << src_sig_bits; | ||
| 90 | const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); | ||
| 91 | const src_abs_mask = src_sign_mask - 1; | ||
| 92 | const src_qnan = 1 << (src_sig_bits - 1); | ||
| 93 | const src_nan_code = src_qnan - 1; | ||
| 94 | |||
| 95 | var dst: std.math.F80 = undefined; | ||
| 96 | |||
| 97 | // Break a into a sign and representation of the absolute value | ||
| 98 | const a_abs = a & src_abs_mask; | ||
| 99 | const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; | ||
| 100 | |||
| 101 | if (a_abs -% src_min_normal < src_inf - src_min_normal) { | ||
| 102 | // a is a normal number. | ||
| 103 | // Extend to the destination type by shifting the significand and | ||
| 104 | // exponent into the proper position and rebiasing the exponent. | ||
| 105 | dst.exp = @intCast(u16, a_abs >> src_sig_bits); | ||
| 106 | dst.exp += dst_exp_bias - src_exp_bias; | ||
| 107 | dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); | ||
| 108 | dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers | ||
| 109 | } else if (a_abs >= src_inf) { | ||
| 110 | // a is NaN or infinity. | ||
| 111 | // Conjure the result by beginning with infinity, then setting the qNaN | ||
| 112 | // bit (if needed) and right-aligning the rest of the trailing NaN | ||
| 113 | // payload field. | ||
| 114 | dst.exp = 0x7fff; | ||
| 115 | dst.fraction = dst_int_bit; | ||
| 116 | dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); | ||
| 117 | dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); | ||
| 118 | } else if (a_abs != 0) { | ||
| 119 | // a is denormal. | ||
| 120 | // renormalize the significand and clear the leading bit, then insert | ||
| 121 | // the correct adjusted exponent in the destination type. | ||
| 122 | const scale: u16 = @clz(src_rep_t, a_abs) - | ||
| 123 | @clz(src_rep_t, @as(src_rep_t, src_min_normal)); | ||
| 124 | |||
| 125 | dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); | ||
| 126 | dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers | ||
| 127 | dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); | ||
| 128 | dst.exp ^= 1; | ||
| 129 | dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; | ||
| 130 | } else { | ||
| 131 | // a is zero. | ||
| 132 | dst.exp = 0; | ||
| 133 | dst.fraction = 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | dst.exp |= sign; | ||
| 137 | return std.math.make_f80(dst); | ||
| 138 | } | ||
| 139 | |||
| 140 | test { | ||
| 141 | _ = @import("extendXfYf2_test.zig"); | ||
| 142 | } | ||
lib/compiler_rt/extendhfsf2.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_gnu_abi) { | ||
| 8 | @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = common.linkage }); | ||
| 9 | } else if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage }); | ||
| 11 | } else { | ||
| 12 | @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage }); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | fn __extendhfsf2(a: common.F16T) callconv(.C) f32 { | ||
| 17 | return extendf(f32, f16, @bitCast(u16, a)); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 { | ||
| 21 | return extendf(f32, f16, @bitCast(u16, a)); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 { | ||
| 25 | return extendf(f32, f16, @bitCast(u16, a)); | ||
| 26 | } | ||
lib/compiler_rt/extendhftf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __extendhftf2(a: common.F16T) callconv(.C) f128 { | ||
| 11 | return extendf(f128, f16, @bitCast(u16, a)); | ||
| 12 | } | ||
lib/compiler_rt/extendhfxf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extend_f80 = @import("./extendf.zig").extend_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __extendhfxf2(a: common.F16T) callconv(.C) f80 { | ||
| 11 | return extend_f80(f16, @bitCast(u16, a)); | ||
| 12 | } | ||
lib/compiler_rt/extendsfdf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __extendsfdf2(a: f32) callconv(.C) f64 { | ||
| 15 | return extendf(f64, f32, @bitCast(u32, a)); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_f2d(a: f32) callconv(.AAPCS) f64 { | ||
| 19 | return extendf(f64, f32, @bitCast(u32, a)); | ||
| 20 | } | ||
lib/compiler_rt/extendsftf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __extendsftf2(a: f32) callconv(.C) f128 { | ||
| 15 | return extendf(f128, f32, @bitCast(u32, a)); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __extendsfkf2(a: f32) callconv(.C) f128 { | ||
| 19 | return extendf(f128, f32, @bitCast(u32, a)); | ||
| 20 | } | ||
lib/compiler_rt/extendsfxf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extend_f80 = @import("./extendf.zig").extend_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __extendsfxf2(a: f32) callconv(.C) f80 { | ||
| 11 | return extend_f80(f32, @bitCast(u32, a)); | ||
| 12 | } | ||
lib/compiler_rt/extendxftf2.zig created+50| ... | @@ -0,0 +1,50 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const common = @import("./common.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __extendxftf2(a: f80) callconv(.C) f128 { | ||
| 11 | const src_int_bit: u64 = 0x8000000000000000; | ||
| 12 | const src_sig_mask = ~src_int_bit; | ||
| 13 | const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 14 | const dst_sig_bits = std.math.floatMantissaBits(f128); | ||
| 15 | |||
| 16 | const dst_bits = @bitSizeOf(f128); | ||
| 17 | |||
| 18 | const dst_min_normal = @as(u128, 1) << dst_sig_bits; | ||
| 19 | |||
| 20 | // Break a into a sign and representation of the absolute value | ||
| 21 | var a_rep = std.math.break_f80(a); | ||
| 22 | const sign = a_rep.exp & 0x8000; | ||
| 23 | a_rep.exp &= 0x7FFF; | ||
| 24 | var abs_result: u128 = undefined; | ||
| 25 | |||
| 26 | if (a_rep.exp == 0 and a_rep.fraction == 0) { | ||
| 27 | // zero | ||
| 28 | abs_result = 0; | ||
| 29 | } else if (a_rep.exp == 0x7FFF) { | ||
| 30 | // a is nan or infinite | ||
| 31 | abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); | ||
| 32 | abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; | ||
| 33 | } else if (a_rep.fraction & src_int_bit != 0) { | ||
| 34 | // a is a normal value | ||
| 35 | abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); | ||
| 36 | abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; | ||
| 37 | } else { | ||
| 38 | // a is denormal | ||
| 39 | // renormalize the significand and clear the leading bit and integer part, | ||
| 40 | // then insert the correct adjusted exponent in the destination type. | ||
| 41 | const scale: u32 = @clz(u64, a_rep.fraction); | ||
| 42 | abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); | ||
| 43 | abs_result ^= dst_min_normal; | ||
| 44 | abs_result |= @as(u128, scale + 1) << dst_sig_bits; | ||
| 45 | } | ||
| 46 | |||
| 47 | // Apply the signbit to (dst_t)abs(a). | ||
| 48 | const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); | ||
| 49 | return @bitCast(f128, result); | ||
| 50 | } | ||
lib/compiler_rt/fixXfYi.zig deleted-312| ... | @@ -1,312 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const math = std.math; | ||
| 4 | const Log2Int = math.Log2Int; | ||
| 5 | const arch = builtin.cpu.arch; | ||
| 6 | const is_test = builtin.is_test; | ||
| 7 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 8 | pub const panic = @import("common.zig").panic; | ||
| 9 | |||
| 10 | comptime { | ||
| 11 | // Float -> Integral Conversion | ||
| 12 | |||
| 13 | // Conversion from f32 | ||
| 14 | @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage }); | ||
| 15 | @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage }); | ||
| 16 | |||
| 17 | @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage }); | ||
| 18 | @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage }); | ||
| 19 | |||
| 20 | @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage }); | ||
| 21 | @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage }); | ||
| 22 | |||
| 23 | // Conversion from f64 | ||
| 24 | @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage }); | ||
| 25 | @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage }); | ||
| 26 | |||
| 27 | @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage }); | ||
| 28 | @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage }); | ||
| 29 | |||
| 30 | @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage }); | ||
| 31 | @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage }); | ||
| 32 | |||
| 33 | // Conversion from f80 | ||
| 34 | @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = linkage }); | ||
| 35 | @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = linkage }); | ||
| 36 | |||
| 37 | @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = linkage }); | ||
| 38 | @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = linkage }); | ||
| 39 | |||
| 40 | @export(__fixxfti, .{ .name = "__fixxfti", .linkage = linkage }); | ||
| 41 | @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = linkage }); | ||
| 42 | |||
| 43 | // Conversion from f128 | ||
| 44 | @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage }); | ||
| 45 | @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage }); | ||
| 46 | |||
| 47 | @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage }); | ||
| 48 | @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage }); | ||
| 49 | |||
| 50 | @export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage }); | ||
| 51 | @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage }); | ||
| 52 | |||
| 53 | if (!is_test) { | ||
| 54 | if (arch.isARM() or arch.isThumb()) { | ||
| 55 | @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage }); | ||
| 56 | @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage }); | ||
| 57 | |||
| 58 | @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage }); | ||
| 59 | @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage }); | ||
| 60 | |||
| 61 | @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage }); | ||
| 62 | |||
| 63 | @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage }); | ||
| 64 | |||
| 65 | @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage }); | ||
| 66 | @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage }); | ||
| 67 | } | ||
| 68 | |||
| 69 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 70 | @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = linkage }); | ||
| 71 | @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = linkage }); | ||
| 72 | @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = linkage }); | ||
| 73 | @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = linkage }); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | pub inline fn fixXfYi(comptime I: type, a: anytype) I { | ||
| 79 | @setRuntimeSafety(is_test); | ||
| 80 | |||
| 81 | const F = @TypeOf(a); | ||
| 82 | const float_bits = @typeInfo(F).Float.bits; | ||
| 83 | const int_bits = @typeInfo(I).Int.bits; | ||
| 84 | const rep_t = std.meta.Int(.unsigned, float_bits); | ||
| 85 | const sig_bits = math.floatMantissaBits(F); | ||
| 86 | const exp_bits = math.floatExponentBits(F); | ||
| 87 | const fractional_bits = math.floatFractionalBits(F); | ||
| 88 | |||
| 89 | const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; | ||
| 90 | const max_exp = (1 << (exp_bits - 1)); | ||
| 91 | const exp_bias = max_exp - 1; | ||
| 92 | const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; | ||
| 93 | |||
| 94 | // Break a into sign, exponent, significand | ||
| 95 | const a_rep: rep_t = @bitCast(rep_t, a); | ||
| 96 | const negative = (a_rep >> (float_bits - 1)) != 0; | ||
| 97 | const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; | ||
| 98 | const significand: rep_t = (a_rep & sig_mask) | implicit_bit; | ||
| 99 | |||
| 100 | // If the exponent is negative, the result rounds to zero. | ||
| 101 | if (exponent < 0) return 0; | ||
| 102 | |||
| 103 | // If the value is too large for the integer type, saturate. | ||
| 104 | switch (@typeInfo(I).Int.signedness) { | ||
| 105 | .unsigned => { | ||
| 106 | if (negative) return 0; | ||
| 107 | if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); | ||
| 108 | }, | ||
| 109 | .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { | ||
| 110 | return if (negative) math.minInt(I) else math.maxInt(I); | ||
| 111 | }, | ||
| 112 | } | ||
| 113 | |||
| 114 | // If 0 <= exponent < sig_bits, right shift to get the result. | ||
| 115 | // Otherwise, shift left. | ||
| 116 | var result: I = undefined; | ||
| 117 | if (exponent < fractional_bits) { | ||
| 118 | result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); | ||
| 119 | } else { | ||
| 120 | result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); | ||
| 121 | } | ||
| 122 | |||
| 123 | if ((@typeInfo(I).Int.signedness == .signed) and negative) | ||
| 124 | return ~result +% 1; | ||
| 125 | return result; | ||
| 126 | } | ||
| 127 | |||
| 128 | // Conversion from f16 | ||
| 129 | |||
| 130 | pub fn __fixhfsi(a: f16) callconv(.C) i32 { | ||
| 131 | return fixXfYi(i32, a); | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn __fixunshfsi(a: f16) callconv(.C) u32 { | ||
| 135 | return fixXfYi(u32, a); | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn __fixhfdi(a: f16) callconv(.C) i64 { | ||
| 139 | return fixXfYi(i64, a); | ||
| 140 | } | ||
| 141 | |||
| 142 | pub fn __fixunshfdi(a: f16) callconv(.C) u64 { | ||
| 143 | return fixXfYi(u64, a); | ||
| 144 | } | ||
| 145 | |||
| 146 | pub fn __fixhfti(a: f16) callconv(.C) i128 { | ||
| 147 | return fixXfYi(i128, a); | ||
| 148 | } | ||
| 149 | |||
| 150 | pub fn __fixunshfti(a: f16) callconv(.C) u128 { | ||
| 151 | return fixXfYi(u128, a); | ||
| 152 | } | ||
| 153 | |||
| 154 | // Conversion from f32 | ||
| 155 | |||
| 156 | pub fn __fixsfsi(a: f32) callconv(.C) i32 { | ||
| 157 | return fixXfYi(i32, a); | ||
| 158 | } | ||
| 159 | |||
| 160 | pub fn __fixunssfsi(a: f32) callconv(.C) u32 { | ||
| 161 | return fixXfYi(u32, a); | ||
| 162 | } | ||
| 163 | |||
| 164 | pub fn __fixsfdi(a: f32) callconv(.C) i64 { | ||
| 165 | return fixXfYi(i64, a); | ||
| 166 | } | ||
| 167 | |||
| 168 | pub fn __fixunssfdi(a: f32) callconv(.C) u64 { | ||
| 169 | return fixXfYi(u64, a); | ||
| 170 | } | ||
| 171 | |||
| 172 | pub fn __fixsfti(a: f32) callconv(.C) i128 { | ||
| 173 | return fixXfYi(i128, a); | ||
| 174 | } | ||
| 175 | |||
| 176 | pub fn __fixunssfti(a: f32) callconv(.C) u128 { | ||
| 177 | return fixXfYi(u128, a); | ||
| 178 | } | ||
| 179 | |||
| 180 | // Conversion from f64 | ||
| 181 | |||
| 182 | pub fn __fixdfsi(a: f64) callconv(.C) i32 { | ||
| 183 | return fixXfYi(i32, a); | ||
| 184 | } | ||
| 185 | |||
| 186 | pub fn __fixunsdfsi(a: f64) callconv(.C) u32 { | ||
| 187 | return fixXfYi(u32, a); | ||
| 188 | } | ||
| 189 | |||
| 190 | pub fn __fixdfdi(a: f64) callconv(.C) i64 { | ||
| 191 | return fixXfYi(i64, a); | ||
| 192 | } | ||
| 193 | |||
| 194 | pub fn __fixunsdfdi(a: f64) callconv(.C) u64 { | ||
| 195 | return fixXfYi(u64, a); | ||
| 196 | } | ||
| 197 | |||
| 198 | pub fn __fixdfti(a: f64) callconv(.C) i128 { | ||
| 199 | return fixXfYi(i128, a); | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn __fixunsdfti(a: f64) callconv(.C) u128 { | ||
| 203 | return fixXfYi(u128, a); | ||
| 204 | } | ||
| 205 | |||
| 206 | // Conversion from f80 | ||
| 207 | |||
| 208 | pub fn __fixxfsi(a: f80) callconv(.C) i32 { | ||
| 209 | return fixXfYi(i32, a); | ||
| 210 | } | ||
| 211 | |||
| 212 | pub fn __fixunsxfsi(a: f80) callconv(.C) u32 { | ||
| 213 | return fixXfYi(u32, a); | ||
| 214 | } | ||
| 215 | |||
| 216 | pub fn __fixxfdi(a: f80) callconv(.C) i64 { | ||
| 217 | return fixXfYi(i64, a); | ||
| 218 | } | ||
| 219 | |||
| 220 | pub fn __fixunsxfdi(a: f80) callconv(.C) u64 { | ||
| 221 | return fixXfYi(u64, a); | ||
| 222 | } | ||
| 223 | |||
| 224 | pub fn __fixxfti(a: f80) callconv(.C) i128 { | ||
| 225 | return fixXfYi(i128, a); | ||
| 226 | } | ||
| 227 | |||
| 228 | pub fn __fixunsxfti(a: f80) callconv(.C) u128 { | ||
| 229 | return fixXfYi(u128, a); | ||
| 230 | } | ||
| 231 | |||
| 232 | // Conversion from f128 | ||
| 233 | |||
| 234 | pub fn __fixtfsi(a: f128) callconv(.C) i32 { | ||
| 235 | return fixXfYi(i32, a); | ||
| 236 | } | ||
| 237 | |||
| 238 | pub fn __fixkfsi(a: f128) callconv(.C) i32 { | ||
| 239 | return __fixtfsi(a); | ||
| 240 | } | ||
| 241 | |||
| 242 | pub fn __fixunstfsi(a: f128) callconv(.C) u32 { | ||
| 243 | return fixXfYi(u32, a); | ||
| 244 | } | ||
| 245 | |||
| 246 | pub fn __fixunskfsi(a: f128) callconv(.C) u32 { | ||
| 247 | return @call(.{ .modifier = .always_inline }, __fixunstfsi, .{a}); | ||
| 248 | } | ||
| 249 | |||
| 250 | pub fn __fixtfdi(a: f128) callconv(.C) i64 { | ||
| 251 | return fixXfYi(i64, a); | ||
| 252 | } | ||
| 253 | |||
| 254 | pub fn __fixkfdi(a: f128) callconv(.C) i64 { | ||
| 255 | return @call(.{ .modifier = .always_inline }, __fixtfdi, .{a}); | ||
| 256 | } | ||
| 257 | |||
| 258 | pub fn __fixunstfdi(a: f128) callconv(.C) u64 { | ||
| 259 | return fixXfYi(u64, a); | ||
| 260 | } | ||
| 261 | |||
| 262 | pub fn __fixunskfdi(a: f128) callconv(.C) u64 { | ||
| 263 | return @call(.{ .modifier = .always_inline }, __fixunstfdi, .{a}); | ||
| 264 | } | ||
| 265 | |||
| 266 | pub fn __fixtfti(a: f128) callconv(.C) i128 { | ||
| 267 | return fixXfYi(i128, a); | ||
| 268 | } | ||
| 269 | |||
| 270 | pub fn __fixunstfti(a: f128) callconv(.C) u128 { | ||
| 271 | return fixXfYi(u128, a); | ||
| 272 | } | ||
| 273 | |||
| 274 | // Conversion from f32 | ||
| 275 | |||
| 276 | pub fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { | ||
| 277 | return fixXfYi(i32, a); | ||
| 278 | } | ||
| 279 | |||
| 280 | pub fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { | ||
| 281 | return fixXfYi(u32, a); | ||
| 282 | } | ||
| 283 | |||
| 284 | pub fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { | ||
| 285 | return fixXfYi(i64, a); | ||
| 286 | } | ||
| 287 | |||
| 288 | pub fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { | ||
| 289 | return fixXfYi(u64, a); | ||
| 290 | } | ||
| 291 | |||
| 292 | // Conversion from f64 | ||
| 293 | |||
| 294 | pub fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { | ||
| 295 | return fixXfYi(i32, a); | ||
| 296 | } | ||
| 297 | |||
| 298 | pub fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { | ||
| 299 | return fixXfYi(u32, a); | ||
| 300 | } | ||
| 301 | |||
| 302 | pub fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { | ||
| 303 | return fixXfYi(i64, a); | ||
| 304 | } | ||
| 305 | |||
| 306 | pub fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { | ||
| 307 | return fixXfYi(u64, a); | ||
| 308 | } | ||
| 309 | |||
| 310 | test { | ||
| 311 | _ = @import("fixXfYi_test.zig"); | ||
| 312 | } | ||
lib/compiler_rt/fixXfYi_test.zig deleted-948| ... | @@ -1,948 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const math = std.math; | ||
| 4 | const fixXfYi = @import("fixXfYi.zig").fixXfYi; | ||
| 5 | |||
| 6 | // Conversion from f32 | ||
| 7 | const __fixsfsi = @import("fixXfYi.zig").__fixsfsi; | ||
| 8 | const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi; | ||
| 9 | const __fixsfdi = @import("fixXfYi.zig").__fixsfdi; | ||
| 10 | const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi; | ||
| 11 | const __fixsfti = @import("fixXfYi.zig").__fixsfti; | ||
| 12 | const __fixunssfti = @import("fixXfYi.zig").__fixunssfti; | ||
| 13 | |||
| 14 | // Conversion from f64 | ||
| 15 | const __fixdfsi = @import("fixXfYi.zig").__fixdfsi; | ||
| 16 | const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi; | ||
| 17 | const __fixdfdi = @import("fixXfYi.zig").__fixdfdi; | ||
| 18 | const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi; | ||
| 19 | const __fixdfti = @import("fixXfYi.zig").__fixdfti; | ||
| 20 | const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti; | ||
| 21 | |||
| 22 | // Conversion from f128 | ||
| 23 | const __fixtfsi = @import("fixXfYi.zig").__fixtfsi; | ||
| 24 | const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi; | ||
| 25 | const __fixtfdi = @import("fixXfYi.zig").__fixtfdi; | ||
| 26 | const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi; | ||
| 27 | const __fixtfti = @import("fixXfYi.zig").__fixtfti; | ||
| 28 | const __fixunstfti = @import("fixXfYi.zig").__fixunstfti; | ||
| 29 | |||
| 30 | fn test__fixsfsi(a: f32, expected: i32) !void { | ||
| 31 | const x = __fixsfsi(a); | ||
| 32 | try testing.expect(x == expected); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn test__fixunssfsi(a: f32, expected: u32) !void { | ||
| 36 | const x = __fixunssfsi(a); | ||
| 37 | try testing.expect(x == expected); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "fixsfsi" { | ||
| 41 | try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); | ||
| 42 | |||
| 43 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 44 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 45 | |||
| 46 | try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 47 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 48 | try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 49 | |||
| 50 | try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 51 | try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 52 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 53 | try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 54 | |||
| 55 | try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 56 | try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 57 | |||
| 58 | try test__fixsfsi(-0x1.000000p+31, -0x80000000); | ||
| 59 | try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); | ||
| 60 | try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 61 | try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 62 | |||
| 63 | try test__fixsfsi(-2.01, -2); | ||
| 64 | try test__fixsfsi(-2.0, -2); | ||
| 65 | try test__fixsfsi(-1.99, -1); | ||
| 66 | try test__fixsfsi(-1.0, -1); | ||
| 67 | try test__fixsfsi(-0.99, 0); | ||
| 68 | try test__fixsfsi(-0.5, 0); | ||
| 69 | try test__fixsfsi(-math.floatMin(f32), 0); | ||
| 70 | try test__fixsfsi(0.0, 0); | ||
| 71 | try test__fixsfsi(math.floatMin(f32), 0); | ||
| 72 | try test__fixsfsi(0.5, 0); | ||
| 73 | try test__fixsfsi(0.99, 0); | ||
| 74 | try test__fixsfsi(1.0, 1); | ||
| 75 | try test__fixsfsi(1.5, 1); | ||
| 76 | try test__fixsfsi(1.99, 1); | ||
| 77 | try test__fixsfsi(2.0, 2); | ||
| 78 | try test__fixsfsi(2.01, 2); | ||
| 79 | |||
| 80 | try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 81 | try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 82 | try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); | ||
| 83 | try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 84 | |||
| 85 | try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 86 | try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 87 | |||
| 88 | try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 89 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 90 | try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 91 | try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 92 | |||
| 93 | try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 94 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 95 | try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 96 | |||
| 97 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 98 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 99 | |||
| 100 | try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); | ||
| 101 | } | ||
| 102 | |||
| 103 | test "fixunssfsi" { | ||
| 104 | try test__fixunssfsi(0.0, 0); | ||
| 105 | |||
| 106 | try test__fixunssfsi(0.5, 0); | ||
| 107 | try test__fixunssfsi(0.99, 0); | ||
| 108 | try test__fixunssfsi(1.0, 1); | ||
| 109 | try test__fixunssfsi(1.5, 1); | ||
| 110 | try test__fixunssfsi(1.99, 1); | ||
| 111 | try test__fixunssfsi(2.0, 2); | ||
| 112 | try test__fixunssfsi(2.01, 2); | ||
| 113 | try test__fixunssfsi(-0.5, 0); | ||
| 114 | try test__fixunssfsi(-0.99, 0); | ||
| 115 | |||
| 116 | try test__fixunssfsi(-1.0, 0); | ||
| 117 | try test__fixunssfsi(-1.5, 0); | ||
| 118 | try test__fixunssfsi(-1.99, 0); | ||
| 119 | try test__fixunssfsi(-2.0, 0); | ||
| 120 | try test__fixunssfsi(-2.01, 0); | ||
| 121 | |||
| 122 | try test__fixunssfsi(0x1.000000p+31, 0x80000000); | ||
| 123 | try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); | ||
| 124 | try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); | ||
| 125 | try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 126 | try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 127 | |||
| 128 | try test__fixunssfsi(-0x1.FFFFFEp+30, 0); | ||
| 129 | try test__fixunssfsi(-0x1.FFFFFCp+30, 0); | ||
| 130 | } | ||
| 131 | |||
| 132 | fn test__fixsfdi(a: f32, expected: i64) !void { | ||
| 133 | const x = __fixsfdi(a); | ||
| 134 | try testing.expect(x == expected); | ||
| 135 | } | ||
| 136 | |||
| 137 | fn test__fixunssfdi(a: f32, expected: u64) !void { | ||
| 138 | const x = __fixunssfdi(a); | ||
| 139 | try testing.expect(x == expected); | ||
| 140 | } | ||
| 141 | |||
| 142 | test "fixsfdi" { | ||
| 143 | try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); | ||
| 144 | |||
| 145 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 146 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 147 | |||
| 148 | try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 149 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 150 | try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 151 | |||
| 152 | try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 153 | try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 154 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); | ||
| 155 | try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); | ||
| 156 | |||
| 157 | try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); | ||
| 158 | try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 159 | try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 160 | |||
| 161 | try test__fixsfdi(-2.01, -2); | ||
| 162 | try test__fixsfdi(-2.0, -2); | ||
| 163 | try test__fixsfdi(-1.99, -1); | ||
| 164 | try test__fixsfdi(-1.0, -1); | ||
| 165 | try test__fixsfdi(-0.99, 0); | ||
| 166 | try test__fixsfdi(-0.5, 0); | ||
| 167 | try test__fixsfdi(-math.floatMin(f32), 0); | ||
| 168 | try test__fixsfdi(0.0, 0); | ||
| 169 | try test__fixsfdi(math.floatMin(f32), 0); | ||
| 170 | try test__fixsfdi(0.5, 0); | ||
| 171 | try test__fixsfdi(0.99, 0); | ||
| 172 | try test__fixsfdi(1.0, 1); | ||
| 173 | try test__fixsfdi(1.5, 1); | ||
| 174 | try test__fixsfdi(1.99, 1); | ||
| 175 | try test__fixsfdi(2.0, 2); | ||
| 176 | try test__fixsfdi(2.01, 2); | ||
| 177 | |||
| 178 | try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 179 | try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 180 | try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 181 | |||
| 182 | try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 183 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 184 | try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 185 | try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 186 | |||
| 187 | try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 188 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 189 | try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 190 | |||
| 191 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 192 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 193 | |||
| 194 | try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); | ||
| 195 | } | ||
| 196 | |||
| 197 | test "fixunssfdi" { | ||
| 198 | try test__fixunssfdi(0.0, 0); | ||
| 199 | |||
| 200 | try test__fixunssfdi(0.5, 0); | ||
| 201 | try test__fixunssfdi(0.99, 0); | ||
| 202 | try test__fixunssfdi(1.0, 1); | ||
| 203 | try test__fixunssfdi(1.5, 1); | ||
| 204 | try test__fixunssfdi(1.99, 1); | ||
| 205 | try test__fixunssfdi(2.0, 2); | ||
| 206 | try test__fixunssfdi(2.01, 2); | ||
| 207 | try test__fixunssfdi(-0.5, 0); | ||
| 208 | try test__fixunssfdi(-0.99, 0); | ||
| 209 | |||
| 210 | try test__fixunssfdi(-1.0, 0); | ||
| 211 | try test__fixunssfdi(-1.5, 0); | ||
| 212 | try test__fixunssfdi(-1.99, 0); | ||
| 213 | try test__fixunssfdi(-2.0, 0); | ||
| 214 | try test__fixunssfdi(-2.01, 0); | ||
| 215 | |||
| 216 | try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); | ||
| 217 | try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); | ||
| 218 | try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 219 | try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 220 | |||
| 221 | try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); | ||
| 222 | try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); | ||
| 223 | } | ||
| 224 | |||
| 225 | fn test__fixsfti(a: f32, expected: i128) !void { | ||
| 226 | const x = __fixsfti(a); | ||
| 227 | try testing.expect(x == expected); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn test__fixunssfti(a: f32, expected: u128) !void { | ||
| 231 | const x = __fixunssfti(a); | ||
| 232 | try testing.expect(x == expected); | ||
| 233 | } | ||
| 234 | |||
| 235 | test "fixsfti" { | ||
| 236 | try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); | ||
| 237 | |||
| 238 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 239 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 240 | |||
| 241 | try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 242 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); | ||
| 243 | try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); | ||
| 244 | try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); | ||
| 245 | try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); | ||
| 246 | try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); | ||
| 247 | |||
| 248 | try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 249 | try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 250 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); | ||
| 251 | try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); | ||
| 252 | |||
| 253 | try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); | ||
| 254 | try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 255 | try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 256 | |||
| 257 | try test__fixsfti(-0x1.000000p+31, -0x80000000); | ||
| 258 | try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); | ||
| 259 | try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 260 | try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 261 | |||
| 262 | try test__fixsfti(-2.01, -2); | ||
| 263 | try test__fixsfti(-2.0, -2); | ||
| 264 | try test__fixsfti(-1.99, -1); | ||
| 265 | try test__fixsfti(-1.0, -1); | ||
| 266 | try test__fixsfti(-0.99, 0); | ||
| 267 | try test__fixsfti(-0.5, 0); | ||
| 268 | try test__fixsfti(-math.floatMin(f32), 0); | ||
| 269 | try test__fixsfti(0.0, 0); | ||
| 270 | try test__fixsfti(math.floatMin(f32), 0); | ||
| 271 | try test__fixsfti(0.5, 0); | ||
| 272 | try test__fixsfti(0.99, 0); | ||
| 273 | try test__fixsfti(1.0, 1); | ||
| 274 | try test__fixsfti(1.5, 1); | ||
| 275 | try test__fixsfti(1.99, 1); | ||
| 276 | try test__fixsfti(2.0, 2); | ||
| 277 | try test__fixsfti(2.01, 2); | ||
| 278 | |||
| 279 | try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 280 | try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 281 | try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); | ||
| 282 | try test__fixsfti(0x1.000000p+31, 0x80000000); | ||
| 283 | |||
| 284 | try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 285 | try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 286 | try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); | ||
| 287 | |||
| 288 | try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); | ||
| 289 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); | ||
| 290 | try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 291 | try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); | ||
| 292 | |||
| 293 | try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); | ||
| 294 | try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); | ||
| 295 | try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 296 | try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 297 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 298 | try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 299 | |||
| 300 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 301 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 302 | |||
| 303 | try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); | ||
| 304 | } | ||
| 305 | |||
| 306 | test "fixunssfti" { | ||
| 307 | try test__fixunssfti(0.0, 0); | ||
| 308 | |||
| 309 | try test__fixunssfti(0.5, 0); | ||
| 310 | try test__fixunssfti(0.99, 0); | ||
| 311 | try test__fixunssfti(1.0, 1); | ||
| 312 | try test__fixunssfti(1.5, 1); | ||
| 313 | try test__fixunssfti(1.99, 1); | ||
| 314 | try test__fixunssfti(2.0, 2); | ||
| 315 | try test__fixunssfti(2.01, 2); | ||
| 316 | try test__fixunssfti(-0.5, 0); | ||
| 317 | try test__fixunssfti(-0.99, 0); | ||
| 318 | |||
| 319 | try test__fixunssfti(-1.0, 0); | ||
| 320 | try test__fixunssfti(-1.5, 0); | ||
| 321 | try test__fixunssfti(-1.99, 0); | ||
| 322 | try test__fixunssfti(-2.0, 0); | ||
| 323 | try test__fixunssfti(-2.01, 0); | ||
| 324 | |||
| 325 | try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); | ||
| 326 | try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); | ||
| 327 | try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 328 | try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 329 | try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); | ||
| 330 | try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); | ||
| 331 | try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); | ||
| 332 | try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); | ||
| 333 | |||
| 334 | try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); | ||
| 335 | try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); | ||
| 336 | try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); | ||
| 337 | try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); | ||
| 338 | try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); | ||
| 339 | try test__fixunssfti(math.inf(f32), math.maxInt(u128)); | ||
| 340 | } | ||
| 341 | |||
| 342 | fn test__fixdfsi(a: f64, expected: i32) !void { | ||
| 343 | const x = __fixdfsi(a); | ||
| 344 | try testing.expect(x == expected); | ||
| 345 | } | ||
| 346 | |||
| 347 | fn test__fixunsdfsi(a: f64, expected: u32) !void { | ||
| 348 | const x = __fixunsdfsi(a); | ||
| 349 | try testing.expect(x == expected); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "fixdfsi" { | ||
| 353 | try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); | ||
| 354 | |||
| 355 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 356 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 357 | |||
| 358 | try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 359 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 360 | try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 361 | |||
| 362 | try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 363 | try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 364 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 365 | try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 366 | |||
| 367 | try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 368 | try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 369 | |||
| 370 | try test__fixdfsi(-0x1.000000p+31, -0x80000000); | ||
| 371 | try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 372 | try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 373 | |||
| 374 | try test__fixdfsi(-2.01, -2); | ||
| 375 | try test__fixdfsi(-2.0, -2); | ||
| 376 | try test__fixdfsi(-1.99, -1); | ||
| 377 | try test__fixdfsi(-1.0, -1); | ||
| 378 | try test__fixdfsi(-0.99, 0); | ||
| 379 | try test__fixdfsi(-0.5, 0); | ||
| 380 | try test__fixdfsi(-math.floatMin(f64), 0); | ||
| 381 | try test__fixdfsi(0.0, 0); | ||
| 382 | try test__fixdfsi(math.floatMin(f64), 0); | ||
| 383 | try test__fixdfsi(0.5, 0); | ||
| 384 | try test__fixdfsi(0.99, 0); | ||
| 385 | try test__fixdfsi(1.0, 1); | ||
| 386 | try test__fixdfsi(1.5, 1); | ||
| 387 | try test__fixdfsi(1.99, 1); | ||
| 388 | try test__fixdfsi(2.0, 2); | ||
| 389 | try test__fixdfsi(2.01, 2); | ||
| 390 | |||
| 391 | try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 392 | try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 393 | try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 394 | |||
| 395 | try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 396 | try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 397 | |||
| 398 | try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 399 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 400 | try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 401 | try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 402 | |||
| 403 | try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 404 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 405 | try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 406 | |||
| 407 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 408 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 409 | |||
| 410 | try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); | ||
| 411 | } | ||
| 412 | |||
| 413 | test "fixunsdfsi" { | ||
| 414 | try test__fixunsdfsi(0.0, 0); | ||
| 415 | |||
| 416 | try test__fixunsdfsi(0.5, 0); | ||
| 417 | try test__fixunsdfsi(0.99, 0); | ||
| 418 | try test__fixunsdfsi(1.0, 1); | ||
| 419 | try test__fixunsdfsi(1.5, 1); | ||
| 420 | try test__fixunsdfsi(1.99, 1); | ||
| 421 | try test__fixunsdfsi(2.0, 2); | ||
| 422 | try test__fixunsdfsi(2.01, 2); | ||
| 423 | try test__fixunsdfsi(-0.5, 0); | ||
| 424 | try test__fixunsdfsi(-0.99, 0); | ||
| 425 | try test__fixunsdfsi(-1.0, 0); | ||
| 426 | try test__fixunsdfsi(-1.5, 0); | ||
| 427 | try test__fixunsdfsi(-1.99, 0); | ||
| 428 | try test__fixunsdfsi(-2.0, 0); | ||
| 429 | try test__fixunsdfsi(-2.01, 0); | ||
| 430 | |||
| 431 | try test__fixunsdfsi(0x1.000000p+31, 0x80000000); | ||
| 432 | try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); | ||
| 433 | try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); | ||
| 434 | try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 435 | try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 436 | |||
| 437 | try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); | ||
| 438 | try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); | ||
| 439 | |||
| 440 | try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); | ||
| 441 | try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); | ||
| 442 | try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); | ||
| 443 | } | ||
| 444 | |||
| 445 | fn test__fixdfdi(a: f64, expected: i64) !void { | ||
| 446 | const x = __fixdfdi(a); | ||
| 447 | try testing.expect(x == expected); | ||
| 448 | } | ||
| 449 | |||
| 450 | fn test__fixunsdfdi(a: f64, expected: u64) !void { | ||
| 451 | const x = __fixunsdfdi(a); | ||
| 452 | try testing.expect(x == expected); | ||
| 453 | } | ||
| 454 | |||
| 455 | test "fixdfdi" { | ||
| 456 | try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); | ||
| 457 | |||
| 458 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 459 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 460 | |||
| 461 | try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 462 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 463 | try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 464 | |||
| 465 | try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 466 | try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 467 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 468 | try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 469 | |||
| 470 | try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 471 | try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 472 | |||
| 473 | try test__fixdfdi(-2.01, -2); | ||
| 474 | try test__fixdfdi(-2.0, -2); | ||
| 475 | try test__fixdfdi(-1.99, -1); | ||
| 476 | try test__fixdfdi(-1.0, -1); | ||
| 477 | try test__fixdfdi(-0.99, 0); | ||
| 478 | try test__fixdfdi(-0.5, 0); | ||
| 479 | try test__fixdfdi(-math.floatMin(f64), 0); | ||
| 480 | try test__fixdfdi(0.0, 0); | ||
| 481 | try test__fixdfdi(math.floatMin(f64), 0); | ||
| 482 | try test__fixdfdi(0.5, 0); | ||
| 483 | try test__fixdfdi(0.99, 0); | ||
| 484 | try test__fixdfdi(1.0, 1); | ||
| 485 | try test__fixdfdi(1.5, 1); | ||
| 486 | try test__fixdfdi(1.99, 1); | ||
| 487 | try test__fixdfdi(2.0, 2); | ||
| 488 | try test__fixdfdi(2.01, 2); | ||
| 489 | |||
| 490 | try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 491 | try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 492 | |||
| 493 | try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 494 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 495 | try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 496 | try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 497 | |||
| 498 | try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 499 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 500 | try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 501 | |||
| 502 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 503 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 504 | |||
| 505 | try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); | ||
| 506 | } | ||
| 507 | |||
| 508 | test "fixunsdfdi" { | ||
| 509 | try test__fixunsdfdi(0.0, 0); | ||
| 510 | try test__fixunsdfdi(0.5, 0); | ||
| 511 | try test__fixunsdfdi(0.99, 0); | ||
| 512 | try test__fixunsdfdi(1.0, 1); | ||
| 513 | try test__fixunsdfdi(1.5, 1); | ||
| 514 | try test__fixunsdfdi(1.99, 1); | ||
| 515 | try test__fixunsdfdi(2.0, 2); | ||
| 516 | try test__fixunsdfdi(2.01, 2); | ||
| 517 | try test__fixunsdfdi(-0.5, 0); | ||
| 518 | try test__fixunsdfdi(-0.99, 0); | ||
| 519 | try test__fixunsdfdi(-1.0, 0); | ||
| 520 | try test__fixunsdfdi(-1.5, 0); | ||
| 521 | try test__fixunsdfdi(-1.99, 0); | ||
| 522 | try test__fixunsdfdi(-2.0, 0); | ||
| 523 | try test__fixunsdfdi(-2.01, 0); | ||
| 524 | |||
| 525 | try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 526 | try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 527 | |||
| 528 | try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); | ||
| 529 | try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); | ||
| 530 | |||
| 531 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); | ||
| 532 | try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 533 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 534 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 535 | |||
| 536 | try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 537 | try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 538 | } | ||
| 539 | |||
| 540 | fn test__fixdfti(a: f64, expected: i128) !void { | ||
| 541 | const x = __fixdfti(a); | ||
| 542 | try testing.expect(x == expected); | ||
| 543 | } | ||
| 544 | |||
| 545 | fn test__fixunsdfti(a: f64, expected: u128) !void { | ||
| 546 | const x = __fixunsdfti(a); | ||
| 547 | try testing.expect(x == expected); | ||
| 548 | } | ||
| 549 | |||
| 550 | test "fixdfti" { | ||
| 551 | try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); | ||
| 552 | |||
| 553 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 554 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 555 | |||
| 556 | try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 557 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); | ||
| 558 | try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); | ||
| 559 | |||
| 560 | try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); | ||
| 561 | try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 562 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 563 | try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 564 | |||
| 565 | try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 566 | try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 567 | |||
| 568 | try test__fixdfti(-2.01, -2); | ||
| 569 | try test__fixdfti(-2.0, -2); | ||
| 570 | try test__fixdfti(-1.99, -1); | ||
| 571 | try test__fixdfti(-1.0, -1); | ||
| 572 | try test__fixdfti(-0.99, 0); | ||
| 573 | try test__fixdfti(-0.5, 0); | ||
| 574 | try test__fixdfti(-math.floatMin(f64), 0); | ||
| 575 | try test__fixdfti(0.0, 0); | ||
| 576 | try test__fixdfti(math.floatMin(f64), 0); | ||
| 577 | try test__fixdfti(0.5, 0); | ||
| 578 | try test__fixdfti(0.99, 0); | ||
| 579 | try test__fixdfti(1.0, 1); | ||
| 580 | try test__fixdfti(1.5, 1); | ||
| 581 | try test__fixdfti(1.99, 1); | ||
| 582 | try test__fixdfti(2.0, 2); | ||
| 583 | try test__fixdfti(2.01, 2); | ||
| 584 | |||
| 585 | try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 586 | try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 587 | |||
| 588 | try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 589 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 590 | try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 591 | try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); | ||
| 592 | |||
| 593 | try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 594 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 595 | try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 596 | |||
| 597 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 598 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 599 | |||
| 600 | try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); | ||
| 601 | } | ||
| 602 | |||
| 603 | test "fixunsdfti" { | ||
| 604 | try test__fixunsdfti(0.0, 0); | ||
| 605 | |||
| 606 | try test__fixunsdfti(0.5, 0); | ||
| 607 | try test__fixunsdfti(0.99, 0); | ||
| 608 | try test__fixunsdfti(1.0, 1); | ||
| 609 | try test__fixunsdfti(1.5, 1); | ||
| 610 | try test__fixunsdfti(1.99, 1); | ||
| 611 | try test__fixunsdfti(2.0, 2); | ||
| 612 | try test__fixunsdfti(2.01, 2); | ||
| 613 | try test__fixunsdfti(-0.5, 0); | ||
| 614 | try test__fixunsdfti(-0.99, 0); | ||
| 615 | try test__fixunsdfti(-1.0, 0); | ||
| 616 | try test__fixunsdfti(-1.5, 0); | ||
| 617 | try test__fixunsdfti(-1.99, 0); | ||
| 618 | try test__fixunsdfti(-2.0, 0); | ||
| 619 | try test__fixunsdfti(-2.01, 0); | ||
| 620 | |||
| 621 | try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 622 | try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 623 | |||
| 624 | try test__fixunsdfti(-0x1.FFFFFEp+62, 0); | ||
| 625 | try test__fixunsdfti(-0x1.FFFFFCp+62, 0); | ||
| 626 | |||
| 627 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); | ||
| 628 | try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 629 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 630 | try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 631 | |||
| 632 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); | ||
| 633 | try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); | ||
| 634 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 635 | try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 636 | try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 637 | |||
| 638 | try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 639 | try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 640 | } | ||
| 641 | |||
| 642 | fn test__fixtfsi(a: f128, expected: i32) !void { | ||
| 643 | const x = __fixtfsi(a); | ||
| 644 | try testing.expect(x == expected); | ||
| 645 | } | ||
| 646 | |||
| 647 | fn test__fixunstfsi(a: f128, expected: u32) !void { | ||
| 648 | const x = __fixunstfsi(a); | ||
| 649 | try testing.expect(x == expected); | ||
| 650 | } | ||
| 651 | |||
| 652 | test "fixtfsi" { | ||
| 653 | try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); | ||
| 654 | |||
| 655 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 656 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 657 | |||
| 658 | try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 659 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 660 | try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 661 | |||
| 662 | try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 663 | try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 664 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 665 | try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 666 | |||
| 667 | try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 668 | try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 669 | |||
| 670 | try test__fixtfsi(-0x1.000000p+31, -0x80000000); | ||
| 671 | try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 672 | try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 673 | try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 674 | |||
| 675 | try test__fixtfsi(-2.01, -2); | ||
| 676 | try test__fixtfsi(-2.0, -2); | ||
| 677 | try test__fixtfsi(-1.99, -1); | ||
| 678 | try test__fixtfsi(-1.0, -1); | ||
| 679 | try test__fixtfsi(-0.99, 0); | ||
| 680 | try test__fixtfsi(-0.5, 0); | ||
| 681 | try test__fixtfsi(-math.floatMin(f32), 0); | ||
| 682 | try test__fixtfsi(0.0, 0); | ||
| 683 | try test__fixtfsi(math.floatMin(f32), 0); | ||
| 684 | try test__fixtfsi(0.5, 0); | ||
| 685 | try test__fixtfsi(0.99, 0); | ||
| 686 | try test__fixtfsi(1.0, 1); | ||
| 687 | try test__fixtfsi(1.5, 1); | ||
| 688 | try test__fixtfsi(1.99, 1); | ||
| 689 | try test__fixtfsi(2.0, 2); | ||
| 690 | try test__fixtfsi(2.01, 2); | ||
| 691 | |||
| 692 | try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 693 | try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 694 | try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 695 | try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 696 | |||
| 697 | try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 698 | try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 699 | |||
| 700 | try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 701 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 702 | try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 703 | try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 704 | |||
| 705 | try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 706 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 707 | try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 708 | |||
| 709 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 710 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 711 | |||
| 712 | try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); | ||
| 713 | } | ||
| 714 | |||
| 715 | test "fixunstfsi" { | ||
| 716 | try test__fixunstfsi(math.inf(f128), 0xffffffff); | ||
| 717 | try test__fixunstfsi(0, 0x0); | ||
| 718 | try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); | ||
| 719 | try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); | ||
| 720 | try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); | ||
| 721 | try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); | ||
| 722 | try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); | ||
| 723 | try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); | ||
| 724 | |||
| 725 | try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); | ||
| 726 | } | ||
| 727 | |||
| 728 | fn test__fixtfdi(a: f128, expected: i64) !void { | ||
| 729 | const x = __fixtfdi(a); | ||
| 730 | try testing.expect(x == expected); | ||
| 731 | } | ||
| 732 | |||
| 733 | fn test__fixunstfdi(a: f128, expected: u64) !void { | ||
| 734 | const x = __fixunstfdi(a); | ||
| 735 | try testing.expect(x == expected); | ||
| 736 | } | ||
| 737 | |||
| 738 | test "fixtfdi" { | ||
| 739 | try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); | ||
| 740 | |||
| 741 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 742 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 743 | |||
| 744 | try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 745 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 746 | try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 747 | |||
| 748 | try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 749 | try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 750 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 751 | try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 752 | |||
| 753 | try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); | ||
| 754 | try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); | ||
| 755 | |||
| 756 | try test__fixtfdi(-0x1.000000p+31, -0x80000000); | ||
| 757 | try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 758 | try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 759 | try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 760 | |||
| 761 | try test__fixtfdi(-2.01, -2); | ||
| 762 | try test__fixtfdi(-2.0, -2); | ||
| 763 | try test__fixtfdi(-1.99, -1); | ||
| 764 | try test__fixtfdi(-1.0, -1); | ||
| 765 | try test__fixtfdi(-0.99, 0); | ||
| 766 | try test__fixtfdi(-0.5, 0); | ||
| 767 | try test__fixtfdi(-math.floatMin(f64), 0); | ||
| 768 | try test__fixtfdi(0.0, 0); | ||
| 769 | try test__fixtfdi(math.floatMin(f64), 0); | ||
| 770 | try test__fixtfdi(0.5, 0); | ||
| 771 | try test__fixtfdi(0.99, 0); | ||
| 772 | try test__fixtfdi(1.0, 1); | ||
| 773 | try test__fixtfdi(1.5, 1); | ||
| 774 | try test__fixtfdi(1.99, 1); | ||
| 775 | try test__fixtfdi(2.0, 2); | ||
| 776 | try test__fixtfdi(2.01, 2); | ||
| 777 | |||
| 778 | try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 779 | try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 780 | try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 781 | try test__fixtfdi(0x1.000000p+31, 0x80000000); | ||
| 782 | |||
| 783 | try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 784 | try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 785 | |||
| 786 | try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 787 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 788 | try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 789 | try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 790 | |||
| 791 | try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 792 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 793 | try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 794 | |||
| 795 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 796 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 797 | |||
| 798 | try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); | ||
| 799 | } | ||
| 800 | |||
| 801 | test "fixunstfdi" { | ||
| 802 | try test__fixunstfdi(0.0, 0); | ||
| 803 | |||
| 804 | try test__fixunstfdi(0.5, 0); | ||
| 805 | try test__fixunstfdi(0.99, 0); | ||
| 806 | try test__fixunstfdi(1.0, 1); | ||
| 807 | try test__fixunstfdi(1.5, 1); | ||
| 808 | try test__fixunstfdi(1.99, 1); | ||
| 809 | try test__fixunstfdi(2.0, 2); | ||
| 810 | try test__fixunstfdi(2.01, 2); | ||
| 811 | try test__fixunstfdi(-0.5, 0); | ||
| 812 | try test__fixunstfdi(-0.99, 0); | ||
| 813 | try test__fixunstfdi(-1.0, 0); | ||
| 814 | try test__fixunstfdi(-1.5, 0); | ||
| 815 | try test__fixunstfdi(-1.99, 0); | ||
| 816 | try test__fixunstfdi(-2.0, 0); | ||
| 817 | try test__fixunstfdi(-2.01, 0); | ||
| 818 | |||
| 819 | try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 820 | try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 821 | |||
| 822 | try test__fixunstfdi(-0x1.FFFFFEp+62, 0); | ||
| 823 | try test__fixunstfdi(-0x1.FFFFFCp+62, 0); | ||
| 824 | |||
| 825 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 826 | try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 827 | |||
| 828 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 829 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 830 | |||
| 831 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); | ||
| 832 | try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); | ||
| 833 | try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); | ||
| 834 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 835 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); | ||
| 836 | try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); | ||
| 837 | |||
| 838 | try test__fixunstfdi(-0x1.0000000000000000p+63, 0); | ||
| 839 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); | ||
| 840 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); | ||
| 841 | } | ||
| 842 | |||
| 843 | fn test__fixtfti(a: f128, expected: i128) !void { | ||
| 844 | const x = __fixtfti(a); | ||
| 845 | try testing.expect(x == expected); | ||
| 846 | } | ||
| 847 | |||
| 848 | fn test__fixunstfti(a: f128, expected: u128) !void { | ||
| 849 | const x = __fixunstfti(a); | ||
| 850 | try testing.expect(x == expected); | ||
| 851 | } | ||
| 852 | |||
| 853 | test "fixtfti" { | ||
| 854 | try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); | ||
| 855 | |||
| 856 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 857 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 858 | |||
| 859 | try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 860 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); | ||
| 861 | try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); | ||
| 862 | |||
| 863 | try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); | ||
| 864 | try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 865 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 866 | try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 867 | |||
| 868 | try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 869 | try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 870 | |||
| 871 | try test__fixtfti(-2.01, -2); | ||
| 872 | try test__fixtfti(-2.0, -2); | ||
| 873 | try test__fixtfti(-1.99, -1); | ||
| 874 | try test__fixtfti(-1.0, -1); | ||
| 875 | try test__fixtfti(-0.99, 0); | ||
| 876 | try test__fixtfti(-0.5, 0); | ||
| 877 | try test__fixtfti(-math.floatMin(f128), 0); | ||
| 878 | try test__fixtfti(0.0, 0); | ||
| 879 | try test__fixtfti(math.floatMin(f128), 0); | ||
| 880 | try test__fixtfti(0.5, 0); | ||
| 881 | try test__fixtfti(0.99, 0); | ||
| 882 | try test__fixtfti(1.0, 1); | ||
| 883 | try test__fixtfti(1.5, 1); | ||
| 884 | try test__fixtfti(1.99, 1); | ||
| 885 | try test__fixtfti(2.0, 2); | ||
| 886 | try test__fixtfti(2.01, 2); | ||
| 887 | |||
| 888 | try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 889 | try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 890 | |||
| 891 | try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 892 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 893 | try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 894 | try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); | ||
| 895 | |||
| 896 | try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 897 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 898 | try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 899 | |||
| 900 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 901 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 902 | |||
| 903 | try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); | ||
| 904 | } | ||
| 905 | |||
| 906 | test "fixunstfti" { | ||
| 907 | try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); | ||
| 908 | |||
| 909 | try test__fixunstfti(0.0, 0); | ||
| 910 | |||
| 911 | try test__fixunstfti(0.5, 0); | ||
| 912 | try test__fixunstfti(0.99, 0); | ||
| 913 | try test__fixunstfti(1.0, 1); | ||
| 914 | try test__fixunstfti(1.5, 1); | ||
| 915 | try test__fixunstfti(1.99, 1); | ||
| 916 | try test__fixunstfti(2.0, 2); | ||
| 917 | try test__fixunstfti(2.01, 2); | ||
| 918 | try test__fixunstfti(-0.01, 0); | ||
| 919 | try test__fixunstfti(-0.99, 0); | ||
| 920 | |||
| 921 | try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); | ||
| 922 | |||
| 923 | try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); | ||
| 924 | try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); | ||
| 925 | try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); | ||
| 926 | try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); | ||
| 927 | } | ||
| 928 | |||
| 929 | fn test__fixunshfti(a: f16, expected: u128) !void { | ||
| 930 | const x = fixXfYi(u128, a); | ||
| 931 | try testing.expect(x == expected); | ||
| 932 | } | ||
| 933 | |||
| 934 | test "fixXfYi for f16" { | ||
| 935 | try test__fixunshfti(math.inf(f16), math.maxInt(u128)); | ||
| 936 | try test__fixunshfti(math.floatMax(f16), 65504); | ||
| 937 | } | ||
| 938 | |||
| 939 | fn test__fixunsxfti(a: f80, expected: u128) !void { | ||
| 940 | const x = fixXfYi(u128, a); | ||
| 941 | try testing.expect(x == expected); | ||
| 942 | } | ||
| 943 | |||
| 944 | test "fixXfYi for f80" { | ||
| 945 | try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); | ||
| 946 | try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); | ||
| 947 | try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); | ||
| 948 | } | ||
lib/compiler_rt/fixdfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixdfdi(a: f64) callconv(.C) i64 { | ||
| 15 | return floatToInt(i64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { | ||
| 19 | return floatToInt(i64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixdfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixdfsi(a: f64) callconv(.C) i32 { | ||
| 15 | return floatToInt(i32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { | ||
| 19 | return floatToInt(i32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixdfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixdfti, .{ .name = "__fixdfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixdfti(a: f64) callconv(.C) i128 { | ||
| 11 | return floatToInt(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixhfdi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixhfdi, .{ .name = "__fixhfdi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixhfdi(a: f16) callconv(.C) i64 { | ||
| 11 | return floatToInt(i64, a); | ||
| 12 | } | ||
lib/compiler_rt/fixhfsi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixhfsi, .{ .name = "__fixhfsi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixhfsi(a: f16) callconv(.C) i32 { | ||
| 11 | return floatToInt(i32, a); | ||
| 12 | } | ||
lib/compiler_rt/fixhfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixhfti, .{ .name = "__fixhfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixhfti(a: f16) callconv(.C) i128 { | ||
| 11 | return floatToInt(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixsfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixsfdi(a: f32) callconv(.C) i64 { | ||
| 15 | return floatToInt(i64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { | ||
| 19 | return floatToInt(i64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixsfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixsfsi(a: f32) callconv(.C) i32 { | ||
| 15 | return floatToInt(i32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { | ||
| 19 | return floatToInt(i32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixsfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixsfti, .{ .name = "__fixsfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixsfti(a: f32) callconv(.C) i128 { | ||
| 11 | return floatToInt(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixtfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixtfdi(a: f128) callconv(.C) i64 { | ||
| 15 | return floatToInt(i64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __fixkfdi(a: f128) callconv(.C) i64 { | ||
| 19 | return floatToInt(i64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixtfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixtfsi(a: f128) callconv(.C) i32 { | ||
| 15 | return floatToInt(i32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __fixkfsi(a: f128) callconv(.C) i32 { | ||
| 19 | return floatToInt(i32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixtfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixtfti, .{ .name = "__fixtfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixtfti(a: f128) callconv(.C) i128 { | ||
| 11 | return floatToInt(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunsdfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunsdfdi(a: f64) callconv(.C) u64 { | ||
| 15 | return floatToInt(u64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { | ||
| 19 | return floatToInt(u64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunsdfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunsdfsi(a: f64) callconv(.C) u32 { | ||
| 15 | return floatToInt(u32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { | ||
| 19 | return floatToInt(u32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunsdfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunsdfti(a: f64) callconv(.C) u128 { | ||
| 11 | return floatToInt(u128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunshfdi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunshfdi, .{ .name = "__fixunshfdi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunshfdi(a: f16) callconv(.C) u64 { | ||
| 11 | return floatToInt(u64, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunshfsi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunshfsi, .{ .name = "__fixunshfsi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunshfsi(a: f16) callconv(.C) u32 { | ||
| 11 | return floatToInt(u32, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunshfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunshfti, .{ .name = "__fixunshfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunshfti(a: f16) callconv(.C) u128 { | ||
| 11 | return floatToInt(u128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunssfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunssfdi(a: f32) callconv(.C) u64 { | ||
| 15 | return floatToInt(u64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { | ||
| 19 | return floatToInt(u64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunssfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunssfsi(a: f32) callconv(.C) u32 { | ||
| 15 | return floatToInt(u32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { | ||
| 19 | return floatToInt(u32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunssfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunssfti(a: f32) callconv(.C) u128 { | ||
| 11 | return floatToInt(u128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunstfdi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunstfdi(a: f128) callconv(.C) u64 { | ||
| 15 | return floatToInt(u64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __fixunskfdi(a: f128) callconv(.C) u64 { | ||
| 19 | return floatToInt(u64, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunstfsi.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __fixunstfsi(a: f128) callconv(.C) u32 { | ||
| 15 | return floatToInt(u32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __fixunskfsi(a: f128) callconv(.C) u32 { | ||
| 19 | return floatToInt(u32, a); | ||
| 20 | } | ||
lib/compiler_rt/fixunstfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunstfti(a: f128) callconv(.C) u128 { | ||
| 11 | return floatToInt(u128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunsxfdi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunsxfdi(a: f80) callconv(.C) u64 { | ||
| 11 | return floatToInt(u64, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunsxfsi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunsxfsi(a: f80) callconv(.C) u32 { | ||
| 11 | return floatToInt(u32, a); | ||
| 12 | } | ||
lib/compiler_rt/fixunsxfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixunsxfti(a: f80) callconv(.C) u128 { | ||
| 11 | return floatToInt(u128, a); | ||
| 12 | } | ||
lib/compiler_rt/fixxfdi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixxfdi(a: f80) callconv(.C) i64 { | ||
| 11 | return floatToInt(i64, a); | ||
| 12 | } | ||
lib/compiler_rt/fixxfsi.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixxfsi(a: f80) callconv(.C) i32 { | ||
| 11 | return floatToInt(i32, a); | ||
| 12 | } | ||
lib/compiler_rt/fixxfti.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const floatToInt = @import("./float_to_int.zig").floatToInt; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__fixxfti, .{ .name = "__fixxfti", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __fixxfti(a: f80) callconv(.C) i128 { | ||
| 11 | return floatToInt(i128, a); | ||
| 12 | } | ||
lib/compiler_rt/floatXiYf.zig deleted-311| ... | @@ -1,311 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const math = std.math; | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const arch = builtin.cpu.arch; | ||
| 6 | const is_test = builtin.is_test; | ||
| 7 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 8 | pub const panic = @import("common.zig").panic; | ||
| 9 | |||
| 10 | comptime { | ||
| 11 | // Integral -> Float Conversion | ||
| 12 | |||
| 13 | // Conversion to f32 | ||
| 14 | @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage }); | ||
| 15 | @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage }); | ||
| 16 | |||
| 17 | @export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage }); | ||
| 18 | @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage }); | ||
| 19 | |||
| 20 | @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage }); | ||
| 21 | @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage }); | ||
| 22 | |||
| 23 | // Conversion to f64 | ||
| 24 | @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage }); | ||
| 25 | @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage }); | ||
| 26 | |||
| 27 | @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage }); | ||
| 28 | @export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage }); | ||
| 29 | |||
| 30 | @export(__floattidf, .{ .name = "__floattidf", .linkage = linkage }); | ||
| 31 | @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage }); | ||
| 32 | |||
| 33 | // Conversion to f80 | ||
| 34 | @export(__floatsixf, .{ .name = "__floatsixf", .linkage = linkage }); | ||
| 35 | @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = linkage }); | ||
| 36 | |||
| 37 | @export(__floatdixf, .{ .name = "__floatdixf", .linkage = linkage }); | ||
| 38 | @export(__floatundixf, .{ .name = "__floatundixf", .linkage = linkage }); | ||
| 39 | |||
| 40 | @export(__floattixf, .{ .name = "__floattixf", .linkage = linkage }); | ||
| 41 | @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = linkage }); | ||
| 42 | |||
| 43 | // Conversion to f128 | ||
| 44 | @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage }); | ||
| 45 | @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage }); | ||
| 46 | |||
| 47 | @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage }); | ||
| 48 | @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage }); | ||
| 49 | |||
| 50 | @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage }); | ||
| 51 | @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage }); | ||
| 52 | |||
| 53 | if (!is_test) { | ||
| 54 | if (arch.isARM() or arch.isThumb()) { | ||
| 55 | @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage }); | ||
| 56 | @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage }); | ||
| 57 | @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage }); | ||
| 58 | @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage }); | ||
| 59 | @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage }); | ||
| 60 | @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage }); | ||
| 61 | @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage }); | ||
| 62 | |||
| 63 | @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage }); | ||
| 64 | } | ||
| 65 | |||
| 66 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 67 | @export(__floatsikf, .{ .name = "__floatsikf", .linkage = linkage }); | ||
| 68 | @export(__floatdikf, .{ .name = "__floatdikf", .linkage = linkage }); | ||
| 69 | @export(__floatundikf, .{ .name = "__floatundikf", .linkage = linkage }); | ||
| 70 | @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = linkage }); | ||
| 71 | @export(__floatuntikf, .{ .name = "__floatuntikf", .linkage = linkage }); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | pub fn floatXiYf(comptime T: type, x: anytype) T { | ||
| 77 | @setRuntimeSafety(is_test); | ||
| 78 | |||
| 79 | if (x == 0) return 0; | ||
| 80 | |||
| 81 | // Various constants whose values follow from the type parameters. | ||
| 82 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 83 | const Z = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(x))); | ||
| 84 | const uT = std.meta.Int(.unsigned, @bitSizeOf(T)); | ||
| 85 | const inf = math.inf(T); | ||
| 86 | const float_bits = @bitSizeOf(T); | ||
| 87 | const int_bits = @bitSizeOf(@TypeOf(x)); | ||
| 88 | const exp_bits = math.floatExponentBits(T); | ||
| 89 | const fractional_bits = math.floatFractionalBits(T); | ||
| 90 | const exp_bias = math.maxInt(std.meta.Int(.unsigned, exp_bits - 1)); | ||
| 91 | const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; | ||
| 92 | const max_exp = exp_bias; | ||
| 93 | |||
| 94 | // Sign | ||
| 95 | var abs_val = math.absCast(x); | ||
| 96 | const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; | ||
| 97 | var result: uT = sign_bit; | ||
| 98 | |||
| 99 | // Compute significand | ||
| 100 | var exp = int_bits - @clz(Z, abs_val) - 1; | ||
| 101 | if (int_bits <= fractional_bits or exp <= fractional_bits) { | ||
| 102 | const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); | ||
| 103 | |||
| 104 | // Shift up result to line up with the significand - no rounding required | ||
| 105 | result = (@intCast(uT, abs_val) << shift_amt); | ||
| 106 | result ^= implicit_bit; // Remove implicit integer bit | ||
| 107 | } else { | ||
| 108 | var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); | ||
| 109 | const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; | ||
| 110 | |||
| 111 | // Shift down result and remove implicit integer bit | ||
| 112 | result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); | ||
| 113 | |||
| 114 | // Round result, including round-to-even for exact ties | ||
| 115 | result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); | ||
| 116 | } | ||
| 117 | |||
| 118 | // Compute exponent | ||
| 119 | if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity | ||
| 120 | return @bitCast(T, sign_bit | @bitCast(uT, inf)); | ||
| 121 | |||
| 122 | result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); | ||
| 123 | |||
| 124 | // If the result included a carry, we need to restore the explicit integer bit | ||
| 125 | if (T == f80) result |= 1 << fractional_bits; | ||
| 126 | |||
| 127 | return @bitCast(T, sign_bit | result); | ||
| 128 | } | ||
| 129 | |||
| 130 | // Conversion to f16 | ||
| 131 | pub fn __floatsihf(a: i32) callconv(.C) f16 { | ||
| 132 | return floatXiYf(f16, a); | ||
| 133 | } | ||
| 134 | |||
| 135 | pub fn __floatunsihf(a: u32) callconv(.C) f16 { | ||
| 136 | return floatXiYf(f16, a); | ||
| 137 | } | ||
| 138 | |||
| 139 | pub fn __floatdihf(a: i64) callconv(.C) f16 { | ||
| 140 | return floatXiYf(f16, a); | ||
| 141 | } | ||
| 142 | |||
| 143 | pub fn __floatundihf(a: u64) callconv(.C) f16 { | ||
| 144 | return floatXiYf(f16, a); | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn __floattihf(a: i128) callconv(.C) f16 { | ||
| 148 | return floatXiYf(f16, a); | ||
| 149 | } | ||
| 150 | |||
| 151 | pub fn __floatuntihf(a: u128) callconv(.C) f16 { | ||
| 152 | return floatXiYf(f16, a); | ||
| 153 | } | ||
| 154 | |||
| 155 | // Conversion to f32 | ||
| 156 | pub fn __floatsisf(a: i32) callconv(.C) f32 { | ||
| 157 | return floatXiYf(f32, a); | ||
| 158 | } | ||
| 159 | |||
| 160 | pub fn __floatunsisf(a: u32) callconv(.C) f32 { | ||
| 161 | return floatXiYf(f32, a); | ||
| 162 | } | ||
| 163 | |||
| 164 | pub fn __floatdisf(a: i64) callconv(.C) f32 { | ||
| 165 | return floatXiYf(f32, a); | ||
| 166 | } | ||
| 167 | |||
| 168 | pub fn __floatundisf(a: u64) callconv(.C) f32 { | ||
| 169 | return floatXiYf(f32, a); | ||
| 170 | } | ||
| 171 | |||
| 172 | pub fn __floattisf(a: i128) callconv(.C) f32 { | ||
| 173 | return floatXiYf(f32, a); | ||
| 174 | } | ||
| 175 | |||
| 176 | pub fn __floatuntisf(a: u128) callconv(.C) f32 { | ||
| 177 | return floatXiYf(f32, a); | ||
| 178 | } | ||
| 179 | |||
| 180 | // Conversion to f64 | ||
| 181 | pub fn __floatsidf(a: i32) callconv(.C) f64 { | ||
| 182 | return floatXiYf(f64, a); | ||
| 183 | } | ||
| 184 | |||
| 185 | pub fn __floatunsidf(a: u32) callconv(.C) f64 { | ||
| 186 | return floatXiYf(f64, a); | ||
| 187 | } | ||
| 188 | |||
| 189 | pub fn __floatdidf(a: i64) callconv(.C) f64 { | ||
| 190 | return floatXiYf(f64, a); | ||
| 191 | } | ||
| 192 | |||
| 193 | pub fn __floatundidf(a: u64) callconv(.C) f64 { | ||
| 194 | return floatXiYf(f64, a); | ||
| 195 | } | ||
| 196 | |||
| 197 | pub fn __floattidf(a: i128) callconv(.C) f64 { | ||
| 198 | return floatXiYf(f64, a); | ||
| 199 | } | ||
| 200 | |||
| 201 | pub fn __floatuntidf(a: u128) callconv(.C) f64 { | ||
| 202 | return floatXiYf(f64, a); | ||
| 203 | } | ||
| 204 | |||
| 205 | // Conversion to f80 | ||
| 206 | pub fn __floatsixf(a: i32) callconv(.C) f80 { | ||
| 207 | return floatXiYf(f80, a); | ||
| 208 | } | ||
| 209 | |||
| 210 | pub fn __floatunsixf(a: u32) callconv(.C) f80 { | ||
| 211 | return floatXiYf(f80, a); | ||
| 212 | } | ||
| 213 | |||
| 214 | pub fn __floatdixf(a: i64) callconv(.C) f80 { | ||
| 215 | return floatXiYf(f80, a); | ||
| 216 | } | ||
| 217 | |||
| 218 | pub fn __floatundixf(a: u64) callconv(.C) f80 { | ||
| 219 | return floatXiYf(f80, a); | ||
| 220 | } | ||
| 221 | |||
| 222 | pub fn __floattixf(a: i128) callconv(.C) f80 { | ||
| 223 | return floatXiYf(f80, a); | ||
| 224 | } | ||
| 225 | |||
| 226 | pub fn __floatuntixf(a: u128) callconv(.C) f80 { | ||
| 227 | return floatXiYf(f80, a); | ||
| 228 | } | ||
| 229 | |||
| 230 | // Conversion to f128 | ||
| 231 | pub fn __floatsitf(a: i32) callconv(.C) f128 { | ||
| 232 | return floatXiYf(f128, a); | ||
| 233 | } | ||
| 234 | |||
| 235 | pub fn __floatsikf(a: i32) callconv(.C) f128 { | ||
| 236 | return @call(.{ .modifier = .always_inline }, __floatsitf, .{a}); | ||
| 237 | } | ||
| 238 | |||
| 239 | pub fn __floatunsitf(a: u32) callconv(.C) f128 { | ||
| 240 | return floatXiYf(f128, a); | ||
| 241 | } | ||
| 242 | |||
| 243 | pub fn __floatunsikf(a: u32) callconv(.C) f128 { | ||
| 244 | return @call(.{ .modifier = .always_inline }, __floatunsitf, .{a}); | ||
| 245 | } | ||
| 246 | |||
| 247 | pub fn __floatditf(a: i64) callconv(.C) f128 { | ||
| 248 | return floatXiYf(f128, a); | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn __floatdikf(a: i64) callconv(.C) f128 { | ||
| 252 | return @call(.{ .modifier = .always_inline }, __floatditf, .{a}); | ||
| 253 | } | ||
| 254 | |||
| 255 | pub fn __floatunditf(a: u64) callconv(.C) f128 { | ||
| 256 | return floatXiYf(f128, a); | ||
| 257 | } | ||
| 258 | |||
| 259 | pub fn __floatundikf(a: u64) callconv(.C) f128 { | ||
| 260 | return @call(.{ .modifier = .always_inline }, __floatunditf, .{a}); | ||
| 261 | } | ||
| 262 | |||
| 263 | pub fn __floattitf(a: i128) callconv(.C) f128 { | ||
| 264 | return floatXiYf(f128, a); | ||
| 265 | } | ||
| 266 | |||
| 267 | pub fn __floatuntitf(a: u128) callconv(.C) f128 { | ||
| 268 | return floatXiYf(f128, a); | ||
| 269 | } | ||
| 270 | |||
| 271 | pub fn __floatuntikf(a: u128) callconv(.C) f128 { | ||
| 272 | return @call(.{ .modifier = .always_inline }, __floatuntitf, .{a}); | ||
| 273 | } | ||
| 274 | |||
| 275 | // Conversion to f32 | ||
| 276 | pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 { | ||
| 277 | return floatXiYf(f32, arg); | ||
| 278 | } | ||
| 279 | |||
| 280 | pub fn __aeabi_i2f(arg: i32) callconv(.AAPCS) f32 { | ||
| 281 | return floatXiYf(f32, arg); | ||
| 282 | } | ||
| 283 | |||
| 284 | pub fn __aeabi_ul2f(arg: u64) callconv(.AAPCS) f32 { | ||
| 285 | return floatXiYf(f32, arg); | ||
| 286 | } | ||
| 287 | |||
| 288 | pub fn __aeabi_l2f(arg: i64) callconv(.AAPCS) f32 { | ||
| 289 | return floatXiYf(f32, arg); | ||
| 290 | } | ||
| 291 | |||
| 292 | // Conversion to f64 | ||
| 293 | pub fn __aeabi_ui2d(arg: u32) callconv(.AAPCS) f64 { | ||
| 294 | return floatXiYf(f64, arg); | ||
| 295 | } | ||
| 296 | |||
| 297 | pub fn __aeabi_i2d(arg: i32) callconv(.AAPCS) f64 { | ||
| 298 | return floatXiYf(f64, arg); | ||
| 299 | } | ||
| 300 | |||
| 301 | pub fn __aeabi_ul2d(arg: u64) callconv(.AAPCS) f64 { | ||
| 302 | return floatXiYf(f64, arg); | ||
| 303 | } | ||
| 304 | |||
| 305 | pub fn __aeabi_l2d(arg: i64) callconv(.AAPCS) f64 { | ||
| 306 | return floatXiYf(f64, arg); | ||
| 307 | } | ||
| 308 | |||
| 309 | test { | ||
| 310 | _ = @import("floatXiYf_test.zig"); | ||
| 311 | } | ||
lib/compiler_rt/float_to_int.zig created+55| ... | @@ -0,0 +1,55 @@ | ||
| 1 | const Int = @import("std").meta.Int; | ||
| 2 | const math = @import("std").math; | ||
| 3 | const Log2Int = math.Log2Int; | ||
| 4 | |||
| 5 | pub inline fn floatToInt(comptime I: type, a: anytype) I { | ||
| 6 | const F = @TypeOf(a); | ||
| 7 | const float_bits = @typeInfo(F).Float.bits; | ||
| 8 | const int_bits = @typeInfo(I).Int.bits; | ||
| 9 | const rep_t = Int(.unsigned, float_bits); | ||
| 10 | const sig_bits = math.floatMantissaBits(F); | ||
| 11 | const exp_bits = math.floatExponentBits(F); | ||
| 12 | const fractional_bits = math.floatFractionalBits(F); | ||
| 13 | |||
| 14 | const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; | ||
| 15 | const max_exp = (1 << (exp_bits - 1)); | ||
| 16 | const exp_bias = max_exp - 1; | ||
| 17 | const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; | ||
| 18 | |||
| 19 | // Break a into sign, exponent, significand | ||
| 20 | const a_rep: rep_t = @bitCast(rep_t, a); | ||
| 21 | const negative = (a_rep >> (float_bits - 1)) != 0; | ||
| 22 | const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; | ||
| 23 | const significand: rep_t = (a_rep & sig_mask) | implicit_bit; | ||
| 24 | |||
| 25 | // If the exponent is negative, the result rounds to zero. | ||
| 26 | if (exponent < 0) return 0; | ||
| 27 | |||
| 28 | // If the value is too large for the integer type, saturate. | ||
| 29 | switch (@typeInfo(I).Int.signedness) { | ||
| 30 | .unsigned => { | ||
| 31 | if (negative) return 0; | ||
| 32 | if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); | ||
| 33 | }, | ||
| 34 | .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { | ||
| 35 | return if (negative) math.minInt(I) else math.maxInt(I); | ||
| 36 | }, | ||
| 37 | } | ||
| 38 | |||
| 39 | // If 0 <= exponent < sig_bits, right shift to get the result. | ||
| 40 | // Otherwise, shift left. | ||
| 41 | var result: I = undefined; | ||
| 42 | if (exponent < fractional_bits) { | ||
| 43 | result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); | ||
| 44 | } else { | ||
| 45 | result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); | ||
| 46 | } | ||
| 47 | |||
| 48 | if ((@typeInfo(I).Int.signedness == .signed) and negative) | ||
| 49 | return ~result +% 1; | ||
| 50 | return result; | ||
| 51 | } | ||
| 52 | |||
| 53 | test { | ||
| 54 | _ = @import("float_to_int_test.zig"); | ||
| 55 | } | ||
lib/compiler_rt/float_to_int_test.zig created+948| ... | @@ -0,0 +1,948 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const math = std.math; | ||
| 4 | const fixXfYi = @import("fixXfYi.zig").fixXfYi; | ||
| 5 | |||
| 6 | // Conversion from f32 | ||
| 7 | const __fixsfsi = @import("fixXfYi.zig").__fixsfsi; | ||
| 8 | const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi; | ||
| 9 | const __fixsfdi = @import("fixXfYi.zig").__fixsfdi; | ||
| 10 | const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi; | ||
| 11 | const __fixsfti = @import("fixXfYi.zig").__fixsfti; | ||
| 12 | const __fixunssfti = @import("fixXfYi.zig").__fixunssfti; | ||
| 13 | |||
| 14 | // Conversion from f64 | ||
| 15 | const __fixdfsi = @import("fixXfYi.zig").__fixdfsi; | ||
| 16 | const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi; | ||
| 17 | const __fixdfdi = @import("fixXfYi.zig").__fixdfdi; | ||
| 18 | const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi; | ||
| 19 | const __fixdfti = @import("fixXfYi.zig").__fixdfti; | ||
| 20 | const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti; | ||
| 21 | |||
| 22 | // Conversion from f128 | ||
| 23 | const __fixtfsi = @import("fixXfYi.zig").__fixtfsi; | ||
| 24 | const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi; | ||
| 25 | const __fixtfdi = @import("fixXfYi.zig").__fixtfdi; | ||
| 26 | const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi; | ||
| 27 | const __fixtfti = @import("fixXfYi.zig").__fixtfti; | ||
| 28 | const __fixunstfti = @import("fixXfYi.zig").__fixunstfti; | ||
| 29 | |||
| 30 | fn test__fixsfsi(a: f32, expected: i32) !void { | ||
| 31 | const x = __fixsfsi(a); | ||
| 32 | try testing.expect(x == expected); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn test__fixunssfsi(a: f32, expected: u32) !void { | ||
| 36 | const x = __fixunssfsi(a); | ||
| 37 | try testing.expect(x == expected); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "fixsfsi" { | ||
| 41 | try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); | ||
| 42 | |||
| 43 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 44 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 45 | |||
| 46 | try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 47 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 48 | try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 49 | |||
| 50 | try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 51 | try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 52 | try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 53 | try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 54 | |||
| 55 | try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 56 | try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 57 | |||
| 58 | try test__fixsfsi(-0x1.000000p+31, -0x80000000); | ||
| 59 | try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); | ||
| 60 | try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 61 | try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 62 | |||
| 63 | try test__fixsfsi(-2.01, -2); | ||
| 64 | try test__fixsfsi(-2.0, -2); | ||
| 65 | try test__fixsfsi(-1.99, -1); | ||
| 66 | try test__fixsfsi(-1.0, -1); | ||
| 67 | try test__fixsfsi(-0.99, 0); | ||
| 68 | try test__fixsfsi(-0.5, 0); | ||
| 69 | try test__fixsfsi(-math.floatMin(f32), 0); | ||
| 70 | try test__fixsfsi(0.0, 0); | ||
| 71 | try test__fixsfsi(math.floatMin(f32), 0); | ||
| 72 | try test__fixsfsi(0.5, 0); | ||
| 73 | try test__fixsfsi(0.99, 0); | ||
| 74 | try test__fixsfsi(1.0, 1); | ||
| 75 | try test__fixsfsi(1.5, 1); | ||
| 76 | try test__fixsfsi(1.99, 1); | ||
| 77 | try test__fixsfsi(2.0, 2); | ||
| 78 | try test__fixsfsi(2.01, 2); | ||
| 79 | |||
| 80 | try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 81 | try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 82 | try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); | ||
| 83 | try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 84 | |||
| 85 | try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 86 | try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 87 | |||
| 88 | try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 89 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 90 | try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 91 | try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 92 | |||
| 93 | try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 94 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 95 | try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 96 | |||
| 97 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 98 | try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 99 | |||
| 100 | try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); | ||
| 101 | } | ||
| 102 | |||
| 103 | test "fixunssfsi" { | ||
| 104 | try test__fixunssfsi(0.0, 0); | ||
| 105 | |||
| 106 | try test__fixunssfsi(0.5, 0); | ||
| 107 | try test__fixunssfsi(0.99, 0); | ||
| 108 | try test__fixunssfsi(1.0, 1); | ||
| 109 | try test__fixunssfsi(1.5, 1); | ||
| 110 | try test__fixunssfsi(1.99, 1); | ||
| 111 | try test__fixunssfsi(2.0, 2); | ||
| 112 | try test__fixunssfsi(2.01, 2); | ||
| 113 | try test__fixunssfsi(-0.5, 0); | ||
| 114 | try test__fixunssfsi(-0.99, 0); | ||
| 115 | |||
| 116 | try test__fixunssfsi(-1.0, 0); | ||
| 117 | try test__fixunssfsi(-1.5, 0); | ||
| 118 | try test__fixunssfsi(-1.99, 0); | ||
| 119 | try test__fixunssfsi(-2.0, 0); | ||
| 120 | try test__fixunssfsi(-2.01, 0); | ||
| 121 | |||
| 122 | try test__fixunssfsi(0x1.000000p+31, 0x80000000); | ||
| 123 | try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); | ||
| 124 | try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); | ||
| 125 | try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 126 | try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 127 | |||
| 128 | try test__fixunssfsi(-0x1.FFFFFEp+30, 0); | ||
| 129 | try test__fixunssfsi(-0x1.FFFFFCp+30, 0); | ||
| 130 | } | ||
| 131 | |||
| 132 | fn test__fixsfdi(a: f32, expected: i64) !void { | ||
| 133 | const x = __fixsfdi(a); | ||
| 134 | try testing.expect(x == expected); | ||
| 135 | } | ||
| 136 | |||
| 137 | fn test__fixunssfdi(a: f32, expected: u64) !void { | ||
| 138 | const x = __fixunssfdi(a); | ||
| 139 | try testing.expect(x == expected); | ||
| 140 | } | ||
| 141 | |||
| 142 | test "fixsfdi" { | ||
| 143 | try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); | ||
| 144 | |||
| 145 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 146 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 147 | |||
| 148 | try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 149 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 150 | try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 151 | |||
| 152 | try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 153 | try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 154 | try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); | ||
| 155 | try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); | ||
| 156 | |||
| 157 | try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); | ||
| 158 | try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 159 | try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 160 | |||
| 161 | try test__fixsfdi(-2.01, -2); | ||
| 162 | try test__fixsfdi(-2.0, -2); | ||
| 163 | try test__fixsfdi(-1.99, -1); | ||
| 164 | try test__fixsfdi(-1.0, -1); | ||
| 165 | try test__fixsfdi(-0.99, 0); | ||
| 166 | try test__fixsfdi(-0.5, 0); | ||
| 167 | try test__fixsfdi(-math.floatMin(f32), 0); | ||
| 168 | try test__fixsfdi(0.0, 0); | ||
| 169 | try test__fixsfdi(math.floatMin(f32), 0); | ||
| 170 | try test__fixsfdi(0.5, 0); | ||
| 171 | try test__fixsfdi(0.99, 0); | ||
| 172 | try test__fixsfdi(1.0, 1); | ||
| 173 | try test__fixsfdi(1.5, 1); | ||
| 174 | try test__fixsfdi(1.99, 1); | ||
| 175 | try test__fixsfdi(2.0, 2); | ||
| 176 | try test__fixsfdi(2.01, 2); | ||
| 177 | |||
| 178 | try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 179 | try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 180 | try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 181 | |||
| 182 | try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 183 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 184 | try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 185 | try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 186 | |||
| 187 | try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 188 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 189 | try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 190 | |||
| 191 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 192 | try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 193 | |||
| 194 | try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); | ||
| 195 | } | ||
| 196 | |||
| 197 | test "fixunssfdi" { | ||
| 198 | try test__fixunssfdi(0.0, 0); | ||
| 199 | |||
| 200 | try test__fixunssfdi(0.5, 0); | ||
| 201 | try test__fixunssfdi(0.99, 0); | ||
| 202 | try test__fixunssfdi(1.0, 1); | ||
| 203 | try test__fixunssfdi(1.5, 1); | ||
| 204 | try test__fixunssfdi(1.99, 1); | ||
| 205 | try test__fixunssfdi(2.0, 2); | ||
| 206 | try test__fixunssfdi(2.01, 2); | ||
| 207 | try test__fixunssfdi(-0.5, 0); | ||
| 208 | try test__fixunssfdi(-0.99, 0); | ||
| 209 | |||
| 210 | try test__fixunssfdi(-1.0, 0); | ||
| 211 | try test__fixunssfdi(-1.5, 0); | ||
| 212 | try test__fixunssfdi(-1.99, 0); | ||
| 213 | try test__fixunssfdi(-2.0, 0); | ||
| 214 | try test__fixunssfdi(-2.01, 0); | ||
| 215 | |||
| 216 | try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); | ||
| 217 | try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); | ||
| 218 | try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 219 | try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 220 | |||
| 221 | try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); | ||
| 222 | try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); | ||
| 223 | } | ||
| 224 | |||
| 225 | fn test__fixsfti(a: f32, expected: i128) !void { | ||
| 226 | const x = __fixsfti(a); | ||
| 227 | try testing.expect(x == expected); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn test__fixunssfti(a: f32, expected: u128) !void { | ||
| 231 | const x = __fixunssfti(a); | ||
| 232 | try testing.expect(x == expected); | ||
| 233 | } | ||
| 234 | |||
| 235 | test "fixsfti" { | ||
| 236 | try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); | ||
| 237 | |||
| 238 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 239 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 240 | |||
| 241 | try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 242 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); | ||
| 243 | try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); | ||
| 244 | try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); | ||
| 245 | try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); | ||
| 246 | try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); | ||
| 247 | |||
| 248 | try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 249 | try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 250 | try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); | ||
| 251 | try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); | ||
| 252 | |||
| 253 | try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); | ||
| 254 | try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 255 | try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 256 | |||
| 257 | try test__fixsfti(-0x1.000000p+31, -0x80000000); | ||
| 258 | try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); | ||
| 259 | try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 260 | try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 261 | |||
| 262 | try test__fixsfti(-2.01, -2); | ||
| 263 | try test__fixsfti(-2.0, -2); | ||
| 264 | try test__fixsfti(-1.99, -1); | ||
| 265 | try test__fixsfti(-1.0, -1); | ||
| 266 | try test__fixsfti(-0.99, 0); | ||
| 267 | try test__fixsfti(-0.5, 0); | ||
| 268 | try test__fixsfti(-math.floatMin(f32), 0); | ||
| 269 | try test__fixsfti(0.0, 0); | ||
| 270 | try test__fixsfti(math.floatMin(f32), 0); | ||
| 271 | try test__fixsfti(0.5, 0); | ||
| 272 | try test__fixsfti(0.99, 0); | ||
| 273 | try test__fixsfti(1.0, 1); | ||
| 274 | try test__fixsfti(1.5, 1); | ||
| 275 | try test__fixsfti(1.99, 1); | ||
| 276 | try test__fixsfti(2.0, 2); | ||
| 277 | try test__fixsfti(2.01, 2); | ||
| 278 | |||
| 279 | try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 280 | try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 281 | try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); | ||
| 282 | try test__fixsfti(0x1.000000p+31, 0x80000000); | ||
| 283 | |||
| 284 | try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 285 | try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 286 | try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); | ||
| 287 | |||
| 288 | try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); | ||
| 289 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); | ||
| 290 | try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 291 | try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); | ||
| 292 | |||
| 293 | try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); | ||
| 294 | try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); | ||
| 295 | try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 296 | try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 297 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 298 | try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 299 | |||
| 300 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 301 | try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 302 | |||
| 303 | try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); | ||
| 304 | } | ||
| 305 | |||
| 306 | test "fixunssfti" { | ||
| 307 | try test__fixunssfti(0.0, 0); | ||
| 308 | |||
| 309 | try test__fixunssfti(0.5, 0); | ||
| 310 | try test__fixunssfti(0.99, 0); | ||
| 311 | try test__fixunssfti(1.0, 1); | ||
| 312 | try test__fixunssfti(1.5, 1); | ||
| 313 | try test__fixunssfti(1.99, 1); | ||
| 314 | try test__fixunssfti(2.0, 2); | ||
| 315 | try test__fixunssfti(2.01, 2); | ||
| 316 | try test__fixunssfti(-0.5, 0); | ||
| 317 | try test__fixunssfti(-0.99, 0); | ||
| 318 | |||
| 319 | try test__fixunssfti(-1.0, 0); | ||
| 320 | try test__fixunssfti(-1.5, 0); | ||
| 321 | try test__fixunssfti(-1.99, 0); | ||
| 322 | try test__fixunssfti(-2.0, 0); | ||
| 323 | try test__fixunssfti(-2.01, 0); | ||
| 324 | |||
| 325 | try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); | ||
| 326 | try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); | ||
| 327 | try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 328 | try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 329 | try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); | ||
| 330 | try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); | ||
| 331 | try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); | ||
| 332 | try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); | ||
| 333 | |||
| 334 | try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); | ||
| 335 | try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); | ||
| 336 | try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); | ||
| 337 | try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); | ||
| 338 | try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); | ||
| 339 | try test__fixunssfti(math.inf(f32), math.maxInt(u128)); | ||
| 340 | } | ||
| 341 | |||
| 342 | fn test__fixdfsi(a: f64, expected: i32) !void { | ||
| 343 | const x = __fixdfsi(a); | ||
| 344 | try testing.expect(x == expected); | ||
| 345 | } | ||
| 346 | |||
| 347 | fn test__fixunsdfsi(a: f64, expected: u32) !void { | ||
| 348 | const x = __fixunsdfsi(a); | ||
| 349 | try testing.expect(x == expected); | ||
| 350 | } | ||
| 351 | |||
| 352 | test "fixdfsi" { | ||
| 353 | try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); | ||
| 354 | |||
| 355 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 356 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 357 | |||
| 358 | try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 359 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 360 | try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 361 | |||
| 362 | try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 363 | try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 364 | try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 365 | try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 366 | |||
| 367 | try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 368 | try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 369 | |||
| 370 | try test__fixdfsi(-0x1.000000p+31, -0x80000000); | ||
| 371 | try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 372 | try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 373 | |||
| 374 | try test__fixdfsi(-2.01, -2); | ||
| 375 | try test__fixdfsi(-2.0, -2); | ||
| 376 | try test__fixdfsi(-1.99, -1); | ||
| 377 | try test__fixdfsi(-1.0, -1); | ||
| 378 | try test__fixdfsi(-0.99, 0); | ||
| 379 | try test__fixdfsi(-0.5, 0); | ||
| 380 | try test__fixdfsi(-math.floatMin(f64), 0); | ||
| 381 | try test__fixdfsi(0.0, 0); | ||
| 382 | try test__fixdfsi(math.floatMin(f64), 0); | ||
| 383 | try test__fixdfsi(0.5, 0); | ||
| 384 | try test__fixdfsi(0.99, 0); | ||
| 385 | try test__fixdfsi(1.0, 1); | ||
| 386 | try test__fixdfsi(1.5, 1); | ||
| 387 | try test__fixdfsi(1.99, 1); | ||
| 388 | try test__fixdfsi(2.0, 2); | ||
| 389 | try test__fixdfsi(2.01, 2); | ||
| 390 | |||
| 391 | try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 392 | try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 393 | try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 394 | |||
| 395 | try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 396 | try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 397 | |||
| 398 | try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 399 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 400 | try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 401 | try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 402 | |||
| 403 | try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 404 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 405 | try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 406 | |||
| 407 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 408 | try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 409 | |||
| 410 | try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); | ||
| 411 | } | ||
| 412 | |||
| 413 | test "fixunsdfsi" { | ||
| 414 | try test__fixunsdfsi(0.0, 0); | ||
| 415 | |||
| 416 | try test__fixunsdfsi(0.5, 0); | ||
| 417 | try test__fixunsdfsi(0.99, 0); | ||
| 418 | try test__fixunsdfsi(1.0, 1); | ||
| 419 | try test__fixunsdfsi(1.5, 1); | ||
| 420 | try test__fixunsdfsi(1.99, 1); | ||
| 421 | try test__fixunsdfsi(2.0, 2); | ||
| 422 | try test__fixunsdfsi(2.01, 2); | ||
| 423 | try test__fixunsdfsi(-0.5, 0); | ||
| 424 | try test__fixunsdfsi(-0.99, 0); | ||
| 425 | try test__fixunsdfsi(-1.0, 0); | ||
| 426 | try test__fixunsdfsi(-1.5, 0); | ||
| 427 | try test__fixunsdfsi(-1.99, 0); | ||
| 428 | try test__fixunsdfsi(-2.0, 0); | ||
| 429 | try test__fixunsdfsi(-2.01, 0); | ||
| 430 | |||
| 431 | try test__fixunsdfsi(0x1.000000p+31, 0x80000000); | ||
| 432 | try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); | ||
| 433 | try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); | ||
| 434 | try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 435 | try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 436 | |||
| 437 | try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); | ||
| 438 | try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); | ||
| 439 | |||
| 440 | try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); | ||
| 441 | try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); | ||
| 442 | try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); | ||
| 443 | } | ||
| 444 | |||
| 445 | fn test__fixdfdi(a: f64, expected: i64) !void { | ||
| 446 | const x = __fixdfdi(a); | ||
| 447 | try testing.expect(x == expected); | ||
| 448 | } | ||
| 449 | |||
| 450 | fn test__fixunsdfdi(a: f64, expected: u64) !void { | ||
| 451 | const x = __fixunsdfdi(a); | ||
| 452 | try testing.expect(x == expected); | ||
| 453 | } | ||
| 454 | |||
| 455 | test "fixdfdi" { | ||
| 456 | try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); | ||
| 457 | |||
| 458 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 459 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 460 | |||
| 461 | try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 462 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 463 | try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 464 | |||
| 465 | try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 466 | try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 467 | try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 468 | try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 469 | |||
| 470 | try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 471 | try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 472 | |||
| 473 | try test__fixdfdi(-2.01, -2); | ||
| 474 | try test__fixdfdi(-2.0, -2); | ||
| 475 | try test__fixdfdi(-1.99, -1); | ||
| 476 | try test__fixdfdi(-1.0, -1); | ||
| 477 | try test__fixdfdi(-0.99, 0); | ||
| 478 | try test__fixdfdi(-0.5, 0); | ||
| 479 | try test__fixdfdi(-math.floatMin(f64), 0); | ||
| 480 | try test__fixdfdi(0.0, 0); | ||
| 481 | try test__fixdfdi(math.floatMin(f64), 0); | ||
| 482 | try test__fixdfdi(0.5, 0); | ||
| 483 | try test__fixdfdi(0.99, 0); | ||
| 484 | try test__fixdfdi(1.0, 1); | ||
| 485 | try test__fixdfdi(1.5, 1); | ||
| 486 | try test__fixdfdi(1.99, 1); | ||
| 487 | try test__fixdfdi(2.0, 2); | ||
| 488 | try test__fixdfdi(2.01, 2); | ||
| 489 | |||
| 490 | try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 491 | try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 492 | |||
| 493 | try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 494 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 495 | try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 496 | try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 497 | |||
| 498 | try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 499 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 500 | try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 501 | |||
| 502 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 503 | try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 504 | |||
| 505 | try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); | ||
| 506 | } | ||
| 507 | |||
| 508 | test "fixunsdfdi" { | ||
| 509 | try test__fixunsdfdi(0.0, 0); | ||
| 510 | try test__fixunsdfdi(0.5, 0); | ||
| 511 | try test__fixunsdfdi(0.99, 0); | ||
| 512 | try test__fixunsdfdi(1.0, 1); | ||
| 513 | try test__fixunsdfdi(1.5, 1); | ||
| 514 | try test__fixunsdfdi(1.99, 1); | ||
| 515 | try test__fixunsdfdi(2.0, 2); | ||
| 516 | try test__fixunsdfdi(2.01, 2); | ||
| 517 | try test__fixunsdfdi(-0.5, 0); | ||
| 518 | try test__fixunsdfdi(-0.99, 0); | ||
| 519 | try test__fixunsdfdi(-1.0, 0); | ||
| 520 | try test__fixunsdfdi(-1.5, 0); | ||
| 521 | try test__fixunsdfdi(-1.99, 0); | ||
| 522 | try test__fixunsdfdi(-2.0, 0); | ||
| 523 | try test__fixunsdfdi(-2.01, 0); | ||
| 524 | |||
| 525 | try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 526 | try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 527 | |||
| 528 | try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); | ||
| 529 | try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); | ||
| 530 | |||
| 531 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); | ||
| 532 | try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 533 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 534 | try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 535 | |||
| 536 | try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 537 | try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 538 | } | ||
| 539 | |||
| 540 | fn test__fixdfti(a: f64, expected: i128) !void { | ||
| 541 | const x = __fixdfti(a); | ||
| 542 | try testing.expect(x == expected); | ||
| 543 | } | ||
| 544 | |||
| 545 | fn test__fixunsdfti(a: f64, expected: u128) !void { | ||
| 546 | const x = __fixunsdfti(a); | ||
| 547 | try testing.expect(x == expected); | ||
| 548 | } | ||
| 549 | |||
| 550 | test "fixdfti" { | ||
| 551 | try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); | ||
| 552 | |||
| 553 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 554 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 555 | |||
| 556 | try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 557 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); | ||
| 558 | try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); | ||
| 559 | |||
| 560 | try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); | ||
| 561 | try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 562 | try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 563 | try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 564 | |||
| 565 | try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 566 | try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 567 | |||
| 568 | try test__fixdfti(-2.01, -2); | ||
| 569 | try test__fixdfti(-2.0, -2); | ||
| 570 | try test__fixdfti(-1.99, -1); | ||
| 571 | try test__fixdfti(-1.0, -1); | ||
| 572 | try test__fixdfti(-0.99, 0); | ||
| 573 | try test__fixdfti(-0.5, 0); | ||
| 574 | try test__fixdfti(-math.floatMin(f64), 0); | ||
| 575 | try test__fixdfti(0.0, 0); | ||
| 576 | try test__fixdfti(math.floatMin(f64), 0); | ||
| 577 | try test__fixdfti(0.5, 0); | ||
| 578 | try test__fixdfti(0.99, 0); | ||
| 579 | try test__fixdfti(1.0, 1); | ||
| 580 | try test__fixdfti(1.5, 1); | ||
| 581 | try test__fixdfti(1.99, 1); | ||
| 582 | try test__fixdfti(2.0, 2); | ||
| 583 | try test__fixdfti(2.01, 2); | ||
| 584 | |||
| 585 | try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 586 | try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 587 | |||
| 588 | try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 589 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 590 | try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 591 | try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); | ||
| 592 | |||
| 593 | try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 594 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 595 | try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 596 | |||
| 597 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 598 | try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 599 | |||
| 600 | try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); | ||
| 601 | } | ||
| 602 | |||
| 603 | test "fixunsdfti" { | ||
| 604 | try test__fixunsdfti(0.0, 0); | ||
| 605 | |||
| 606 | try test__fixunsdfti(0.5, 0); | ||
| 607 | try test__fixunsdfti(0.99, 0); | ||
| 608 | try test__fixunsdfti(1.0, 1); | ||
| 609 | try test__fixunsdfti(1.5, 1); | ||
| 610 | try test__fixunsdfti(1.99, 1); | ||
| 611 | try test__fixunsdfti(2.0, 2); | ||
| 612 | try test__fixunsdfti(2.01, 2); | ||
| 613 | try test__fixunsdfti(-0.5, 0); | ||
| 614 | try test__fixunsdfti(-0.99, 0); | ||
| 615 | try test__fixunsdfti(-1.0, 0); | ||
| 616 | try test__fixunsdfti(-1.5, 0); | ||
| 617 | try test__fixunsdfti(-1.99, 0); | ||
| 618 | try test__fixunsdfti(-2.0, 0); | ||
| 619 | try test__fixunsdfti(-2.01, 0); | ||
| 620 | |||
| 621 | try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 622 | try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 623 | |||
| 624 | try test__fixunsdfti(-0x1.FFFFFEp+62, 0); | ||
| 625 | try test__fixunsdfti(-0x1.FFFFFCp+62, 0); | ||
| 626 | |||
| 627 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); | ||
| 628 | try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 629 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 630 | try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 631 | |||
| 632 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); | ||
| 633 | try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); | ||
| 634 | try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 635 | try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 636 | try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 637 | |||
| 638 | try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 639 | try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 640 | } | ||
| 641 | |||
| 642 | fn test__fixtfsi(a: f128, expected: i32) !void { | ||
| 643 | const x = __fixtfsi(a); | ||
| 644 | try testing.expect(x == expected); | ||
| 645 | } | ||
| 646 | |||
| 647 | fn test__fixunstfsi(a: f128, expected: u32) !void { | ||
| 648 | const x = __fixunstfsi(a); | ||
| 649 | try testing.expect(x == expected); | ||
| 650 | } | ||
| 651 | |||
| 652 | test "fixtfsi" { | ||
| 653 | try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); | ||
| 654 | |||
| 655 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); | ||
| 656 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); | ||
| 657 | |||
| 658 | try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); | ||
| 659 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); | ||
| 660 | try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); | ||
| 661 | |||
| 662 | try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); | ||
| 663 | try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); | ||
| 664 | try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); | ||
| 665 | try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); | ||
| 666 | |||
| 667 | try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); | ||
| 668 | try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); | ||
| 669 | |||
| 670 | try test__fixtfsi(-0x1.000000p+31, -0x80000000); | ||
| 671 | try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 672 | try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 673 | try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 674 | |||
| 675 | try test__fixtfsi(-2.01, -2); | ||
| 676 | try test__fixtfsi(-2.0, -2); | ||
| 677 | try test__fixtfsi(-1.99, -1); | ||
| 678 | try test__fixtfsi(-1.0, -1); | ||
| 679 | try test__fixtfsi(-0.99, 0); | ||
| 680 | try test__fixtfsi(-0.5, 0); | ||
| 681 | try test__fixtfsi(-math.floatMin(f32), 0); | ||
| 682 | try test__fixtfsi(0.0, 0); | ||
| 683 | try test__fixtfsi(math.floatMin(f32), 0); | ||
| 684 | try test__fixtfsi(0.5, 0); | ||
| 685 | try test__fixtfsi(0.99, 0); | ||
| 686 | try test__fixtfsi(1.0, 1); | ||
| 687 | try test__fixtfsi(1.5, 1); | ||
| 688 | try test__fixtfsi(1.99, 1); | ||
| 689 | try test__fixtfsi(2.0, 2); | ||
| 690 | try test__fixtfsi(2.01, 2); | ||
| 691 | |||
| 692 | try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 693 | try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 694 | try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 695 | try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); | ||
| 696 | |||
| 697 | try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); | ||
| 698 | try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); | ||
| 699 | |||
| 700 | try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); | ||
| 701 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); | ||
| 702 | try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); | ||
| 703 | try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); | ||
| 704 | |||
| 705 | try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); | ||
| 706 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); | ||
| 707 | try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); | ||
| 708 | |||
| 709 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); | ||
| 710 | try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); | ||
| 711 | |||
| 712 | try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); | ||
| 713 | } | ||
| 714 | |||
| 715 | test "fixunstfsi" { | ||
| 716 | try test__fixunstfsi(math.inf(f128), 0xffffffff); | ||
| 717 | try test__fixunstfsi(0, 0x0); | ||
| 718 | try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); | ||
| 719 | try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); | ||
| 720 | try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); | ||
| 721 | try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); | ||
| 722 | try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); | ||
| 723 | try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); | ||
| 724 | |||
| 725 | try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); | ||
| 726 | } | ||
| 727 | |||
| 728 | fn test__fixtfdi(a: f128, expected: i64) !void { | ||
| 729 | const x = __fixtfdi(a); | ||
| 730 | try testing.expect(x == expected); | ||
| 731 | } | ||
| 732 | |||
| 733 | fn test__fixunstfdi(a: f128, expected: u64) !void { | ||
| 734 | const x = __fixunstfdi(a); | ||
| 735 | try testing.expect(x == expected); | ||
| 736 | } | ||
| 737 | |||
| 738 | test "fixtfdi" { | ||
| 739 | try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); | ||
| 740 | |||
| 741 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); | ||
| 742 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); | ||
| 743 | |||
| 744 | try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); | ||
| 745 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); | ||
| 746 | try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); | ||
| 747 | |||
| 748 | try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); | ||
| 749 | try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 750 | try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 751 | try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 752 | |||
| 753 | try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); | ||
| 754 | try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); | ||
| 755 | |||
| 756 | try test__fixtfdi(-0x1.000000p+31, -0x80000000); | ||
| 757 | try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); | ||
| 758 | try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); | ||
| 759 | try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); | ||
| 760 | |||
| 761 | try test__fixtfdi(-2.01, -2); | ||
| 762 | try test__fixtfdi(-2.0, -2); | ||
| 763 | try test__fixtfdi(-1.99, -1); | ||
| 764 | try test__fixtfdi(-1.0, -1); | ||
| 765 | try test__fixtfdi(-0.99, 0); | ||
| 766 | try test__fixtfdi(-0.5, 0); | ||
| 767 | try test__fixtfdi(-math.floatMin(f64), 0); | ||
| 768 | try test__fixtfdi(0.0, 0); | ||
| 769 | try test__fixtfdi(math.floatMin(f64), 0); | ||
| 770 | try test__fixtfdi(0.5, 0); | ||
| 771 | try test__fixtfdi(0.99, 0); | ||
| 772 | try test__fixtfdi(1.0, 1); | ||
| 773 | try test__fixtfdi(1.5, 1); | ||
| 774 | try test__fixtfdi(1.99, 1); | ||
| 775 | try test__fixtfdi(2.0, 2); | ||
| 776 | try test__fixtfdi(2.01, 2); | ||
| 777 | |||
| 778 | try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); | ||
| 779 | try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); | ||
| 780 | try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); | ||
| 781 | try test__fixtfdi(0x1.000000p+31, 0x80000000); | ||
| 782 | |||
| 783 | try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 784 | try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 785 | |||
| 786 | try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 787 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 788 | try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 789 | try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); | ||
| 790 | |||
| 791 | try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 792 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); | ||
| 793 | try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); | ||
| 794 | |||
| 795 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); | ||
| 796 | try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); | ||
| 797 | |||
| 798 | try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); | ||
| 799 | } | ||
| 800 | |||
| 801 | test "fixunstfdi" { | ||
| 802 | try test__fixunstfdi(0.0, 0); | ||
| 803 | |||
| 804 | try test__fixunstfdi(0.5, 0); | ||
| 805 | try test__fixunstfdi(0.99, 0); | ||
| 806 | try test__fixunstfdi(1.0, 1); | ||
| 807 | try test__fixunstfdi(1.5, 1); | ||
| 808 | try test__fixunstfdi(1.99, 1); | ||
| 809 | try test__fixunstfdi(2.0, 2); | ||
| 810 | try test__fixunstfdi(2.01, 2); | ||
| 811 | try test__fixunstfdi(-0.5, 0); | ||
| 812 | try test__fixunstfdi(-0.99, 0); | ||
| 813 | try test__fixunstfdi(-1.0, 0); | ||
| 814 | try test__fixunstfdi(-1.5, 0); | ||
| 815 | try test__fixunstfdi(-1.99, 0); | ||
| 816 | try test__fixunstfdi(-2.0, 0); | ||
| 817 | try test__fixunstfdi(-2.01, 0); | ||
| 818 | |||
| 819 | try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 820 | try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 821 | |||
| 822 | try test__fixunstfdi(-0x1.FFFFFEp+62, 0); | ||
| 823 | try test__fixunstfdi(-0x1.FFFFFCp+62, 0); | ||
| 824 | |||
| 825 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 826 | try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 827 | |||
| 828 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); | ||
| 829 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); | ||
| 830 | |||
| 831 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); | ||
| 832 | try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); | ||
| 833 | try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); | ||
| 834 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); | ||
| 835 | try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); | ||
| 836 | try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); | ||
| 837 | |||
| 838 | try test__fixunstfdi(-0x1.0000000000000000p+63, 0); | ||
| 839 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); | ||
| 840 | try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); | ||
| 841 | } | ||
| 842 | |||
| 843 | fn test__fixtfti(a: f128, expected: i128) !void { | ||
| 844 | const x = __fixtfti(a); | ||
| 845 | try testing.expect(x == expected); | ||
| 846 | } | ||
| 847 | |||
| 848 | fn test__fixunstfti(a: f128, expected: u128) !void { | ||
| 849 | const x = __fixunstfti(a); | ||
| 850 | try testing.expect(x == expected); | ||
| 851 | } | ||
| 852 | |||
| 853 | test "fixtfti" { | ||
| 854 | try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); | ||
| 855 | |||
| 856 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); | ||
| 857 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); | ||
| 858 | |||
| 859 | try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); | ||
| 860 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); | ||
| 861 | try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); | ||
| 862 | |||
| 863 | try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); | ||
| 864 | try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); | ||
| 865 | try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); | ||
| 866 | try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); | ||
| 867 | |||
| 868 | try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); | ||
| 869 | try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); | ||
| 870 | |||
| 871 | try test__fixtfti(-2.01, -2); | ||
| 872 | try test__fixtfti(-2.0, -2); | ||
| 873 | try test__fixtfti(-1.99, -1); | ||
| 874 | try test__fixtfti(-1.0, -1); | ||
| 875 | try test__fixtfti(-0.99, 0); | ||
| 876 | try test__fixtfti(-0.5, 0); | ||
| 877 | try test__fixtfti(-math.floatMin(f128), 0); | ||
| 878 | try test__fixtfti(0.0, 0); | ||
| 879 | try test__fixtfti(math.floatMin(f128), 0); | ||
| 880 | try test__fixtfti(0.5, 0); | ||
| 881 | try test__fixtfti(0.99, 0); | ||
| 882 | try test__fixtfti(1.0, 1); | ||
| 883 | try test__fixtfti(1.5, 1); | ||
| 884 | try test__fixtfti(1.99, 1); | ||
| 885 | try test__fixtfti(2.0, 2); | ||
| 886 | try test__fixtfti(2.01, 2); | ||
| 887 | |||
| 888 | try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); | ||
| 889 | try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); | ||
| 890 | |||
| 891 | try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); | ||
| 892 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); | ||
| 893 | try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); | ||
| 894 | try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); | ||
| 895 | |||
| 896 | try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); | ||
| 897 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); | ||
| 898 | try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 899 | |||
| 900 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 901 | try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); | ||
| 902 | |||
| 903 | try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); | ||
| 904 | } | ||
| 905 | |||
| 906 | test "fixunstfti" { | ||
| 907 | try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); | ||
| 908 | |||
| 909 | try test__fixunstfti(0.0, 0); | ||
| 910 | |||
| 911 | try test__fixunstfti(0.5, 0); | ||
| 912 | try test__fixunstfti(0.99, 0); | ||
| 913 | try test__fixunstfti(1.0, 1); | ||
| 914 | try test__fixunstfti(1.5, 1); | ||
| 915 | try test__fixunstfti(1.99, 1); | ||
| 916 | try test__fixunstfti(2.0, 2); | ||
| 917 | try test__fixunstfti(2.01, 2); | ||
| 918 | try test__fixunstfti(-0.01, 0); | ||
| 919 | try test__fixunstfti(-0.99, 0); | ||
| 920 | |||
| 921 | try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); | ||
| 922 | |||
| 923 | try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); | ||
| 924 | try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); | ||
| 925 | try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); | ||
| 926 | try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); | ||
| 927 | } | ||
| 928 | |||
| 929 | fn test__fixunshfti(a: f16, expected: u128) !void { | ||
| 930 | const x = fixXfYi(u128, a); | ||
| 931 | try testing.expect(x == expected); | ||
| 932 | } | ||
| 933 | |||
| 934 | test "fixXfYi for f16" { | ||
| 935 | try test__fixunshfti(math.inf(f16), math.maxInt(u128)); | ||
| 936 | try test__fixunshfti(math.floatMax(f16), 65504); | ||
| 937 | } | ||
| 938 | |||
| 939 | fn test__fixunsxfti(a: f80, expected: u128) !void { | ||
| 940 | const x = fixXfYi(u128, a); | ||
| 941 | try testing.expect(x == expected); | ||
| 942 | } | ||
| 943 | |||
| 944 | test "fixXfYi for f80" { | ||
| 945 | try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); | ||
| 946 | try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); | ||
| 947 | try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); | ||
| 948 | } | ||
lib/compiler_rt/floatdidf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatdidf, .{ .name = "__floatdidf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatdidf(a: i64) callconv(.C) f64 { | ||
| 15 | return intToFloat(f64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_l2d(a: i64) callconv(.AAPCS) f64 { | ||
| 19 | return intToFloat(f64, a); | ||
| 20 | } | ||
lib/compiler_rt/floatdihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatdihf, .{ .name = "__floatdihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatdihf(a: i64) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floatdisf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatdisf, .{ .name = "__floatdisf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatdisf(a: i64) callconv(.C) f32 { | ||
| 15 | return intToFloat(f32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_l2f(a: i64) callconv(.AAPCS) f32 { | ||
| 19 | return intToFloat(f32, a); | ||
| 20 | } | ||
lib/compiler_rt/floatditf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__floatdikf, .{ .name = "__floatdikf", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatditf, .{ .name = "__floatditf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatditf(a: i64) callconv(.C) f128 { | ||
| 15 | return intToFloat(f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __floatdikf(a: i64) callconv(.C) f128 { | ||
| 19 | return intToFloat(f128, a); | ||
| 20 | } | ||
lib/compiler_rt/floatdixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatdixf, .{ .name = "__floatdixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatdixf(a: i64) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/floatsidf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatsidf, .{ .name = "__floatsidf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatsidf(a: i32) callconv(.C) f64 { | ||
| 15 | return intToFloat(f64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_i2d(a: i32) callconv(.AAPCS) f64 { | ||
| 19 | return intToFloat(f64, a); | ||
| 20 | } | ||
lib/compiler_rt/floatsihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatsihf, .{ .name = "__floatsihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatsihf(a: i32) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floatsisf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatsisf, .{ .name = "__floatsisf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatsisf(a: i32) callconv(.C) f32 { | ||
| 15 | return intToFloat(f32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_i2f(a: i32) callconv(.AAPCS) f32 { | ||
| 19 | return intToFloat(f32, a); | ||
| 20 | } | ||
lib/compiler_rt/floatsitf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__floatsikf, .{ .name = "__floatsikf", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatsitf, .{ .name = "__floatsitf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatsitf(a: i32) callconv(.C) f128 { | ||
| 15 | return intToFloat(f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __floatsikf(a: i32) callconv(.C) f128 { | ||
| 19 | return intToFloat(f128, a); | ||
| 20 | } | ||
lib/compiler_rt/floatsixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatsixf, .{ .name = "__floatsixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatsixf(a: i32) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/floattidf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floattidf, .{ .name = "__floattidf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floattidf(a: i128) callconv(.C) f64 { | ||
| 11 | return intToFloat(f64, a); | ||
| 12 | } | ||
lib/compiler_rt/floattihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floattihf, .{ .name = "__floattihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floattihf(a: i128) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floattisf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floattisf, .{ .name = "__floattisf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floattisf(a: i128) callconv(.C) f32 { | ||
| 11 | return intToFloat(f32, a); | ||
| 12 | } | ||
lib/compiler_rt/floattitf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floattitf, .{ .name = "__floattitf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floattitf(a: i128) callconv(.C) f128 { | ||
| 11 | return intToFloat(f128, a); | ||
| 12 | } | ||
lib/compiler_rt/floattixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floattixf, .{ .name = "__floattixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floattixf(a: i128) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/floatundidf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatundidf, .{ .name = "__floatundidf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatundidf(a: u64) callconv(.C) f64 { | ||
| 15 | return intToFloat(f64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_ul2d(a: u64) callconv(.AAPCS) f64 { | ||
| 19 | return intToFloat(f64, a); | ||
| 20 | } | ||
lib/compiler_rt/floatundihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatundihf, .{ .name = "__floatundihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatundihf(a: u64) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floatundisf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatundisf, .{ .name = "__floatundisf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatundisf(a: u64) callconv(.C) f32 { | ||
| 15 | return intToFloat(f32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_ul2f(a: u64) callconv(.AAPCS) f32 { | ||
| 19 | return intToFloat(f32, a); | ||
| 20 | } | ||
lib/compiler_rt/floatunditf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__floatundikf, .{ .name = "__floatundikf", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatunditf, .{ .name = "__floatunditf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatunditf(a: u64) callconv(.C) f128 { | ||
| 15 | return intToFloat(f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __floatundikf(a: u64) callconv(.C) f128 { | ||
| 19 | return intToFloat(f128, a); | ||
| 20 | } | ||
lib/compiler_rt/floatundixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatundixf, .{ .name = "__floatundixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatundixf(a: u64) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/floatunsidf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatunsidf(a: u32) callconv(.C) f64 { | ||
| 15 | return intToFloat(f64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_ui2d(a: u32) callconv(.AAPCS) f64 { | ||
| 19 | return intToFloat(f64, a); | ||
| 20 | } | ||
lib/compiler_rt/floatunsihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatunsihf, .{ .name = "__floatunsihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatunsihf(a: u32) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floatunsisf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatunsisf(a: u32) callconv(.C) f32 { | ||
| 15 | return intToFloat(f32, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_ui2f(a: u32) callconv(.AAPCS) f32 { | ||
| 19 | return intToFloat(f32, a); | ||
| 20 | } | ||
lib/compiler_rt/floatunsitf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatunsitf(a: u32) callconv(.C) f128 { | ||
| 15 | return intToFloat(f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __floatunsikf(a: u32) callconv(.C) f128 { | ||
| 19 | return intToFloat(f128, a); | ||
| 20 | } | ||
lib/compiler_rt/floatunsixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatunsixf(a: u32) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/floatuntidf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatuntidf(a: u128) callconv(.C) f64 { | ||
| 11 | return intToFloat(f64, a); | ||
| 12 | } | ||
lib/compiler_rt/floatuntihf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatuntihf, .{ .name = "__floatuntihf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatuntihf(a: u128) callconv(.C) f16 { | ||
| 11 | return intToFloat(f16, a); | ||
| 12 | } | ||
lib/compiler_rt/floatuntisf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __floatuntisf(a: u128) callconv(.C) f32 { | ||
| 11 | return intToFloat(f32, a); | ||
| 12 | } | ||
lib/compiler_rt/floatuntitf.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__floatuntikf, .{ .name = "__floatuntikf", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __floatuntitf(a: u128) callconv(.C) f128 { | ||
| 15 | return intToFloat(f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __floatuntikf(a: u128) callconv(.C) f128 { | ||
| 19 | return intToFloat(f128, a); | ||
| 20 | } | ||
lib/compiler_rt/floatuntixf.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const intToFloat = @import("./int_to_float.zig").intToFloat; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __floatuntixf(a: u128) callconv(.C) f80 { | ||
| 11 | return intToFloat(f80, a); | ||
| 12 | } | ||
lib/compiler_rt/gedf2.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = common.linkage }); | ||
| 11 | @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = common.linkage }); | ||
| 12 | } else { | ||
| 13 | @export(__gedf2, .{ .name = "__gedf2", .linkage = common.linkage }); | ||
| 14 | @export(__gtdf2, .{ .name = "__gtdf2", .linkage = common.linkage }); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | /// "These functions return a value greater than or equal to zero if neither | ||
| 19 | /// argument is NaN, and a is greater than or equal to b." | ||
| 20 | fn __gedf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 21 | return @enumToInt(comparef.cmpf2(f64, comparef.GE, a, b)); | ||
| 22 | } | ||
| 23 | |||
| 24 | /// "These functions return a value greater than zero if neither argument is NaN, | ||
| 25 | /// and a is strictly greater than b." | ||
| 26 | fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 27 | return __gedf2(a, b); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 31 | return comparef.cmpf2(f64, comparef.GE, a, b) != .Less; | ||
| 32 | } | ||
| 33 | |||
| 34 | fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 35 | return @boolToInt(comparef.cmpf2(f64, comparef.GE, a, b) == .Greater); | ||
| 36 | } | ||
lib/compiler_rt/gesf2.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = common.linkage }); | ||
| 11 | @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = common.linkage }); | ||
| 12 | } else { | ||
| 13 | @export(__gesf2, .{ .name = "__gesf2", .linkage = common.linkage }); | ||
| 14 | @export(__gtsf2, .{ .name = "__gtsf2", .linkage = common.linkage }); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | /// "These functions return a value greater than or equal to zero if neither | ||
| 19 | /// argument is NaN, and a is greater than or equal to b." | ||
| 20 | fn __gesf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 21 | return @enumToInt(comparef.cmpf2(f32, comparef.GE, a, b)); | ||
| 22 | } | ||
| 23 | |||
| 24 | /// "These functions return a value greater than zero if neither argument is NaN, | ||
| 25 | /// and a is strictly greater than b." | ||
| 26 | fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 27 | return __gesf2(a, b); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 31 | return comparef.cmpf2(f32, comparef.GE, a, b) != .Less; | ||
| 32 | } | ||
| 33 | |||
| 34 | fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 35 | return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Greater); | ||
| 36 | } | ||
lib/compiler_rt/getf2.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | ///! The quoted behavior definitions are from | ||
| 2 | ///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | if (common.want_ppc_abi) { | ||
| 10 | @export(__gekf2, .{ .name = "__gekf2", .linkage = common.linkage }); | ||
| 11 | @export(__gtkf2, .{ .name = "__gtkf2", .linkage = common.linkage }); | ||
| 12 | } else { | ||
| 13 | @export(__getf2, .{ .name = "__getf2", .linkage = common.linkage }); | ||
| 14 | @export(__gttf2, .{ .name = "__gttf2", .linkage = common.linkage }); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | /// "These functions return a value greater than or equal to zero if neither | ||
| 19 | /// argument is NaN, and a is greater than or equal to b." | ||
| 20 | fn __getf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 21 | return @enumToInt(comparef.cmpf2(f128, comparef.GE, a, b)); | ||
| 22 | } | ||
| 23 | |||
| 24 | /// "These functions return a value greater than zero if neither argument is NaN, | ||
| 25 | /// and a is strictly greater than b." | ||
| 26 | fn __gttf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 27 | return __getf2(a, b); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn __gekf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 31 | return __getf2(a, b); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn __gtkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 35 | return __getf2(a, b); | ||
| 36 | } | ||
lib/compiler_rt/gexf2.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__gexf2, .{ .name = "__gexf2", .linkage = common.linkage }); | ||
| 8 | @export(__gtxf2, .{ .name = "__gtxf2", .linkage = common.linkage }); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn __gexf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 12 | return @enumToInt(comparef.cmp_f80(comparef.GE, a, b)); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn __gtxf2(a: f80, b: f80) callconv(.C) i32 { | ||
| 16 | return __gexf2(a, b); | ||
| 17 | } | ||
lib/compiler_rt/int_to_float.zig created+58| ... | @@ -0,0 +1,58 @@ | ||
| 1 | const Int = @import("std").meta.Int; | ||
| 2 | const math = @import("std").math; | ||
| 3 | |||
| 4 | pub fn intToFloat(comptime T: type, x: anytype) T { | ||
| 5 | if (x == 0) return 0; | ||
| 6 | |||
| 7 | // Various constants whose values follow from the type parameters. | ||
| 8 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 9 | const Z = Int(.unsigned, @bitSizeOf(@TypeOf(x))); | ||
| 10 | const uT = Int(.unsigned, @bitSizeOf(T)); | ||
| 11 | const inf = math.inf(T); | ||
| 12 | const float_bits = @bitSizeOf(T); | ||
| 13 | const int_bits = @bitSizeOf(@TypeOf(x)); | ||
| 14 | const exp_bits = math.floatExponentBits(T); | ||
| 15 | const fractional_bits = math.floatFractionalBits(T); | ||
| 16 | const exp_bias = math.maxInt(Int(.unsigned, exp_bits - 1)); | ||
| 17 | const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; | ||
| 18 | const max_exp = exp_bias; | ||
| 19 | |||
| 20 | // Sign | ||
| 21 | var abs_val = math.absCast(x); | ||
| 22 | const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; | ||
| 23 | var result: uT = sign_bit; | ||
| 24 | |||
| 25 | // Compute significand | ||
| 26 | var exp = int_bits - @clz(Z, abs_val) - 1; | ||
| 27 | if (int_bits <= fractional_bits or exp <= fractional_bits) { | ||
| 28 | const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); | ||
| 29 | |||
| 30 | // Shift up result to line up with the significand - no rounding required | ||
| 31 | result = (@intCast(uT, abs_val) << shift_amt); | ||
| 32 | result ^= implicit_bit; // Remove implicit integer bit | ||
| 33 | } else { | ||
| 34 | var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); | ||
| 35 | const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; | ||
| 36 | |||
| 37 | // Shift down result and remove implicit integer bit | ||
| 38 | result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); | ||
| 39 | |||
| 40 | // Round result, including round-to-even for exact ties | ||
| 41 | result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); | ||
| 42 | } | ||
| 43 | |||
| 44 | // Compute exponent | ||
| 45 | if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity | ||
| 46 | return @bitCast(T, sign_bit | @bitCast(uT, inf)); | ||
| 47 | |||
| 48 | result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); | ||
| 49 | |||
| 50 | // If the result included a carry, we need to restore the explicit integer bit | ||
| 51 | if (T == f80) result |= 1 << fractional_bits; | ||
| 52 | |||
| 53 | return @bitCast(T, sign_bit | result); | ||
| 54 | } | ||
| 55 | |||
| 56 | test { | ||
| 57 | _ = @import("floatXiYf_test.zig"); | ||
| 58 | } | ||
lib/compiler_rt/mulXf3.zig deleted-368| ... | @@ -1,368 +0,0 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc | ||
| 4 | |||
| 5 | const std = @import("std"); | ||
| 6 | const math = std.math; | ||
| 7 | const builtin = @import("builtin"); | ||
| 8 | const arch = builtin.cpu.arch; | ||
| 9 | const is_test = builtin.is_test; | ||
| 10 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 11 | pub const panic = @import("common.zig").panic; | ||
| 12 | |||
| 13 | comptime { | ||
| 14 | @export(__mulsf3, .{ .name = "__mulsf3", .linkage = linkage }); | ||
| 15 | @export(__muldf3, .{ .name = "__muldf3", .linkage = linkage }); | ||
| 16 | @export(__mulxf3, .{ .name = "__mulxf3", .linkage = linkage }); | ||
| 17 | @export(__multf3, .{ .name = "__multf3", .linkage = linkage }); | ||
| 18 | |||
| 19 | if (!is_test) { | ||
| 20 | if (arch.isARM() or arch.isThumb()) { | ||
| 21 | @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = linkage }); | ||
| 22 | @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = linkage }); | ||
| 23 | } | ||
| 24 | |||
| 25 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 26 | @export(__mulkf3, .{ .name = "__mulkf3", .linkage = linkage }); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | pub fn __mulkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 32 | return @call(.{ .modifier = .always_inline }, __multf3, .{ a, b }); | ||
| 33 | } | ||
| 34 | pub fn __multf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 35 | return mulXf3(f128, a, b); | ||
| 36 | } | ||
| 37 | pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 38 | return mulXf3(f80, a, b); | ||
| 39 | } | ||
| 40 | pub fn __muldf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 41 | return mulXf3(f64, a, b); | ||
| 42 | } | ||
| 43 | pub fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 44 | return mulXf3(f32, a, b); | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn __aeabi_fmul(a: f32, b: f32) callconv(.C) f32 { | ||
| 48 | @setRuntimeSafety(false); | ||
| 49 | return @call(.{ .modifier = .always_inline }, __mulsf3, .{ a, b }); | ||
| 50 | } | ||
| 51 | |||
| 52 | pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { | ||
| 53 | @setRuntimeSafety(false); | ||
| 54 | return @call(.{ .modifier = .always_inline }, __muldf3, .{ a, b }); | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn mulXf3(comptime T: type, a: T, b: T) T { | ||
| 58 | @setRuntimeSafety(builtin.is_test); | ||
| 59 | const typeWidth = @typeInfo(T).Float.bits; | ||
| 60 | const significandBits = math.floatMantissaBits(T); | ||
| 61 | const fractionalBits = math.floatFractionalBits(T); | ||
| 62 | const exponentBits = math.floatExponentBits(T); | ||
| 63 | |||
| 64 | const Z = std.meta.Int(.unsigned, typeWidth); | ||
| 65 | |||
| 66 | // ZSignificand is large enough to contain the significand, including an explicit integer bit | ||
| 67 | const ZSignificand = PowerOfTwoSignificandZ(T); | ||
| 68 | const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; | ||
| 69 | |||
| 70 | const roundBit = (1 << (ZSignificandBits - 1)); | ||
| 71 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | ||
| 72 | const maxExponent = ((1 << exponentBits) - 1); | ||
| 73 | const exponentBias = (maxExponent >> 1); | ||
| 74 | |||
| 75 | const integerBit = (@as(ZSignificand, 1) << fractionalBits); | ||
| 76 | const quietBit = integerBit >> 1; | ||
| 77 | const significandMask = (@as(Z, 1) << significandBits) - 1; | ||
| 78 | |||
| 79 | const absMask = signBit - 1; | ||
| 80 | const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; | ||
| 81 | const infRep = @bitCast(Z, math.inf(T)); | ||
| 82 | const minNormalRep = @bitCast(Z, math.floatMin(T)); | ||
| 83 | |||
| 84 | const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); | ||
| 85 | const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); | ||
| 86 | const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; | ||
| 87 | |||
| 88 | var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); | ||
| 89 | var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); | ||
| 90 | var scale: i32 = 0; | ||
| 91 | |||
| 92 | // Detect if a or b is zero, denormal, infinity, or NaN. | ||
| 93 | if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { | ||
| 94 | const aAbs: Z = @bitCast(Z, a) & absMask; | ||
| 95 | const bAbs: Z = @bitCast(Z, b) & absMask; | ||
| 96 | |||
| 97 | // NaN * anything = qNaN | ||
| 98 | if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); | ||
| 99 | // anything * NaN = qNaN | ||
| 100 | if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); | ||
| 101 | |||
| 102 | if (aAbs == infRep) { | ||
| 103 | // infinity * non-zero = +/- infinity | ||
| 104 | if (bAbs != 0) { | ||
| 105 | return @bitCast(T, aAbs | productSign); | ||
| 106 | } else { | ||
| 107 | // infinity * zero = NaN | ||
| 108 | return @bitCast(T, qnanRep); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | if (bAbs == infRep) { | ||
| 113 | //? non-zero * infinity = +/- infinity | ||
| 114 | if (aAbs != 0) { | ||
| 115 | return @bitCast(T, bAbs | productSign); | ||
| 116 | } else { | ||
| 117 | // zero * infinity = NaN | ||
| 118 | return @bitCast(T, qnanRep); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | // zero * anything = +/- zero | ||
| 123 | if (aAbs == 0) return @bitCast(T, productSign); | ||
| 124 | // anything * zero = +/- zero | ||
| 125 | if (bAbs == 0) return @bitCast(T, productSign); | ||
| 126 | |||
| 127 | // one or both of a or b is denormal, the other (if applicable) is a | ||
| 128 | // normal number. Renormalize one or both of a and b, and set scale to | ||
| 129 | // include the necessary exponent adjustment. | ||
| 130 | if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); | ||
| 131 | if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); | ||
| 132 | } | ||
| 133 | |||
| 134 | // Or in the implicit significand bit. (If we fell through from the | ||
| 135 | // denormal path it was already set by normalize( ), but setting it twice | ||
| 136 | // won't hurt anything.) | ||
| 137 | aSignificand |= integerBit; | ||
| 138 | bSignificand |= integerBit; | ||
| 139 | |||
| 140 | // Get the significand of a*b. Before multiplying the significands, shift | ||
| 141 | // one of them left to left-align it in the field. Thus, the product will | ||
| 142 | // have (exponentBits + 2) integral digits, all but two of which must be | ||
| 143 | // zero. Normalizing this result is just a conditional left-shift by one | ||
| 144 | // and bumping the exponent accordingly. | ||
| 145 | var productHi: ZSignificand = undefined; | ||
| 146 | var productLo: ZSignificand = undefined; | ||
| 147 | const left_align_shift = ZSignificandBits - fractionalBits - 1; | ||
| 148 | wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); | ||
| 149 | |||
| 150 | var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; | ||
| 151 | |||
| 152 | // Normalize the significand, adjust exponent if needed. | ||
| 153 | if ((productHi & integerBit) != 0) { | ||
| 154 | productExponent +%= 1; | ||
| 155 | } else { | ||
| 156 | productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); | ||
| 157 | productLo = productLo << 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | // If we have overflowed the type, return +/- infinity. | ||
| 161 | if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); | ||
| 162 | |||
| 163 | var result: Z = undefined; | ||
| 164 | if (productExponent <= 0) { | ||
| 165 | // Result is denormal before rounding | ||
| 166 | // | ||
| 167 | // If the result is so small that it just underflows to zero, return | ||
| 168 | // a zero of the appropriate sign. Mathematically there is no need to | ||
| 169 | // handle this case separately, but we make it a special case to | ||
| 170 | // simplify the shift logic. | ||
| 171 | const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); | ||
| 172 | if (shift >= ZSignificandBits) return @bitCast(T, productSign); | ||
| 173 | |||
| 174 | // Otherwise, shift the significand of the result so that the round | ||
| 175 | // bit is the high bit of productLo. | ||
| 176 | const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); | ||
| 177 | productLo |= @boolToInt(sticky); | ||
| 178 | result = productHi; | ||
| 179 | |||
| 180 | // We include the integer bit so that rounding will carry to the exponent, | ||
| 181 | // but it will be removed later if the result is still denormal | ||
| 182 | if (significandBits != fractionalBits) result |= integerBit; | ||
| 183 | } else { | ||
| 184 | // Result is normal before rounding; insert the exponent. | ||
| 185 | result = productHi & significandMask; | ||
| 186 | result |= @intCast(Z, productExponent) << significandBits; | ||
| 187 | } | ||
| 188 | |||
| 189 | // Final rounding. The final result may overflow to infinity, or underflow | ||
| 190 | // to zero, but those are the correct results in those cases. We use the | ||
| 191 | // default IEEE-754 round-to-nearest, ties-to-even rounding mode. | ||
| 192 | if (productLo > roundBit) result +%= 1; | ||
| 193 | if (productLo == roundBit) result +%= result & 1; | ||
| 194 | |||
| 195 | // Restore any explicit integer bit, if it was rounded off | ||
| 196 | if (significandBits != fractionalBits) { | ||
| 197 | if ((result >> significandBits) != 0) { | ||
| 198 | result |= integerBit; | ||
| 199 | } else { | ||
| 200 | result &= ~integerBit; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | // Insert the sign of the result: | ||
| 205 | result |= productSign; | ||
| 206 | |||
| 207 | return @bitCast(T, result); | ||
| 208 | } | ||
| 209 | |||
| 210 | fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | ||
| 211 | @setRuntimeSafety(builtin.is_test); | ||
| 212 | switch (Z) { | ||
| 213 | u16 => { | ||
| 214 | // 16x16 --> 32 bit multiply | ||
| 215 | const product = @as(u32, a) * @as(u32, b); | ||
| 216 | hi.* = @intCast(u16, product >> 16); | ||
| 217 | lo.* = @truncate(u16, product); | ||
| 218 | }, | ||
| 219 | u32 => { | ||
| 220 | // 32x32 --> 64 bit multiply | ||
| 221 | const product = @as(u64, a) * @as(u64, b); | ||
| 222 | hi.* = @intCast(u32, product >> 32); | ||
| 223 | lo.* = @truncate(u32, product); | ||
| 224 | }, | ||
| 225 | u64 => { | ||
| 226 | const S = struct { | ||
| 227 | fn loWord(x: u64) u64 { | ||
| 228 | return @truncate(u32, x); | ||
| 229 | } | ||
| 230 | fn hiWord(x: u64) u64 { | ||
| 231 | return @intCast(u32, x >> 32); | ||
| 232 | } | ||
| 233 | }; | ||
| 234 | // 64x64 -> 128 wide multiply for platforms that don't have such an operation; | ||
| 235 | // many 64-bit platforms have this operation, but they tend to have hardware | ||
| 236 | // floating-point, so we don't bother with a special case for them here. | ||
| 237 | // Each of the component 32x32 -> 64 products | ||
| 238 | const plolo: u64 = S.loWord(a) * S.loWord(b); | ||
| 239 | const plohi: u64 = S.loWord(a) * S.hiWord(b); | ||
| 240 | const philo: u64 = S.hiWord(a) * S.loWord(b); | ||
| 241 | const phihi: u64 = S.hiWord(a) * S.hiWord(b); | ||
| 242 | // Sum terms that contribute to lo in a way that allows us to get the carry | ||
| 243 | const r0: u64 = S.loWord(plolo); | ||
| 244 | const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); | ||
| 245 | lo.* = r0 +% (r1 << 32); | ||
| 246 | // Sum terms contributing to hi with the carry from lo | ||
| 247 | hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; | ||
| 248 | }, | ||
| 249 | u128 => { | ||
| 250 | const Word_LoMask = @as(u64, 0x00000000ffffffff); | ||
| 251 | const Word_HiMask = @as(u64, 0xffffffff00000000); | ||
| 252 | const Word_FullMask = @as(u64, 0xffffffffffffffff); | ||
| 253 | const S = struct { | ||
| 254 | fn Word_1(x: u128) u64 { | ||
| 255 | return @truncate(u32, x >> 96); | ||
| 256 | } | ||
| 257 | fn Word_2(x: u128) u64 { | ||
| 258 | return @truncate(u32, x >> 64); | ||
| 259 | } | ||
| 260 | fn Word_3(x: u128) u64 { | ||
| 261 | return @truncate(u32, x >> 32); | ||
| 262 | } | ||
| 263 | fn Word_4(x: u128) u64 { | ||
| 264 | return @truncate(u32, x); | ||
| 265 | } | ||
| 266 | }; | ||
| 267 | // 128x128 -> 256 wide multiply for platforms that don't have such an operation; | ||
| 268 | // many 64-bit platforms have this operation, but they tend to have hardware | ||
| 269 | // floating-point, so we don't bother with a special case for them here. | ||
| 270 | |||
| 271 | const product11: u64 = S.Word_1(a) * S.Word_1(b); | ||
| 272 | const product12: u64 = S.Word_1(a) * S.Word_2(b); | ||
| 273 | const product13: u64 = S.Word_1(a) * S.Word_3(b); | ||
| 274 | const product14: u64 = S.Word_1(a) * S.Word_4(b); | ||
| 275 | const product21: u64 = S.Word_2(a) * S.Word_1(b); | ||
| 276 | const product22: u64 = S.Word_2(a) * S.Word_2(b); | ||
| 277 | const product23: u64 = S.Word_2(a) * S.Word_3(b); | ||
| 278 | const product24: u64 = S.Word_2(a) * S.Word_4(b); | ||
| 279 | const product31: u64 = S.Word_3(a) * S.Word_1(b); | ||
| 280 | const product32: u64 = S.Word_3(a) * S.Word_2(b); | ||
| 281 | const product33: u64 = S.Word_3(a) * S.Word_3(b); | ||
| 282 | const product34: u64 = S.Word_3(a) * S.Word_4(b); | ||
| 283 | const product41: u64 = S.Word_4(a) * S.Word_1(b); | ||
| 284 | const product42: u64 = S.Word_4(a) * S.Word_2(b); | ||
| 285 | const product43: u64 = S.Word_4(a) * S.Word_3(b); | ||
| 286 | const product44: u64 = S.Word_4(a) * S.Word_4(b); | ||
| 287 | |||
| 288 | const sum0: u128 = @as(u128, product44); | ||
| 289 | const sum1: u128 = @as(u128, product34) +% | ||
| 290 | @as(u128, product43); | ||
| 291 | const sum2: u128 = @as(u128, product24) +% | ||
| 292 | @as(u128, product33) +% | ||
| 293 | @as(u128, product42); | ||
| 294 | const sum3: u128 = @as(u128, product14) +% | ||
| 295 | @as(u128, product23) +% | ||
| 296 | @as(u128, product32) +% | ||
| 297 | @as(u128, product41); | ||
| 298 | const sum4: u128 = @as(u128, product13) +% | ||
| 299 | @as(u128, product22) +% | ||
| 300 | @as(u128, product31); | ||
| 301 | const sum5: u128 = @as(u128, product12) +% | ||
| 302 | @as(u128, product21); | ||
| 303 | const sum6: u128 = @as(u128, product11); | ||
| 304 | |||
| 305 | const r0: u128 = (sum0 & Word_FullMask) +% | ||
| 306 | ((sum1 & Word_LoMask) << 32); | ||
| 307 | const r1: u128 = (sum0 >> 64) +% | ||
| 308 | ((sum1 >> 32) & Word_FullMask) +% | ||
| 309 | (sum2 & Word_FullMask) +% | ||
| 310 | ((sum3 << 32) & Word_HiMask); | ||
| 311 | |||
| 312 | lo.* = r0 +% (r1 << 64); | ||
| 313 | hi.* = (r1 >> 64) +% | ||
| 314 | (sum1 >> 96) +% | ||
| 315 | (sum2 >> 64) +% | ||
| 316 | (sum3 >> 32) +% | ||
| 317 | sum4 +% | ||
| 318 | (sum5 << 32) +% | ||
| 319 | (sum6 << 64); | ||
| 320 | }, | ||
| 321 | else => @compileError("unsupported"), | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | /// Returns a power-of-two integer type that is large enough to contain | ||
| 326 | /// the significand of T, including an explicit integer bit | ||
| 327 | fn PowerOfTwoSignificandZ(comptime T: type) type { | ||
| 328 | const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); | ||
| 329 | return std.meta.Int(.unsigned, bits); | ||
| 330 | } | ||
| 331 | |||
| 332 | fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { | ||
| 333 | @setRuntimeSafety(builtin.is_test); | ||
| 334 | const Z = PowerOfTwoSignificandZ(T); | ||
| 335 | const integerBit = @as(Z, 1) << math.floatFractionalBits(T); | ||
| 336 | |||
| 337 | const shift = @clz(Z, significand.*) - @clz(Z, integerBit); | ||
| 338 | significand.* <<= @intCast(math.Log2Int(Z), shift); | ||
| 339 | return @as(i32, 1) - shift; | ||
| 340 | } | ||
| 341 | |||
| 342 | // Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) | ||
| 343 | // | ||
| 344 | // This is analogous to an shr version of `@shlWithOverflow` | ||
| 345 | fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { | ||
| 346 | @setRuntimeSafety(builtin.is_test); | ||
| 347 | const typeWidth = @typeInfo(Z).Int.bits; | ||
| 348 | const S = math.Log2Int(Z); | ||
| 349 | var inexact = false; | ||
| 350 | if (count < typeWidth) { | ||
| 351 | inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; | ||
| 352 | lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); | ||
| 353 | hi.* = hi.* >> @intCast(S, count); | ||
| 354 | } else if (count < 2 * typeWidth) { | ||
| 355 | inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; | ||
| 356 | lo.* = hi.* >> @intCast(S, count -% typeWidth); | ||
| 357 | hi.* = 0; | ||
| 358 | } else { | ||
| 359 | inexact = (hi.* | lo.*) != 0; | ||
| 360 | lo.* = 0; | ||
| 361 | hi.* = 0; | ||
| 362 | } | ||
| 363 | return inexact; | ||
| 364 | } | ||
| 365 | |||
| 366 | test { | ||
| 367 | _ = @import("mulXf3_test.zig"); | ||
| 368 | } | ||
lib/compiler_rt/mulXf3_test.zig deleted-171| ... | @@ -1,171 +0,0 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c | ||
| 4 | |||
| 5 | const std = @import("std"); | ||
| 6 | const math = std.math; | ||
| 7 | const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); | ||
| 8 | const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); | ||
| 9 | |||
| 10 | const __multf3 = @import("mulXf3.zig").__multf3; | ||
| 11 | const __mulxf3 = @import("mulXf3.zig").__mulxf3; | ||
| 12 | const __muldf3 = @import("mulXf3.zig").__muldf3; | ||
| 13 | const __mulsf3 = @import("mulXf3.zig").__mulsf3; | ||
| 14 | |||
| 15 | // return true if equal | ||
| 16 | // use two 64-bit integers intead of one 128-bit integer | ||
| 17 | // because 128-bit integer constant can't be assigned directly | ||
| 18 | fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { | ||
| 19 | const rep = @bitCast(u128, result); | ||
| 20 | const hi = @intCast(u64, rep >> 64); | ||
| 21 | const lo = @truncate(u64, rep); | ||
| 22 | |||
| 23 | if (hi == expectedHi and lo == expectedLo) { | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | // test other possible NaN representation(signal NaN) | ||
| 27 | if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { | ||
| 28 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 29 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 30 | { | ||
| 31 | return true; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | return false; | ||
| 35 | } | ||
| 36 | |||
| 37 | fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 38 | const x = __multf3(a, b); | ||
| 39 | |||
| 40 | if (compareResultLD(x, expected_hi, expected_lo)) | ||
| 41 | return; | ||
| 42 | |||
| 43 | @panic("__multf3 test failure"); | ||
| 44 | } | ||
| 45 | |||
| 46 | fn makeNaN128(rand: u64) f128 { | ||
| 47 | const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; | ||
| 48 | const float_result = @bitCast(f128, int_result); | ||
| 49 | return float_result; | ||
| 50 | } | ||
| 51 | test "multf3" { | ||
| 52 | // qNaN * any = qNaN | ||
| 53 | try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 54 | |||
| 55 | // NaN * any = NaN | ||
| 56 | const a = makeNaN128(0x800030000000); | ||
| 57 | try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 58 | // inf * any = inf | ||
| 59 | try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 60 | |||
| 61 | // any * any | ||
| 62 | try test__multf3( | ||
| 63 | @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), | ||
| 64 | @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), | ||
| 65 | 0x400423e7f9e3c9fc, | ||
| 66 | 0xd906c2c2a85777c4, | ||
| 67 | ); | ||
| 68 | |||
| 69 | try test__multf3( | ||
| 70 | @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), | ||
| 71 | @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), | ||
| 72 | 0x3fc52a163c6223fc, | ||
| 73 | 0xc94c4bf0430768b4, | ||
| 74 | ); | ||
| 75 | |||
| 76 | try test__multf3( | ||
| 77 | 0x1.234425696abcad34a35eeffefdcbap+456, | ||
| 78 | 0x451.ed98d76e5d46e5f24323dff21ffp+600, | ||
| 79 | 0x44293a91de5e0e94, | ||
| 80 | 0xe8ed17cc2cdf64ac, | ||
| 81 | ); | ||
| 82 | |||
| 83 | try test__multf3( | ||
| 84 | @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), | ||
| 85 | @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), | ||
| 86 | 0x3d4f37c1a3137cae, | ||
| 87 | 0xfc6807048bc2836a, | ||
| 88 | ); | ||
| 89 | |||
| 90 | try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); | ||
| 91 | |||
| 92 | // Denormal operands. | ||
| 93 | try test__multf3( | ||
| 94 | 0x0.0000000000000000000000000001p-16382, | ||
| 95 | 0x1p16383, | ||
| 96 | 0x3f90000000000000, | ||
| 97 | 0x0, | ||
| 98 | ); | ||
| 99 | try test__multf3( | ||
| 100 | 0x1p16383, | ||
| 101 | 0x0.0000000000000000000000000001p-16382, | ||
| 102 | 0x3f90000000000000, | ||
| 103 | 0x0, | ||
| 104 | ); | ||
| 105 | |||
| 106 | try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); | ||
| 107 | try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); | ||
| 108 | try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); | ||
| 109 | } | ||
| 110 | |||
| 111 | const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); | ||
| 112 | |||
| 113 | fn test__mulxf3(a: f80, b: f80, expected: u80) !void { | ||
| 114 | const x = __mulxf3(a, b); | ||
| 115 | const rep = @bitCast(u80, x); | ||
| 116 | |||
| 117 | if (rep == expected) | ||
| 118 | return; | ||
| 119 | |||
| 120 | if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) | ||
| 121 | return; // We don't currently test NaN payload propagation | ||
| 122 | |||
| 123 | return error.TestFailed; | ||
| 124 | } | ||
| 125 | |||
| 126 | test "mulxf3" { | ||
| 127 | // NaN * any = NaN | ||
| 128 | try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 129 | try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 130 | |||
| 131 | // any * NaN = NaN | ||
| 132 | try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); | ||
| 133 | try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); | ||
| 134 | |||
| 135 | // NaN * inf = NaN | ||
| 136 | try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); | ||
| 137 | |||
| 138 | // inf * NaN = NaN | ||
| 139 | try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); | ||
| 140 | |||
| 141 | // inf * inf = inf | ||
| 142 | try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 143 | |||
| 144 | // inf * -inf = -inf | ||
| 145 | try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); | ||
| 146 | |||
| 147 | // -inf + inf = -inf | ||
| 148 | try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); | ||
| 149 | |||
| 150 | // inf * any = inf | ||
| 151 | try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); | ||
| 152 | |||
| 153 | // any * inf = inf | ||
| 154 | try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 155 | |||
| 156 | // any * any | ||
| 157 | try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); | ||
| 158 | try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact | ||
| 159 | |||
| 160 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact | ||
| 161 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down | ||
| 162 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even | ||
| 163 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up | ||
| 164 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact | ||
| 165 | |||
| 166 | try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even | ||
| 167 | try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up | ||
| 168 | try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal | ||
| 169 | try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal | ||
| 170 | try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal | ||
| 171 | } | ||
lib/compiler_rt/muldf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulf3 = @import("./mulf3.zig").mulf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__muldf3, .{ .name = "__muldf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __muldf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 15 | return mulf3(f64, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { | ||
| 19 | return mulf3(f64, a, b); | ||
| 20 | } | ||
lib/compiler_rt/mulf3.zig created+203| ... | @@ -0,0 +1,203 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const common = @import("./common.zig"); | ||
| 5 | |||
| 6 | /// Ported from: | ||
| 7 | /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc | ||
| 8 | pub inline fn mulf3(comptime T: type, a: T, b: T) T { | ||
| 9 | @setRuntimeSafety(builtin.is_test); | ||
| 10 | const typeWidth = @typeInfo(T).Float.bits; | ||
| 11 | const significandBits = math.floatMantissaBits(T); | ||
| 12 | const fractionalBits = math.floatFractionalBits(T); | ||
| 13 | const exponentBits = math.floatExponentBits(T); | ||
| 14 | |||
| 15 | const Z = std.meta.Int(.unsigned, typeWidth); | ||
| 16 | |||
| 17 | // ZSignificand is large enough to contain the significand, including an explicit integer bit | ||
| 18 | const ZSignificand = PowerOfTwoSignificandZ(T); | ||
| 19 | const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; | ||
| 20 | |||
| 21 | const roundBit = (1 << (ZSignificandBits - 1)); | ||
| 22 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | ||
| 23 | const maxExponent = ((1 << exponentBits) - 1); | ||
| 24 | const exponentBias = (maxExponent >> 1); | ||
| 25 | |||
| 26 | const integerBit = (@as(ZSignificand, 1) << fractionalBits); | ||
| 27 | const quietBit = integerBit >> 1; | ||
| 28 | const significandMask = (@as(Z, 1) << significandBits) - 1; | ||
| 29 | |||
| 30 | const absMask = signBit - 1; | ||
| 31 | const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; | ||
| 32 | const infRep = @bitCast(Z, math.inf(T)); | ||
| 33 | const minNormalRep = @bitCast(Z, math.floatMin(T)); | ||
| 34 | |||
| 35 | const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); | ||
| 36 | const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); | ||
| 37 | const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; | ||
| 38 | |||
| 39 | var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); | ||
| 40 | var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); | ||
| 41 | var scale: i32 = 0; | ||
| 42 | |||
| 43 | // Detect if a or b is zero, denormal, infinity, or NaN. | ||
| 44 | if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { | ||
| 45 | const aAbs: Z = @bitCast(Z, a) & absMask; | ||
| 46 | const bAbs: Z = @bitCast(Z, b) & absMask; | ||
| 47 | |||
| 48 | // NaN * anything = qNaN | ||
| 49 | if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); | ||
| 50 | // anything * NaN = qNaN | ||
| 51 | if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); | ||
| 52 | |||
| 53 | if (aAbs == infRep) { | ||
| 54 | // infinity * non-zero = +/- infinity | ||
| 55 | if (bAbs != 0) { | ||
| 56 | return @bitCast(T, aAbs | productSign); | ||
| 57 | } else { | ||
| 58 | // infinity * zero = NaN | ||
| 59 | return @bitCast(T, qnanRep); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | if (bAbs == infRep) { | ||
| 64 | //? non-zero * infinity = +/- infinity | ||
| 65 | if (aAbs != 0) { | ||
| 66 | return @bitCast(T, bAbs | productSign); | ||
| 67 | } else { | ||
| 68 | // zero * infinity = NaN | ||
| 69 | return @bitCast(T, qnanRep); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | // zero * anything = +/- zero | ||
| 74 | if (aAbs == 0) return @bitCast(T, productSign); | ||
| 75 | // anything * zero = +/- zero | ||
| 76 | if (bAbs == 0) return @bitCast(T, productSign); | ||
| 77 | |||
| 78 | // one or both of a or b is denormal, the other (if applicable) is a | ||
| 79 | // normal number. Renormalize one or both of a and b, and set scale to | ||
| 80 | // include the necessary exponent adjustment. | ||
| 81 | if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); | ||
| 82 | if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); | ||
| 83 | } | ||
| 84 | |||
| 85 | // Or in the implicit significand bit. (If we fell through from the | ||
| 86 | // denormal path it was already set by normalize( ), but setting it twice | ||
| 87 | // won't hurt anything.) | ||
| 88 | aSignificand |= integerBit; | ||
| 89 | bSignificand |= integerBit; | ||
| 90 | |||
| 91 | // Get the significand of a*b. Before multiplying the significands, shift | ||
| 92 | // one of them left to left-align it in the field. Thus, the product will | ||
| 93 | // have (exponentBits + 2) integral digits, all but two of which must be | ||
| 94 | // zero. Normalizing this result is just a conditional left-shift by one | ||
| 95 | // and bumping the exponent accordingly. | ||
| 96 | var productHi: ZSignificand = undefined; | ||
| 97 | var productLo: ZSignificand = undefined; | ||
| 98 | const left_align_shift = ZSignificandBits - fractionalBits - 1; | ||
| 99 | common.wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); | ||
| 100 | |||
| 101 | var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; | ||
| 102 | |||
| 103 | // Normalize the significand, adjust exponent if needed. | ||
| 104 | if ((productHi & integerBit) != 0) { | ||
| 105 | productExponent +%= 1; | ||
| 106 | } else { | ||
| 107 | productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); | ||
| 108 | productLo = productLo << 1; | ||
| 109 | } | ||
| 110 | |||
| 111 | // If we have overflowed the type, return +/- infinity. | ||
| 112 | if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); | ||
| 113 | |||
| 114 | var result: Z = undefined; | ||
| 115 | if (productExponent <= 0) { | ||
| 116 | // Result is denormal before rounding | ||
| 117 | // | ||
| 118 | // If the result is so small that it just underflows to zero, return | ||
| 119 | // a zero of the appropriate sign. Mathematically there is no need to | ||
| 120 | // handle this case separately, but we make it a special case to | ||
| 121 | // simplify the shift logic. | ||
| 122 | const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); | ||
| 123 | if (shift >= ZSignificandBits) return @bitCast(T, productSign); | ||
| 124 | |||
| 125 | // Otherwise, shift the significand of the result so that the round | ||
| 126 | // bit is the high bit of productLo. | ||
| 127 | const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); | ||
| 128 | productLo |= @boolToInt(sticky); | ||
| 129 | result = productHi; | ||
| 130 | |||
| 131 | // We include the integer bit so that rounding will carry to the exponent, | ||
| 132 | // but it will be removed later if the result is still denormal | ||
| 133 | if (significandBits != fractionalBits) result |= integerBit; | ||
| 134 | } else { | ||
| 135 | // Result is normal before rounding; insert the exponent. | ||
| 136 | result = productHi & significandMask; | ||
| 137 | result |= @intCast(Z, productExponent) << significandBits; | ||
| 138 | } | ||
| 139 | |||
| 140 | // Final rounding. The final result may overflow to infinity, or underflow | ||
| 141 | // to zero, but those are the correct results in those cases. We use the | ||
| 142 | // default IEEE-754 round-to-nearest, ties-to-even rounding mode. | ||
| 143 | if (productLo > roundBit) result +%= 1; | ||
| 144 | if (productLo == roundBit) result +%= result & 1; | ||
| 145 | |||
| 146 | // Restore any explicit integer bit, if it was rounded off | ||
| 147 | if (significandBits != fractionalBits) { | ||
| 148 | if ((result >> significandBits) != 0) { | ||
| 149 | result |= integerBit; | ||
| 150 | } else { | ||
| 151 | result &= ~integerBit; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | // Insert the sign of the result: | ||
| 156 | result |= productSign; | ||
| 157 | |||
| 158 | return @bitCast(T, result); | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) | ||
| 162 | /// | ||
| 163 | /// This is analogous to an shr version of `@shlWithOverflow` | ||
| 164 | fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { | ||
| 165 | @setRuntimeSafety(builtin.is_test); | ||
| 166 | const typeWidth = @typeInfo(Z).Int.bits; | ||
| 167 | const S = math.Log2Int(Z); | ||
| 168 | var inexact = false; | ||
| 169 | if (count < typeWidth) { | ||
| 170 | inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; | ||
| 171 | lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); | ||
| 172 | hi.* = hi.* >> @intCast(S, count); | ||
| 173 | } else if (count < 2 * typeWidth) { | ||
| 174 | inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; | ||
| 175 | lo.* = hi.* >> @intCast(S, count -% typeWidth); | ||
| 176 | hi.* = 0; | ||
| 177 | } else { | ||
| 178 | inexact = (hi.* | lo.*) != 0; | ||
| 179 | lo.* = 0; | ||
| 180 | hi.* = 0; | ||
| 181 | } | ||
| 182 | return inexact; | ||
| 183 | } | ||
| 184 | |||
| 185 | fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { | ||
| 186 | const Z = PowerOfTwoSignificandZ(T); | ||
| 187 | const integerBit = @as(Z, 1) << math.floatFractionalBits(T); | ||
| 188 | |||
| 189 | const shift = @clz(Z, significand.*) - @clz(Z, integerBit); | ||
| 190 | significand.* <<= @intCast(math.Log2Int(Z), shift); | ||
| 191 | return @as(i32, 1) - shift; | ||
| 192 | } | ||
| 193 | |||
| 194 | /// Returns a power-of-two integer type that is large enough to contain | ||
| 195 | /// the significand of T, including an explicit integer bit | ||
| 196 | fn PowerOfTwoSignificandZ(comptime T: type) type { | ||
| 197 | const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); | ||
| 198 | return std.meta.Int(.unsigned, bits); | ||
| 199 | } | ||
| 200 | |||
| 201 | test { | ||
| 202 | _ = @import("mulf3_test.zig"); | ||
| 203 | } | ||
lib/compiler_rt/mulf3_test.zig created+171| ... | @@ -0,0 +1,171 @@ | ||
| 1 | // Ported from: | ||
| 2 | // | ||
| 3 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c | ||
| 4 | |||
| 5 | const std = @import("std"); | ||
| 6 | const math = std.math; | ||
| 7 | const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); | ||
| 8 | const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); | ||
| 9 | |||
| 10 | const __multf3 = @import("mulf3.zig").__multf3; | ||
| 11 | const __mulxf3 = @import("mulf3.zig").__mulxf3; | ||
| 12 | const __muldf3 = @import("mulf3.zig").__muldf3; | ||
| 13 | const __mulsf3 = @import("mulf3.zig").__mulsf3; | ||
| 14 | |||
| 15 | // return true if equal | ||
| 16 | // use two 64-bit integers intead of one 128-bit integer | ||
| 17 | // because 128-bit integer constant can't be assigned directly | ||
| 18 | fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { | ||
| 19 | const rep = @bitCast(u128, result); | ||
| 20 | const hi = @intCast(u64, rep >> 64); | ||
| 21 | const lo = @truncate(u64, rep); | ||
| 22 | |||
| 23 | if (hi == expectedHi and lo == expectedLo) { | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | // test other possible NaN representation(signal NaN) | ||
| 27 | if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { | ||
| 28 | if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and | ||
| 29 | ((hi & 0xffffffffffff) > 0 or lo > 0)) | ||
| 30 | { | ||
| 31 | return true; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | return false; | ||
| 35 | } | ||
| 36 | |||
| 37 | fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { | ||
| 38 | const x = __multf3(a, b); | ||
| 39 | |||
| 40 | if (compareResultLD(x, expected_hi, expected_lo)) | ||
| 41 | return; | ||
| 42 | |||
| 43 | @panic("__multf3 test failure"); | ||
| 44 | } | ||
| 45 | |||
| 46 | fn makeNaN128(rand: u64) f128 { | ||
| 47 | const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; | ||
| 48 | const float_result = @bitCast(f128, int_result); | ||
| 49 | return float_result; | ||
| 50 | } | ||
| 51 | test "multf3" { | ||
| 52 | // qNaN * any = qNaN | ||
| 53 | try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 54 | |||
| 55 | // NaN * any = NaN | ||
| 56 | const a = makeNaN128(0x800030000000); | ||
| 57 | try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); | ||
| 58 | // inf * any = inf | ||
| 59 | try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); | ||
| 60 | |||
| 61 | // any * any | ||
| 62 | try test__multf3( | ||
| 63 | @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), | ||
| 64 | @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), | ||
| 65 | 0x400423e7f9e3c9fc, | ||
| 66 | 0xd906c2c2a85777c4, | ||
| 67 | ); | ||
| 68 | |||
| 69 | try test__multf3( | ||
| 70 | @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), | ||
| 71 | @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), | ||
| 72 | 0x3fc52a163c6223fc, | ||
| 73 | 0xc94c4bf0430768b4, | ||
| 74 | ); | ||
| 75 | |||
| 76 | try test__multf3( | ||
| 77 | 0x1.234425696abcad34a35eeffefdcbap+456, | ||
| 78 | 0x451.ed98d76e5d46e5f24323dff21ffp+600, | ||
| 79 | 0x44293a91de5e0e94, | ||
| 80 | 0xe8ed17cc2cdf64ac, | ||
| 81 | ); | ||
| 82 | |||
| 83 | try test__multf3( | ||
| 84 | @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), | ||
| 85 | @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), | ||
| 86 | 0x3d4f37c1a3137cae, | ||
| 87 | 0xfc6807048bc2836a, | ||
| 88 | ); | ||
| 89 | |||
| 90 | try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); | ||
| 91 | |||
| 92 | // Denormal operands. | ||
| 93 | try test__multf3( | ||
| 94 | 0x0.0000000000000000000000000001p-16382, | ||
| 95 | 0x1p16383, | ||
| 96 | 0x3f90000000000000, | ||
| 97 | 0x0, | ||
| 98 | ); | ||
| 99 | try test__multf3( | ||
| 100 | 0x1p16383, | ||
| 101 | 0x0.0000000000000000000000000001p-16382, | ||
| 102 | 0x3f90000000000000, | ||
| 103 | 0x0, | ||
| 104 | ); | ||
| 105 | |||
| 106 | try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); | ||
| 107 | try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); | ||
| 108 | try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); | ||
| 109 | } | ||
| 110 | |||
| 111 | const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); | ||
| 112 | |||
| 113 | fn test__mulxf3(a: f80, b: f80, expected: u80) !void { | ||
| 114 | const x = __mulxf3(a, b); | ||
| 115 | const rep = @bitCast(u80, x); | ||
| 116 | |||
| 117 | if (rep == expected) | ||
| 118 | return; | ||
| 119 | |||
| 120 | if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) | ||
| 121 | return; // We don't currently test NaN payload propagation | ||
| 122 | |||
| 123 | return error.TestFailed; | ||
| 124 | } | ||
| 125 | |||
| 126 | test "mulxf3" { | ||
| 127 | // NaN * any = NaN | ||
| 128 | try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 129 | try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); | ||
| 130 | |||
| 131 | // any * NaN = NaN | ||
| 132 | try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); | ||
| 133 | try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); | ||
| 134 | |||
| 135 | // NaN * inf = NaN | ||
| 136 | try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); | ||
| 137 | |||
| 138 | // inf * NaN = NaN | ||
| 139 | try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); | ||
| 140 | |||
| 141 | // inf * inf = inf | ||
| 142 | try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 143 | |||
| 144 | // inf * -inf = -inf | ||
| 145 | try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); | ||
| 146 | |||
| 147 | // -inf + inf = -inf | ||
| 148 | try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); | ||
| 149 | |||
| 150 | // inf * any = inf | ||
| 151 | try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); | ||
| 152 | |||
| 153 | // any * inf = inf | ||
| 154 | try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); | ||
| 155 | |||
| 156 | // any * any | ||
| 157 | try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); | ||
| 158 | try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact | ||
| 159 | |||
| 160 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact | ||
| 161 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down | ||
| 162 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even | ||
| 163 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up | ||
| 164 | try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact | ||
| 165 | |||
| 166 | try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even | ||
| 167 | try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up | ||
| 168 | try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal | ||
| 169 | try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal | ||
| 170 | try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal | ||
| 171 | } | ||
lib/compiler_rt/mulsf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulf3 = @import("./mulf3.zig").mulf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__mulsf3, .{ .name = "__mulsf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 15 | return mulf3(f32, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_fmul(a: f32, b: f32) callconv(.C) f32 { | ||
| 19 | return mulf3(f32, a, b); | ||
| 20 | } | ||
lib/compiler_rt/multf3.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulf3 = @import("./mulf3.zig").mulf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__mulkf3, .{ .name = "__mulkf3", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__multf3, .{ .name = "__multf3", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __multf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 15 | return mulf3(f128, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __mulkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 19 | return mulf3(f128, a, b); | ||
| 20 | } | ||
lib/compiler_rt/mulxf3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulf3 = @import("./mulf3.zig").mulf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__mulxf3, .{ .name = "__mulxf3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 11 | return mulf3(f80, a, b); | ||
| 12 | } | ||
lib/compiler_rt/sparc.zig+3-3| ... | @@ -50,7 +50,7 @@ const FCMP = enum(i32) { | ... | @@ -50,7 +50,7 @@ const FCMP = enum(i32) { |
| 50 | // Basic arithmetic | 50 | // Basic arithmetic |
| 51 | 51 | ||
| 52 | pub fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { | 52 | pub fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { |
| 53 | c.* = @import("addXf3.zig").__addtf3(a.*, b.*); | 53 | c.* = @import("addf3.zig").__addtf3(a.*, b.*); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { | 56 | pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { |
| ... | @@ -58,11 +58,11 @@ pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { | ... | @@ -58,11 +58,11 @@ pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | pub fn _Qp_mul(c: *f128, a: *f128, b: *f128) callconv(.C) void { | 60 | pub fn _Qp_mul(c: *f128, a: *f128, b: *f128) callconv(.C) void { |
| 61 | c.* = @import("mulXf3.zig").__multf3(a.*, b.*); | 61 | c.* = @import("mulf3.zig").__multf3(a.*, b.*); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | pub fn _Qp_sub(c: *f128, a: *f128, b: *f128) callconv(.C) void { | 64 | pub fn _Qp_sub(c: *f128, a: *f128, b: *f128) callconv(.C) void { |
| 65 | c.* = @import("addXf3.zig").__subtf3(a.*, b.*); | 65 | c.* = @import("addf3.zig").__subtf3(a.*, b.*); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | // Comparison | 68 | // Comparison |
lib/compiler_rt/subdf3.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | |||
| 3 | pub const panic = common.panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | if (common.want_aeabi) { | ||
| 7 | @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = common.linkage }); | ||
| 8 | } else { | ||
| 9 | @export(__subdf3, .{ .name = "__subdf3", .linkage = common.linkage }); | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | fn __subdf3(a: f64, b: f64) callconv(.C) f64 { | ||
| 14 | const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); | ||
| 15 | return a + neg_b; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { | ||
| 19 | const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); | ||
| 20 | return a + neg_b; | ||
| 21 | } | ||
lib/compiler_rt/subsf3.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | |||
| 3 | pub const panic = common.panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | if (common.want_aeabi) { | ||
| 7 | @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = common.linkage }); | ||
| 8 | } else { | ||
| 9 | @export(__subsf3, .{ .name = "__subsf3", .linkage = common.linkage }); | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | fn __subsf3(a: f32, b: f32) callconv(.C) f32 { | ||
| 14 | const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); | ||
| 15 | return a + neg_b; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { | ||
| 19 | const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); | ||
| 20 | return a + neg_b; | ||
| 21 | } | ||
lib/compiler_rt/subtf3.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | |||
| 3 | pub const panic = common.panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | if (common.want_ppc_abi) { | ||
| 7 | @export(__subkf3, .{ .name = "__subkf3", .linkage = common.linkage }); | ||
| 8 | } else { | ||
| 9 | @export(__subtf3, .{ .name = "__subtf3", .linkage = common.linkage }); | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | fn __subtf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 14 | const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); | ||
| 15 | return a + neg_b; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __subkf3(a: f128, b: f128) callconv(.C) f128 { | ||
| 19 | const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); | ||
| 20 | return a + neg_b; | ||
| 21 | } | ||
lib/compiler_rt/subxf3.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const common = @import("./common.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__subxf3, .{ .name = "__subxf3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __subxf3(a: f80, b: f80) callconv(.C) f80 { | ||
| 11 | var b_rep = std.math.break_f80(b); | ||
| 12 | b_rep.exp ^= 0x8000; | ||
| 13 | const neg_b = std.math.make_f80(b_rep); | ||
| 14 | return a + neg_b; | ||
| 15 | } | ||
lib/compiler_rt/truncXfYf2.zig deleted-192| ... | @@ -1,192 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const arch = builtin.cpu.arch; | ||
| 4 | const is_test = builtin.is_test; | ||
| 5 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 6 | pub const panic = @import("common.zig").panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 9 | @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage }); | ||
| 10 | @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage }); | ||
| 11 | @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage }); | ||
| 12 | @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage }); | ||
| 13 | |||
| 14 | @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage }); | ||
| 15 | @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage }); | ||
| 16 | |||
| 17 | if (!is_test) { | ||
| 18 | @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = linkage }); | ||
| 19 | |||
| 20 | if (arch.isARM() or arch.isThumb()) { | ||
| 21 | @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage }); | ||
| 22 | @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage }); | ||
| 23 | @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage }); | ||
| 24 | } | ||
| 25 | |||
| 26 | if (arch.isPPC() or arch.isPPC64()) { | ||
| 27 | @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = linkage }); | ||
| 28 | @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = linkage }); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | // AArch64 is the only ABI (at the moment) to support f16 arguments without the | ||
| 34 | // need for extending them to wider fp types. | ||
| 35 | // TODO remove this; do this type selection in the language rather than | ||
| 36 | // here in compiler-rt. | ||
| 37 | const F16T = if (arch.isAARCH64()) f16 else u16; | ||
| 38 | |||
| 39 | pub fn __truncsfhf2(a: f32) callconv(.C) F16T { | ||
| 40 | return @bitCast(F16T, truncXfYf2(f16, f32, a)); | ||
| 41 | } | ||
| 42 | |||
| 43 | pub fn __gnu_f2h_ieee(a: f32) callconv(.C) F16T { | ||
| 44 | return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a}); | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn __truncdfhf2(a: f64) callconv(.C) F16T { | ||
| 48 | return @bitCast(F16T, truncXfYf2(f16, f64, a)); | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn __trunctfhf2(a: f128) callconv(.C) F16T { | ||
| 52 | return @bitCast(F16T, truncXfYf2(f16, f128, a)); | ||
| 53 | } | ||
| 54 | |||
| 55 | pub fn __trunctfsf2(a: f128) callconv(.C) f32 { | ||
| 56 | return truncXfYf2(f32, f128, a); | ||
| 57 | } | ||
| 58 | |||
| 59 | pub fn __trunckfsf2(a: f128) callconv(.C) f32 { | ||
| 60 | return truncXfYf2(f32, f128, a); | ||
| 61 | } | ||
| 62 | |||
| 63 | pub fn __trunctfdf2(a: f128) callconv(.C) f64 { | ||
| 64 | return truncXfYf2(f64, f128, a); | ||
| 65 | } | ||
| 66 | |||
| 67 | pub fn __trunckfdf2(a: f128) callconv(.C) f64 { | ||
| 68 | return truncXfYf2(f64, f128, a); | ||
| 69 | } | ||
| 70 | |||
| 71 | pub fn __truncdfsf2(a: f64) callconv(.C) f32 { | ||
| 72 | return truncXfYf2(f32, f64, a); | ||
| 73 | } | ||
| 74 | |||
| 75 | pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { | ||
| 76 | @setRuntimeSafety(false); | ||
| 77 | return truncXfYf2(f32, f64, a); | ||
| 78 | } | ||
| 79 | |||
| 80 | pub fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { | ||
| 81 | @setRuntimeSafety(false); | ||
| 82 | return @bitCast(F16T, truncXfYf2(f16, f64, a)); | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { | ||
| 86 | @setRuntimeSafety(false); | ||
| 87 | return @bitCast(F16T, truncXfYf2(f16, f32, a)); | ||
| 88 | } | ||
| 89 | |||
| 90 | inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { | ||
| 91 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 92 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 93 | const srcSigBits = std.math.floatMantissaBits(src_t); | ||
| 94 | const dstSigBits = std.math.floatMantissaBits(dst_t); | ||
| 95 | const SrcShift = std.math.Log2Int(src_rep_t); | ||
| 96 | |||
| 97 | // Various constants whose values follow from the type parameters. | ||
| 98 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 99 | const srcBits = @typeInfo(src_t).Float.bits; | ||
| 100 | const srcExpBits = srcBits - srcSigBits - 1; | ||
| 101 | const srcInfExp = (1 << srcExpBits) - 1; | ||
| 102 | const srcExpBias = srcInfExp >> 1; | ||
| 103 | |||
| 104 | const srcMinNormal = 1 << srcSigBits; | ||
| 105 | const srcSignificandMask = srcMinNormal - 1; | ||
| 106 | const srcInfinity = srcInfExp << srcSigBits; | ||
| 107 | const srcSignMask = 1 << (srcSigBits + srcExpBits); | ||
| 108 | const srcAbsMask = srcSignMask - 1; | ||
| 109 | const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; | ||
| 110 | const halfway = 1 << (srcSigBits - dstSigBits - 1); | ||
| 111 | const srcQNaN = 1 << (srcSigBits - 1); | ||
| 112 | const srcNaNCode = srcQNaN - 1; | ||
| 113 | |||
| 114 | const dstBits = @typeInfo(dst_t).Float.bits; | ||
| 115 | const dstExpBits = dstBits - dstSigBits - 1; | ||
| 116 | const dstInfExp = (1 << dstExpBits) - 1; | ||
| 117 | const dstExpBias = dstInfExp >> 1; | ||
| 118 | |||
| 119 | const underflowExponent = srcExpBias + 1 - dstExpBias; | ||
| 120 | const overflowExponent = srcExpBias + dstInfExp - dstExpBias; | ||
| 121 | const underflow = underflowExponent << srcSigBits; | ||
| 122 | const overflow = overflowExponent << srcSigBits; | ||
| 123 | |||
| 124 | const dstQNaN = 1 << (dstSigBits - 1); | ||
| 125 | const dstNaNCode = dstQNaN - 1; | ||
| 126 | |||
| 127 | // Break a into a sign and representation of the absolute value | ||
| 128 | const aRep: src_rep_t = @bitCast(src_rep_t, a); | ||
| 129 | const aAbs: src_rep_t = aRep & srcAbsMask; | ||
| 130 | const sign: src_rep_t = aRep & srcSignMask; | ||
| 131 | var absResult: dst_rep_t = undefined; | ||
| 132 | |||
| 133 | if (aAbs -% underflow < aAbs -% overflow) { | ||
| 134 | // The exponent of a is within the range of normal numbers in the | ||
| 135 | // destination format. We can convert by simply right-shifting with | ||
| 136 | // rounding and adjusting the exponent. | ||
| 137 | absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); | ||
| 138 | absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; | ||
| 139 | |||
| 140 | const roundBits: src_rep_t = aAbs & roundMask; | ||
| 141 | if (roundBits > halfway) { | ||
| 142 | // Round to nearest | ||
| 143 | absResult += 1; | ||
| 144 | } else if (roundBits == halfway) { | ||
| 145 | // Ties to even | ||
| 146 | absResult += absResult & 1; | ||
| 147 | } | ||
| 148 | } else if (aAbs > srcInfinity) { | ||
| 149 | // a is NaN. | ||
| 150 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 151 | // bit and inserting the (truncated) trailing NaN field. | ||
| 152 | absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; | ||
| 153 | absResult |= dstQNaN; | ||
| 154 | absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); | ||
| 155 | } else if (aAbs >= overflow) { | ||
| 156 | // a overflows to infinity. | ||
| 157 | absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; | ||
| 158 | } else { | ||
| 159 | // a underflows on conversion to the destination type or is an exact | ||
| 160 | // zero. The result may be a denormal or zero. Extract the exponent | ||
| 161 | // to get the shift amount for the denormalization. | ||
| 162 | const aExp = @intCast(u32, aAbs >> srcSigBits); | ||
| 163 | const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); | ||
| 164 | |||
| 165 | const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; | ||
| 166 | |||
| 167 | // Right shift by the denormalization amount with sticky. | ||
| 168 | if (shift > srcSigBits) { | ||
| 169 | absResult = 0; | ||
| 170 | } else { | ||
| 171 | const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); | ||
| 172 | const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; | ||
| 173 | absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); | ||
| 174 | const roundBits: src_rep_t = denormalizedSignificand & roundMask; | ||
| 175 | if (roundBits > halfway) { | ||
| 176 | // Round to nearest | ||
| 177 | absResult += 1; | ||
| 178 | } else if (roundBits == halfway) { | ||
| 179 | // Ties to even | ||
| 180 | absResult += absResult & 1; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | const result: dst_rep_t align(@alignOf(dst_t)) = absResult | | ||
| 186 | @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); | ||
| 187 | return @bitCast(dst_t, result); | ||
| 188 | } | ||
| 189 | |||
| 190 | test { | ||
| 191 | _ = @import("truncXfYf2_test.zig"); | ||
| 192 | } | ||
lib/compiler_rt/truncXfYf2_test.zig deleted-296| ... | @@ -1,296 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; | ||
| 3 | |||
| 4 | fn test__truncsfhf2(a: u32, expected: u16) !void { | ||
| 5 | const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); | ||
| 6 | |||
| 7 | if (actual == expected) { | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 11 | return error.TestFailure; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "truncsfhf2" { | ||
| 15 | try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN | ||
| 16 | try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN | ||
| 17 | |||
| 18 | try test__truncsfhf2(0, 0); // 0 | ||
| 19 | try test__truncsfhf2(0x80000000, 0x8000); // -0 | ||
| 20 | |||
| 21 | try test__truncsfhf2(0x7f800000, 0x7c00); // inf | ||
| 22 | try test__truncsfhf2(0xff800000, 0xfc00); // -inf | ||
| 23 | |||
| 24 | try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf | ||
| 25 | try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf | ||
| 26 | |||
| 27 | try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf | ||
| 28 | try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf | ||
| 29 | |||
| 30 | try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 | ||
| 31 | try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 | ||
| 32 | |||
| 33 | try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 | ||
| 34 | try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 | ||
| 35 | |||
| 36 | try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 | ||
| 37 | try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 | ||
| 38 | |||
| 39 | try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 | ||
| 40 | try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 | ||
| 41 | |||
| 42 | try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 | ||
| 43 | try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 | ||
| 44 | |||
| 45 | try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 | ||
| 46 | try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 | ||
| 47 | |||
| 48 | try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 | ||
| 49 | try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 | ||
| 50 | |||
| 51 | try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 | ||
| 52 | |||
| 53 | try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 | ||
| 54 | try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 | ||
| 55 | |||
| 56 | try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 | ||
| 57 | try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 | ||
| 58 | |||
| 59 | try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 | ||
| 60 | try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 | ||
| 61 | |||
| 62 | try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 | ||
| 63 | try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 | ||
| 64 | try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero | ||
| 65 | } | ||
| 66 | |||
| 67 | const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; | ||
| 68 | |||
| 69 | fn test__truncdfhf2(a: f64, expected: u16) void { | ||
| 70 | const rep = @bitCast(u16, __truncdfhf2(a)); | ||
| 71 | |||
| 72 | if (rep == expected) { | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | // test other possible NaN representation(signal NaN) | ||
| 76 | else if (expected == 0x7e00) { | ||
| 77 | if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | @panic("__truncdfhf2 test failure"); | ||
| 83 | } | ||
| 84 | |||
| 85 | fn test__truncdfhf2_raw(a: u64, expected: u16) void { | ||
| 86 | const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); | ||
| 87 | |||
| 88 | if (actual == expected) { | ||
| 89 | return; | ||
| 90 | } | ||
| 91 | |||
| 92 | @panic("__truncdfhf2 test failure"); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "truncdfhf2" { | ||
| 96 | test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN | ||
| 97 | test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN | ||
| 98 | |||
| 99 | test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf | ||
| 100 | test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf | ||
| 101 | |||
| 102 | test__truncdfhf2(0.0, 0x0); // zero | ||
| 103 | test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero | ||
| 104 | |||
| 105 | test__truncdfhf2(3.1415926535, 0x4248); | ||
| 106 | test__truncdfhf2(-3.1415926535, 0xc248); | ||
| 107 | |||
| 108 | test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); | ||
| 109 | test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); | ||
| 110 | test__truncdfhf2(0x1.0p+0, 0x3c00); | ||
| 111 | test__truncdfhf2(0x1.0p-14, 0x0400); | ||
| 112 | |||
| 113 | // denormal | ||
| 114 | test__truncdfhf2(0x1.0p-20, 0x0010); | ||
| 115 | test__truncdfhf2(0x1.0p-24, 0x0001); | ||
| 116 | test__truncdfhf2(-0x1.0p-24, 0x8001); | ||
| 117 | test__truncdfhf2(0x1.5p-25, 0x0001); | ||
| 118 | |||
| 119 | // and back to zero | ||
| 120 | test__truncdfhf2(0x1.0p-25, 0x0000); | ||
| 121 | test__truncdfhf2(-0x1.0p-25, 0x8000); | ||
| 122 | |||
| 123 | // max (precise) | ||
| 124 | test__truncdfhf2(65504.0, 0x7bff); | ||
| 125 | |||
| 126 | // max (rounded) | ||
| 127 | test__truncdfhf2(65519.0, 0x7bff); | ||
| 128 | |||
| 129 | // max (to +inf) | ||
| 130 | test__truncdfhf2(65520.0, 0x7c00); | ||
| 131 | test__truncdfhf2(-65520.0, 0xfc00); | ||
| 132 | test__truncdfhf2(65536.0, 0x7c00); | ||
| 133 | } | ||
| 134 | |||
| 135 | const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; | ||
| 136 | |||
| 137 | fn test__trunctfsf2(a: f128, expected: u32) void { | ||
| 138 | const x = __trunctfsf2(a); | ||
| 139 | |||
| 140 | const rep = @bitCast(u32, x); | ||
| 141 | if (rep == expected) { | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | // test other possible NaN representation(signal NaN) | ||
| 145 | else if (expected == 0x7fc00000) { | ||
| 146 | if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | @panic("__trunctfsf2 test failure"); | ||
| 152 | } | ||
| 153 | |||
| 154 | test "trunctfsf2" { | ||
| 155 | // qnan | ||
| 156 | test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); | ||
| 157 | // nan | ||
| 158 | test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); | ||
| 159 | // inf | ||
| 160 | test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); | ||
| 161 | // zero | ||
| 162 | test__trunctfsf2(0.0, 0x0); | ||
| 163 | |||
| 164 | test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); | ||
| 165 | test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); | ||
| 166 | test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); | ||
| 167 | test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); | ||
| 168 | } | ||
| 169 | |||
| 170 | const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2; | ||
| 171 | |||
| 172 | fn test__trunctfdf2(a: f128, expected: u64) void { | ||
| 173 | const x = __trunctfdf2(a); | ||
| 174 | |||
| 175 | const rep = @bitCast(u64, x); | ||
| 176 | if (rep == expected) { | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | // test other possible NaN representation(signal NaN) | ||
| 180 | else if (expected == 0x7ff8000000000000) { | ||
| 181 | if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | @panic("__trunctfsf2 test failure"); | ||
| 187 | } | ||
| 188 | |||
| 189 | test "trunctfdf2" { | ||
| 190 | // qnan | ||
| 191 | test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); | ||
| 192 | // nan | ||
| 193 | test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); | ||
| 194 | // inf | ||
| 195 | test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); | ||
| 196 | // zero | ||
| 197 | test__trunctfdf2(0.0, 0x0); | ||
| 198 | |||
| 199 | test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); | ||
| 200 | test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); | ||
| 201 | test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); | ||
| 202 | test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); | ||
| 203 | } | ||
| 204 | |||
| 205 | const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; | ||
| 206 | |||
| 207 | fn test__truncdfsf2(a: f64, expected: u32) void { | ||
| 208 | const x = __truncdfsf2(a); | ||
| 209 | |||
| 210 | const rep = @bitCast(u32, x); | ||
| 211 | if (rep == expected) { | ||
| 212 | return; | ||
| 213 | } | ||
| 214 | // test other possible NaN representation(signal NaN) | ||
| 215 | else if (expected == 0x7fc00000) { | ||
| 216 | if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); | ||
| 222 | |||
| 223 | @panic("__trunctfsf2 test failure"); | ||
| 224 | } | ||
| 225 | |||
| 226 | test "truncdfsf2" { | ||
| 227 | // nan & qnan | ||
| 228 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); | ||
| 229 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); | ||
| 230 | // inf | ||
| 231 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); | ||
| 232 | test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); | ||
| 233 | |||
| 234 | test__truncdfsf2(0.0, 0x0); | ||
| 235 | test__truncdfsf2(1.0, 0x3f800000); | ||
| 236 | test__truncdfsf2(-1.0, 0xbf800000); | ||
| 237 | |||
| 238 | // huge number becomes inf | ||
| 239 | test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); | ||
| 240 | } | ||
| 241 | |||
| 242 | const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; | ||
| 243 | |||
| 244 | fn test__trunctfhf2(a: f128, expected: u16) void { | ||
| 245 | const x = __trunctfhf2(a); | ||
| 246 | |||
| 247 | const rep = @bitCast(u16, x); | ||
| 248 | if (rep == expected) { | ||
| 249 | return; | ||
| 250 | } | ||
| 251 | |||
| 252 | std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); | ||
| 253 | |||
| 254 | @panic("__trunctfhf2 test failure"); | ||
| 255 | } | ||
| 256 | |||
| 257 | test "trunctfhf2" { | ||
| 258 | // qNaN | ||
| 259 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); | ||
| 260 | // NaN | ||
| 261 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); | ||
| 262 | // inf | ||
| 263 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); | ||
| 264 | test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); | ||
| 265 | // zero | ||
| 266 | test__trunctfhf2(0.0, 0x0); | ||
| 267 | test__trunctfhf2(-0.0, 0x8000); | ||
| 268 | |||
| 269 | test__trunctfhf2(3.1415926535, 0x4248); | ||
| 270 | test__trunctfhf2(-3.1415926535, 0xc248); | ||
| 271 | test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); | ||
| 272 | test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); | ||
| 273 | test__trunctfhf2(0x1.0p+0, 0x3c00); | ||
| 274 | test__trunctfhf2(0x1.0p-14, 0x0400); | ||
| 275 | // denormal | ||
| 276 | test__trunctfhf2(0x1.0p-20, 0x0010); | ||
| 277 | test__trunctfhf2(0x1.0p-24, 0x0001); | ||
| 278 | test__trunctfhf2(-0x1.0p-24, 0x8001); | ||
| 279 | test__trunctfhf2(0x1.5p-25, 0x0001); | ||
| 280 | // and back to zero | ||
| 281 | test__trunctfhf2(0x1.0p-25, 0x0000); | ||
| 282 | test__trunctfhf2(-0x1.0p-25, 0x8000); | ||
| 283 | // max (precise) | ||
| 284 | test__trunctfhf2(65504.0, 0x7bff); | ||
| 285 | // max (rounded) | ||
| 286 | test__trunctfhf2(65519.0, 0x7bff); | ||
| 287 | // max (to +inf) | ||
| 288 | test__trunctfhf2(65520.0, 0x7c00); | ||
| 289 | test__trunctfhf2(65536.0, 0x7c00); | ||
| 290 | test__trunctfhf2(-65520.0, 0xfc00); | ||
| 291 | |||
| 292 | test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); | ||
| 293 | test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); | ||
| 294 | test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); | ||
| 295 | test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); | ||
| 296 | } | ||
lib/compiler_rt/trunc_f80.zig deleted-183| ... | @@ -1,183 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const arch = builtin.cpu.arch; | ||
| 4 | const testing = std.testing; | ||
| 5 | const is_test = builtin.is_test; | ||
| 6 | const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | ||
| 7 | pub const panic = @import("common.zig").panic; | ||
| 8 | |||
| 9 | comptime { | ||
| 10 | @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = linkage }); | ||
| 11 | @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = linkage }); | ||
| 12 | @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = linkage }); | ||
| 13 | @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = linkage }); | ||
| 14 | } | ||
| 15 | |||
| 16 | // AArch64 is the only ABI (at the moment) to support f16 arguments without the | ||
| 17 | // need for extending them to wider fp types. | ||
| 18 | const F16T = if (arch.isAARCH64()) f16 else u16; | ||
| 19 | |||
| 20 | pub fn __truncxfhf2(a: f80) callconv(.C) F16T { | ||
| 21 | return @bitCast(F16T, trunc(f16, a)); | ||
| 22 | } | ||
| 23 | |||
| 24 | pub fn __truncxfsf2(a: f80) callconv(.C) f32 { | ||
| 25 | return trunc(f32, a); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn __truncxfdf2(a: f80) callconv(.C) f64 { | ||
| 29 | return trunc(f64, a); | ||
| 30 | } | ||
| 31 | |||
| 32 | inline fn trunc(comptime dst_t: type, a: f80) dst_t { | ||
| 33 | @setRuntimeSafety(builtin.is_test); | ||
| 34 | |||
| 35 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 36 | const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 37 | const dst_sig_bits = std.math.floatMantissaBits(dst_t); | ||
| 38 | |||
| 39 | const src_exp_bias = 16383; | ||
| 40 | |||
| 41 | const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; | ||
| 42 | const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); | ||
| 43 | |||
| 44 | const dst_bits = @typeInfo(dst_t).Float.bits; | ||
| 45 | const dst_exp_bits = dst_bits - dst_sig_bits - 1; | ||
| 46 | const dst_inf_exp = (1 << dst_exp_bits) - 1; | ||
| 47 | const dst_exp_bias = dst_inf_exp >> 1; | ||
| 48 | |||
| 49 | const underflow = src_exp_bias + 1 - dst_exp_bias; | ||
| 50 | const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; | ||
| 51 | |||
| 52 | const dst_qnan = 1 << (dst_sig_bits - 1); | ||
| 53 | const dst_nan_mask = dst_qnan - 1; | ||
| 54 | |||
| 55 | // Break a into a sign and representation of the absolute value | ||
| 56 | var a_rep = std.math.break_f80(a); | ||
| 57 | const sign = a_rep.exp & 0x8000; | ||
| 58 | a_rep.exp &= 0x7FFF; | ||
| 59 | a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; | ||
| 60 | var abs_result: dst_rep_t = undefined; | ||
| 61 | |||
| 62 | if (a_rep.exp -% underflow < a_rep.exp -% overflow) { | ||
| 63 | // The exponent of a is within the range of normal numbers in the | ||
| 64 | // destination format. We can convert by simply right-shifting with | ||
| 65 | // rounding and adjusting the exponent. | ||
| 66 | abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; | ||
| 67 | abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); | ||
| 68 | abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; | ||
| 69 | |||
| 70 | const round_bits = a_rep.fraction & round_mask; | ||
| 71 | if (round_bits > halfway) { | ||
| 72 | // Round to nearest | ||
| 73 | abs_result += 1; | ||
| 74 | } else if (round_bits == halfway) { | ||
| 75 | // Ties to even | ||
| 76 | abs_result += abs_result & 1; | ||
| 77 | } | ||
| 78 | } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { | ||
| 79 | // a is NaN. | ||
| 80 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 81 | // bit and inserting the (truncated) trailing NaN field. | ||
| 82 | abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; | ||
| 83 | abs_result |= dst_qnan; | ||
| 84 | abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); | ||
| 85 | } else if (a_rep.exp >= overflow) { | ||
| 86 | // a overflows to infinity. | ||
| 87 | abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; | ||
| 88 | } else { | ||
| 89 | // a underflows on conversion to the destination type or is an exact | ||
| 90 | // zero. The result may be a denormal or zero. Extract the exponent | ||
| 91 | // to get the shift amount for the denormalization. | ||
| 92 | const shift = src_exp_bias - dst_exp_bias - a_rep.exp; | ||
| 93 | |||
| 94 | // Right shift by the denormalization amount with sticky. | ||
| 95 | if (shift > src_sig_bits) { | ||
| 96 | abs_result = 0; | ||
| 97 | } else { | ||
| 98 | const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); | ||
| 99 | const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; | ||
| 100 | abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); | ||
| 101 | const round_bits = denormalized_significand & round_mask; | ||
| 102 | if (round_bits > halfway) { | ||
| 103 | // Round to nearest | ||
| 104 | abs_result += 1; | ||
| 105 | } else if (round_bits == halfway) { | ||
| 106 | // Ties to even | ||
| 107 | abs_result += abs_result & 1; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; | ||
| 113 | return @bitCast(dst_t, result); | ||
| 114 | } | ||
| 115 | |||
| 116 | pub fn __trunctfxf2(a: f128) callconv(.C) f80 { | ||
| 117 | const src_sig_bits = std.math.floatMantissaBits(f128); | ||
| 118 | const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 119 | |||
| 120 | // Various constants whose values follow from the type parameters. | ||
| 121 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 122 | const src_bits = @typeInfo(f128).Float.bits; | ||
| 123 | const src_exp_bits = src_bits - src_sig_bits - 1; | ||
| 124 | const src_inf_exp = 0x7FFF; | ||
| 125 | |||
| 126 | const src_inf = src_inf_exp << src_sig_bits; | ||
| 127 | const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); | ||
| 128 | const src_abs_mask = src_sign_mask - 1; | ||
| 129 | const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; | ||
| 130 | const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); | ||
| 131 | |||
| 132 | // Break a into a sign and representation of the absolute value | ||
| 133 | const a_rep = @bitCast(u128, a); | ||
| 134 | const a_abs = a_rep & src_abs_mask; | ||
| 135 | const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; | ||
| 136 | const integer_bit = 1 << 63; | ||
| 137 | |||
| 138 | var res: std.math.F80 = undefined; | ||
| 139 | |||
| 140 | if (a_abs > src_inf) { | ||
| 141 | // a is NaN. | ||
| 142 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 143 | // bit and inserting the (truncated) trailing NaN field. | ||
| 144 | res.exp = 0x7fff; | ||
| 145 | res.fraction = 0x8000000000000000; | ||
| 146 | res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)); | ||
| 147 | } else { | ||
| 148 | // The exponent of a is within the range of normal numbers in the | ||
| 149 | // destination format. We can convert by simply right-shifting with | ||
| 150 | // rounding, adding the explicit integer bit, and adjusting the exponent | ||
| 151 | res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; | ||
| 152 | res.exp = @truncate(u16, a_abs >> src_sig_bits); | ||
| 153 | |||
| 154 | const round_bits = a_abs & round_mask; | ||
| 155 | if (round_bits > halfway) { | ||
| 156 | // Round to nearest | ||
| 157 | const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); | ||
| 158 | res.exp += carry; | ||
| 159 | res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry | ||
| 160 | } else if (round_bits == halfway) { | ||
| 161 | // Ties to even | ||
| 162 | const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); | ||
| 163 | res.exp += carry; | ||
| 164 | res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry | ||
| 165 | } | ||
| 166 | if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals | ||
| 167 | } | ||
| 168 | |||
| 169 | res.exp |= sign; | ||
| 170 | return std.math.make_f80(res); | ||
| 171 | } | ||
| 172 | |||
| 173 | fn test__trunctfxf2(a: f128, expected: f80) !void { | ||
| 174 | const x = __trunctfxf2(a); | ||
| 175 | try testing.expect(x == expected); | ||
| 176 | } | ||
| 177 | |||
| 178 | test { | ||
| 179 | try test__trunctfxf2(1.5, 1.5); | ||
| 180 | try test__trunctfxf2(2.5, 2.5); | ||
| 181 | try test__trunctfxf2(-2.5, -2.5); | ||
| 182 | try test__trunctfxf2(0.0, 0.0); | ||
| 183 | } | ||
lib/compiler_rt/truncdfhf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __truncdfhf2(a: f64) callconv(.C) common.F16T { | ||
| 15 | return @bitCast(common.F16T, truncf(f16, f64, a)); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { | ||
| 19 | return @bitCast(common.F16T, truncf(f16, f64, a)); | ||
| 20 | } | ||
lib/compiler_rt/truncdfsf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __truncdfsf2(a: f64) callconv(.C) f32 { | ||
| 15 | return truncf(f32, f64, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { | ||
| 19 | return truncf(f32, f64, a); | ||
| 20 | } | ||
lib/compiler_rt/truncf.zig created+187| ... | @@ -0,0 +1,187 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { | ||
| 4 | const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); | ||
| 5 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 6 | const srcSigBits = std.math.floatMantissaBits(src_t); | ||
| 7 | const dstSigBits = std.math.floatMantissaBits(dst_t); | ||
| 8 | const SrcShift = std.math.Log2Int(src_rep_t); | ||
| 9 | |||
| 10 | // Various constants whose values follow from the type parameters. | ||
| 11 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 12 | const srcBits = @typeInfo(src_t).Float.bits; | ||
| 13 | const srcExpBits = srcBits - srcSigBits - 1; | ||
| 14 | const srcInfExp = (1 << srcExpBits) - 1; | ||
| 15 | const srcExpBias = srcInfExp >> 1; | ||
| 16 | |||
| 17 | const srcMinNormal = 1 << srcSigBits; | ||
| 18 | const srcSignificandMask = srcMinNormal - 1; | ||
| 19 | const srcInfinity = srcInfExp << srcSigBits; | ||
| 20 | const srcSignMask = 1 << (srcSigBits + srcExpBits); | ||
| 21 | const srcAbsMask = srcSignMask - 1; | ||
| 22 | const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; | ||
| 23 | const halfway = 1 << (srcSigBits - dstSigBits - 1); | ||
| 24 | const srcQNaN = 1 << (srcSigBits - 1); | ||
| 25 | const srcNaNCode = srcQNaN - 1; | ||
| 26 | |||
| 27 | const dstBits = @typeInfo(dst_t).Float.bits; | ||
| 28 | const dstExpBits = dstBits - dstSigBits - 1; | ||
| 29 | const dstInfExp = (1 << dstExpBits) - 1; | ||
| 30 | const dstExpBias = dstInfExp >> 1; | ||
| 31 | |||
| 32 | const underflowExponent = srcExpBias + 1 - dstExpBias; | ||
| 33 | const overflowExponent = srcExpBias + dstInfExp - dstExpBias; | ||
| 34 | const underflow = underflowExponent << srcSigBits; | ||
| 35 | const overflow = overflowExponent << srcSigBits; | ||
| 36 | |||
| 37 | const dstQNaN = 1 << (dstSigBits - 1); | ||
| 38 | const dstNaNCode = dstQNaN - 1; | ||
| 39 | |||
| 40 | // Break a into a sign and representation of the absolute value | ||
| 41 | const aRep: src_rep_t = @bitCast(src_rep_t, a); | ||
| 42 | const aAbs: src_rep_t = aRep & srcAbsMask; | ||
| 43 | const sign: src_rep_t = aRep & srcSignMask; | ||
| 44 | var absResult: dst_rep_t = undefined; | ||
| 45 | |||
| 46 | if (aAbs -% underflow < aAbs -% overflow) { | ||
| 47 | // The exponent of a is within the range of normal numbers in the | ||
| 48 | // destination format. We can convert by simply right-shifting with | ||
| 49 | // rounding and adjusting the exponent. | ||
| 50 | absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); | ||
| 51 | absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; | ||
| 52 | |||
| 53 | const roundBits: src_rep_t = aAbs & roundMask; | ||
| 54 | if (roundBits > halfway) { | ||
| 55 | // Round to nearest | ||
| 56 | absResult += 1; | ||
| 57 | } else if (roundBits == halfway) { | ||
| 58 | // Ties to even | ||
| 59 | absResult += absResult & 1; | ||
| 60 | } | ||
| 61 | } else if (aAbs > srcInfinity) { | ||
| 62 | // a is NaN. | ||
| 63 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 64 | // bit and inserting the (truncated) trailing NaN field. | ||
| 65 | absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; | ||
| 66 | absResult |= dstQNaN; | ||
| 67 | absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); | ||
| 68 | } else if (aAbs >= overflow) { | ||
| 69 | // a overflows to infinity. | ||
| 70 | absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; | ||
| 71 | } else { | ||
| 72 | // a underflows on conversion to the destination type or is an exact | ||
| 73 | // zero. The result may be a denormal or zero. Extract the exponent | ||
| 74 | // to get the shift amount for the denormalization. | ||
| 75 | const aExp = @intCast(u32, aAbs >> srcSigBits); | ||
| 76 | const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); | ||
| 77 | |||
| 78 | const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; | ||
| 79 | |||
| 80 | // Right shift by the denormalization amount with sticky. | ||
| 81 | if (shift > srcSigBits) { | ||
| 82 | absResult = 0; | ||
| 83 | } else { | ||
| 84 | const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); | ||
| 85 | const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; | ||
| 86 | absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); | ||
| 87 | const roundBits: src_rep_t = denormalizedSignificand & roundMask; | ||
| 88 | if (roundBits > halfway) { | ||
| 89 | // Round to nearest | ||
| 90 | absResult += 1; | ||
| 91 | } else if (roundBits == halfway) { | ||
| 92 | // Ties to even | ||
| 93 | absResult += absResult & 1; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | const result: dst_rep_t align(@alignOf(dst_t)) = absResult | | ||
| 99 | @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); | ||
| 100 | return @bitCast(dst_t, result); | ||
| 101 | } | ||
| 102 | |||
| 103 | pub inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { | ||
| 104 | const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); | ||
| 105 | const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 106 | const dst_sig_bits = std.math.floatMantissaBits(dst_t); | ||
| 107 | |||
| 108 | const src_exp_bias = 16383; | ||
| 109 | |||
| 110 | const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; | ||
| 111 | const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); | ||
| 112 | |||
| 113 | const dst_bits = @typeInfo(dst_t).Float.bits; | ||
| 114 | const dst_exp_bits = dst_bits - dst_sig_bits - 1; | ||
| 115 | const dst_inf_exp = (1 << dst_exp_bits) - 1; | ||
| 116 | const dst_exp_bias = dst_inf_exp >> 1; | ||
| 117 | |||
| 118 | const underflow = src_exp_bias + 1 - dst_exp_bias; | ||
| 119 | const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; | ||
| 120 | |||
| 121 | const dst_qnan = 1 << (dst_sig_bits - 1); | ||
| 122 | const dst_nan_mask = dst_qnan - 1; | ||
| 123 | |||
| 124 | // Break a into a sign and representation of the absolute value | ||
| 125 | var a_rep = std.math.break_f80(a); | ||
| 126 | const sign = a_rep.exp & 0x8000; | ||
| 127 | a_rep.exp &= 0x7FFF; | ||
| 128 | a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; | ||
| 129 | var abs_result: dst_rep_t = undefined; | ||
| 130 | |||
| 131 | if (a_rep.exp -% underflow < a_rep.exp -% overflow) { | ||
| 132 | // The exponent of a is within the range of normal numbers in the | ||
| 133 | // destination format. We can convert by simply right-shifting with | ||
| 134 | // rounding and adjusting the exponent. | ||
| 135 | abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; | ||
| 136 | abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); | ||
| 137 | abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; | ||
| 138 | |||
| 139 | const round_bits = a_rep.fraction & round_mask; | ||
| 140 | if (round_bits > halfway) { | ||
| 141 | // Round to nearest | ||
| 142 | abs_result += 1; | ||
| 143 | } else if (round_bits == halfway) { | ||
| 144 | // Ties to even | ||
| 145 | abs_result += abs_result & 1; | ||
| 146 | } | ||
| 147 | } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { | ||
| 148 | // a is NaN. | ||
| 149 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 150 | // bit and inserting the (truncated) trailing NaN field. | ||
| 151 | abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; | ||
| 152 | abs_result |= dst_qnan; | ||
| 153 | abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); | ||
| 154 | } else if (a_rep.exp >= overflow) { | ||
| 155 | // a overflows to infinity. | ||
| 156 | abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; | ||
| 157 | } else { | ||
| 158 | // a underflows on conversion to the destination type or is an exact | ||
| 159 | // zero. The result may be a denormal or zero. Extract the exponent | ||
| 160 | // to get the shift amount for the denormalization. | ||
| 161 | const shift = src_exp_bias - dst_exp_bias - a_rep.exp; | ||
| 162 | |||
| 163 | // Right shift by the denormalization amount with sticky. | ||
| 164 | if (shift > src_sig_bits) { | ||
| 165 | abs_result = 0; | ||
| 166 | } else { | ||
| 167 | const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); | ||
| 168 | const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; | ||
| 169 | abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); | ||
| 170 | const round_bits = denormalized_significand & round_mask; | ||
| 171 | if (round_bits > halfway) { | ||
| 172 | // Round to nearest | ||
| 173 | abs_result += 1; | ||
| 174 | } else if (round_bits == halfway) { | ||
| 175 | // Ties to even | ||
| 176 | abs_result += abs_result & 1; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; | ||
| 182 | return @bitCast(dst_t, result); | ||
| 183 | } | ||
| 184 | |||
| 185 | test { | ||
| 186 | _ = @import("truncf_test.zig"); | ||
| 187 | } | ||
lib/compiler_rt/truncf_test.zig created+310| ... | @@ -0,0 +1,310 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; | ||
| 4 | const __trunctfxf2 = @import("trunctfxf2.zig").__trunctfxf2; | ||
| 5 | |||
| 6 | fn test__truncsfhf2(a: u32, expected: u16) !void { | ||
| 7 | const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); | ||
| 8 | |||
| 9 | if (actual == expected) { | ||
| 10 | return; | ||
| 11 | } | ||
| 12 | |||
| 13 | return error.TestFailure; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "truncsfhf2" { | ||
| 17 | try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN | ||
| 18 | try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN | ||
| 19 | |||
| 20 | try test__truncsfhf2(0, 0); // 0 | ||
| 21 | try test__truncsfhf2(0x80000000, 0x8000); // -0 | ||
| 22 | |||
| 23 | try test__truncsfhf2(0x7f800000, 0x7c00); // inf | ||
| 24 | try test__truncsfhf2(0xff800000, 0xfc00); // -inf | ||
| 25 | |||
| 26 | try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf | ||
| 27 | try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf | ||
| 28 | |||
| 29 | try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf | ||
| 30 | try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf | ||
| 31 | |||
| 32 | try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 | ||
| 33 | try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 | ||
| 34 | |||
| 35 | try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 | ||
| 36 | try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 | ||
| 37 | |||
| 38 | try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 | ||
| 39 | try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 | ||
| 40 | |||
| 41 | try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 | ||
| 42 | try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 | ||
| 43 | |||
| 44 | try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 | ||
| 45 | try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 | ||
| 46 | |||
| 47 | try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 | ||
| 48 | try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 | ||
| 49 | |||
| 50 | try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 | ||
| 51 | try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 | ||
| 52 | |||
| 53 | try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 | ||
| 54 | |||
| 55 | try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 | ||
| 56 | try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 | ||
| 57 | |||
| 58 | try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 | ||
| 59 | try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 | ||
| 60 | |||
| 61 | try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 | ||
| 62 | try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 | ||
| 63 | |||
| 64 | try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 | ||
| 65 | try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 | ||
| 66 | try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero | ||
| 67 | } | ||
| 68 | |||
| 69 | const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; | ||
| 70 | |||
| 71 | fn test__truncdfhf2(a: f64, expected: u16) void { | ||
| 72 | const rep = @bitCast(u16, __truncdfhf2(a)); | ||
| 73 | |||
| 74 | if (rep == expected) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | // test other possible NaN representation(signal NaN) | ||
| 78 | else if (expected == 0x7e00) { | ||
| 79 | if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | @panic("__truncdfhf2 test failure"); | ||
| 85 | } | ||
| 86 | |||
| 87 | fn test__truncdfhf2_raw(a: u64, expected: u16) void { | ||
| 88 | const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); | ||
| 89 | |||
| 90 | if (actual == expected) { | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | @panic("__truncdfhf2 test failure"); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "truncdfhf2" { | ||
| 98 | test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN | ||
| 99 | test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN | ||
| 100 | |||
| 101 | test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf | ||
| 102 | test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf | ||
| 103 | |||
| 104 | test__truncdfhf2(0.0, 0x0); // zero | ||
| 105 | test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero | ||
| 106 | |||
| 107 | test__truncdfhf2(3.1415926535, 0x4248); | ||
| 108 | test__truncdfhf2(-3.1415926535, 0xc248); | ||
| 109 | |||
| 110 | test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); | ||
| 111 | test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); | ||
| 112 | test__truncdfhf2(0x1.0p+0, 0x3c00); | ||
| 113 | test__truncdfhf2(0x1.0p-14, 0x0400); | ||
| 114 | |||
| 115 | // denormal | ||
| 116 | test__truncdfhf2(0x1.0p-20, 0x0010); | ||
| 117 | test__truncdfhf2(0x1.0p-24, 0x0001); | ||
| 118 | test__truncdfhf2(-0x1.0p-24, 0x8001); | ||
| 119 | test__truncdfhf2(0x1.5p-25, 0x0001); | ||
| 120 | |||
| 121 | // and back to zero | ||
| 122 | test__truncdfhf2(0x1.0p-25, 0x0000); | ||
| 123 | test__truncdfhf2(-0x1.0p-25, 0x8000); | ||
| 124 | |||
| 125 | // max (precise) | ||
| 126 | test__truncdfhf2(65504.0, 0x7bff); | ||
| 127 | |||
| 128 | // max (rounded) | ||
| 129 | test__truncdfhf2(65519.0, 0x7bff); | ||
| 130 | |||
| 131 | // max (to +inf) | ||
| 132 | test__truncdfhf2(65520.0, 0x7c00); | ||
| 133 | test__truncdfhf2(-65520.0, 0xfc00); | ||
| 134 | test__truncdfhf2(65536.0, 0x7c00); | ||
| 135 | } | ||
| 136 | |||
| 137 | const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; | ||
| 138 | |||
| 139 | fn test__trunctfsf2(a: f128, expected: u32) void { | ||
| 140 | const x = __trunctfsf2(a); | ||
| 141 | |||
| 142 | const rep = @bitCast(u32, x); | ||
| 143 | if (rep == expected) { | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | // test other possible NaN representation(signal NaN) | ||
| 147 | else if (expected == 0x7fc00000) { | ||
| 148 | if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | @panic("__trunctfsf2 test failure"); | ||
| 154 | } | ||
| 155 | |||
| 156 | test "trunctfsf2" { | ||
| 157 | // qnan | ||
| 158 | test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); | ||
| 159 | // nan | ||
| 160 | test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); | ||
| 161 | // inf | ||
| 162 | test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); | ||
| 163 | // zero | ||
| 164 | test__trunctfsf2(0.0, 0x0); | ||
| 165 | |||
| 166 | test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); | ||
| 167 | test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); | ||
| 168 | test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); | ||
| 169 | test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); | ||
| 170 | } | ||
| 171 | |||
| 172 | const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2; | ||
| 173 | |||
| 174 | fn test__trunctfdf2(a: f128, expected: u64) void { | ||
| 175 | const x = __trunctfdf2(a); | ||
| 176 | |||
| 177 | const rep = @bitCast(u64, x); | ||
| 178 | if (rep == expected) { | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | // test other possible NaN representation(signal NaN) | ||
| 182 | else if (expected == 0x7ff8000000000000) { | ||
| 183 | if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | @panic("__trunctfsf2 test failure"); | ||
| 189 | } | ||
| 190 | |||
| 191 | test "trunctfdf2" { | ||
| 192 | // qnan | ||
| 193 | test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); | ||
| 194 | // nan | ||
| 195 | test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); | ||
| 196 | // inf | ||
| 197 | test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); | ||
| 198 | // zero | ||
| 199 | test__trunctfdf2(0.0, 0x0); | ||
| 200 | |||
| 201 | test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); | ||
| 202 | test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); | ||
| 203 | test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); | ||
| 204 | test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); | ||
| 205 | } | ||
| 206 | |||
| 207 | const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; | ||
| 208 | |||
| 209 | fn test__truncdfsf2(a: f64, expected: u32) void { | ||
| 210 | const x = __truncdfsf2(a); | ||
| 211 | |||
| 212 | const rep = @bitCast(u32, x); | ||
| 213 | if (rep == expected) { | ||
| 214 | return; | ||
| 215 | } | ||
| 216 | // test other possible NaN representation(signal NaN) | ||
| 217 | else if (expected == 0x7fc00000) { | ||
| 218 | if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); | ||
| 224 | |||
| 225 | @panic("__trunctfsf2 test failure"); | ||
| 226 | } | ||
| 227 | |||
| 228 | test "truncdfsf2" { | ||
| 229 | // nan & qnan | ||
| 230 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); | ||
| 231 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); | ||
| 232 | // inf | ||
| 233 | test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); | ||
| 234 | test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); | ||
| 235 | |||
| 236 | test__truncdfsf2(0.0, 0x0); | ||
| 237 | test__truncdfsf2(1.0, 0x3f800000); | ||
| 238 | test__truncdfsf2(-1.0, 0xbf800000); | ||
| 239 | |||
| 240 | // huge number becomes inf | ||
| 241 | test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); | ||
| 242 | } | ||
| 243 | |||
| 244 | const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; | ||
| 245 | |||
| 246 | fn test__trunctfhf2(a: f128, expected: u16) void { | ||
| 247 | const x = __trunctfhf2(a); | ||
| 248 | |||
| 249 | const rep = @bitCast(u16, x); | ||
| 250 | if (rep == expected) { | ||
| 251 | return; | ||
| 252 | } | ||
| 253 | |||
| 254 | std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); | ||
| 255 | |||
| 256 | @panic("__trunctfhf2 test failure"); | ||
| 257 | } | ||
| 258 | |||
| 259 | test "trunctfhf2" { | ||
| 260 | // qNaN | ||
| 261 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); | ||
| 262 | // NaN | ||
| 263 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); | ||
| 264 | // inf | ||
| 265 | test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); | ||
| 266 | test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); | ||
| 267 | // zero | ||
| 268 | test__trunctfhf2(0.0, 0x0); | ||
| 269 | test__trunctfhf2(-0.0, 0x8000); | ||
| 270 | |||
| 271 | test__trunctfhf2(3.1415926535, 0x4248); | ||
| 272 | test__trunctfhf2(-3.1415926535, 0xc248); | ||
| 273 | test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); | ||
| 274 | test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); | ||
| 275 | test__trunctfhf2(0x1.0p+0, 0x3c00); | ||
| 276 | test__trunctfhf2(0x1.0p-14, 0x0400); | ||
| 277 | // denormal | ||
| 278 | test__trunctfhf2(0x1.0p-20, 0x0010); | ||
| 279 | test__trunctfhf2(0x1.0p-24, 0x0001); | ||
| 280 | test__trunctfhf2(-0x1.0p-24, 0x8001); | ||
| 281 | test__trunctfhf2(0x1.5p-25, 0x0001); | ||
| 282 | // and back to zero | ||
| 283 | test__trunctfhf2(0x1.0p-25, 0x0000); | ||
| 284 | test__trunctfhf2(-0x1.0p-25, 0x8000); | ||
| 285 | // max (precise) | ||
| 286 | test__trunctfhf2(65504.0, 0x7bff); | ||
| 287 | // max (rounded) | ||
| 288 | test__trunctfhf2(65519.0, 0x7bff); | ||
| 289 | // max (to +inf) | ||
| 290 | test__trunctfhf2(65520.0, 0x7c00); | ||
| 291 | test__trunctfhf2(65536.0, 0x7c00); | ||
| 292 | test__trunctfhf2(-65520.0, 0xfc00); | ||
| 293 | |||
| 294 | test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); | ||
| 295 | test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); | ||
| 296 | test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); | ||
| 297 | test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); | ||
| 298 | } | ||
| 299 | |||
| 300 | test "trunctfxf2" { | ||
| 301 | try test__trunctfxf2(1.5, 1.5); | ||
| 302 | try test__trunctfxf2(2.5, 2.5); | ||
| 303 | try test__trunctfxf2(-2.5, -2.5); | ||
| 304 | try test__trunctfxf2(0.0, 0.0); | ||
| 305 | } | ||
| 306 | |||
| 307 | fn test__trunctfxf2(a: f128, expected: f80) !void { | ||
| 308 | const x = __trunctfxf2(a); | ||
| 309 | try testing.expect(x == expected); | ||
| 310 | } | ||
lib/compiler_rt/truncsfhf2.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_gnu_abi) { | ||
| 8 | @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = common.linkage }); | ||
| 9 | } else if (common.want_aeabi) { | ||
| 10 | @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage }); | ||
| 11 | } else { | ||
| 12 | @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage }); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | fn __truncsfhf2(a: f32) callconv(.C) common.F16T { | ||
| 17 | return @bitCast(common.F16T, truncf(f16, f32, a)); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T { | ||
| 21 | return @bitCast(common.F16T, truncf(f16, f32, a)); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { | ||
| 25 | return @bitCast(common.F16T, truncf(f16, f32, a)); | ||
| 26 | } | ||
lib/compiler_rt/trunctfdf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __trunctfdf2(a: f128) callconv(.C) f64 { | ||
| 15 | return truncf(f64, f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __trunckfdf2(a: f128) callconv(.C) f64 { | ||
| 19 | return truncf(f64, f128, a); | ||
| 20 | } | ||
lib/compiler_rt/trunctfhf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __trunctfhf2(a: f128) callconv(.C) common.F16T { | ||
| 11 | return @bitCast(common.F16T, truncf(f16, f128, a)); | ||
| 12 | } | ||
lib/compiler_rt/trunctfsf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const truncf = @import("./truncf.zig").truncf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __trunctfsf2(a: f128) callconv(.C) f32 { | ||
| 15 | return truncf(f32, f128, a); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __trunckfsf2(a: f128) callconv(.C) f32 { | ||
| 19 | return truncf(f32, f128, a); | ||
| 20 | } | ||
lib/compiler_rt/trunctfxf2.zig created+66| ... | @@ -0,0 +1,66 @@ | ||
| 1 | const math = @import("std").math; | ||
| 2 | const common = @import("./common.zig"); | ||
| 3 | const trunc_f80 = @import("./truncf.zig").trunc_f80; | ||
| 4 | |||
| 5 | pub const panic = common.panic; | ||
| 6 | |||
| 7 | comptime { | ||
| 8 | @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage }); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn __trunctfxf2(a: f128) callconv(.C) f80 { | ||
| 12 | const src_sig_bits = math.floatMantissaBits(f128); | ||
| 13 | const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit | ||
| 14 | |||
| 15 | // Various constants whose values follow from the type parameters. | ||
| 16 | // Any reasonable optimizer will fold and propagate all of these. | ||
| 17 | const src_bits = @typeInfo(f128).Float.bits; | ||
| 18 | const src_exp_bits = src_bits - src_sig_bits - 1; | ||
| 19 | const src_inf_exp = 0x7FFF; | ||
| 20 | |||
| 21 | const src_inf = src_inf_exp << src_sig_bits; | ||
| 22 | const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); | ||
| 23 | const src_abs_mask = src_sign_mask - 1; | ||
| 24 | const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; | ||
| 25 | const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); | ||
| 26 | |||
| 27 | // Break a into a sign and representation of the absolute value | ||
| 28 | const a_rep = @bitCast(u128, a); | ||
| 29 | const a_abs = a_rep & src_abs_mask; | ||
| 30 | const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; | ||
| 31 | const integer_bit = 1 << 63; | ||
| 32 | |||
| 33 | var res: math.F80 = undefined; | ||
| 34 | |||
| 35 | if (a_abs > src_inf) { | ||
| 36 | // a is NaN. | ||
| 37 | // Conjure the result by beginning with infinity, setting the qNaN | ||
| 38 | // bit and inserting the (truncated) trailing NaN field. | ||
| 39 | res.exp = 0x7fff; | ||
| 40 | res.fraction = 0x8000000000000000; | ||
| 41 | res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)); | ||
| 42 | } else { | ||
| 43 | // The exponent of a is within the range of normal numbers in the | ||
| 44 | // destination format. We can convert by simply right-shifting with | ||
| 45 | // rounding, adding the explicit integer bit, and adjusting the exponent | ||
| 46 | res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; | ||
| 47 | res.exp = @truncate(u16, a_abs >> src_sig_bits); | ||
| 48 | |||
| 49 | const round_bits = a_abs & round_mask; | ||
| 50 | if (round_bits > halfway) { | ||
| 51 | // Round to nearest | ||
| 52 | const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); | ||
| 53 | res.exp += carry; | ||
| 54 | res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry | ||
| 55 | } else if (round_bits == halfway) { | ||
| 56 | // Ties to even | ||
| 57 | const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); | ||
| 58 | res.exp += carry; | ||
| 59 | res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry | ||
| 60 | } | ||
| 61 | if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals | ||
| 62 | } | ||
| 63 | |||
| 64 | res.exp |= sign; | ||
| 65 | return math.make_f80(res); | ||
| 66 | } | ||
lib/compiler_rt/truncxfdf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const trunc_f80 = @import("./truncf.zig").trunc_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __truncxfdf2(a: f80) callconv(.C) f64 { | ||
| 11 | return trunc_f80(f64, a); | ||
| 12 | } | ||
lib/compiler_rt/truncxfhf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const trunc_f80 = @import("./truncf.zig").trunc_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __truncxfhf2(a: f80) callconv(.C) common.F16T { | ||
| 11 | return @bitCast(common.F16T, trunc_f80(f16, a)); | ||
| 12 | } | ||
lib/compiler_rt/truncxfsf2.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const trunc_f80 = @import("./truncf.zig").trunc_f80; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __truncxfsf2(a: f80) callconv(.C) f32 { | ||
| 11 | return trunc_f80(f32, a); | ||
| 12 | } | ||
lib/compiler_rt/unorddf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__unorddf2, .{ .name = "__unorddf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { | ||
| 15 | return comparef.unordcmp(f64, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { | ||
| 19 | return comparef.unordcmp(f64, a, b); | ||
| 20 | } | ||
lib/compiler_rt/unordsf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_aeabi) { | ||
| 8 | @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__unordsf2, .{ .name = "__unordsf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { | ||
| 15 | return comparef.unordcmp(f32, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { | ||
| 19 | return comparef.unordcmp(f32, a, b); | ||
| 20 | } | ||
lib/compiler_rt/unordtf2.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (common.want_ppc_abi) { | ||
| 8 | @export(__unordkf2, .{ .name = "__unordkf2", .linkage = common.linkage }); | ||
| 9 | } else { | ||
| 10 | @export(__unordtf2, .{ .name = "__unordtf2", .linkage = common.linkage }); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 15 | return comparef.unordcmp(f128, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn __unordkf2(a: f128, b: f128) callconv(.C) i32 { | ||
| 19 | return comparef.unordcmp(f128, a, b); | ||
| 20 | } | ||
src/compiler_rt.zig+2-2| ... | @@ -200,8 +200,8 @@ const sources = &[_][]const u8{ | ... | @@ -200,8 +200,8 @@ const sources = &[_][]const u8{ |
| 200 | "compiler_rt/umodti3.zig", | 200 | "compiler_rt/umodti3.zig", |
| 201 | "compiler_rt/truncXfYf2.zig", | 201 | "compiler_rt/truncXfYf2.zig", |
| 202 | "compiler_rt/trunc_f80.zig", | 202 | "compiler_rt/trunc_f80.zig", |
| 203 | "compiler_rt/addXf3.zig", | 203 | "compiler_rt/addf3.zig", |
| 204 | "compiler_rt/mulXf3.zig", | 204 | "compiler_rt/mulf3.zig", |
| 205 | "compiler_rt/divsf3.zig", | 205 | "compiler_rt/divsf3.zig", |
| 206 | "compiler_rt/divdf3.zig", | 206 | "compiler_rt/divdf3.zig", |
| 207 | "compiler_rt/divxf3.zig", | 207 | "compiler_rt/divxf3.zig", |