zig

fork of https://codeberg.org/ziglang/zig
Log | Tree | Refs | README | LICENSE

commit 74442f35030a9c4f4ff65db01a18e8fb2f2a1ecf (tree)
parent 33cf6ef621114daad63d14067b6ff374e664d410
Author: Jakub Konka <kubkon@jakubkonka.com>
Date:   Mon, 20 Jun 2022 00:26:39 +0200

Merge pull request #11847 from ziglang/better-libcompiler_rt


Diffstat:
MCMakeLists.txt | 123++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mci/azure/macos_script | 2+-
Mlib/compiler_rt.zig | 1057++++++++++++++-----------------------------------------------------------------
Mlib/compiler_rt/absv.zig | 20+++-----------------
Alib/compiler_rt/absvdi2.zig | 12++++++++++++
Mlib/compiler_rt/absvdi2_test.zig | 5+++--
Alib/compiler_rt/absvsi2.zig | 12++++++++++++
Mlib/compiler_rt/absvsi2_test.zig | 5+++--
Alib/compiler_rt/absvti2.zig | 12++++++++++++
Mlib/compiler_rt/absvti2_test.zig | 5+++--
Dlib/compiler_rt/addXf3.zig | 244-------------------------------------------------------------------------------
Dlib/compiler_rt/addXf3_test.zig | 157-------------------------------------------------------------------------------
Alib/compiler_rt/adddf3.zig | 20++++++++++++++++++++
Alib/compiler_rt/addf3.zig | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/addf3_test.zig | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/compiler_rt/addo.zig | 10++++++++++
Alib/compiler_rt/addsf3.zig | 20++++++++++++++++++++
Alib/compiler_rt/addtf3.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/addxf3.zig | 12++++++++++++
Mlib/compiler_rt/arm.zig | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mlib/compiler_rt/atomics.zig | 2+-
Mlib/compiler_rt/aulldiv.zig | 15++++++++++++++-
Mlib/compiler_rt/aullrem.zig | 15++++++++++++++-
Mlib/compiler_rt/bswap.zig | 10+++++++++-
Mlib/compiler_rt/ceil.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/clear_cache.zig | 9++++++++-
Mlib/compiler_rt/cmp.zig | 14+++++++++++++-
Alib/compiler_rt/cmpdf2.zig | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/cmpsf2.zig | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/cmptf2.zig | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/cmpxf2.zig | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/common.zig | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dlib/compiler_rt/compareXf2.zig | 328-------------------------------------------------------------------------------
Mlib/compiler_rt/comparedf2_test.zig | 24++++++++++++++++--------
Alib/compiler_rt/comparef.zig | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/compiler_rt/comparesf2_test.zig | 24++++++++++++++++--------
Mlib/compiler_rt/cos.zig | 15+++++++++++++++
Mlib/compiler_rt/count0bits.zig | 22++++++++++++++++------
Mlib/compiler_rt/divdf3.zig | 155++++++++++++++-----------------------------------------------------------------
Mlib/compiler_rt/divsf3.zig | 45+++++++++++++++++++++++++--------------------
Mlib/compiler_rt/divtf3.zig | 30+++++++++++++++++++++++++++---
Mlib/compiler_rt/divti3.zig | 46++++++++++++++++++++++++++++++++++++----------
Mlib/compiler_rt/divxf3.zig | 14+++++++++++---
Mlib/compiler_rt/emutls.zig | 28++++++++++++++++++++--------
Mlib/compiler_rt/exp.zig | 15+++++++++++++++
Mlib/compiler_rt/exp2.zig | 15+++++++++++++++
Dlib/compiler_rt/extendXfYf2.zig | 112-------------------------------------------------------------------------------
Dlib/compiler_rt/extendXfYf2_test.zig | 206-------------------------------------------------------------------------------
Dlib/compiler_rt/extend_f80.zig | 131-------------------------------------------------------------------------------
Alib/compiler_rt/extenddftf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/extenddfxf2.zig | 12++++++++++++
Alib/compiler_rt/extendf.zig | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/extendf_test.zig | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/extendhfsf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/extendhftf2.zig | 12++++++++++++
Alib/compiler_rt/extendhfxf2.zig | 12++++++++++++
Alib/compiler_rt/extendsfdf2.zig | 20++++++++++++++++++++
Alib/compiler_rt/extendsftf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/extendsfxf2.zig | 12++++++++++++
Alib/compiler_rt/extendxftf2.zig | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/compiler_rt/fabs.zig | 15+++++++++++++++
Dlib/compiler_rt/fixXfYi.zig | 224-------------------------------------------------------------------------------
Dlib/compiler_rt/fixXfYi_test.zig | 948-------------------------------------------------------------------------------
Alib/compiler_rt/fixdfdi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixdfsi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixdfti.zig | 12++++++++++++
Alib/compiler_rt/fixhfdi.zig | 12++++++++++++
Alib/compiler_rt/fixhfsi.zig | 12++++++++++++
Alib/compiler_rt/fixhfti.zig | 12++++++++++++
Alib/compiler_rt/fixsfdi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixsfsi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixsfti.zig | 12++++++++++++
Alib/compiler_rt/fixtfdi.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/fixtfsi.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/fixtfti.zig | 12++++++++++++
Alib/compiler_rt/fixunsdfdi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixunsdfsi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixunsdfti.zig | 12++++++++++++
Alib/compiler_rt/fixunshfdi.zig | 12++++++++++++
Alib/compiler_rt/fixunshfsi.zig | 12++++++++++++
Alib/compiler_rt/fixunshfti.zig | 12++++++++++++
Alib/compiler_rt/fixunssfdi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixunssfsi.zig | 20++++++++++++++++++++
Alib/compiler_rt/fixunssfti.zig | 12++++++++++++
Alib/compiler_rt/fixunstfdi.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/fixunstfsi.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/fixunstfti.zig | 12++++++++++++
Alib/compiler_rt/fixunsxfdi.zig | 12++++++++++++
Alib/compiler_rt/fixunsxfsi.zig | 12++++++++++++
Alib/compiler_rt/fixunsxfti.zig | 12++++++++++++
Alib/compiler_rt/fixxfdi.zig | 12++++++++++++
Alib/compiler_rt/fixxfsi.zig | 12++++++++++++
Alib/compiler_rt/fixxfti.zig | 12++++++++++++
Dlib/compiler_rt/floatXiYf.zig | 222-------------------------------------------------------------------------------
Dlib/compiler_rt/floatXiYf_test.zig | 835-------------------------------------------------------------------------------
Alib/compiler_rt/float_to_int.zig | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/float_to_int_test.zig | 950+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/floatdidf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatdihf.zig | 12++++++++++++
Alib/compiler_rt/floatdisf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatditf.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/floatdixf.zig | 12++++++++++++
Alib/compiler_rt/floatsidf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatsihf.zig | 12++++++++++++
Alib/compiler_rt/floatsisf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatsitf.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/floatsixf.zig | 12++++++++++++
Alib/compiler_rt/floattidf.zig | 12++++++++++++
Alib/compiler_rt/floattihf.zig | 12++++++++++++
Alib/compiler_rt/floattisf.zig | 12++++++++++++
Alib/compiler_rt/floattitf.zig | 12++++++++++++
Alib/compiler_rt/floattixf.zig | 12++++++++++++
Alib/compiler_rt/floatundidf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatundihf.zig | 12++++++++++++
Alib/compiler_rt/floatundisf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatunditf.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/floatundixf.zig | 12++++++++++++
Alib/compiler_rt/floatunsidf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatunsihf.zig | 12++++++++++++
Alib/compiler_rt/floatunsisf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatunsitf.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/floatunsixf.zig | 12++++++++++++
Alib/compiler_rt/floatuntidf.zig | 12++++++++++++
Alib/compiler_rt/floatuntihf.zig | 12++++++++++++
Alib/compiler_rt/floatuntisf.zig | 12++++++++++++
Alib/compiler_rt/floatuntitf.zig | 20++++++++++++++++++++
Alib/compiler_rt/floatuntixf.zig | 12++++++++++++
Mlib/compiler_rt/floor.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/fma.zig | 27+++++++++++++++++++++------
Mlib/compiler_rt/fmax.zig | 15+++++++++++++++
Mlib/compiler_rt/fmin.zig | 15+++++++++++++++
Mlib/compiler_rt/fmod.zig | 21+++++++++++++++------
Alib/compiler_rt/gedf2.zig | 36++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/gesf2.zig | 36++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/getf2.zig | 39+++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/gexf2.zig | 17+++++++++++++++++
Mlib/compiler_rt/int.zig | 66++++++++++++++++++++++++++++++++++++++++++------------------------
Alib/compiler_rt/int_to_float.zig | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/int_to_float_test.zig | 838+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/compiler_rt/log.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/log10.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/log2.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/modti3.zig | 53+++++++++++++++++++++++++++++++++++++++--------------
Dlib/compiler_rt/mulXf3.zig | 344-------------------------------------------------------------------------------
Dlib/compiler_rt/mulXf3_test.zig | 171-------------------------------------------------------------------------------
Alib/compiler_rt/muldf3.zig | 20++++++++++++++++++++
Mlib/compiler_rt/muldi3.zig | 46++++++++++++++++++++++++++++++----------------
Alib/compiler_rt/mulf3.zig | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/mulf3_test.zig | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/compiler_rt/mulo.zig | 13++++++++++---
Alib/compiler_rt/mulsf3.zig | 20++++++++++++++++++++
Alib/compiler_rt/multf3.zig | 26++++++++++++++++++++++++++
Mlib/compiler_rt/multi3.zig | 53+++++++++++++++++++++++++++++++++++++----------------
Alib/compiler_rt/mulxf3.zig | 12++++++++++++
Mlib/compiler_rt/negXf2.zig | 30+++++++++++++++++++++---------
Mlib/compiler_rt/negXi2.zig | 30++++++++++++++++++------------
Mlib/compiler_rt/negv.zig | 42++++++++++++++++++++++++++----------------
Mlib/compiler_rt/os_version_check.zig | 53++++++++++++++++++++++++++++++++---------------------
Mlib/compiler_rt/parity.zig | 39+++++++++++++++++++++++----------------
Mlib/compiler_rt/popcount.zig | 47+++++++++++++++++++++++++++--------------------
Mlib/compiler_rt/round.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/shift.zig | 60++++++++++++++++++++++++++++++++++++++++++------------------
Mlib/compiler_rt/sin.zig | 25++++++++++++++++++++-----
Mlib/compiler_rt/sincos.zig | 19++++++++++++++++---
Dlib/compiler_rt/sparc.zig | 114-------------------------------------------------------------------------------
Mlib/compiler_rt/sqrt.zig | 15+++++++++++++++
Mlib/compiler_rt/stack_probe.zig | 53++++++++++++++++++++++++++++++++++++++++++++++-------
Alib/compiler_rt/subdf3.zig | 21+++++++++++++++++++++
Mlib/compiler_rt/subo.zig | 39++++++++++++++++++++++++---------------
Alib/compiler_rt/subsf3.zig | 21+++++++++++++++++++++
Alib/compiler_rt/subtf3.zig | 30++++++++++++++++++++++++++++++
Alib/compiler_rt/subxf3.zig | 15+++++++++++++++
Mlib/compiler_rt/tan.zig | 28++++++++++++++++++++++------
Mlib/compiler_rt/trunc.zig | 25++++++++++++++++++++-----
Dlib/compiler_rt/truncXfYf2.zig | 152-------------------------------------------------------------------------------
Dlib/compiler_rt/truncXfYf2_test.zig | 296-------------------------------------------------------------------------------
Dlib/compiler_rt/trunc_f80.zig | 173-------------------------------------------------------------------------------
Alib/compiler_rt/truncdfhf2.zig | 20++++++++++++++++++++
Alib/compiler_rt/truncdfsf2.zig | 20++++++++++++++++++++
Alib/compiler_rt/truncf.zig | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/truncf_test.zig | 306+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/truncsfhf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/trunctfdf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/trunctfhf2.zig | 12++++++++++++
Alib/compiler_rt/trunctfsf2.zig | 26++++++++++++++++++++++++++
Alib/compiler_rt/trunctfxf2.zig | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/compiler_rt/truncxfdf2.zig | 12++++++++++++
Alib/compiler_rt/truncxfhf2.zig | 12++++++++++++
Alib/compiler_rt/truncxfsf2.zig | 12++++++++++++
Mlib/compiler_rt/udivmodti4.zig | 33+++++++++++++++++++++++++++------
Mlib/compiler_rt/udivti3.zig | 39++++++++++++++++++++++++++++++++-------
Mlib/compiler_rt/umodti3.zig | 44++++++++++++++++++++++++++++++++++----------
Alib/compiler_rt/unorddf2.zig | 20++++++++++++++++++++
Alib/compiler_rt/unordsf2.zig | 20++++++++++++++++++++
Alib/compiler_rt/unordtf2.zig | 23+++++++++++++++++++++++
Msrc/Compilation.zig | 158++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/ThreadPool.zig | 81++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/WaitGroup.zig | 7+++++++
Msrc/link.zig | 7++-----
Msrc/link/Coff.zig | 2+-
Msrc/link/Elf.zig | 2+-
Msrc/link/MachO.zig | 50++++++++++++++++++++++++--------------------------
Msrc/link/Wasm.zig | 2+-
Msrc/musl.zig | 1-
204 files changed, 7587 insertions(+), 6205 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -480,8 +480,15 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absv.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addXf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absvdi2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absvsi2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absvti2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/adddf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addo.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addsf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addtf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addxf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/arm.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/atomics.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/aulldiv.zig" @@ -490,7 +497,12 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/ceil.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/clear_cache.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmp.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/compareXf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmptf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/common.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/comparef.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cos.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/count0bits.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/divdf3.zig" @@ -501,25 +513,101 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/emutls.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendXfYf2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extend_f80.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendxftf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fabs.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixXfYi.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatXiYf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/float_to_int.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatditf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunditf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntixf.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floor.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fma.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmax.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmin.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmod.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gedf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gesf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/getf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gexf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/int.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/int_to_float.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulXf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulsf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig" @@ -533,19 +621,34 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/shift.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sin.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sincos.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sparc.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sqrt.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncXfYf2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc_f80.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncdfhf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncdfsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncsfhf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunctfdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunctfhf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunctfsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunctfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncxfdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncxfhf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncxfsf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmod.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmodti4.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivti3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/umodti3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unorddf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordtf2.zig" "${CMAKE_SOURCE_DIR}/lib/std/start.zig" "${CMAKE_SOURCE_DIR}/lib/std/std.zig" "${CMAKE_SOURCE_DIR}/lib/std/target.zig" diff --git a/ci/azure/macos_script b/ci/azure/macos_script @@ -75,7 +75,7 @@ release/bin/zig build test-translate-c -Denable-macos-sdk release/bin/zig build test-run-translated-c -Denable-macos-sdk release/bin/zig build docs -Denable-macos-sdk release/bin/zig build test-fmt -Denable-macos-sdk -release/bin/zig build test-cases -Denable-macos-sdk +release/bin/zig build test-cases -Denable-macos-sdk -Dsingle-threaded if [ "${BUILD_REASON}" != "PullRequest" ]; then mv ../LICENSE release/ diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig @@ -1,885 +1,182 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const os_tag = builtin.os.tag; -const arch = builtin.cpu.arch; -const abi = builtin.abi; - -const is_gnu = abi.isGnu(); -const is_mingw = os_tag == .windows and is_gnu; -const is_darwin = std.Target.Os.Tag.isDarwin(os_tag); -const is_ppc = arch.isPPC() or arch.isPPC64(); - -const linkage = if (is_test) - std.builtin.GlobalLinkage.Internal -else - std.builtin.GlobalLinkage.Weak; - -const strong_linkage = if (is_test) - std.builtin.GlobalLinkage.Internal -else - std.builtin.GlobalLinkage.Strong; +pub const panic = @import("compiler_rt/common.zig").panic; comptime { - // These files do their own comptime exporting logic. _ = @import("compiler_rt/atomics.zig"); - if (builtin.zig_backend != .stage2_llvm) { // TODO - _ = @import("compiler_rt/clear_cache.zig").clear_cache; - } - - const __extenddftf2 = @import("compiler_rt/extendXfYf2.zig").__extenddftf2; - @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage }); - const __extendsftf2 = @import("compiler_rt/extendXfYf2.zig").__extendsftf2; - @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = linkage }); - const __extendhfsf2 = @import("compiler_rt/extendXfYf2.zig").__extendhfsf2; - @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = linkage }); - const __extendhftf2 = @import("compiler_rt/extendXfYf2.zig").__extendhftf2; - @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage }); - - const __extendhfxf2 = @import("compiler_rt/extend_f80.zig").__extendhfxf2; - @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = linkage }); - const __extendsfxf2 = @import("compiler_rt/extend_f80.zig").__extendsfxf2; - @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = linkage }); - const __extenddfxf2 = @import("compiler_rt/extend_f80.zig").__extenddfxf2; - @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = linkage }); - const __extendxftf2 = @import("compiler_rt/extend_f80.zig").__extendxftf2; - @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = linkage }); - - const __lesf2 = @import("compiler_rt/compareXf2.zig").__lesf2; - @export(__lesf2, .{ .name = "__lesf2", .linkage = linkage }); - const __ledf2 = @import("compiler_rt/compareXf2.zig").__ledf2; - @export(__ledf2, .{ .name = "__ledf2", .linkage = linkage }); - const __letf2 = @import("compiler_rt/compareXf2.zig").__letf2; - @export(__letf2, .{ .name = "__letf2", .linkage = linkage }); - const __lexf2 = @import("compiler_rt/compareXf2.zig").__lexf2; - @export(__lexf2, .{ .name = "__lexf2", .linkage = linkage }); - - const __gesf2 = @import("compiler_rt/compareXf2.zig").__gesf2; - @export(__gesf2, .{ .name = "__gesf2", .linkage = linkage }); - const __gedf2 = @import("compiler_rt/compareXf2.zig").__gedf2; - @export(__gedf2, .{ .name = "__gedf2", .linkage = linkage }); - const __getf2 = @import("compiler_rt/compareXf2.zig").__getf2; - @export(__getf2, .{ .name = "__getf2", .linkage = linkage }); - const __gexf2 = @import("compiler_rt/compareXf2.zig").__gexf2; - @export(__gexf2, .{ .name = "__gexf2", .linkage = linkage }); - - const __eqsf2 = @import("compiler_rt/compareXf2.zig").__eqsf2; - @export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage }); - const __eqdf2 = @import("compiler_rt/compareXf2.zig").__eqdf2; - @export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage }); - const __eqxf2 = @import("compiler_rt/compareXf2.zig").__eqxf2; - @export(__eqxf2, .{ .name = "__eqxf2", .linkage = linkage }); - - const __ltsf2 = @import("compiler_rt/compareXf2.zig").__ltsf2; - @export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage }); - const __ltdf2 = @import("compiler_rt/compareXf2.zig").__ltdf2; - @export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage }); - const __ltxf2 = @import("compiler_rt/compareXf2.zig").__ltxf2; - @export(__ltxf2, .{ .name = "__ltxf2", .linkage = linkage }); - - const __nesf2 = @import("compiler_rt/compareXf2.zig").__nesf2; - @export(__nesf2, .{ .name = "__nesf2", .linkage = linkage }); - const __nedf2 = @import("compiler_rt/compareXf2.zig").__nedf2; - @export(__nedf2, .{ .name = "__nedf2", .linkage = linkage }); - const __nexf2 = @import("compiler_rt/compareXf2.zig").__nexf2; - @export(__nexf2, .{ .name = "__nexf2", .linkage = linkage }); - - const __gtsf2 = @import("compiler_rt/compareXf2.zig").__gtsf2; - @export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage }); - const __gtdf2 = @import("compiler_rt/compareXf2.zig").__gtdf2; - @export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage }); - const __gtxf2 = @import("compiler_rt/compareXf2.zig").__gtxf2; - @export(__gtxf2, .{ .name = "__gtxf2", .linkage = linkage }); - - if (!is_test) { - @export(__lesf2, .{ .name = "__cmpsf2", .linkage = linkage }); - @export(__ledf2, .{ .name = "__cmpdf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__cmptf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__eqtf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__lttf2", .linkage = linkage }); - @export(__getf2, .{ .name = "__gttf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__netf2", .linkage = linkage }); - @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage }); - } - - if (builtin.os.tag == .windows) { - // Default stack-probe functions emitted by LLVM - if (is_mingw) { - const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk; - @export(_chkstk, .{ .name = "_alloca", .linkage = strong_linkage }); - const ___chkstk_ms = @import("compiler_rt/stack_probe.zig").___chkstk_ms; - @export(___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = strong_linkage }); - } else if (!builtin.link_libc) { - // This symbols are otherwise exported by MSVCRT.lib - const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk; - @export(_chkstk, .{ .name = "_chkstk", .linkage = strong_linkage }); - const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk; - @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); - } - - switch (arch) { - .i386 => { - const __divti3 = @import("compiler_rt/divti3.zig").__divti3; - @export(__divti3, .{ .name = "__divti3", .linkage = linkage }); - const __modti3 = @import("compiler_rt/modti3.zig").__modti3; - @export(__modti3, .{ .name = "__modti3", .linkage = linkage }); - const __multi3 = @import("compiler_rt/multi3.zig").__multi3; - @export(__multi3, .{ .name = "__multi3", .linkage = linkage }); - const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3; - @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage }); - const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4; - @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage }); - const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3; - @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage }); - }, - .x86_64 => { - // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI - // that LLVM expects compiler-rt to have. - const __divti3_windows_x86_64 = @import("compiler_rt/divti3.zig").__divti3_windows_x86_64; - @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = linkage }); - const __modti3_windows_x86_64 = @import("compiler_rt/modti3.zig").__modti3_windows_x86_64; - @export(__modti3_windows_x86_64, .{ .name = "__modti3", .linkage = linkage }); - const __multi3_windows_x86_64 = @import("compiler_rt/multi3.zig").__multi3_windows_x86_64; - @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = linkage }); - const __udivti3_windows_x86_64 = @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64; - @export(__udivti3_windows_x86_64, .{ .name = "__udivti3", .linkage = linkage }); - const __udivmodti4_windows_x86_64 = @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64; - @export(__udivmodti4_windows_x86_64, .{ .name = "__udivmodti4", .linkage = linkage }); - const __umodti3_windows_x86_64 = @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64; - @export(__umodti3_windows_x86_64, .{ .name = "__umodti3", .linkage = linkage }); - }, - else => {}, - } - if (arch.isAARCH64()) { - const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk; - @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); - const __divti3_windows = @import("compiler_rt/divti3.zig").__divti3; - @export(__divti3_windows, .{ .name = "__divti3", .linkage = linkage }); - const __modti3 = @import("compiler_rt/modti3.zig").__modti3; - @export(__modti3, .{ .name = "__modti3", .linkage = linkage }); - const __udivti3_windows = @import("compiler_rt/udivti3.zig").__udivti3; - @export(__udivti3_windows, .{ .name = "__udivti3", .linkage = linkage }); - const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3; - @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage }); - } - } else { - const __divti3 = @import("compiler_rt/divti3.zig").__divti3; - @export(__divti3, .{ .name = "__divti3", .linkage = linkage }); - const __modti3 = @import("compiler_rt/modti3.zig").__modti3; - @export(__modti3, .{ .name = "__modti3", .linkage = linkage }); - const __multi3 = @import("compiler_rt/multi3.zig").__multi3; - @export(__multi3, .{ .name = "__multi3", .linkage = linkage }); - const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3; - @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage }); - const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4; - @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage }); - const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3; - @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage }); - } - - const __truncdfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfhf2; - @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage }); - const __trunctfhf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfhf2; - @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage }); - const __trunctfdf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfdf2; - @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage }); - const __trunctfsf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfsf2; - @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage }); - - const __truncdfsf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfsf2; - @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage }); - - const __truncxfhf2 = @import("compiler_rt/trunc_f80.zig").__truncxfhf2; - @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = linkage }); - const __truncxfsf2 = @import("compiler_rt/trunc_f80.zig").__truncxfsf2; - @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = linkage }); - const __truncxfdf2 = @import("compiler_rt/trunc_f80.zig").__truncxfdf2; - @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = linkage }); - const __trunctfxf2 = @import("compiler_rt/trunc_f80.zig").__trunctfxf2; - @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = linkage }); - - switch (arch) { - .i386, - .x86_64, - => { - const zig_probe_stack = @import("compiler_rt/stack_probe.zig").zig_probe_stack; - @export(zig_probe_stack, .{ - .name = "__zig_probe_stack", - .linkage = linkage, - }); - }, - else => {}, - } - - const __unordsf2 = @import("compiler_rt/compareXf2.zig").__unordsf2; - @export(__unordsf2, .{ .name = "__unordsf2", .linkage = linkage }); - const __unorddf2 = @import("compiler_rt/compareXf2.zig").__unorddf2; - @export(__unorddf2, .{ .name = "__unorddf2", .linkage = linkage }); - const __unordtf2 = @import("compiler_rt/compareXf2.zig").__unordtf2; - @export(__unordtf2, .{ .name = "__unordtf2", .linkage = linkage }); - - const __addsf3 = @import("compiler_rt/addXf3.zig").__addsf3; - @export(__addsf3, .{ .name = "__addsf3", .linkage = linkage }); - const __adddf3 = @import("compiler_rt/addXf3.zig").__adddf3; - @export(__adddf3, .{ .name = "__adddf3", .linkage = linkage }); - const __addxf3 = @import("compiler_rt/addXf3.zig").__addxf3; - @export(__addxf3, .{ .name = "__addxf3", .linkage = linkage }); - const __addtf3 = @import("compiler_rt/addXf3.zig").__addtf3; - @export(__addtf3, .{ .name = "__addtf3", .linkage = linkage }); - - const __subsf3 = @import("compiler_rt/addXf3.zig").__subsf3; - @export(__subsf3, .{ .name = "__subsf3", .linkage = linkage }); - const __subdf3 = @import("compiler_rt/addXf3.zig").__subdf3; - @export(__subdf3, .{ .name = "__subdf3", .linkage = linkage }); - const __subxf3 = @import("compiler_rt/addXf3.zig").__subxf3; - @export(__subxf3, .{ .name = "__subxf3", .linkage = linkage }); - const __subtf3 = @import("compiler_rt/addXf3.zig").__subtf3; - @export(__subtf3, .{ .name = "__subtf3", .linkage = linkage }); - - const __mulsf3 = @import("compiler_rt/mulXf3.zig").__mulsf3; - @export(__mulsf3, .{ .name = "__mulsf3", .linkage = linkage }); - const __muldf3 = @import("compiler_rt/mulXf3.zig").__muldf3; - @export(__muldf3, .{ .name = "__muldf3", .linkage = linkage }); - const __mulxf3 = @import("compiler_rt/mulXf3.zig").__mulxf3; - @export(__mulxf3, .{ .name = "__mulxf3", .linkage = linkage }); - const __multf3 = @import("compiler_rt/mulXf3.zig").__multf3; - @export(__multf3, .{ .name = "__multf3", .linkage = linkage }); - - const __divsf3 = @import("compiler_rt/divsf3.zig").__divsf3; - @export(__divsf3, .{ .name = "__divsf3", .linkage = linkage }); - const __divdf3 = @import("compiler_rt/divdf3.zig").__divdf3; - @export(__divdf3, .{ .name = "__divdf3", .linkage = linkage }); - const __divxf3 = @import("compiler_rt/divxf3.zig").__divxf3; - @export(__divxf3, .{ .name = "__divxf3", .linkage = linkage }); - const __divtf3 = @import("compiler_rt/divtf3.zig").__divtf3; - @export(__divtf3, .{ .name = "__divtf3", .linkage = linkage }); - - // Integer Bit operations - const __clzsi2 = @import("compiler_rt/count0bits.zig").__clzsi2; - @export(__clzsi2, .{ .name = "__clzsi2", .linkage = linkage }); - const __clzdi2 = @import("compiler_rt/count0bits.zig").__clzdi2; - @export(__clzdi2, .{ .name = "__clzdi2", .linkage = linkage }); - const __clzti2 = @import("compiler_rt/count0bits.zig").__clzti2; - @export(__clzti2, .{ .name = "__clzti2", .linkage = linkage }); - const __ctzsi2 = @import("compiler_rt/count0bits.zig").__ctzsi2; - @export(__ctzsi2, .{ .name = "__ctzsi2", .linkage = linkage }); - const __ctzdi2 = @import("compiler_rt/count0bits.zig").__ctzdi2; - @export(__ctzdi2, .{ .name = "__ctzdi2", .linkage = linkage }); - const __ctzti2 = @import("compiler_rt/count0bits.zig").__ctzti2; - @export(__ctzti2, .{ .name = "__ctzti2", .linkage = linkage }); - const __ffssi2 = @import("compiler_rt/count0bits.zig").__ffssi2; - @export(__ffssi2, .{ .name = "__ffssi2", .linkage = linkage }); - const __ffsdi2 = @import("compiler_rt/count0bits.zig").__ffsdi2; - @export(__ffsdi2, .{ .name = "__ffsdi2", .linkage = linkage }); - const __ffsti2 = @import("compiler_rt/count0bits.zig").__ffsti2; - @export(__ffsti2, .{ .name = "__ffsti2", .linkage = linkage }); - const __paritysi2 = @import("compiler_rt/parity.zig").__paritysi2; - @export(__paritysi2, .{ .name = "__paritysi2", .linkage = linkage }); - const __paritydi2 = @import("compiler_rt/parity.zig").__paritydi2; - @export(__paritydi2, .{ .name = "__paritydi2", .linkage = linkage }); - const __parityti2 = @import("compiler_rt/parity.zig").__parityti2; - @export(__parityti2, .{ .name = "__parityti2", .linkage = linkage }); - const __popcountsi2 = @import("compiler_rt/popcount.zig").__popcountsi2; - @export(__popcountsi2, .{ .name = "__popcountsi2", .linkage = linkage }); - const __popcountdi2 = @import("compiler_rt/popcount.zig").__popcountdi2; - @export(__popcountdi2, .{ .name = "__popcountdi2", .linkage = linkage }); - const __popcountti2 = @import("compiler_rt/popcount.zig").__popcountti2; - @export(__popcountti2, .{ .name = "__popcountti2", .linkage = linkage }); - const __bswapsi2 = @import("compiler_rt/bswap.zig").__bswapsi2; - @export(__bswapsi2, .{ .name = "__bswapsi2", .linkage = linkage }); - const __bswapdi2 = @import("compiler_rt/bswap.zig").__bswapdi2; - @export(__bswapdi2, .{ .name = "__bswapdi2", .linkage = linkage }); - const __bswapti2 = @import("compiler_rt/bswap.zig").__bswapti2; - @export(__bswapti2, .{ .name = "__bswapti2", .linkage = linkage }); - - // Integral -> Float Conversion - - // Conversion to f32 - const __floatsisf = @import("compiler_rt/floatXiYf.zig").__floatsisf; - @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage }); - const __floatunsisf = @import("compiler_rt/floatXiYf.zig").__floatunsisf; - @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage }); - - const __floatundisf = @import("compiler_rt/floatXiYf.zig").__floatundisf; - @export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage }); - const __floatdisf = @import("compiler_rt/floatXiYf.zig").__floatdisf; - @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage }); - - const __floattisf = @import("compiler_rt/floatXiYf.zig").__floattisf; - @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage }); - const __floatuntisf = @import("compiler_rt/floatXiYf.zig").__floatuntisf; - @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage }); - - // Conversion to f64 - const __floatsidf = @import("compiler_rt/floatXiYf.zig").__floatsidf; - @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage }); - const __floatunsidf = @import("compiler_rt/floatXiYf.zig").__floatunsidf; - @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage }); - - const __floatdidf = @import("compiler_rt/floatXiYf.zig").__floatdidf; - @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage }); - const __floatundidf = @import("compiler_rt/floatXiYf.zig").__floatundidf; - @export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage }); - - const __floattidf = @import("compiler_rt/floatXiYf.zig").__floattidf; - @export(__floattidf, .{ .name = "__floattidf", .linkage = linkage }); - const __floatuntidf = @import("compiler_rt/floatXiYf.zig").__floatuntidf; - @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage }); - - // Conversion to f80 - const __floatsixf = @import("compiler_rt/floatXiYf.zig").__floatsixf; - @export(__floatsixf, .{ .name = "__floatsixf", .linkage = linkage }); - const __floatunsixf = @import("compiler_rt/floatXiYf.zig").__floatunsixf; - @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = linkage }); - - const __floatdixf = @import("compiler_rt/floatXiYf.zig").__floatdixf; - @export(__floatdixf, .{ .name = "__floatdixf", .linkage = linkage }); - const __floatundixf = @import("compiler_rt/floatXiYf.zig").__floatundixf; - @export(__floatundixf, .{ .name = "__floatundixf", .linkage = linkage }); - - const __floattixf = @import("compiler_rt/floatXiYf.zig").__floattixf; - @export(__floattixf, .{ .name = "__floattixf", .linkage = linkage }); - const __floatuntixf = @import("compiler_rt/floatXiYf.zig").__floatuntixf; - @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = linkage }); - - // Conversion to f128 - const __floatsitf = @import("compiler_rt/floatXiYf.zig").__floatsitf; - @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage }); - const __floatunsitf = @import("compiler_rt/floatXiYf.zig").__floatunsitf; - @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage }); - - const __floatditf = @import("compiler_rt/floatXiYf.zig").__floatditf; - @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage }); - const __floatunditf = @import("compiler_rt/floatXiYf.zig").__floatunditf; - @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage }); - - const __floattitf = @import("compiler_rt/floatXiYf.zig").__floattitf; - @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage }); - const __floatuntitf = @import("compiler_rt/floatXiYf.zig").__floatuntitf; - @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage }); - - // Float -> Integral Conversion - - // Conversion from f32 - const __fixsfsi = @import("compiler_rt/fixXfYi.zig").__fixsfsi; - @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage }); - const __fixunssfsi = @import("compiler_rt/fixXfYi.zig").__fixunssfsi; - @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage }); - - const __fixsfdi = @import("compiler_rt/fixXfYi.zig").__fixsfdi; - @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage }); - const __fixunssfdi = @import("compiler_rt/fixXfYi.zig").__fixunssfdi; - @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage }); - - const __fixsfti = @import("compiler_rt/fixXfYi.zig").__fixsfti; - @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage }); - const __fixunssfti = @import("compiler_rt/fixXfYi.zig").__fixunssfti; - @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage }); - - // Conversion from f64 - const __fixdfsi = @import("compiler_rt/fixXfYi.zig").__fixdfsi; - @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage }); - const __fixunsdfsi = @import("compiler_rt/fixXfYi.zig").__fixunsdfsi; - @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage }); - - const __fixdfdi = @import("compiler_rt/fixXfYi.zig").__fixdfdi; - @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage }); - const __fixunsdfdi = @import("compiler_rt/fixXfYi.zig").__fixunsdfdi; - @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage }); - - const __fixdfti = @import("compiler_rt/fixXfYi.zig").__fixdfti; - @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage }); - const __fixunsdfti = @import("compiler_rt/fixXfYi.zig").__fixunsdfti; - @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage }); - - // Conversion from f80 - const __fixxfsi = @import("compiler_rt/fixXfYi.zig").__fixxfsi; - @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = linkage }); - const __fixunsxfsi = @import("compiler_rt/fixXfYi.zig").__fixunsxfsi; - @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = linkage }); - - const __fixxfdi = @import("compiler_rt/fixXfYi.zig").__fixxfdi; - @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = linkage }); - const __fixunsxfdi = @import("compiler_rt/fixXfYi.zig").__fixunsxfdi; - @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = linkage }); - - const __fixxfti = @import("compiler_rt/fixXfYi.zig").__fixxfti; - @export(__fixxfti, .{ .name = "__fixxfti", .linkage = linkage }); - const __fixunsxfti = @import("compiler_rt/fixXfYi.zig").__fixunsxfti; - @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = linkage }); - - // Conversion from f128 - const __fixtfsi = @import("compiler_rt/fixXfYi.zig").__fixtfsi; - @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage }); - const __fixunstfsi = @import("compiler_rt/fixXfYi.zig").__fixunstfsi; - @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage }); - - const __fixtfdi = @import("compiler_rt/fixXfYi.zig").__fixtfdi; - @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage }); - const __fixunstfdi = @import("compiler_rt/fixXfYi.zig").__fixunstfdi; - @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage }); - - const __fixtfti = @import("compiler_rt/fixXfYi.zig").__fixtfti; - @export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage }); - const __fixunstfti = @import("compiler_rt/fixXfYi.zig").__fixunstfti; - @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage }); - - const __udivmoddi4 = @import("compiler_rt/int.zig").__udivmoddi4; - @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = linkage }); - - const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2; - @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage }); - if (!is_test) { - @export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage }); - } - const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2; - @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage }); - - if (is_darwin) { - const __isPlatformVersionAtLeast = @import("compiler_rt/os_version_check.zig").__isPlatformVersionAtLeast; - @export(__isPlatformVersionAtLeast, .{ .name = "__isPlatformVersionAtLeast", .linkage = linkage }); - } - - // Integer Arithmetic - const __ashldi3 = @import("compiler_rt/shift.zig").__ashldi3; - @export(__ashldi3, .{ .name = "__ashldi3", .linkage = linkage }); - const __ashlti3 = @import("compiler_rt/shift.zig").__ashlti3; - @export(__ashlti3, .{ .name = "__ashlti3", .linkage = linkage }); - const __ashrdi3 = @import("compiler_rt/shift.zig").__ashrdi3; - @export(__ashrdi3, .{ .name = "__ashrdi3", .linkage = linkage }); - const __ashrti3 = @import("compiler_rt/shift.zig").__ashrti3; - @export(__ashrti3, .{ .name = "__ashrti3", .linkage = linkage }); - const __lshrdi3 = @import("compiler_rt/shift.zig").__lshrdi3; - @export(__lshrdi3, .{ .name = "__lshrdi3", .linkage = linkage }); - const __lshrti3 = @import("compiler_rt/shift.zig").__lshrti3; - @export(__lshrti3, .{ .name = "__lshrti3", .linkage = linkage }); - const __negsi2 = @import("compiler_rt/negXi2.zig").__negsi2; - @export(__negsi2, .{ .name = "__negsi2", .linkage = linkage }); - const __negdi2 = @import("compiler_rt/negXi2.zig").__negdi2; - @export(__negdi2, .{ .name = "__negdi2", .linkage = linkage }); - const __negti2 = @import("compiler_rt/negXi2.zig").__negti2; - @export(__negti2, .{ .name = "__negti2", .linkage = linkage }); - - const __mulsi3 = @import("compiler_rt/int.zig").__mulsi3; - @export(__mulsi3, .{ .name = "__mulsi3", .linkage = linkage }); - const __muldi3 = @import("compiler_rt/muldi3.zig").__muldi3; - @export(__muldi3, .{ .name = "__muldi3", .linkage = linkage }); - const __divmoddi4 = @import("compiler_rt/int.zig").__divmoddi4; - @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = linkage }); - const __divsi3 = @import("compiler_rt/int.zig").__divsi3; - @export(__divsi3, .{ .name = "__divsi3", .linkage = linkage }); - const __divdi3 = @import("compiler_rt/int.zig").__divdi3; - @export(__divdi3, .{ .name = "__divdi3", .linkage = linkage }); - const __udivsi3 = @import("compiler_rt/int.zig").__udivsi3; - @export(__udivsi3, .{ .name = "__udivsi3", .linkage = linkage }); - const __udivdi3 = @import("compiler_rt/int.zig").__udivdi3; - @export(__udivdi3, .{ .name = "__udivdi3", .linkage = linkage }); - const __modsi3 = @import("compiler_rt/int.zig").__modsi3; - @export(__modsi3, .{ .name = "__modsi3", .linkage = linkage }); - const __moddi3 = @import("compiler_rt/int.zig").__moddi3; - @export(__moddi3, .{ .name = "__moddi3", .linkage = linkage }); - const __umodsi3 = @import("compiler_rt/int.zig").__umodsi3; - @export(__umodsi3, .{ .name = "__umodsi3", .linkage = linkage }); - const __umoddi3 = @import("compiler_rt/int.zig").__umoddi3; - @export(__umoddi3, .{ .name = "__umoddi3", .linkage = linkage }); - const __divmodsi4 = @import("compiler_rt/int.zig").__divmodsi4; - @export(__divmodsi4, .{ .name = "__divmodsi4", .linkage = linkage }); - const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4; - @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage }); - - // Integer Arithmetic with trapping overflow - const __absvsi2 = @import("compiler_rt/absv.zig").__absvsi2; - @export(__absvsi2, .{ .name = "__absvsi2", .linkage = linkage }); - const __absvdi2 = @import("compiler_rt/absv.zig").__absvdi2; - @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); - const __absvti2 = @import("compiler_rt/absv.zig").__absvti2; - @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); - const __negvsi2 = @import("compiler_rt/negv.zig").__negvsi2; - @export(__negvsi2, .{ .name = "__negvsi2", .linkage = linkage }); - const __negvdi2 = @import("compiler_rt/negv.zig").__negvdi2; - @export(__negvdi2, .{ .name = "__negvdi2", .linkage = linkage }); - const __negvti2 = @import("compiler_rt/negv.zig").__negvti2; - @export(__negvti2, .{ .name = "__negvti2", .linkage = linkage }); - - // Integer arithmetic which returns if overflow - const __addosi4 = @import("compiler_rt/addo.zig").__addosi4; - @export(__addosi4, .{ .name = "__addosi4", .linkage = linkage }); - const __addodi4 = @import("compiler_rt/addo.zig").__addodi4; - @export(__addodi4, .{ .name = "__addodi4", .linkage = linkage }); - const __addoti4 = @import("compiler_rt/addo.zig").__addoti4; - @export(__addoti4, .{ .name = "__addoti4", .linkage = linkage }); - const __subosi4 = @import("compiler_rt/subo.zig").__subosi4; - @export(__subosi4, .{ .name = "__subosi4", .linkage = linkage }); - const __subodi4 = @import("compiler_rt/subo.zig").__subodi4; - @export(__subodi4, .{ .name = "__subodi4", .linkage = linkage }); - const __suboti4 = @import("compiler_rt/subo.zig").__suboti4; - @export(__suboti4, .{ .name = "__suboti4", .linkage = linkage }); - const __mulosi4 = @import("compiler_rt/mulo.zig").__mulosi4; - @export(__mulosi4, .{ .name = "__mulosi4", .linkage = linkage }); - const __mulodi4 = @import("compiler_rt/mulo.zig").__mulodi4; - @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage }); - const __muloti4 = @import("compiler_rt/mulo.zig").__muloti4; - @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage }); - - // Integer Comparison - // (a < b) => 0 - // (a == b) => 1 - // (a > b) => 2 - const __cmpsi2 = @import("compiler_rt/cmp.zig").__cmpsi2; - @export(__cmpsi2, .{ .name = "__cmpsi2", .linkage = linkage }); - const __cmpdi2 = @import("compiler_rt/cmp.zig").__cmpdi2; - @export(__cmpdi2, .{ .name = "__cmpdi2", .linkage = linkage }); - const __cmpti2 = @import("compiler_rt/cmp.zig").__cmpti2; - @export(__cmpti2, .{ .name = "__cmpti2", .linkage = linkage }); - const __ucmpsi2 = @import("compiler_rt/cmp.zig").__ucmpsi2; - @export(__ucmpsi2, .{ .name = "__ucmpsi2", .linkage = linkage }); - const __ucmpdi2 = @import("compiler_rt/cmp.zig").__ucmpdi2; - @export(__ucmpdi2, .{ .name = "__ucmpdi2", .linkage = linkage }); - const __ucmpti2 = @import("compiler_rt/cmp.zig").__ucmpti2; - @export(__ucmpti2, .{ .name = "__ucmpti2", .linkage = linkage }); - - // missing: Floating point raised to integer power - - // missing: Complex arithmetic - // (a + ib) * (c + id) - // (a + ib) / (c + id) - - const __negsf2 = @import("compiler_rt/negXf2.zig").__negsf2; - @export(__negsf2, .{ .name = "__negsf2", .linkage = linkage }); - const __negdf2 = @import("compiler_rt/negXf2.zig").__negdf2; - @export(__negdf2, .{ .name = "__negdf2", .linkage = linkage }); - - if (builtin.link_libc and os_tag == .openbsd) { - const __emutls_get_address = @import("compiler_rt/emutls.zig").__emutls_get_address; - @export(__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = linkage }); - } - - if ((arch.isARM() or arch.isThumb()) and !is_test) { - const __aeabi_unwind_cpp_pr0 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0; - @export(__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage }); - const __aeabi_unwind_cpp_pr1 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1; - @export(__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage }); - const __aeabi_unwind_cpp_pr2 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2; - @export(__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage }); - - @export(__muldi3, .{ .name = "__aeabi_lmul", .linkage = linkage }); - - const __aeabi_ldivmod = @import("compiler_rt/arm.zig").__aeabi_ldivmod; - @export(__aeabi_ldivmod, .{ .name = "__aeabi_ldivmod", .linkage = linkage }); - const __aeabi_uldivmod = @import("compiler_rt/arm.zig").__aeabi_uldivmod; - @export(__aeabi_uldivmod, .{ .name = "__aeabi_uldivmod", .linkage = linkage }); - - @export(__divsi3, .{ .name = "__aeabi_idiv", .linkage = linkage }); - const __aeabi_idivmod = @import("compiler_rt/arm.zig").__aeabi_idivmod; - @export(__aeabi_idivmod, .{ .name = "__aeabi_idivmod", .linkage = linkage }); - @export(__udivsi3, .{ .name = "__aeabi_uidiv", .linkage = linkage }); - const __aeabi_uidivmod = @import("compiler_rt/arm.zig").__aeabi_uidivmod; - @export(__aeabi_uidivmod, .{ .name = "__aeabi_uidivmod", .linkage = linkage }); - - const __aeabi_memcpy = @import("compiler_rt/arm.zig").__aeabi_memcpy; - @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy", .linkage = linkage }); - @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy4", .linkage = linkage }); - @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy8", .linkage = linkage }); - - const __aeabi_memmove = @import("compiler_rt/arm.zig").__aeabi_memmove; - @export(__aeabi_memmove, .{ .name = "__aeabi_memmove", .linkage = linkage }); - @export(__aeabi_memmove, .{ .name = "__aeabi_memmove4", .linkage = linkage }); - @export(__aeabi_memmove, .{ .name = "__aeabi_memmove8", .linkage = linkage }); - - const __aeabi_memset = @import("compiler_rt/arm.zig").__aeabi_memset; - @export(__aeabi_memset, .{ .name = "__aeabi_memset", .linkage = linkage }); - @export(__aeabi_memset, .{ .name = "__aeabi_memset4", .linkage = linkage }); - @export(__aeabi_memset, .{ .name = "__aeabi_memset8", .linkage = linkage }); - - const __aeabi_memclr = @import("compiler_rt/arm.zig").__aeabi_memclr; - @export(__aeabi_memclr, .{ .name = "__aeabi_memclr", .linkage = linkage }); - @export(__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage }); - @export(__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage }); - - if (os_tag == .linux) { - const __aeabi_read_tp = @import("compiler_rt/arm.zig").__aeabi_read_tp; - @export(__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage }); - } - - const __aeabi_f2d = @import("compiler_rt/extendXfYf2.zig").__aeabi_f2d; - @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage }); - const __aeabi_i2d = @import("compiler_rt/floatXiYf.zig").__aeabi_i2d; - @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage }); - const __aeabi_l2d = @import("compiler_rt/floatXiYf.zig").__aeabi_l2d; - @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage }); - const __aeabi_l2f = @import("compiler_rt/floatXiYf.zig").__aeabi_l2f; - @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage }); - const __aeabi_ui2d = @import("compiler_rt/floatXiYf.zig").__aeabi_ui2d; - @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage }); - const __aeabi_ul2d = @import("compiler_rt/floatXiYf.zig").__aeabi_ul2d; - @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage }); - const __aeabi_ui2f = @import("compiler_rt/floatXiYf.zig").__aeabi_ui2f; - @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage }); - const __aeabi_ul2f = @import("compiler_rt/floatXiYf.zig").__aeabi_ul2f; - @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage }); - - const __aeabi_fneg = @import("compiler_rt/negXf2.zig").__aeabi_fneg; - @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = linkage }); - const __aeabi_dneg = @import("compiler_rt/negXf2.zig").__aeabi_dneg; - @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = linkage }); - - const __aeabi_fmul = @import("compiler_rt/mulXf3.zig").__aeabi_fmul; - @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = linkage }); - const __aeabi_dmul = @import("compiler_rt/mulXf3.zig").__aeabi_dmul; - @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = linkage }); - - const __aeabi_d2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2h; - @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage }); - - const __aeabi_f2ulz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2ulz; - @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage }); - const __aeabi_d2ulz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2ulz; - @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage }); - - const __aeabi_f2lz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2lz; - @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage }); - const __aeabi_d2lz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2lz; - @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage }); - - const __aeabi_d2uiz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2uiz; - @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage }); - - const __aeabi_h2f = @import("compiler_rt/extendXfYf2.zig").__aeabi_h2f; - @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = linkage }); - const __aeabi_f2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_f2h; - @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage }); - - const __aeabi_i2f = @import("compiler_rt/floatXiYf.zig").__aeabi_i2f; - @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage }); - const __aeabi_d2f = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2f; - @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage }); - - const __aeabi_fadd = @import("compiler_rt/addXf3.zig").__aeabi_fadd; - @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = linkage }); - const __aeabi_dadd = @import("compiler_rt/addXf3.zig").__aeabi_dadd; - @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = linkage }); - const __aeabi_fsub = @import("compiler_rt/addXf3.zig").__aeabi_fsub; - @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = linkage }); - const __aeabi_dsub = @import("compiler_rt/addXf3.zig").__aeabi_dsub; - @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage }); - - const __aeabi_f2uiz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2uiz; - @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage }); - - const __aeabi_f2iz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2iz; - @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage }); - const __aeabi_d2iz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2iz; - @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage }); - - const __aeabi_fdiv = @import("compiler_rt/divsf3.zig").__aeabi_fdiv; - @export(__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = linkage }); - const __aeabi_ddiv = @import("compiler_rt/divdf3.zig").__aeabi_ddiv; - @export(__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = linkage }); - - const __aeabi_llsl = @import("compiler_rt/shift.zig").__aeabi_llsl; - @export(__aeabi_llsl, .{ .name = "__aeabi_llsl", .linkage = linkage }); - const __aeabi_lasr = @import("compiler_rt/shift.zig").__aeabi_lasr; - @export(__aeabi_lasr, .{ .name = "__aeabi_lasr", .linkage = linkage }); - const __aeabi_llsr = @import("compiler_rt/shift.zig").__aeabi_llsr; - @export(__aeabi_llsr, .{ .name = "__aeabi_llsr", .linkage = linkage }); - - const __aeabi_fcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpeq; - @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage }); - const __aeabi_fcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmplt; - @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage }); - const __aeabi_fcmple = @import("compiler_rt/compareXf2.zig").__aeabi_fcmple; - @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage }); - const __aeabi_fcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpge; - @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage }); - const __aeabi_fcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpgt; - @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage }); - const __aeabi_fcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpun; - @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage }); - - const __aeabi_dcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpeq; - @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage }); - const __aeabi_dcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmplt; - @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage }); - const __aeabi_dcmple = @import("compiler_rt/compareXf2.zig").__aeabi_dcmple; - @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage }); - const __aeabi_dcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpge; - @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage }); - const __aeabi_dcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpgt; - @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage }); - const __aeabi_dcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpun; - @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage }); - } - - if (arch == .i386 and abi == .msvc) { - // Don't let LLVM apply the stdcall name mangling on those MSVC builtins - const _alldiv = @import("compiler_rt/aulldiv.zig")._alldiv; - @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage }); - const _aulldiv = @import("compiler_rt/aulldiv.zig")._aulldiv; - @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage }); - const _allrem = @import("compiler_rt/aullrem.zig")._allrem; - @export(_allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage }); - const _aullrem = @import("compiler_rt/aullrem.zig")._aullrem; - @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage }); - } - - mathExport("ceil", @import("./compiler_rt/ceil.zig")); - mathExport("cos", @import("./compiler_rt/cos.zig")); - mathExport("exp", @import("./compiler_rt/exp.zig")); - mathExport("exp2", @import("./compiler_rt/exp2.zig")); - mathExport("fabs", @import("./compiler_rt/fabs.zig")); - mathExport("floor", @import("./compiler_rt/floor.zig")); - mathExport("fma", @import("./compiler_rt/fma.zig")); - mathExport("fmax", @import("./compiler_rt/fmax.zig")); - mathExport("fmin", @import("./compiler_rt/fmin.zig")); - mathExport("fmod", @import("./compiler_rt/fmod.zig")); - mathExport("log", @import("./compiler_rt/log.zig")); - mathExport("log10", @import("./compiler_rt/log10.zig")); - mathExport("log2", @import("./compiler_rt/log2.zig")); - mathExport("round", @import("./compiler_rt/round.zig")); - mathExport("sin", @import("./compiler_rt/sin.zig")); - mathExport("sincos", @import("./compiler_rt/sincos.zig")); - mathExport("sqrt", @import("./compiler_rt/sqrt.zig")); - mathExport("tan", @import("./compiler_rt/tan.zig")); - mathExport("trunc", @import("./compiler_rt/trunc.zig")); - - if (arch.isSPARC()) { - // SPARC systems use a different naming scheme - const _Qp_add = @import("compiler_rt/sparc.zig")._Qp_add; - @export(_Qp_add, .{ .name = "_Qp_add", .linkage = linkage }); - const _Qp_div = @import("compiler_rt/sparc.zig")._Qp_div; - @export(_Qp_div, .{ .name = "_Qp_div", .linkage = linkage }); - const _Qp_mul = @import("compiler_rt/sparc.zig")._Qp_mul; - @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = linkage }); - const _Qp_sub = @import("compiler_rt/sparc.zig")._Qp_sub; - @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = linkage }); - - const _Qp_cmp = @import("compiler_rt/sparc.zig")._Qp_cmp; - @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = linkage }); - const _Qp_feq = @import("compiler_rt/sparc.zig")._Qp_feq; - @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = linkage }); - const _Qp_fne = @import("compiler_rt/sparc.zig")._Qp_fne; - @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = linkage }); - const _Qp_flt = @import("compiler_rt/sparc.zig")._Qp_flt; - @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = linkage }); - const _Qp_fle = @import("compiler_rt/sparc.zig")._Qp_fle; - @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = linkage }); - const _Qp_fgt = @import("compiler_rt/sparc.zig")._Qp_fgt; - @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = linkage }); - const _Qp_fge = @import("compiler_rt/sparc.zig")._Qp_fge; - @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = linkage }); - - const _Qp_itoq = @import("compiler_rt/sparc.zig")._Qp_itoq; - @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = linkage }); - const _Qp_uitoq = @import("compiler_rt/sparc.zig")._Qp_uitoq; - @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = linkage }); - const _Qp_xtoq = @import("compiler_rt/sparc.zig")._Qp_xtoq; - @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = linkage }); - const _Qp_uxtoq = @import("compiler_rt/sparc.zig")._Qp_uxtoq; - @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = linkage }); - const _Qp_stoq = @import("compiler_rt/sparc.zig")._Qp_stoq; - @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = linkage }); - const _Qp_dtoq = @import("compiler_rt/sparc.zig")._Qp_dtoq; - @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = linkage }); - const _Qp_qtoi = @import("compiler_rt/sparc.zig")._Qp_qtoi; - @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = linkage }); - const _Qp_qtoui = @import("compiler_rt/sparc.zig")._Qp_qtoui; - @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = linkage }); - const _Qp_qtox = @import("compiler_rt/sparc.zig")._Qp_qtox; - @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = linkage }); - const _Qp_qtoux = @import("compiler_rt/sparc.zig")._Qp_qtoux; - @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = linkage }); - const _Qp_qtos = @import("compiler_rt/sparc.zig")._Qp_qtos; - @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = linkage }); - const _Qp_qtod = @import("compiler_rt/sparc.zig")._Qp_qtod; - @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage }); - } - - if (is_ppc and !is_test) { - @export(__addtf3, .{ .name = "__addkf3", .linkage = linkage }); - @export(__subtf3, .{ .name = "__subkf3", .linkage = linkage }); - @export(__multf3, .{ .name = "__mulkf3", .linkage = linkage }); - @export(__divtf3, .{ .name = "__divkf3", .linkage = linkage }); - @export(__extendsftf2, .{ .name = "__extendsfkf2", .linkage = linkage }); - @export(__extenddftf2, .{ .name = "__extenddfkf2", .linkage = linkage }); - @export(__trunctfsf2, .{ .name = "__trunckfsf2", .linkage = linkage }); - @export(__trunctfdf2, .{ .name = "__trunckfdf2", .linkage = linkage }); - @export(__fixtfdi, .{ .name = "__fixkfdi", .linkage = linkage }); - @export(__fixtfsi, .{ .name = "__fixkfsi", .linkage = linkage }); - @export(__fixunstfsi, .{ .name = "__fixunskfsi", .linkage = linkage }); - @export(__fixunstfdi, .{ .name = "__fixunskfdi", .linkage = linkage }); - @export(__floatsitf, .{ .name = "__floatsikf", .linkage = linkage }); - @export(__floatditf, .{ .name = "__floatdikf", .linkage = linkage }); - @export(__floatunditf, .{ .name = "__floatundikf", .linkage = linkage }); - @export(__floatunsitf, .{ .name = "__floatunsikf", .linkage = linkage }); - @export(__floatuntitf, .{ .name = "__floatuntikf", .linkage = linkage }); - - @export(__letf2, .{ .name = "__eqkf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__nekf2", .linkage = linkage }); - @export(__getf2, .{ .name = "__gekf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__ltkf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__lekf2", .linkage = linkage }); - @export(__getf2, .{ .name = "__gtkf2", .linkage = linkage }); - @export(__unordtf2, .{ .name = "__unordkf2", .linkage = linkage }); - } -} - -inline fn mathExport(double_name: []const u8, comptime import: type) void { - const half_name = "__" ++ double_name ++ "h"; - const half_fn = @field(import, half_name); - const float_name = double_name ++ "f"; - const float_fn = @field(import, float_name); - const double_fn = @field(import, double_name); - const long_double_name = double_name ++ "l"; - const xf80_name = "__" ++ double_name ++ "x"; - const xf80_fn = @field(import, xf80_name); - const quad_name = double_name ++ "q"; - const quad_fn = @field(import, quad_name); - - @export(half_fn, .{ .name = half_name, .linkage = linkage }); - @export(float_fn, .{ .name = float_name, .linkage = linkage }); - @export(double_fn, .{ .name = double_name, .linkage = linkage }); - @export(xf80_fn, .{ .name = xf80_name, .linkage = linkage }); - @export(quad_fn, .{ .name = quad_name, .linkage = linkage }); - - if (is_test) return; - - const pairs = .{ - .{ f16, half_fn }, - .{ f32, float_fn }, - .{ f64, double_fn }, - .{ f80, xf80_fn }, - .{ f128, quad_fn }, - }; - - if (builtin.os.tag == .windows) { - // Weak aliases don't work on Windows, so we have to provide the 'l' variants - // as additional function definitions that jump to the real definition. - const long_double_fn = @field(import, long_double_name); - @export(long_double_fn, .{ .name = long_double_name, .linkage = linkage }); - } else { - inline for (pairs) |pair| { - const F = pair[0]; - const func = pair[1]; - if (builtin.target.longDoubleIs(F)) { - @export(func, .{ .name = long_double_name, .linkage = linkage }); - } - } - } - - if (is_ppc) { - // LLVM PPC backend lowers f128 ops with the suffix `f128` instead of `l`. - @export(quad_fn, .{ .name = double_name ++ "f128", .linkage = linkage }); - } -} -// Avoid dragging in the runtime safety mechanisms into this .o file, -// unless we're trying to test this file. -pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { - _ = error_return_trace; - @setCold(true); - if (is_test) { - std.debug.panic("{s}", .{msg}); - } else { - unreachable; - } + _ = @import("compiler_rt/addf3.zig"); + _ = @import("compiler_rt/addsf3.zig"); + _ = @import("compiler_rt/addtf3.zig"); + _ = @import("compiler_rt/addxf3.zig"); + _ = @import("compiler_rt/subdf3.zig"); + _ = @import("compiler_rt/subsf3.zig"); + _ = @import("compiler_rt/subtf3.zig"); + _ = @import("compiler_rt/subxf3.zig"); + + _ = @import("compiler_rt/mulf3.zig"); + _ = @import("compiler_rt/muldf3.zig"); + _ = @import("compiler_rt/mulsf3.zig"); + _ = @import("compiler_rt/multf3.zig"); + _ = @import("compiler_rt/mulxf3.zig"); + + _ = @import("compiler_rt/comparef.zig"); + _ = @import("compiler_rt/cmpsf2.zig"); + _ = @import("compiler_rt/cmpdf2.zig"); + _ = @import("compiler_rt/cmptf2.zig"); + _ = @import("compiler_rt/cmpxf2.zig"); + _ = @import("compiler_rt/gesf2.zig"); + _ = @import("compiler_rt/gedf2.zig"); + _ = @import("compiler_rt/getf2.zig"); + _ = @import("compiler_rt/gexf2.zig"); + _ = @import("compiler_rt/unordsf2.zig"); + _ = @import("compiler_rt/unorddf2.zig"); + _ = @import("compiler_rt/unordtf2.zig"); + + _ = @import("compiler_rt/extendf.zig"); + _ = @import("compiler_rt/extenddftf2.zig"); + _ = @import("compiler_rt/extenddfxf2.zig"); + _ = @import("compiler_rt/extendhfsf2.zig"); + _ = @import("compiler_rt/extendhftf2.zig"); + _ = @import("compiler_rt/extendhfxf2.zig"); + _ = @import("compiler_rt/extendsfdf2.zig"); + _ = @import("compiler_rt/extendsftf2.zig"); + _ = @import("compiler_rt/extendsfxf2.zig"); + _ = @import("compiler_rt/extendxftf2.zig"); + + _ = @import("compiler_rt/truncf.zig"); + _ = @import("compiler_rt/truncsfhf2.zig"); + _ = @import("compiler_rt/truncdfhf2.zig"); + _ = @import("compiler_rt/truncdfsf2.zig"); + _ = @import("compiler_rt/trunctfhf2.zig"); + _ = @import("compiler_rt/trunctfsf2.zig"); + _ = @import("compiler_rt/trunctfdf2.zig"); + _ = @import("compiler_rt/trunctfxf2.zig"); + _ = @import("compiler_rt/truncxfhf2.zig"); + _ = @import("compiler_rt/truncxfsf2.zig"); + _ = @import("compiler_rt/truncxfdf2.zig"); + + _ = @import("compiler_rt/divtf3.zig"); + _ = @import("compiler_rt/divsf3.zig"); + _ = @import("compiler_rt/divdf3.zig"); + _ = @import("compiler_rt/divxf3.zig"); + _ = @import("compiler_rt/sin.zig"); + _ = @import("compiler_rt/cos.zig"); + _ = @import("compiler_rt/sincos.zig"); + _ = @import("compiler_rt/ceil.zig"); + _ = @import("compiler_rt/exp.zig"); + _ = @import("compiler_rt/exp2.zig"); + _ = @import("compiler_rt/fabs.zig"); + _ = @import("compiler_rt/floor.zig"); + _ = @import("compiler_rt/fma.zig"); + _ = @import("compiler_rt/fmax.zig"); + _ = @import("compiler_rt/fmin.zig"); + _ = @import("compiler_rt/fmod.zig"); + _ = @import("compiler_rt/log.zig"); + _ = @import("compiler_rt/log10.zig"); + _ = @import("compiler_rt/log2.zig"); + _ = @import("compiler_rt/round.zig"); + _ = @import("compiler_rt/sqrt.zig"); + _ = @import("compiler_rt/tan.zig"); + _ = @import("compiler_rt/trunc.zig"); + _ = @import("compiler_rt/stack_probe.zig"); + _ = @import("compiler_rt/divti3.zig"); + _ = @import("compiler_rt/modti3.zig"); + _ = @import("compiler_rt/multi3.zig"); + _ = @import("compiler_rt/udivti3.zig"); + _ = @import("compiler_rt/udivmodti4.zig"); + _ = @import("compiler_rt/umodti3.zig"); + + _ = @import("compiler_rt/int_to_float.zig"); + _ = @import("compiler_rt/floatsihf.zig"); + _ = @import("compiler_rt/floatsisf.zig"); + _ = @import("compiler_rt/floatsidf.zig"); + _ = @import("compiler_rt/floatsitf.zig"); + _ = @import("compiler_rt/floatsixf.zig"); + _ = @import("compiler_rt/floatdihf.zig"); + _ = @import("compiler_rt/floatdisf.zig"); + _ = @import("compiler_rt/floatdidf.zig"); + _ = @import("compiler_rt/floatditf.zig"); + _ = @import("compiler_rt/floatdixf.zig"); + _ = @import("compiler_rt/floattihf.zig"); + _ = @import("compiler_rt/floattisf.zig"); + _ = @import("compiler_rt/floattidf.zig"); + _ = @import("compiler_rt/floattitf.zig"); + _ = @import("compiler_rt/floattixf.zig"); + _ = @import("compiler_rt/floatundihf.zig"); + _ = @import("compiler_rt/floatundisf.zig"); + _ = @import("compiler_rt/floatundidf.zig"); + _ = @import("compiler_rt/floatunditf.zig"); + _ = @import("compiler_rt/floatundixf.zig"); + _ = @import("compiler_rt/floatunsihf.zig"); + _ = @import("compiler_rt/floatunsisf.zig"); + _ = @import("compiler_rt/floatunsidf.zig"); + _ = @import("compiler_rt/floatunsitf.zig"); + _ = @import("compiler_rt/floatunsixf.zig"); + _ = @import("compiler_rt/floatuntihf.zig"); + _ = @import("compiler_rt/floatuntisf.zig"); + _ = @import("compiler_rt/floatuntidf.zig"); + _ = @import("compiler_rt/floatuntitf.zig"); + _ = @import("compiler_rt/floatuntixf.zig"); + + _ = @import("compiler_rt/float_to_int.zig"); + _ = @import("compiler_rt/fixhfsi.zig"); + _ = @import("compiler_rt/fixhfdi.zig"); + _ = @import("compiler_rt/fixhfti.zig"); + _ = @import("compiler_rt/fixsfsi.zig"); + _ = @import("compiler_rt/fixsfdi.zig"); + _ = @import("compiler_rt/fixsfti.zig"); + _ = @import("compiler_rt/fixdfsi.zig"); + _ = @import("compiler_rt/fixdfdi.zig"); + _ = @import("compiler_rt/fixdfti.zig"); + _ = @import("compiler_rt/fixtfsi.zig"); + _ = @import("compiler_rt/fixtfdi.zig"); + _ = @import("compiler_rt/fixtfti.zig"); + _ = @import("compiler_rt/fixxfsi.zig"); + _ = @import("compiler_rt/fixxfdi.zig"); + _ = @import("compiler_rt/fixxfti.zig"); + _ = @import("compiler_rt/fixunshfsi.zig"); + _ = @import("compiler_rt/fixunshfdi.zig"); + _ = @import("compiler_rt/fixunshfti.zig"); + _ = @import("compiler_rt/fixunssfsi.zig"); + _ = @import("compiler_rt/fixunssfdi.zig"); + _ = @import("compiler_rt/fixunssfti.zig"); + _ = @import("compiler_rt/fixunsdfsi.zig"); + _ = @import("compiler_rt/fixunsdfdi.zig"); + _ = @import("compiler_rt/fixunsdfti.zig"); + _ = @import("compiler_rt/fixunstfsi.zig"); + _ = @import("compiler_rt/fixunstfdi.zig"); + _ = @import("compiler_rt/fixunstfti.zig"); + _ = @import("compiler_rt/fixunsxfsi.zig"); + _ = @import("compiler_rt/fixunsxfdi.zig"); + _ = @import("compiler_rt/fixunsxfti.zig"); + + _ = @import("compiler_rt/count0bits.zig"); + _ = @import("compiler_rt/parity.zig"); + _ = @import("compiler_rt/popcount.zig"); + _ = @import("compiler_rt/bswap.zig"); + _ = @import("compiler_rt/int.zig"); + _ = @import("compiler_rt/shift.zig"); + + _ = @import("compiler_rt/negXi2.zig"); + + _ = @import("compiler_rt/muldi3.zig"); + + _ = @import("compiler_rt/absv.zig"); + _ = @import("compiler_rt/absvsi2.zig"); + _ = @import("compiler_rt/absvdi2.zig"); + _ = @import("compiler_rt/absvti2.zig"); + + _ = @import("compiler_rt/negv.zig"); + _ = @import("compiler_rt/addo.zig"); + _ = @import("compiler_rt/subo.zig"); + _ = @import("compiler_rt/mulo.zig"); + _ = @import("compiler_rt/cmp.zig"); + + _ = @import("compiler_rt/negXf2.zig"); + + _ = @import("compiler_rt/os_version_check.zig"); + _ = @import("compiler_rt/emutls.zig"); + _ = @import("compiler_rt/arm.zig"); + _ = @import("compiler_rt/aulldiv.zig"); + _ = @import("compiler_rt/aullrem.zig"); + _ = @import("compiler_rt/clear_cache.zig"); } diff --git a/lib/compiler_rt/absv.zig b/lib/compiler_rt/absv.zig @@ -1,8 +1,6 @@ -// absv - absolute oVerflow -// * @panic, if value can not be represented -// - absvXi4_generic for unoptimized version - -inline fn absvXi(comptime ST: type, a: ST) ST { +/// absv - absolute oVerflow +/// * @panic if value can not be represented +pub inline fn absv(comptime ST: type, a: ST) ST { const UT = switch (ST) { i32 => u32, i64 => u64, @@ -21,18 +19,6 @@ inline fn absvXi(comptime ST: type, a: ST) ST { return x; } -pub fn __absvsi2(a: i32) callconv(.C) i32 { - return absvXi(i32, a); -} - -pub fn __absvdi2(a: i64) callconv(.C) i64 { - return absvXi(i64, a); -} - -pub fn __absvti2(a: i128) callconv(.C) i128 { - return absvXi(i128, a); -} - test { _ = @import("absvsi2_test.zig"); _ = @import("absvdi2_test.zig"); diff --git a/lib/compiler_rt/absvdi2.zig b/lib/compiler_rt/absvdi2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvdi2, .{ .name = "__absvdi2", .linkage = common.linkage }); +} + +pub fn __absvdi2(a: i64) callconv(.C) i64 { + return absv(i64, a); +} diff --git a/lib/compiler_rt/absvdi2_test.zig b/lib/compiler_rt/absvdi2_test.zig @@ -1,8 +1,9 @@ -const absv = @import("absv.zig"); const testing = @import("std").testing; +const __absvdi2 = @import("absvdi2.zig").__absvdi2; + fn test__absvdi2(a: i64, expected: i64) !void { - var result = absv.__absvdi2(a); + var result = __absvdi2(a); try testing.expectEqual(expected, result); } diff --git a/lib/compiler_rt/absvsi2.zig b/lib/compiler_rt/absvsi2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvsi2, .{ .name = "__absvsi2", .linkage = common.linkage }); +} + +pub fn __absvsi2(a: i32) callconv(.C) i32 { + return absv(i32, a); +} diff --git a/lib/compiler_rt/absvsi2_test.zig b/lib/compiler_rt/absvsi2_test.zig @@ -1,8 +1,9 @@ -const absv = @import("absv.zig"); const testing = @import("std").testing; +const __absvsi2 = @import("absvsi2.zig").__absvsi2; + fn test__absvsi2(a: i32, expected: i32) !void { - var result = absv.__absvsi2(a); + var result = __absvsi2(a); try testing.expectEqual(expected, result); } diff --git a/lib/compiler_rt/absvti2.zig b/lib/compiler_rt/absvti2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvti2, .{ .name = "__absvti2", .linkage = common.linkage }); +} + +pub fn __absvti2(a: i128) callconv(.C) i128 { + return absv(i128, a); +} diff --git a/lib/compiler_rt/absvti2_test.zig b/lib/compiler_rt/absvti2_test.zig @@ -1,8 +1,9 @@ -const absv = @import("absv.zig"); const testing = @import("std").testing; +const __absvti2 = @import("absvti2.zig").__absvti2; + fn test__absvti2(a: i128, expected: i128) !void { - var result = absv.__absvti2(a); + var result = __absvti2(a); try testing.expectEqual(expected, result); } diff --git a/lib/compiler_rt/addXf3.zig b/lib/compiler_rt/addXf3.zig @@ -1,244 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc - -const std = @import("std"); -const math = std.math; -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); - -pub fn __addsf3(a: f32, b: f32) callconv(.C) f32 { - return addXf3(f32, a, b); -} - -pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { - return addXf3(f64, a, b); -} - -pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { - return addXf3(f80, a, b); -} - -pub fn __subxf3(a: f80, b: f80) callconv(.C) f80 { - var b_rep = std.math.break_f80(b); - b_rep.exp ^= 0x8000; - return __addxf3(a, std.math.make_f80(b_rep)); -} - -pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { - return addXf3(f128, a, b); -} - -pub fn __subsf3(a: f32, b: f32) callconv(.C) f32 { - const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); - return addXf3(f32, a, neg_b); -} - -pub fn __subdf3(a: f64, b: f64) callconv(.C) f64 { - const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); - return addXf3(f64, a, neg_b); -} - -pub fn __subtf3(a: f128, b: f128) callconv(.C) f128 { - const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); - return addXf3(f128, a, neg_b); -} - -pub fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __addsf3, .{ a, b }); -} - -pub fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __adddf3, .{ a, b }); -} - -pub fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __subsf3, .{ a, b }); -} - -pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __subdf3, .{ a, b }); -} - -// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 -fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { - const bits = @typeInfo(T).Float.bits; - const Z = std.meta.Int(.unsigned, bits); - const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); - const fractionalBits = math.floatFractionalBits(T); - const integerBit = @as(Z, 1) << fractionalBits; - - const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, integerBit); - significand.* <<= @intCast(S, shift); - return @as(i32, 1) - shift; -} - -// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 -fn addXf3(comptime T: type, a: T, b: T) T { - const bits = @typeInfo(T).Float.bits; - const Z = std.meta.Int(.unsigned, bits); - const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); - - const typeWidth = bits; - const significandBits = math.floatMantissaBits(T); - const fractionalBits = math.floatFractionalBits(T); - const exponentBits = math.floatExponentBits(T); - - const signBit = (@as(Z, 1) << (significandBits + exponentBits)); - const maxExponent = ((1 << exponentBits) - 1); - - const integerBit = (@as(Z, 1) << fractionalBits); - const quietBit = integerBit >> 1; - const significandMask = (@as(Z, 1) << significandBits) - 1; - - const absMask = signBit - 1; - const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; - - var aRep = @bitCast(Z, a); - var bRep = @bitCast(Z, b); - const aAbs = aRep & absMask; - const bAbs = bRep & absMask; - - const infRep = @bitCast(Z, math.inf(T)); - - // Detect if a or b is zero, infinity, or NaN. - if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or - bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) - { - // NaN + anything = qNaN - if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); - // anything + NaN = qNaN - if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); - - if (aAbs == infRep) { - // +/-infinity + -/+infinity = qNaN - if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { - return @bitCast(T, qnanRep); - } - // +/-infinity + anything remaining = +/- infinity - else { - return a; - } - } - - // anything remaining + +/-infinity = +/-infinity - if (bAbs == infRep) return b; - - // zero + anything = anything - if (aAbs == 0) { - // but we need to get the sign right for zero + zero - if (bAbs == 0) { - return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); - } else { - return b; - } - } - - // anything + zero = anything - if (bAbs == 0) return a; - } - - // Swap a and b if necessary so that a has the larger absolute value. - if (bAbs > aAbs) { - const temp = aRep; - aRep = bRep; - bRep = temp; - } - - // Extract the exponent and significand from the (possibly swapped) a and b. - var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); - var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); - var aSignificand = aRep & significandMask; - var bSignificand = bRep & significandMask; - - // Normalize any denormals, and adjust the exponent accordingly. - if (aExponent == 0) aExponent = normalize(T, &aSignificand); - if (bExponent == 0) bExponent = normalize(T, &bSignificand); - - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - const resultSign = aRep & signBit; - const subtraction = (aRep ^ bRep) & signBit != 0; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize( ), but setting it twice won't hurt - // anything.) - aSignificand = (aSignificand | integerBit) << 3; - bSignificand = (bSignificand | integerBit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - const @"align" = @intCast(u32, aExponent - bExponent); - if (@"align" != 0) { - if (@"align" < typeWidth) { - const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; - bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; - } else { - bSignificand = 1; // sticky; b is known to be non-zero. - } - } - if (subtraction) { - aSignificand -= bSignificand; - // If a == -b, return +zero. - if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); - - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if (aSignificand < integerBit << 3) { - const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); - aSignificand <<= @intCast(S, shift); - aExponent -= shift; - } - } else { // addition - aSignificand += bSignificand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if (aSignificand & (integerBit << 4) != 0) { - const sticky = aSignificand & 1; - aSignificand = aSignificand >> 1 | sticky; - aExponent += 1; - } - } - - // If we have overflowed the type, return +/- infinity: - if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); - - if (aExponent <= 0) { - // Result is denormal; the exponent and round/sticky bits are zero. - // All we need to do is shift the significand and apply the correct sign. - aSignificand >>= @intCast(S, 4 - aExponent); - return @bitCast(T, resultSign | aSignificand); - } - - // Low three bits are round, guard, and sticky. - const roundGuardSticky = aSignificand & 0x7; - - // Shift the significand into place, and mask off the integer bit, if it's implicit. - var result = (aSignificand >> 3) & significandMask; - - // Insert the exponent and sign. - result |= @intCast(Z, aExponent) << significandBits; - result |= resultSign; - - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if (roundGuardSticky > 0x4) result += 1; - if (roundGuardSticky == 0x4) result += result & 1; - - // Restore any explicit integer bit, if it was rounded off - if (significandBits != fractionalBits) { - if ((result >> significandBits) != 0) result |= integerBit; - } - - return @bitCast(T, result); -} - -test { - _ = @import("addXf3_test.zig"); -} diff --git a/lib/compiler_rt/addXf3_test.zig b/lib/compiler_rt/addXf3_test.zig @@ -1,157 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c - -const std = @import("std"); -const math = std.math; -const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); - -const __addtf3 = @import("addXf3.zig").__addtf3; - -fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __addtf3(a, b); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expected_hi and lo == expected_lo) { - return; - } - // test other possible NaN representation (signal NaN) - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailed; -} - -test "addtf3" { - try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN + any = NaN - try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // inf + inf = inf - try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); - - // inf + any = inf - try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); - - // any + any - try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); - try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); -} - -const __subtf3 = @import("addXf3.zig").__subtf3; - -fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __subtf3(a, b); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expected_hi and lo == expected_lo) { - return; - } - // test other possible NaN representation (signal NaN) - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailed; -} - -test "subtf3" { - // qNaN - any = qNaN - try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN + any = NaN - try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // inf - any = inf - try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); - - // any + any - try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); - try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); -} - -const __addxf3 = @import("addXf3.zig").__addxf3; -const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); - -fn test__addxf3(a: f80, b: f80, expected: u80) !void { - const x = __addxf3(a, b); - const rep = @bitCast(u80, x); - - if (rep == expected) - return; - - if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) - return; // We don't currently test NaN payload propagation - - return error.TestFailed; -} - -test "addxf3" { - // NaN + any = NaN - try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - - // any + NaN = NaN - try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); - try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); - - // NaN + inf = NaN - try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); - - // inf + NaN = NaN - try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); - - // inf + inf = inf - try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); - - // inf + -inf = NaN - try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); - - // -inf + inf = NaN - try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); - - // inf + any = inf - try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); - - // any + inf = inf - try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); - - // any + any - try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); - try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact - - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact - try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact - try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact -} diff --git a/lib/compiler_rt/adddf3.zig b/lib/compiler_rt/adddf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = common.linkage }); + } else { + @export(__adddf3, .{ .name = "__adddf3", .linkage = common.linkage }); + } +} + +fn __adddf3(a: f64, b: f64) callconv(.C) f64 { + return addf3(f64, a, b); +} + +fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { + return addf3(f64, a, b); +} diff --git a/lib/compiler_rt/addf3.zig b/lib/compiler_rt/addf3.zig @@ -0,0 +1,172 @@ +const std = @import("std"); +const math = std.math; +const common = @import("./common.zig"); +const normalize = common.normalize; + +/// Ported from: +/// +/// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc +pub inline fn addf3(comptime T: type, a: T, b: T) T { + const bits = @typeInfo(T).Float.bits; + const Z = std.meta.Int(.unsigned, bits); + const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); + + const typeWidth = bits; + const significandBits = math.floatMantissaBits(T); + const fractionalBits = math.floatFractionalBits(T); + const exponentBits = math.floatExponentBits(T); + + const signBit = (@as(Z, 1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + + const integerBit = (@as(Z, 1) << fractionalBits); + const quietBit = integerBit >> 1; + const significandMask = (@as(Z, 1) << significandBits) - 1; + + const absMask = signBit - 1; + const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; + + var aRep = @bitCast(Z, a); + var bRep = @bitCast(Z, b); + const aAbs = aRep & absMask; + const bAbs = bRep & absMask; + + const infRep = @bitCast(Z, math.inf(T)); + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or + bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) + { + // NaN + anything = qNaN + if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { + return @bitCast(T, qnanRep); + } + // +/-infinity + anything remaining = +/- infinity + else { + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (aAbs == 0) { + // but we need to get the sign right for zero + zero + if (bAbs == 0) { + return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); + } else { + return b; + } + } + + // anything + zero = anything + if (bAbs == 0) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); + var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); + var aSignificand = aRep & significandMask; + var bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(T, &aSignificand); + if (bExponent == 0) bExponent = normalize(T, &bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const resultSign = aRep & signBit; + const subtraction = (aRep ^ bRep) & signBit != 0; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | integerBit) << 3; + bSignificand = (bSignificand | integerBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const @"align" = @intCast(u32, aExponent - bExponent); + if (@"align" != 0) { + if (@"align" < typeWidth) { + const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; + bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + if (subtraction) { + aSignificand -= bSignificand; + // If a == -b, return +zero. + if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < integerBit << 3) { + const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); + aSignificand <<= @intCast(S, shift); + aExponent -= shift; + } + } else { // addition + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & (integerBit << 4) != 0) { + const sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal; the exponent and round/sticky bits are zero. + // All we need to do is shift the significand and apply the correct sign. + aSignificand >>= @intCast(S, 4 - aExponent); + return @bitCast(T, resultSign | aSignificand); + } + + // Low three bits are round, guard, and sticky. + const roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the integer bit, if it's implicit. + var result = (aSignificand >> 3) & significandMask; + + // Insert the exponent and sign. + result |= @intCast(Z, aExponent) << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result += 1; + if (roundGuardSticky == 0x4) result += result & 1; + + // Restore any explicit integer bit, if it was rounded off + if (significandBits != fractionalBits) { + if ((result >> significandBits) != 0) result |= integerBit; + } + + return @bitCast(T, result); +} + +test { + _ = @import("addf3_test.zig"); +} diff --git a/lib/compiler_rt/addf3_test.zig b/lib/compiler_rt/addf3_test.zig @@ -0,0 +1,156 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c + +const std = @import("std"); +const math = std.math; +const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); + +const __addtf3 = @import("addtf3.zig").__addtf3; +const __addxf3 = @import("addxf3.zig").__addxf3; +const __subtf3 = @import("subtf3.zig").__subtf3; + +fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __addtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailed; +} + +test "addtf3" { + try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf + inf = inf + try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); + + // inf + any = inf + try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); + try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); +} + +fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __subtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailed; +} + +test "subtf3" { + // qNaN - any = qNaN + try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf - any = inf + try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); + try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); +} + +const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); + +fn test__addxf3(a: f80, b: f80, expected: u80) !void { + const x = __addxf3(a, b); + const rep = @bitCast(u80, x); + + if (rep == expected) + return; + + if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) + return; // We don't currently test NaN payload propagation + + return error.TestFailed; +} + +test "addxf3" { + // NaN + any = NaN + try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + + // any + NaN = NaN + try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); + try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); + + // NaN + inf = NaN + try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); + + // inf + NaN = NaN + try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); + + // inf + inf = inf + try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); + + // inf + -inf = NaN + try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); + + // -inf + inf = NaN + try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); + + // inf + any = inf + try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); + + // any + inf = inf + try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); + + // any + any + try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); + try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact + + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact + try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact + try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact +} diff --git a/lib/compiler_rt/addo.zig b/lib/compiler_rt/addo.zig @@ -1,4 +1,14 @@ +const std = @import("std"); const builtin = @import("builtin"); +const is_test = builtin.is_test; +const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +pub const panic = @import("common.zig").panic; + +comptime { + @export(__addosi4, .{ .name = "__addosi4", .linkage = linkage }); + @export(__addodi4, .{ .name = "__addodi4", .linkage = linkage }); + @export(__addoti4, .{ .name = "__addoti4", .linkage = linkage }); +} // addo - add overflow // * return a+%b. diff --git a/lib/compiler_rt/addsf3.zig b/lib/compiler_rt/addsf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = common.linkage }); + } else { + @export(__addsf3, .{ .name = "__addsf3", .linkage = common.linkage }); + } +} + +fn __addsf3(a: f32, b: f32) callconv(.C) f32 { + return addf3(f32, a, b); +} + +fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { + return addf3(f32, a, b); +} diff --git a/lib/compiler_rt/addtf3.zig b/lib/compiler_rt/addtf3.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__addkf3, .{ .name = "__addkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_add, .{ .name = "_Qp_add", .linkage = common.linkage }); + } else { + @export(__addtf3, .{ .name = "__addtf3", .linkage = common.linkage }); + } +} + +pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { + return addf3(f128, a, b); +} + +fn __addkf3(a: f128, b: f128) callconv(.C) f128 { + return addf3(f128, a, b); +} + +fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { + c.* = addf3(f128, a.*, b.*); +} diff --git a/lib/compiler_rt/addxf3.zig b/lib/compiler_rt/addxf3.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + @export(__addxf3, .{ .name = "__addxf3", .linkage = common.linkage }); +} + +pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { + return addf3(f80, a, b); +} diff --git a/lib/compiler_rt/arm.zig b/lib/compiler_rt/arm.zig @@ -1,5 +1,46 @@ // ARM specific builtins +const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (!builtin.is_test) { + if (arch.isARM() or arch.isThumb()) { + @export(__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = common.linkage }); + @export(__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = common.linkage }); + @export(__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = common.linkage }); + + @export(__aeabi_ldivmod, .{ .name = "__aeabi_ldivmod", .linkage = common.linkage }); + @export(__aeabi_uldivmod, .{ .name = "__aeabi_uldivmod", .linkage = common.linkage }); + + @export(__aeabi_idivmod, .{ .name = "__aeabi_idivmod", .linkage = common.linkage }); + @export(__aeabi_uidivmod, .{ .name = "__aeabi_uidivmod", .linkage = common.linkage }); + + @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy", .linkage = common.linkage }); + @export(__aeabi_memcpy4, .{ .name = "__aeabi_memcpy4", .linkage = common.linkage }); + @export(__aeabi_memcpy8, .{ .name = "__aeabi_memcpy8", .linkage = common.linkage }); + + @export(__aeabi_memmove, .{ .name = "__aeabi_memmove", .linkage = common.linkage }); + @export(__aeabi_memmove4, .{ .name = "__aeabi_memmove4", .linkage = common.linkage }); + @export(__aeabi_memmove8, .{ .name = "__aeabi_memmove8", .linkage = common.linkage }); + + @export(__aeabi_memset, .{ .name = "__aeabi_memset", .linkage = common.linkage }); + @export(__aeabi_memset4, .{ .name = "__aeabi_memset4", .linkage = common.linkage }); + @export(__aeabi_memset8, .{ .name = "__aeabi_memset8", .linkage = common.linkage }); + + @export(__aeabi_memclr, .{ .name = "__aeabi_memclr", .linkage = common.linkage }); + @export(__aeabi_memclr4, .{ .name = "__aeabi_memclr4", .linkage = common.linkage }); + @export(__aeabi_memclr8, .{ .name = "__aeabi_memclr8", .linkage = common.linkage }); + + if (builtin.os.tag == .linux) { + @export(__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = common.linkage }); + } + } + } +} const __divmodsi4 = @import("int.zig").__divmodsi4; const __udivmodsi4 = @import("int.zig").__udivmodsi4; @@ -14,11 +55,27 @@ pub fn __aeabi_memcpy(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { @setRuntimeSafety(false); _ = memcpy(dest, src, n); } +pub fn __aeabi_memcpy4(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memcpy(dest, src, n); +} +pub fn __aeabi_memcpy8(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memcpy(dest, src, n); +} pub fn __aeabi_memmove(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { @setRuntimeSafety(false); _ = memmove(dest, src, n); } +pub fn __aeabi_memmove4(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memmove(dest, src, n); +} +pub fn __aeabi_memmove8(dest: [*]u8, src: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memmove(dest, src, n); +} pub fn __aeabi_memset(dest: [*]u8, n: usize, c: u8) callconv(.AAPCS) void { @setRuntimeSafety(false); @@ -26,16 +83,32 @@ pub fn __aeabi_memset(dest: [*]u8, n: usize, c: u8) callconv(.AAPCS) void { // two arguments swapped _ = memset(dest, c, n); } +pub fn __aeabi_memset4(dest: [*]u8, n: usize, c: u8) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memset(dest, c, n); +} +pub fn __aeabi_memset8(dest: [*]u8, n: usize, c: u8) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memset(dest, c, n); +} pub fn __aeabi_memclr(dest: [*]u8, n: usize) callconv(.AAPCS) void { @setRuntimeSafety(false); _ = memset(dest, 0, n); } +pub fn __aeabi_memclr4(dest: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memset(dest, 0, n); +} +pub fn __aeabi_memclr8(dest: [*]u8, n: usize) callconv(.AAPCS) void { + @setRuntimeSafety(false); + _ = memset(dest, 0, n); +} // Dummy functions to avoid errors during the linking phase -pub fn __aeabi_unwind_cpp_pr0() callconv(.C) void {} -pub fn __aeabi_unwind_cpp_pr1() callconv(.C) void {} -pub fn __aeabi_unwind_cpp_pr2() callconv(.C) void {} +pub fn __aeabi_unwind_cpp_pr0() callconv(.AAPCS) void {} +pub fn __aeabi_unwind_cpp_pr1() callconv(.AAPCS) void {} +pub fn __aeabi_unwind_cpp_pr2() callconv(.AAPCS) void {} // This function can only clobber r0 according to the ABI pub fn __aeabi_read_tp() callconv(.Naked) void { diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig @@ -2,8 +2,8 @@ const std = @import("std"); const builtin = @import("builtin"); const cpu = builtin.cpu; const arch = cpu.arch; - const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +pub const panic = @import("common.zig").panic; // This parameter is true iff the target architecture supports the bare minimum // to implement the atomic load/store intrinsics. diff --git a/lib/compiler_rt/aulldiv.zig b/lib/compiler_rt/aulldiv.zig @@ -1,7 +1,20 @@ +const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const abi = builtin.abi; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (arch == .i386 and abi == .msvc) { + // Don't let LLVM apply the stdcall name mangling on those MSVC builtins + @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = common.linkage }); + @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = common.linkage }); + } +} pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 { - @setRuntimeSafety(builtin.is_test); const s_a = a >> (64 - 1); const s_b = b >> (64 - 1); diff --git a/lib/compiler_rt/aullrem.zig b/lib/compiler_rt/aullrem.zig @@ -1,7 +1,20 @@ +const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const abi = builtin.abi; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (arch == .i386 and abi == .msvc) { + // Don't let LLVM apply the stdcall name mangling on those MSVC builtins + @export(_allrem, .{ .name = "\x01__allrem", .linkage = common.linkage }); + @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = common.linkage }); + } +} pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { - @setRuntimeSafety(builtin.is_test); const s_a = a >> (64 - 1); const s_b = b >> (64 - 1); diff --git a/lib/compiler_rt/bswap.zig b/lib/compiler_rt/bswap.zig @@ -1,5 +1,14 @@ const std = @import("std"); const builtin = @import("builtin"); +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__bswapsi2, .{ .name = "__bswapsi2", .linkage = common.linkage }); + @export(__bswapdi2, .{ .name = "__bswapdi2", .linkage = common.linkage }); + @export(__bswapti2, .{ .name = "__bswapti2", .linkage = common.linkage }); +} // bswap - byteswap // - bswapXi2 for unoptimized big and little endian @@ -12,7 +21,6 @@ const builtin = @import("builtin"); // 00 00 00 ff << 3*8 (rightmost byte) inline fn bswapXi2(comptime T: type, a: T) T { - @setRuntimeSafety(builtin.is_test); switch (@bitSizeOf(T)) { 32 => { // zig fmt: off diff --git a/lib/compiler_rt/ceil.zig b/lib/compiler_rt/ceil.zig @@ -1,12 +1,27 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c +//! Ported from musl, which is MIT licensed. +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__ceilh, .{ .name = "__ceilh", .linkage = common.linkage }); + @export(ceilf, .{ .name = "ceilf", .linkage = common.linkage }); + @export(ceil, .{ .name = "ceil", .linkage = common.linkage }); + @export(__ceilx, .{ .name = "__ceilx", .linkage = common.linkage }); + const ceilq_sym_name = if (common.want_ppc_abi) "ceilf128" else "ceilq"; + @export(ceilq, .{ .name = ceilq_sym_name, .linkage = common.linkage }); + @export(ceill, .{ .name = "ceill", .linkage = common.linkage }); +} pub fn __ceilh(x: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/clear_cache.zig b/lib/compiler_rt/clear_cache.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const arch = builtin.cpu.arch; const os = builtin.os.tag; +pub const panic = @import("common.zig").panic; // Ported from llvm-project d32170dbd5b0d54436537b6b75beaf44324e0c28 @@ -10,7 +11,13 @@ const os = builtin.os.tag; // It is expected to invalidate the instruction cache for the // specified range. -pub fn clear_cache(start: usize, end: usize) callconv(.C) void { +comptime { + if (builtin.zig_backend != .stage2_llvm) { + _ = clear_cache; + } +} + +fn clear_cache(start: usize, end: usize) callconv(.C) void { const x86 = switch (arch) { .i386, .x86_64 => true, else => false, diff --git a/lib/compiler_rt/cmp.zig b/lib/compiler_rt/cmp.zig @@ -1,5 +1,18 @@ const std = @import("std"); const builtin = @import("builtin"); +const is_test = builtin.is_test; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__cmpsi2, .{ .name = "__cmpsi2", .linkage = common.linkage }); + @export(__cmpdi2, .{ .name = "__cmpdi2", .linkage = common.linkage }); + @export(__cmpti2, .{ .name = "__cmpti2", .linkage = common.linkage }); + @export(__ucmpsi2, .{ .name = "__ucmpsi2", .linkage = common.linkage }); + @export(__ucmpdi2, .{ .name = "__ucmpdi2", .linkage = common.linkage }); + @export(__ucmpti2, .{ .name = "__ucmpti2", .linkage = common.linkage }); +} // cmp - signed compare // - cmpXi2_generic for unoptimized little and big endian @@ -12,7 +25,6 @@ const builtin = @import("builtin"); // a > b => 2 inline fn XcmpXi2(comptime T: type, a: T, b: T) i32 { - @setRuntimeSafety(builtin.is_test); var cmp1: i32 = 0; var cmp2: i32 = 0; if (a > b) diff --git a/lib/compiler_rt/cmpdf2.zig b/lib/compiler_rt/cmpdf2.zig @@ -0,0 +1,68 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = common.linkage }); + @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = common.linkage }); + @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = common.linkage }); + } else { + @export(__eqdf2, .{ .name = "__eqdf2", .linkage = common.linkage }); + @export(__nedf2, .{ .name = "__nedf2", .linkage = common.linkage }); + @export(__ledf2, .{ .name = "__ledf2", .linkage = common.linkage }); + @export(__cmpdf2, .{ .name = "__cmpdf2", .linkage = common.linkage }); + @export(__ltdf2, .{ .name = "__ltdf2", .linkage = common.linkage }); + } +} + +/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; +/// if a is greater than b, they return 1; and if a and b are equal they return 0. +/// If either argument is NaN they return 1..." +/// +/// Note that this matches the definition of `__ledf2`, `__eqdf2`, `__nedf2`, `__cmpdf2`, +/// and `__ltdf2`. +fn __cmpdf2(a: f64, b: f64) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f64, comparef.LE, a, b)); +} + +/// "These functions return a value less than or equal to zero if neither argument is NaN, +/// and a is less than or equal to b." +pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 { + return __cmpdf2(a, b); +} + +/// "These functions return zero if neither argument is NaN, and a and b are equal." +/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined +/// to have the same return value. +pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 { + return __cmpdf2(a, b); +} + +/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." +/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined +/// to have the same return value. +pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 { + return __cmpdf2(a, b); +} + +/// "These functions return a value less than zero if neither argument is NaN, and a +/// is strictly less than b." +pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { + return __cmpdf2(a, b); +} + +fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Equal); +} + +fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Less); +} + +fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater); +} diff --git a/lib/compiler_rt/cmpsf2.zig b/lib/compiler_rt/cmpsf2.zig @@ -0,0 +1,68 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = common.linkage }); + @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = common.linkage }); + @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = common.linkage }); + } else { + @export(__eqsf2, .{ .name = "__eqsf2", .linkage = common.linkage }); + @export(__nesf2, .{ .name = "__nesf2", .linkage = common.linkage }); + @export(__lesf2, .{ .name = "__lesf2", .linkage = common.linkage }); + @export(__cmpsf2, .{ .name = "__cmpsf2", .linkage = common.linkage }); + @export(__ltsf2, .{ .name = "__ltsf2", .linkage = common.linkage }); + } +} + +/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; +/// if a is greater than b, they return 1; and if a and b are equal they return 0. +/// If either argument is NaN they return 1..." +/// +/// Note that this matches the definition of `__lesf2`, `__eqsf2`, `__nesf2`, `__cmpsf2`, +/// and `__ltsf2`. +fn __cmpsf2(a: f32, b: f32) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f32, comparef.LE, a, b)); +} + +/// "These functions return a value less than or equal to zero if neither argument is NaN, +/// and a is less than or equal to b." +pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +/// "These functions return zero if neither argument is NaN, and a and b are equal." +/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined +/// to have the same return value. +pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." +/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined +/// to have the same return value. +pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +/// "These functions return a value less than zero if neither argument is NaN, and a +/// is strictly less than b." +pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Equal); +} + +fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Less); +} + +fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) != .Greater); +} diff --git a/lib/compiler_rt/cmptf2.zig b/lib/compiler_rt/cmptf2.zig @@ -0,0 +1,122 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__eqkf2, .{ .name = "__eqkf2", .linkage = common.linkage }); + @export(__nekf2, .{ .name = "__nekf2", .linkage = common.linkage }); + @export(__ltkf2, .{ .name = "__ltkf2", .linkage = common.linkage }); + @export(__lekf2, .{ .name = "__lekf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = common.linkage }); + @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = common.linkage }); + @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = common.linkage }); + @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = common.linkage }); + @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = common.linkage }); + @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = common.linkage }); + @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = common.linkage }); + } else { + @export(__eqtf2, .{ .name = "__eqtf2", .linkage = common.linkage }); + @export(__netf2, .{ .name = "__netf2", .linkage = common.linkage }); + @export(__letf2, .{ .name = "__letf2", .linkage = common.linkage }); + @export(__cmptf2, .{ .name = "__cmptf2", .linkage = common.linkage }); + @export(__lttf2, .{ .name = "__lttf2", .linkage = common.linkage }); + } +} + +/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; +/// if a is greater than b, they return 1; and if a and b are equal they return 0. +/// If either argument is NaN they return 1..." +/// +/// Note that this matches the definition of `__letf2`, `__eqtf2`, `__netf2`, `__cmptf2`, +/// and `__lttf2`. +fn __cmptf2(a: f128, b: f128) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f128, comparef.LE, a, b)); +} + +/// "These functions return a value less than or equal to zero if neither argument is NaN, +/// and a is less than or equal to b." +fn __letf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +/// "These functions return zero if neither argument is NaN, and a and b are equal." +/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined +/// to have the same return value. +fn __eqtf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." +/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined +/// to have the same return value. +fn __netf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +/// "These functions return a value less than zero if neither argument is NaN, and a +/// is strictly less than b." +fn __lttf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __eqkf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __nekf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __lekf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +const SparcFCMP = enum(i32) { + Equal = 0, + Less = 1, + Greater = 2, + Unordered = 3, +}; + +fn _Qp_cmp(a: *const f128, b: *const f128) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f128, SparcFCMP, a.*, b.*)); +} + +fn _Qp_feq(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Equal; +} + +fn _Qp_fne(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) != .Equal; +} + +fn _Qp_flt(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Less; +} + +fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Greater; +} + +fn _Qp_fge(a: *const f128, b: *const f128) callconv(.C) bool { + return switch (@intToEnum(SparcFCMP, _Qp_cmp(a, b))) { + .Equal, .Greater => true, + .Less, .Unordered => false, + }; +} + +fn _Qp_fle(a: *const f128, b: *const f128) callconv(.C) bool { + return switch (@intToEnum(SparcFCMP, _Qp_cmp(a, b))) { + .Equal, .Less => true, + .Greater, .Unordered => false, + }; +} diff --git a/lib/compiler_rt/cmpxf2.zig b/lib/compiler_rt/cmpxf2.zig @@ -0,0 +1,50 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + @export(__eqxf2, .{ .name = "__eqxf2", .linkage = common.linkage }); + @export(__nexf2, .{ .name = "__nexf2", .linkage = common.linkage }); + @export(__lexf2, .{ .name = "__lexf2", .linkage = common.linkage }); + @export(__cmpxf2, .{ .name = "__cmpxf2", .linkage = common.linkage }); + @export(__ltxf2, .{ .name = "__ltxf2", .linkage = common.linkage }); +} + +/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; +/// if a is greater than b, they return 1; and if a and b are equal they return 0. +/// If either argument is NaN they return 1..." +/// +/// Note that this matches the definition of `__lexf2`, `__eqxf2`, `__nexf2`, `__cmpxf2`, +/// and `__ltxf2`. +fn __cmpxf2(a: f80, b: f80) callconv(.C) i32 { + return @enumToInt(comparef.cmp_f80(comparef.LE, a, b)); +} + +/// "These functions return a value less than or equal to zero if neither argument is NaN, +/// and a is less than or equal to b." +fn __lexf2(a: f80, b: f80) callconv(.C) i32 { + return __cmpxf2(a, b); +} + +/// "These functions return zero if neither argument is NaN, and a and b are equal." +/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined +/// to have the same return value. +fn __eqxf2(a: f80, b: f80) callconv(.C) i32 { + return __cmpxf2(a, b); +} + +/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." +/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined +/// to have the same return value. +fn __nexf2(a: f80, b: f80) callconv(.C) i32 { + return __cmpxf2(a, b); +} + +/// "These functions return a value less than zero if neither argument is NaN, and a +/// is strictly less than b." +fn __ltxf2(a: f80, b: f80) callconv(.C) i32 { + return __cmpxf2(a, b); +} diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig @@ -0,0 +1,190 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +pub const want_aeabi = switch (builtin.abi) { + .eabi, + .eabihf, + .musleabi, + .musleabihf, + .gnueabi, + .gnueabihf, + => switch (builtin.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => true, + else => false, + }, + else => false, +}; +pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); + +/// This governs whether to use these symbol names for f16/f32 conversions +/// rather than the standard names: +/// * __gnu_f2h_ieee +/// * __gnu_h2f_ieee +/// Known correct configurations: +/// x86_64-freestanding-none => true +/// x86_64-linux-none => true +/// x86_64-linux-gnu => true +/// x86_64-linux-musl => true +/// x86_64-linux-eabi => true +/// arm-linux-musleabihf => true +/// arm-linux-gnueabihf => true +/// arm-linux-eabihf => false +/// wasm32-wasi-musl => false +/// wasm32-freestanding-none => false +/// x86_64-windows-gnu => true +/// x86_64-windows-msvc => true +/// any-macos-any => false +pub const gnu_f16_abi = switch (builtin.cpu.arch) { + .wasm32, .wasm64 => false, + + .arm, .armeb, .thumb, .thumbeb => switch (builtin.abi) { + .eabi, .eabihf => false, + else => true, + }, + + else => !builtin.os.tag.isDarwin(), +}; + +pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); + +// Avoid dragging in the runtime safety mechanisms into this .o file, +// unless we're trying to test compiler-rt. +pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { + _ = error_return_trace; + if (builtin.is_test) { + @setCold(true); + std.debug.panic("{s}", .{msg}); + } else { + unreachable; + } +} + +/// AArch64 is the only ABI (at the moment) to support f16 arguments without the +/// need for extending them to wider fp types. +/// TODO remove this; do this type selection in the language rather than +/// here in compiler-rt. +pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16; + +pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { + switch (Z) { + u16 => { + // 16x16 --> 32 bit multiply + const product = @as(u32, a) * @as(u32, b); + hi.* = @intCast(u16, product >> 16); + lo.* = @truncate(u16, product); + }, + u32 => { + // 32x32 --> 64 bit multiply + const product = @as(u64, a) * @as(u64, b); + hi.* = @truncate(u32, product >> 32); + lo.* = @truncate(u32, product); + }, + u64 => { + const S = struct { + fn loWord(x: u64) u64 { + return @truncate(u32, x); + } + fn hiWord(x: u64) u64 { + return @truncate(u32, x >> 32); + } + }; + // 64x64 -> 128 wide multiply for platforms that don't have such an operation; + // many 64-bit platforms have this operation, but they tend to have hardware + // floating-point, so we don't bother with a special case for them here. + // Each of the component 32x32 -> 64 products + const plolo: u64 = S.loWord(a) * S.loWord(b); + const plohi: u64 = S.loWord(a) * S.hiWord(b); + const philo: u64 = S.hiWord(a) * S.loWord(b); + const phihi: u64 = S.hiWord(a) * S.hiWord(b); + // Sum terms that contribute to lo in a way that allows us to get the carry + const r0: u64 = S.loWord(plolo); + const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); + lo.* = r0 +% (r1 << 32); + // Sum terms contributing to hi with the carry from lo + hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; + }, + u128 => { + const Word_LoMask = @as(u64, 0x00000000ffffffff); + const Word_HiMask = @as(u64, 0xffffffff00000000); + const Word_FullMask = @as(u64, 0xffffffffffffffff); + const S = struct { + fn Word_1(x: u128) u64 { + return @truncate(u32, x >> 96); + } + fn Word_2(x: u128) u64 { + return @truncate(u32, x >> 64); + } + fn Word_3(x: u128) u64 { + return @truncate(u32, x >> 32); + } + fn Word_4(x: u128) u64 { + return @truncate(u32, x); + } + }; + // 128x128 -> 256 wide multiply for platforms that don't have such an operation; + // many 64-bit platforms have this operation, but they tend to have hardware + // floating-point, so we don't bother with a special case for them here. + + const product11: u64 = S.Word_1(a) * S.Word_1(b); + const product12: u64 = S.Word_1(a) * S.Word_2(b); + const product13: u64 = S.Word_1(a) * S.Word_3(b); + const product14: u64 = S.Word_1(a) * S.Word_4(b); + const product21: u64 = S.Word_2(a) * S.Word_1(b); + const product22: u64 = S.Word_2(a) * S.Word_2(b); + const product23: u64 = S.Word_2(a) * S.Word_3(b); + const product24: u64 = S.Word_2(a) * S.Word_4(b); + const product31: u64 = S.Word_3(a) * S.Word_1(b); + const product32: u64 = S.Word_3(a) * S.Word_2(b); + const product33: u64 = S.Word_3(a) * S.Word_3(b); + const product34: u64 = S.Word_3(a) * S.Word_4(b); + const product41: u64 = S.Word_4(a) * S.Word_1(b); + const product42: u64 = S.Word_4(a) * S.Word_2(b); + const product43: u64 = S.Word_4(a) * S.Word_3(b); + const product44: u64 = S.Word_4(a) * S.Word_4(b); + + const sum0: u128 = @as(u128, product44); + const sum1: u128 = @as(u128, product34) +% + @as(u128, product43); + const sum2: u128 = @as(u128, product24) +% + @as(u128, product33) +% + @as(u128, product42); + const sum3: u128 = @as(u128, product14) +% + @as(u128, product23) +% + @as(u128, product32) +% + @as(u128, product41); + const sum4: u128 = @as(u128, product13) +% + @as(u128, product22) +% + @as(u128, product31); + const sum5: u128 = @as(u128, product12) +% + @as(u128, product21); + const sum6: u128 = @as(u128, product11); + + const r0: u128 = (sum0 & Word_FullMask) +% + ((sum1 & Word_LoMask) << 32); + const r1: u128 = (sum0 >> 64) +% + ((sum1 >> 32) & Word_FullMask) +% + (sum2 & Word_FullMask) +% + ((sum3 << 32) & Word_HiMask); + + lo.* = r0 +% (r1 << 64); + hi.* = (r1 >> 64) +% + (sum1 >> 96) +% + (sum2 >> 64) +% + (sum3 >> 32) +% + sum4 +% + (sum5 << 32) +% + (sum6 << 64); + }, + else => @compileError("unsupported"), + } +} + +pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { + const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); + const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); + + const shift = @clz(Z, significand.*) - @clz(Z, integerBit); + significand.* <<= @intCast(std.math.Log2Int(Z), shift); + return @as(i32, 1) - shift; +} diff --git a/lib/compiler_rt/compareXf2.zig b/lib/compiler_rt/compareXf2.zig @@ -1,328 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c - -const std = @import("std"); -const builtin = @import("builtin"); - -const LE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, - - const Unordered: LE = .Greater; -}; - -const GE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, - - const Unordered: GE = .Less; -}; - -pub inline fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { - @setRuntimeSafety(builtin.is_test); - - const bits = @typeInfo(T).Float.bits; - const srep_t = std.meta.Int(.signed, bits); - const rep_t = std.meta.Int(.unsigned, bits); - - const significandBits = std.math.floatMantissaBits(T); - const exponentBits = std.math.floatExponentBits(T); - const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); - const absMask = signBit - 1; - const infT = comptime std.math.inf(T); - const infRep = @bitCast(rep_t, infT); - - const aInt = @bitCast(srep_t, a); - const bInt = @bitCast(srep_t, b); - const aAbs = @bitCast(rep_t, aInt) & absMask; - const bAbs = @bitCast(rep_t, bInt) & absMask; - - // If either a or b is NaN, they are unordered. - if (aAbs > infRep or bAbs > infRep) return RT.Unordered; - - // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) return .Equal; - - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a floating-point compare. - if ((aInt & bInt) >= 0) { - if (aInt < bInt) { - return .Less; - } else if (aInt == bInt) { - return .Equal; - } else return .Greater; - } else { - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. (This assumes a twos- or ones- - // complement integer representation; if integers are represented in a - // sign-magnitude representation, then this flip is incorrect). - if (aInt > bInt) { - return .Less; - } else if (aInt == bInt) { - return .Equal; - } else return .Greater; - } -} - -pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { - @setRuntimeSafety(builtin.is_test); - - const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); - - const significandBits = std.math.floatMantissaBits(T); - const exponentBits = std.math.floatExponentBits(T); - const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); - const absMask = signBit - 1; - const infRep = @bitCast(rep_t, std.math.inf(T)); - - const aAbs: rep_t = @bitCast(rep_t, a) & absMask; - const bAbs: rep_t = @bitCast(rep_t, b) & absMask; - - return @boolToInt(aAbs > infRep or bAbs > infRep); -} - -// Comparison between f32 - -pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f32, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f32, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { - return __lesf2(a, b); -} - -pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { - return __lesf2(a, b); -} - -pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 { - return __lesf2(a, b); -} - -pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { - return __gesf2(a, b); -} - -// Comparison between f64 - -pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f64, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f64, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 { - return __ledf2(a, b); -} - -pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { - return __ledf2(a, b); -} - -pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 { - return __ledf2(a, b); -} - -pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { - return __gedf2(a, b); -} - -// Comparison between f80 - -pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { - const a_rep = std.math.break_f80(a); - const b_rep = std.math.break_f80(b); - const sig_bits = std.math.floatMantissaBits(f80); - const int_bit = 0x8000000000000000; - const sign_bit = 0x8000; - const special_exp = 0x7FFF; - - // If either a or b is NaN, they are unordered. - if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or - (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) - return RT.Unordered; - - // If a and b are both zeros, they are equal. - if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) - return .Equal; - - if (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(a_rep.fraction == b_rep.fraction) != 0) { - return .Equal; - } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { - // signs are different - if (@bitCast(i16, a_rep.exp) < @bitCast(i16, b_rep.exp)) { - return .Less; - } else { - return .Greater; - } - } else { - const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); - const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); - if (a_fraction < b_fraction) { - return .Less; - } else { - return .Greater; - } - } -} - -pub fn __lexf2(a: f80, b: f80) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp_f80(LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gexf2(a: f80, b: f80) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp_f80(GE, a, b); - return @bitCast(i32, float); -} - -pub fn __eqxf2(a: f80, b: f80) callconv(.C) i32 { - return __lexf2(a, b); -} - -pub fn __ltxf2(a: f80, b: f80) callconv(.C) i32 { - return __lexf2(a, b); -} - -pub fn __nexf2(a: f80, b: f80) callconv(.C) i32 { - return __lexf2(a, b); -} - -pub fn __gtxf2(a: f80, b: f80) callconv(.C) i32 { - return __gexf2(a, b); -} - -// Comparison between f128 - -pub fn __letf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f128, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __getf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f128, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __eqtf2(a: f128, b: f128) callconv(.C) i32 { - return __letf2(a, b); -} - -pub fn __lttf2(a: f128, b: f128) callconv(.C) i32 { - return __letf2(a, b); -} - -pub fn __netf2(a: f128, b: f128) callconv(.C) i32 { - return __letf2(a, b); -} - -pub fn __gttf2(a: f128, b: f128) callconv(.C) i32 { - return __getf2(a, b); -} - -// Unordered comparison between f32/f64/f128 - -pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f32, a, b); -} - -pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f64, a, b); -} - -pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f128, a, b); -} - -// ARM EABI intrinsics - -pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __eqsf2, .{ a, b }) == 0); -} - -pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ltsf2, .{ a, b }) < 0); -} - -pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }) <= 0); -} - -pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }) >= 0); -} - -pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gtsf2, .{ a, b }) > 0); -} - -pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b }); -} - -pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __eqdf2, .{ a, b }) == 0); -} - -pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ltdf2, .{ a, b }) < 0); -} - -pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }) <= 0); -} - -pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }) >= 0); -} - -pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gtdf2, .{ a, b }) > 0); -} - -pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b }); -} - -test "comparesf2" { - _ = @import("comparesf2_test.zig"); -} -test "comparedf2" { - _ = @import("comparedf2_test.zig"); -} diff --git a/lib/compiler_rt/comparedf2_test.zig b/lib/compiler_rt/comparedf2_test.zig @@ -6,7 +6,15 @@ const std = @import("std"); const builtin = @import("builtin"); const is_test = builtin.is_test; -const comparedf2 = @import("compareXf2.zig"); +const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; +const __ledf2 = @import("./cmpdf2.zig").__ledf2; +const __ltdf2 = @import("./cmpdf2.zig").__ltdf2; +const __nedf2 = @import("./cmpdf2.zig").__nedf2; + +const __gedf2 = @import("./gedf2.zig").__gedf2; +const __gtdf2 = @import("./gedf2.zig").__gtdf2; + +const __unorddf2 = @import("./unorddf2.zig").__unorddf2; const TestVector = struct { a: f64, @@ -21,25 +29,25 @@ const TestVector = struct { }; fn test__cmpdf2(vector: TestVector) bool { - if (comparedf2.__eqdf2(vector.a, vector.b) != vector.eqReference) { + if (__eqdf2(vector.a, vector.b) != vector.eqReference) { return false; } - if (comparedf2.__gedf2(vector.a, vector.b) != vector.geReference) { + if (__gedf2(vector.a, vector.b) != vector.geReference) { return false; } - if (comparedf2.__gtdf2(vector.a, vector.b) != vector.gtReference) { + if (__gtdf2(vector.a, vector.b) != vector.gtReference) { return false; } - if (comparedf2.__ledf2(vector.a, vector.b) != vector.leReference) { + if (__ledf2(vector.a, vector.b) != vector.leReference) { return false; } - if (comparedf2.__ltdf2(vector.a, vector.b) != vector.ltReference) { + if (__ltdf2(vector.a, vector.b) != vector.ltReference) { return false; } - if (comparedf2.__nedf2(vector.a, vector.b) != vector.neReference) { + if (__nedf2(vector.a, vector.b) != vector.neReference) { return false; } - if (comparedf2.__unorddf2(vector.a, vector.b) != vector.unReference) { + if (__unorddf2(vector.a, vector.b) != vector.unReference) { return false; } return true; diff --git a/lib/compiler_rt/comparef.zig b/lib/compiler_rt/comparef.zig @@ -0,0 +1,118 @@ +const std = @import("std"); + +pub const LE = enum(i32) { + Less = -1, + Equal = 0, + Greater = 1, + + const Unordered: LE = .Greater; +}; + +pub const GE = enum(i32) { + Less = -1, + Equal = 0, + Greater = 1, + + const Unordered: GE = .Less; +}; + +pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { + const bits = @typeInfo(T).Float.bits; + const srep_t = std.meta.Int(.signed, bits); + const rep_t = std.meta.Int(.unsigned, bits); + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); + const absMask = signBit - 1; + const infT = comptime std.math.inf(T); + const infRep = @bitCast(rep_t, infT); + + const aInt = @bitCast(srep_t, a); + const bInt = @bitCast(srep_t, b); + const aAbs = @bitCast(rep_t, aInt) & absMask; + const bAbs = @bitCast(rep_t, bInt) & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep or bAbs > infRep) return RT.Unordered; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return .Equal; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a floating-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) { + return .Less; + } else if (aInt == bInt) { + return .Equal; + } else return .Greater; + } else { + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + if (aInt > bInt) { + return .Less; + } else if (aInt == bInt) { + return .Equal; + } else return .Greater; + } +} + +pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { + const a_rep = std.math.break_f80(a); + const b_rep = std.math.break_f80(b); + const sig_bits = std.math.floatMantissaBits(f80); + const int_bit = 0x8000000000000000; + const sign_bit = 0x8000; + const special_exp = 0x7FFF; + + // If either a or b is NaN, they are unordered. + if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or + (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) + return RT.Unordered; + + // If a and b are both zeros, they are equal. + if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) + return .Equal; + + if (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(a_rep.fraction == b_rep.fraction) != 0) { + return .Equal; + } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { + // signs are different + if (@bitCast(i16, a_rep.exp) < @bitCast(i16, b_rep.exp)) { + return .Less; + } else { + return .Greater; + } + } else { + const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); + const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); + if (a_fraction < b_fraction) { + return .Less; + } else { + return .Greater; + } + } +} + +pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { + const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); + const absMask = signBit - 1; + const infRep = @bitCast(rep_t, std.math.inf(T)); + + const aAbs: rep_t = @bitCast(rep_t, a) & absMask; + const bAbs: rep_t = @bitCast(rep_t, b) & absMask; + + return @boolToInt(aAbs > infRep or bAbs > infRep); +} + +test { + _ = @import("comparesf2_test.zig"); + _ = @import("comparedf2_test.zig"); +} diff --git a/lib/compiler_rt/comparesf2_test.zig b/lib/compiler_rt/comparesf2_test.zig @@ -6,7 +6,15 @@ const std = @import("std"); const builtin = @import("builtin"); const is_test = builtin.is_test; -const comparesf2 = @import("compareXf2.zig"); +const __eqsf2 = @import("./cmpsf2.zig").__eqsf2; +const __lesf2 = @import("./cmpsf2.zig").__lesf2; +const __ltsf2 = @import("./cmpsf2.zig").__ltsf2; +const __nesf2 = @import("./cmpsf2.zig").__nesf2; + +const __gesf2 = @import("./gesf2.zig").__gesf2; +const __gtsf2 = @import("./gesf2.zig").__gtsf2; + +const __unordsf2 = @import("./unordsf2.zig").__unordsf2; const TestVector = struct { a: f32, @@ -21,25 +29,25 @@ const TestVector = struct { }; fn test__cmpsf2(vector: TestVector) bool { - if (comparesf2.__eqsf2(vector.a, vector.b) != vector.eqReference) { + if (__eqsf2(vector.a, vector.b) != vector.eqReference) { return false; } - if (comparesf2.__gesf2(vector.a, vector.b) != vector.geReference) { + if (__gesf2(vector.a, vector.b) != vector.geReference) { return false; } - if (comparesf2.__gtsf2(vector.a, vector.b) != vector.gtReference) { + if (__gtsf2(vector.a, vector.b) != vector.gtReference) { return false; } - if (comparesf2.__lesf2(vector.a, vector.b) != vector.leReference) { + if (__lesf2(vector.a, vector.b) != vector.leReference) { return false; } - if (comparesf2.__ltsf2(vector.a, vector.b) != vector.ltReference) { + if (__ltsf2(vector.a, vector.b) != vector.ltReference) { return false; } - if (comparesf2.__nesf2(vector.a, vector.b) != vector.neReference) { + if (__nesf2(vector.a, vector.b) != vector.neReference) { return false; } - if (comparesf2.__unordsf2(vector.a, vector.b) != vector.unReference) { + if (__unordsf2(vector.a, vector.b) != vector.unReference) { return false; } return true; diff --git a/lib/compiler_rt/cos.zig b/lib/compiler_rt/cos.zig @@ -1,11 +1,26 @@ const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); + +pub const panic = common.panic; const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; +comptime { + @export(__cosh, .{ .name = "__cosh", .linkage = common.linkage }); + @export(cosf, .{ .name = "cosf", .linkage = common.linkage }); + @export(cos, .{ .name = "cos", .linkage = common.linkage }); + @export(__cosx, .{ .name = "__cosx", .linkage = common.linkage }); + const cosq_sym_name = if (common.want_ppc_abi) "cosf128" else "cosq"; + @export(cosq, .{ .name = cosq_sym_name, .linkage = common.linkage }); + @export(cosl, .{ .name = "cosl", .linkage = common.linkage }); +} + pub fn __cosh(a: f16) callconv(.C) f16 { // TODO: more efficient implementation return @floatCast(f16, cosf(a)); diff --git a/lib/compiler_rt/count0bits.zig b/lib/compiler_rt/count0bits.zig @@ -1,5 +1,21 @@ const std = @import("std"); const builtin = @import("builtin"); +const is_test = builtin.is_test; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__clzsi2, .{ .name = "__clzsi2", .linkage = common.linkage }); + @export(__clzdi2, .{ .name = "__clzdi2", .linkage = common.linkage }); + @export(__clzti2, .{ .name = "__clzti2", .linkage = common.linkage }); + @export(__ctzsi2, .{ .name = "__ctzsi2", .linkage = common.linkage }); + @export(__ctzdi2, .{ .name = "__ctzdi2", .linkage = common.linkage }); + @export(__ctzti2, .{ .name = "__ctzti2", .linkage = common.linkage }); + @export(__ffssi2, .{ .name = "__ffssi2", .linkage = common.linkage }); + @export(__ffsdi2, .{ .name = "__ffsdi2", .linkage = common.linkage }); + @export(__ffsti2, .{ .name = "__ffsti2", .linkage = common.linkage }); +} // clz - count leading zeroes // - clzXi2 for unoptimized little and big endian @@ -15,8 +31,6 @@ const builtin = @import("builtin"); // - ffsXi2 for unoptimized little and big endian inline fn clzXi2(comptime T: type, a: T) i32 { - @setRuntimeSafety(builtin.is_test); - var x = switch (@bitSizeOf(T)) { 32 => @bitCast(u32, a), 64 => @bitCast(u64, a), @@ -154,8 +168,6 @@ pub fn __clzti2(a: i128) callconv(.C) i32 { } inline fn ctzXi2(comptime T: type, a: T) i32 { - @setRuntimeSafety(builtin.is_test); - var x = switch (@bitSizeOf(T)) { 32 => @bitCast(u32, a), 64 => @bitCast(u64, a), @@ -191,8 +203,6 @@ pub fn __ctzti2(a: i128) callconv(.C) i32 { } inline fn ffsXi2(comptime T: type, a: T) i32 { - @setRuntimeSafety(builtin.is_test); - var x = switch (@bitSizeOf(T)) { 32 => @bitCast(u32, a), 64 => @bitCast(u64, a), diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig @@ -1,12 +1,35 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c +//! Ported from: +//! +//! https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const is_test = builtin.is_test; +const common = @import("common.zig"); + +const normalize = common.normalize; +const wideMultiply = common.wideMultiply; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = common.linkage }); + } else { + @export(__divdf3, .{ .name = "__divdf3", .linkage = common.linkage }); + } +} pub fn __divdf3(a: f64, b: f64) callconv(.C) f64 { - @setRuntimeSafety(builtin.is_test); + return div(a, b); +} + +fn __aeabi_ddiv(a: f64, b: f64) callconv(.AAPCS) f64 { + return div(a, b); +} + +inline fn div(a: f64, b: f64) f64 { const Z = std.meta.Int(.unsigned, 64); const SignedZ = std.meta.Int(.signed, 64); @@ -202,130 +225,6 @@ pub fn __divdf3(a: f64, b: f64) callconv(.C) f64 { } } -pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { - @setRuntimeSafety(builtin.is_test); - switch (Z) { - u32 => { - // 32x32 --> 64 bit multiply - const product = @as(u64, a) * @as(u64, b); - hi.* = @truncate(u32, product >> 32); - lo.* = @truncate(u32, product); - }, - u64 => { - const S = struct { - fn loWord(x: u64) u64 { - return @truncate(u32, x); - } - fn hiWord(x: u64) u64 { - return @truncate(u32, x >> 32); - } - }; - // 64x64 -> 128 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - // Each of the component 32x32 -> 64 products - const plolo: u64 = S.loWord(a) * S.loWord(b); - const plohi: u64 = S.loWord(a) * S.hiWord(b); - const philo: u64 = S.hiWord(a) * S.loWord(b); - const phihi: u64 = S.hiWord(a) * S.hiWord(b); - // Sum terms that contribute to lo in a way that allows us to get the carry - const r0: u64 = S.loWord(plolo); - const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); - lo.* = r0 +% (r1 << 32); - // Sum terms contributing to hi with the carry from lo - hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; - }, - u128 => { - const Word_LoMask = @as(u64, 0x00000000ffffffff); - const Word_HiMask = @as(u64, 0xffffffff00000000); - const Word_FullMask = @as(u64, 0xffffffffffffffff); - const S = struct { - fn Word_1(x: u128) u64 { - return @truncate(u32, x >> 96); - } - fn Word_2(x: u128) u64 { - return @truncate(u32, x >> 64); - } - fn Word_3(x: u128) u64 { - return @truncate(u32, x >> 32); - } - fn Word_4(x: u128) u64 { - return @truncate(u32, x); - } - }; - // 128x128 -> 256 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - - const product11: u64 = S.Word_1(a) * S.Word_1(b); - const product12: u64 = S.Word_1(a) * S.Word_2(b); - const product13: u64 = S.Word_1(a) * S.Word_3(b); - const product14: u64 = S.Word_1(a) * S.Word_4(b); - const product21: u64 = S.Word_2(a) * S.Word_1(b); - const product22: u64 = S.Word_2(a) * S.Word_2(b); - const product23: u64 = S.Word_2(a) * S.Word_3(b); - const product24: u64 = S.Word_2(a) * S.Word_4(b); - const product31: u64 = S.Word_3(a) * S.Word_1(b); - const product32: u64 = S.Word_3(a) * S.Word_2(b); - const product33: u64 = S.Word_3(a) * S.Word_3(b); - const product34: u64 = S.Word_3(a) * S.Word_4(b); - const product41: u64 = S.Word_4(a) * S.Word_1(b); - const product42: u64 = S.Word_4(a) * S.Word_2(b); - const product43: u64 = S.Word_4(a) * S.Word_3(b); - const product44: u64 = S.Word_4(a) * S.Word_4(b); - - const sum0: u128 = @as(u128, product44); - const sum1: u128 = @as(u128, product34) +% - @as(u128, product43); - const sum2: u128 = @as(u128, product24) +% - @as(u128, product33) +% - @as(u128, product42); - const sum3: u128 = @as(u128, product14) +% - @as(u128, product23) +% - @as(u128, product32) +% - @as(u128, product41); - const sum4: u128 = @as(u128, product13) +% - @as(u128, product22) +% - @as(u128, product31); - const sum5: u128 = @as(u128, product12) +% - @as(u128, product21); - const sum6: u128 = @as(u128, product11); - - const r0: u128 = (sum0 & Word_FullMask) +% - ((sum1 & Word_LoMask) << 32); - const r1: u128 = (sum0 >> 64) +% - ((sum1 >> 32) & Word_FullMask) +% - (sum2 & Word_FullMask) +% - ((sum3 << 32) & Word_HiMask); - - lo.* = r0 +% (r1 << 64); - hi.* = (r1 >> 64) +% - (sum1 >> 96) +% - (sum2 >> 64) +% - (sum3 >> 32) +% - sum4 +% - (sum5 << 32) +% - (sum6 << 64); - }, - else => @compileError("unsupported"), - } -} - -pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { - @setRuntimeSafety(builtin.is_test); - const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); - const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); - - const shift = @clz(Z, significand.*) - @clz(Z, integerBit); - significand.* <<= @intCast(std.math.Log2Int(Z), shift); - return @as(i32, 1) - shift; -} - -pub fn __aeabi_ddiv(a: f64, b: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __divdf3, .{ a, b }); -} - test { _ = @import("divdf3_test.zig"); } diff --git a/lib/compiler_rt/divsf3.zig b/lib/compiler_rt/divsf3.zig @@ -1,12 +1,33 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c +//! Ported from: +//! +//! https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; + +const common = @import("common.zig"); +const normalize = common.normalize; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = common.linkage }); + } else { + @export(__divsf3, .{ .name = "__divsf3", .linkage = common.linkage }); + } +} pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { - @setRuntimeSafety(builtin.is_test); + return div(a, b); +} + +fn __aeabi_fdiv(a: f32, b: f32) callconv(.AAPCS) f32 { + return div(a, b); +} + +inline fn div(a: f32, b: f32) f32 { const Z = std.meta.Int(.unsigned, 32); const significandBits = std.math.floatMantissaBits(f32); @@ -184,22 +205,6 @@ pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { } } -fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { - @setRuntimeSafety(builtin.is_test); - const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); - const significandBits = std.math.floatMantissaBits(T); - const implicitBit = @as(Z, 1) << significandBits; - - const shift = @clz(Z, significand.*) - @clz(Z, implicitBit); - significand.* <<= @intCast(std.math.Log2Int(Z), shift); - return 1 - shift; -} - -pub fn __aeabi_fdiv(a: f32, b: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __divsf3, .{ a, b }); -} - test { _ = @import("divsf3_test.zig"); } diff --git a/lib/compiler_rt/divtf3.zig b/lib/compiler_rt/divtf3.zig @@ -1,11 +1,35 @@ const std = @import("std"); const builtin = @import("builtin"); -const normalize = @import("divdf3.zig").normalize; -const wideMultiply = @import("divdf3.zig").wideMultiply; +const common = @import("common.zig"); +const normalize = common.normalize; +const wideMultiply = common.wideMultiply; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__divkf3, .{ .name = "__divkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_div, .{ .name = "_Qp_div", .linkage = common.linkage }); + } else { + @export(__divtf3, .{ .name = "__divtf3", .linkage = common.linkage }); + } +} pub fn __divtf3(a: f128, b: f128) callconv(.C) f128 { - @setRuntimeSafety(builtin.is_test); + return div(a, b); +} + +fn __divkf3(a: f128, b: f128) callconv(.C) f128 { + return div(a, b); +} + +fn _Qp_div(c: *f128, a: *const f128, b: *const f128) callconv(.C) void { + c.* = div(a.*, b.*); +} + +inline fn div(a: f128, b: f128) f128 { const Z = std.meta.Int(.unsigned, 128); const significandBits = std.math.floatMantissaBits(f128); diff --git a/lib/compiler_rt/divti3.zig b/lib/compiler_rt/divti3.zig @@ -1,9 +1,43 @@ -const udivmod = @import("udivmod.zig").udivmod; +const std = @import("std"); const builtin = @import("builtin"); +const udivmod = @import("udivmod.zig").udivmod; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage }); + }, + else => {}, + } + if (arch.isAARCH64()) { + @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage }); + } + } else { + @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage }); + } +} pub fn __divti3(a: i128, b: i128) callconv(.C) i128 { - @setRuntimeSafety(builtin.is_test); + return div(a, b); +} +const v128 = @import("std").meta.Vector(2, u64); + +fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { + return @bitCast(v128, div(@bitCast(i128, a), @bitCast(i128, b))); +} + +inline fn div(a: i128, b: i128) i128 { const s_a = a >> (128 - 1); const s_b = b >> (128 - 1); @@ -15,14 +49,6 @@ pub fn __divti3(a: i128, b: i128) callconv(.C) i128 { return (@bitCast(i128, r) ^ s) -% s; } -const v128 = @import("std").meta.Vector(2, u64); -pub fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { - return @bitCast(v128, @call(.{ .modifier = .always_inline }, __divti3, .{ - @bitCast(i128, a), - @bitCast(i128, b), - })); -} - test { _ = @import("divti3_test.zig"); } diff --git a/lib/compiler_rt/divxf3.zig b/lib/compiler_rt/divxf3.zig @@ -1,10 +1,18 @@ const std = @import("std"); const builtin = @import("builtin"); -const normalize = @import("divdf3.zig").normalize; -const wideMultiply = @import("divdf3.zig").wideMultiply; +const arch = builtin.cpu.arch; + +const common = @import("common.zig"); +const normalize = common.normalize; +const wideMultiply = common.wideMultiply; + +pub const panic = common.panic; + +comptime { + @export(__divxf3, .{ .name = "__divxf3", .linkage = common.linkage }); +} pub fn __divxf3(a: f80, b: f80) callconv(.C) f80 { - @setRuntimeSafety(builtin.is_test); const T = f80; const Z = std.meta.Int(.unsigned, @bitSizeOf(T)); diff --git a/lib/compiler_rt/emutls.zig b/lib/compiler_rt/emutls.zig @@ -1,22 +1,26 @@ -// __emutls_get_address specific builtin -// -// derived work from LLVM Compiler Infrastructure - release 8.0 (MIT) -// https://github.com/llvm-mirror/compiler-rt/blob/release_80/lib/builtins/emutls.c -// +//! __emutls_get_address specific builtin +//! +//! derived work from LLVM Compiler Infrastructure - release 8.0 (MIT) +//! https://github.com/llvm-mirror/compiler-rt/blob/release_80/lib/builtins/emutls.c const std = @import("std"); const builtin = @import("builtin"); +const common = @import("common.zig"); const abort = std.os.abort; const assert = std.debug.assert; const expect = std.testing.expect; -// defined in C as: -// typedef unsigned int gcc_word __attribute__((mode(word))); +/// defined in C as: +/// typedef unsigned int gcc_word __attribute__((mode(word))); const gcc_word = usize; +pub const panic = common.panic; + comptime { - assert(builtin.link_libc); + if (builtin.link_libc and builtin.os.tag == .openbsd) { + @export(__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = common.linkage }); + } } /// public entrypoint for generated code using EmulatedTLS @@ -319,6 +323,8 @@ const emutls_control = extern struct { }; test "simple_allocator" { + if (!builtin.link_libc or builtin.os.tag != .openbsd) return error.SkipZigTest; + var data1: *[64]u8 = simple_allocator.alloc([64]u8); defer simple_allocator.free(data1); for (data1) |*c| { @@ -333,6 +339,8 @@ test "simple_allocator" { } test "__emutls_get_address zeroed" { + if (!builtin.link_libc or builtin.os.tag != .openbsd) return error.SkipZigTest; + var ctl = emutls_control.init(usize, null); try expect(ctl.object.index == 0); @@ -352,6 +360,8 @@ test "__emutls_get_address zeroed" { } test "__emutls_get_address with default_value" { + if (!builtin.link_libc or builtin.os.tag != .openbsd) return error.SkipZigTest; + var value: usize = 5678; // default value var ctl = emutls_control.init(usize, &value); try expect(ctl.object.index == 0); @@ -370,6 +380,8 @@ test "__emutls_get_address with default_value" { } test "test default_value with differents sizes" { + if (!builtin.link_libc or builtin.os.tag != .openbsd) return error.SkipZigTest; + const testType = struct { fn _testType(comptime T: type, value: T) !void { var def: T = value; diff --git a/lib/compiler_rt/exp.zig b/lib/compiler_rt/exp.zig @@ -5,8 +5,23 @@ // https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__exph, .{ .name = "__exph", .linkage = common.linkage }); + @export(expf, .{ .name = "expf", .linkage = common.linkage }); + @export(exp, .{ .name = "exp", .linkage = common.linkage }); + @export(__expx, .{ .name = "__expx", .linkage = common.linkage }); + const expq_sym_name = if (common.want_ppc_abi) "expf128" else "expq"; + @export(expq, .{ .name = expq_sym_name, .linkage = common.linkage }); + @export(expl, .{ .name = "expl", .linkage = common.linkage }); +} pub fn __exph(a: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/exp2.zig b/lib/compiler_rt/exp2.zig @@ -5,8 +5,23 @@ // https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__exp2h, .{ .name = "__exp2h", .linkage = common.linkage }); + @export(exp2f, .{ .name = "exp2f", .linkage = common.linkage }); + @export(exp2, .{ .name = "exp2", .linkage = common.linkage }); + @export(__exp2x, .{ .name = "__exp2x", .linkage = common.linkage }); + const exp2q_sym_name = if (common.want_ppc_abi) "exp2f128" else "exp2q"; + @export(exp2q, .{ .name = exp2q_sym_name, .linkage = common.linkage }); + @export(exp2l, .{ .name = "exp2l", .linkage = common.linkage }); +} pub fn __exp2h(x: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/extendXfYf2.zig b/lib/compiler_rt/extendXfYf2.zig @@ -1,112 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const native_arch = builtin.cpu.arch; - -pub fn __extendsfdf2(a: f32) callconv(.C) f64 { - return extendXfYf2(f64, f32, @bitCast(u32, a)); -} - -pub fn __extenddftf2(a: f64) callconv(.C) f128 { - return extendXfYf2(f128, f64, @bitCast(u64, a)); -} - -pub fn __extendsftf2(a: f32) callconv(.C) f128 { - return extendXfYf2(f128, f32, @bitCast(u32, a)); -} - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -pub const F16T = if (native_arch.isAARCH64()) f16 else u16; - -pub fn __extendhfsf2(a: F16T) callconv(.C) f32 { - return extendXfYf2(f32, f16, @bitCast(u16, a)); -} - -pub fn __extendhftf2(a: F16T) callconv(.C) f128 { - return extendXfYf2(f128, f16, @bitCast(u16, a)); -} - -pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg }); -} - -pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) }); -} - -inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t { - @setRuntimeSafety(builtin.is_test); - - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); - const srcSigBits = std.math.floatMantissaBits(src_t); - const dstSigBits = std.math.floatMantissaBits(dst_t); - const DstShift = std.math.Log2Int(dst_rep_t); - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const srcBits = @bitSizeOf(src_t); - const srcExpBits = srcBits - srcSigBits - 1; - const srcInfExp = (1 << srcExpBits) - 1; - const srcExpBias = srcInfExp >> 1; - - const srcMinNormal = 1 << srcSigBits; - const srcInfinity = srcInfExp << srcSigBits; - const srcSignMask = 1 << (srcSigBits + srcExpBits); - const srcAbsMask = srcSignMask - 1; - const srcQNaN = 1 << (srcSigBits - 1); - const srcNaNCode = srcQNaN - 1; - - const dstBits = @bitSizeOf(dst_t); - const dstExpBits = dstBits - dstSigBits - 1; - const dstInfExp = (1 << dstExpBits) - 1; - const dstExpBias = dstInfExp >> 1; - - const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; - - // Break a into a sign and representation of the absolute value - const aRep: src_rep_t = @bitCast(src_rep_t, a); - const aAbs: src_rep_t = aRep & srcAbsMask; - const sign: src_rep_t = aRep & srcSignMask; - var absResult: dst_rep_t = undefined; - - if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); - absResult += (dstExpBias - srcExpBias) << dstSigBits; - } else if (aAbs >= srcInfinity) { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - absResult = dstInfExp << dstSigBits; - absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); - absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); - } else if (aAbs != 0) { - // a is denormal. - // renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - const scale: u32 = @clz(src_rep_t, aAbs) - - @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); - absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); - absResult ^= dstMinNormal; - const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; - absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; - } else { - // a is zero. - absResult = 0; - } - - // Apply the signbit to (dst_t)abs(a). - const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); - return @bitCast(dst_t, result); -} - -test { - _ = @import("extendXfYf2_test.zig"); -} diff --git a/lib/compiler_rt/extendXfYf2_test.zig b/lib/compiler_rt/extendXfYf2_test.zig @@ -1,206 +0,0 @@ -const builtin = @import("builtin"); -const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; -const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2; -const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; -const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; -const F16T = @import("extendXfYf2.zig").F16T; - -fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void { - const x = __extenddftf2(a); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expectedHi and lo == expectedLo) - return; - - // test other possible NaN representation(signal NaN) - if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - @panic("__extenddftf2 test failure"); -} - -fn test__extendhfsf2(a: u16, expected: u32) !void { - const x = __extendhfsf2(@bitCast(F16T, a)); - const rep = @bitCast(u32, x); - - if (rep == expected) { - if (rep & 0x7fffffff > 0x7f800000) { - return; // NaN is always unequal. - } - if (x == @bitCast(f32, expected)) { - return; - } - } - - return error.TestFailure; -} - -fn test__extendsftf2(a: f32, expectedHi: u64, expectedLo: u64) !void { - const x = __extendsftf2(a); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expectedHi and lo == expectedLo) - return; - - // test other possible NaN representation(signal NaN) - if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailure; -} - -test "extenddftf2" { - // qNaN - try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0); - - // NaN - try test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); - - // inf - try test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0); - - // zero - try test__extenddftf2(0.0, 0x0, 0x0); - - try test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); - - try test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); - - try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); - - try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); -} - -test "extendhfsf2" { - try test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN - try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN - // On x86 the NaN becomes quiet because the return is pushed on the x87 - // stack due to ABI requirements - if (builtin.target.cpu.arch != .i386 and builtin.target.os.tag == .windows) - try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN - - try test__extendhfsf2(0, 0); // 0 - try test__extendhfsf2(0x8000, 0x80000000); // -0 - - try test__extendhfsf2(0x7c00, 0x7f800000); // inf - try test__extendhfsf2(0xfc00, 0xff800000); // -inf - - try test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24 - try test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24 - - try test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 - try test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 - - try test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14 - try test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14 - - try test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504 - try test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504 - - try test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10 - try test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10 - - try test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3 - try test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3 -} - -test "extendsftf2" { - // qNaN - try test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0); - // NaN - try test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0); - // inf - try test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0); - // zero - try test__extendsftf2(0.0, 0x0, 0x0); - try test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); - try test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); -} - -fn makeQNaN64() f64 { - return @bitCast(f64, @as(u64, 0x7ff8000000000000)); -} - -fn makeInf64() f64 { - return @bitCast(f64, @as(u64, 0x7ff0000000000000)); -} - -fn makeNaN64(rand: u64) f64 { - return @bitCast(f64, 0x7ff0000000000000 | (rand & 0xfffffffffffff)); -} - -fn makeQNaN32() f32 { - return @bitCast(f32, @as(u32, 0x7fc00000)); -} - -fn makeNaN32(rand: u32) f32 { - return @bitCast(f32, 0x7f800000 | (rand & 0x7fffff)); -} - -fn makeInf32() f32 { - return @bitCast(f32, @as(u32, 0x7f800000)); -} - -fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) !void { - const x = __extendhftf2(@bitCast(F16T, a)); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expectedHi and lo == expectedLo) - return; - - // test other possible NaN representation(signal NaN) - if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailure; -} - -test "extendhftf2" { - // qNaN - try test__extendhftf2(0x7e00, 0x7fff800000000000, 0x0); - // NaN - try test__extendhftf2(0x7d00, 0x7fff400000000000, 0x0); - // inf - try test__extendhftf2(0x7c00, 0x7fff000000000000, 0x0); - try test__extendhftf2(0xfc00, 0xffff000000000000, 0x0); - // zero - try test__extendhftf2(0x0000, 0x0000000000000000, 0x0); - try test__extendhftf2(0x8000, 0x8000000000000000, 0x0); - // denormal - try test__extendhftf2(0x0010, 0x3feb000000000000, 0x0); - try test__extendhftf2(0x0001, 0x3fe7000000000000, 0x0); - try test__extendhftf2(0x8001, 0xbfe7000000000000, 0x0); - - // pi - try test__extendhftf2(0x4248, 0x4000920000000000, 0x0); - try test__extendhftf2(0xc248, 0xc000920000000000, 0x0); - - try test__extendhftf2(0x508c, 0x4004230000000000, 0x0); - try test__extendhftf2(0x1bb7, 0x3ff6edc000000000, 0x0); -} diff --git a/lib/compiler_rt/extend_f80.zig b/lib/compiler_rt/extend_f80.zig @@ -1,131 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const native_arch = builtin.cpu.arch; - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -pub const F16T = if (native_arch.isAARCH64()) f16 else u16; - -pub fn __extendhfxf2(a: F16T) callconv(.C) f80 { - return extendF80(f16, @bitCast(u16, a)); -} - -pub fn __extendsfxf2(a: f32) callconv(.C) f80 { - return extendF80(f32, @bitCast(u32, a)); -} - -pub fn __extenddfxf2(a: f64) callconv(.C) f80 { - return extendF80(f64, @bitCast(u64, a)); -} - -inline fn extendF80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { - @setRuntimeSafety(builtin.is_test); - - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const src_sig_bits = std.math.floatMantissaBits(src_t); - const dst_int_bit = 0x8000000000000000; - const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - - const dst_exp_bias = 16383; - - const src_bits = @bitSizeOf(src_t); - const src_exp_bits = src_bits - src_sig_bits - 1; - const src_inf_exp = (1 << src_exp_bits) - 1; - const src_exp_bias = src_inf_exp >> 1; - - const src_min_normal = 1 << src_sig_bits; - const src_inf = src_inf_exp << src_sig_bits; - const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); - const src_abs_mask = src_sign_mask - 1; - const src_qnan = 1 << (src_sig_bits - 1); - const src_nan_code = src_qnan - 1; - - var dst: std.math.F80 = undefined; - - // Break a into a sign and representation of the absolute value - const a_abs = a & src_abs_mask; - const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; - - if (a_abs -% src_min_normal < src_inf - src_min_normal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - dst.exp = @intCast(u16, a_abs >> src_sig_bits); - dst.exp += dst_exp_bias - src_exp_bias; - dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); - dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers - } else if (a_abs >= src_inf) { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - dst.exp = 0x7fff; - dst.fraction = dst_int_bit; - dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); - dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); - } else if (a_abs != 0) { - // a is denormal. - // renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - const scale: u16 = @clz(src_rep_t, a_abs) - - @clz(src_rep_t, @as(src_rep_t, src_min_normal)); - - dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); - dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers - dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); - dst.exp ^= 1; - dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; - } else { - // a is zero. - dst.exp = 0; - dst.fraction = 0; - } - - dst.exp |= sign; - return std.math.make_f80(dst); -} - -pub fn __extendxftf2(a: f80) callconv(.C) f128 { - @setRuntimeSafety(builtin.is_test); - - const src_int_bit: u64 = 0x8000000000000000; - const src_sig_mask = ~src_int_bit; - const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - const dst_sig_bits = std.math.floatMantissaBits(f128); - - const dst_bits = @bitSizeOf(f128); - - const dst_min_normal = @as(u128, 1) << dst_sig_bits; - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.break_f80(a); - const sign = a_rep.exp & 0x8000; - a_rep.exp &= 0x7FFF; - var abs_result: u128 = undefined; - - if (a_rep.exp == 0 and a_rep.fraction == 0) { - // zero - abs_result = 0; - } else if (a_rep.exp == 0x7FFF) { - // a is nan or infinite - abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else if (a_rep.fraction & src_int_bit != 0) { - // a is a normal value - abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else { - // a is denormal - // renormalize the significand and clear the leading bit and integer part, - // then insert the correct adjusted exponent in the destination type. - const scale: u32 = @clz(u64, a_rep.fraction); - abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); - abs_result ^= dst_min_normal; - abs_result |= @as(u128, scale + 1) << dst_sig_bits; - } - - // Apply the signbit to (dst_t)abs(a). - const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); - return @bitCast(f128, result); -} diff --git a/lib/compiler_rt/extenddftf2.zig b/lib/compiler_rt/extenddftf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = common.linkage }); + } else { + @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = common.linkage }); + } +} + +pub fn __extenddftf2(a: f64) callconv(.C) f128 { + return extendf(f128, f64, @bitCast(u64, a)); +} + +fn __extenddfkf2(a: f64) callconv(.C) f128 { + return extendf(f128, f64, @bitCast(u64, a)); +} + +fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void { + c.* = extendf(f128, f64, @bitCast(u64, a)); +} diff --git a/lib/compiler_rt/extenddfxf2.zig b/lib/compiler_rt/extenddfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = common.linkage }); +} + +fn __extenddfxf2(a: f64) callconv(.C) f80 { + return extend_f80(f64, @bitCast(u64, a)); +} diff --git a/lib/compiler_rt/extendf.zig b/lib/compiler_rt/extendf.zig @@ -0,0 +1,142 @@ +const std = @import("std"); + +pub inline fn extendf( + comptime dst_t: type, + comptime src_t: type, + a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits), +) dst_t { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); + const srcSigBits = std.math.floatMantissaBits(src_t); + const dstSigBits = std.math.floatMantissaBits(dst_t); + const DstShift = std.math.Log2Int(dst_rep_t); + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const srcBits = @bitSizeOf(src_t); + const srcExpBits = srcBits - srcSigBits - 1; + const srcInfExp = (1 << srcExpBits) - 1; + const srcExpBias = srcInfExp >> 1; + + const srcMinNormal = 1 << srcSigBits; + const srcInfinity = srcInfExp << srcSigBits; + const srcSignMask = 1 << (srcSigBits + srcExpBits); + const srcAbsMask = srcSignMask - 1; + const srcQNaN = 1 << (srcSigBits - 1); + const srcNaNCode = srcQNaN - 1; + + const dstBits = @bitSizeOf(dst_t); + const dstExpBits = dstBits - dstSigBits - 1; + const dstInfExp = (1 << dstExpBits) - 1; + const dstExpBias = dstInfExp >> 1; + + const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; + + // Break a into a sign and representation of the absolute value + const aRep: src_rep_t = @bitCast(src_rep_t, a); + const aAbs: src_rep_t = aRep & srcAbsMask; + const sign: src_rep_t = aRep & srcSignMask; + var absResult: dst_rep_t = undefined; + + if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); + absResult += (dstExpBias - srcExpBias) << dstSigBits; + } else if (aAbs >= srcInfinity) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + absResult = dstInfExp << dstSigBits; + absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); + absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); + } else if (aAbs != 0) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const scale: u32 = @clz(src_rep_t, aAbs) - + @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); + absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); + absResult ^= dstMinNormal; + const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; + absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; + } else { + // a is zero. + absResult = 0; + } + + // Apply the signbit to (dst_t)abs(a). + const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); + return @bitCast(dst_t, result); +} + +pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const src_sig_bits = std.math.floatMantissaBits(src_t); + const dst_int_bit = 0x8000000000000000; + const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + + const dst_exp_bias = 16383; + + const src_bits = @bitSizeOf(src_t); + const src_exp_bits = src_bits - src_sig_bits - 1; + const src_inf_exp = (1 << src_exp_bits) - 1; + const src_exp_bias = src_inf_exp >> 1; + + const src_min_normal = 1 << src_sig_bits; + const src_inf = src_inf_exp << src_sig_bits; + const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); + const src_abs_mask = src_sign_mask - 1; + const src_qnan = 1 << (src_sig_bits - 1); + const src_nan_code = src_qnan - 1; + + var dst: std.math.F80 = undefined; + + // Break a into a sign and representation of the absolute value + const a_abs = a & src_abs_mask; + const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; + + if (a_abs -% src_min_normal < src_inf - src_min_normal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + dst.exp = @intCast(u16, a_abs >> src_sig_bits); + dst.exp += dst_exp_bias - src_exp_bias; + dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); + dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers + } else if (a_abs >= src_inf) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + dst.exp = 0x7fff; + dst.fraction = dst_int_bit; + dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); + dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); + } else if (a_abs != 0) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const scale: u16 = @clz(src_rep_t, a_abs) - + @clz(src_rep_t, @as(src_rep_t, src_min_normal)); + + dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); + dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers + dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); + dst.exp ^= 1; + dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; + } else { + // a is zero. + dst.exp = 0; + dst.fraction = 0; + } + + dst.exp |= sign; + return std.math.make_f80(dst); +} + +test { + _ = @import("extendf_test.zig"); +} diff --git a/lib/compiler_rt/extendf_test.zig b/lib/compiler_rt/extendf_test.zig @@ -0,0 +1,206 @@ +const builtin = @import("builtin"); +const __extendhfsf2 = @import("extendhfsf2.zig").__extendhfsf2; +const __extendhftf2 = @import("extendhftf2.zig").__extendhftf2; +const __extendsftf2 = @import("extendsftf2.zig").__extendsftf2; +const __extenddftf2 = @import("extenddftf2.zig").__extenddftf2; +const F16T = @import("./common.zig").F16T; + +fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { + const x = __extenddftf2(a); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) + return; + + // test other possible NaN representation(signal NaN) + if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + @panic("__extenddftf2 test failure"); +} + +fn test__extendhfsf2(a: u16, expected: u32) !void { + const x = __extendhfsf2(@bitCast(F16T, a)); + const rep = @bitCast(u32, x); + + if (rep == expected) { + if (rep & 0x7fffffff > 0x7f800000) { + return; // NaN is always unequal. + } + if (x == @bitCast(f32, expected)) { + return; + } + } + + return error.TestFailure; +} + +fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { + const x = __extendsftf2(a); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) + return; + + // test other possible NaN representation(signal NaN) + if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailure; +} + +test "extenddftf2" { + // qNaN + try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0); + + // NaN + try test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); + + // inf + try test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0); + + // zero + try test__extenddftf2(0.0, 0x0, 0x0); + + try test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); + + try test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); + + try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); + + try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); +} + +test "extendhfsf2" { + try test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN + try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN + // On x86 the NaN becomes quiet because the return is pushed on the x87 + // stack due to ABI requirements + if (builtin.target.cpu.arch != .i386 and builtin.target.os.tag == .windows) + try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN + + try test__extendhfsf2(0, 0); // 0 + try test__extendhfsf2(0x8000, 0x80000000); // -0 + + try test__extendhfsf2(0x7c00, 0x7f800000); // inf + try test__extendhfsf2(0xfc00, 0xff800000); // -inf + + try test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24 + try test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24 + + try test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 + try test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 + + try test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14 + try test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14 + + try test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504 + try test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504 + + try test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10 + try test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10 + + try test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3 + try test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3 +} + +test "extendsftf2" { + // qNaN + try test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0); + // NaN + try test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0); + // inf + try test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0); + // zero + try test__extendsftf2(0.0, 0x0, 0x0); + try test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0); + try test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); + try test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0); + try test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); +} + +fn makeQNaN64() f64 { + return @bitCast(f64, @as(u64, 0x7ff8000000000000)); +} + +fn makeInf64() f64 { + return @bitCast(f64, @as(u64, 0x7ff0000000000000)); +} + +fn makeNaN64(rand: u64) f64 { + return @bitCast(f64, 0x7ff0000000000000 | (rand & 0xfffffffffffff)); +} + +fn makeQNaN32() f32 { + return @bitCast(f32, @as(u32, 0x7fc00000)); +} + +fn makeNaN32(rand: u32) f32 { + return @bitCast(f32, 0x7f800000 | (rand & 0x7fffff)); +} + +fn makeInf32() f32 { + return @bitCast(f32, @as(u32, 0x7f800000)); +} + +fn test__extendhftf2(a: u16, expected_hi: u64, expected_lo: u64) !void { + const x = __extendhftf2(@bitCast(F16T, a)); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) + return; + + // test other possible NaN representation(signal NaN) + if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailure; +} + +test "extendhftf2" { + // qNaN + try test__extendhftf2(0x7e00, 0x7fff800000000000, 0x0); + // NaN + try test__extendhftf2(0x7d00, 0x7fff400000000000, 0x0); + // inf + try test__extendhftf2(0x7c00, 0x7fff000000000000, 0x0); + try test__extendhftf2(0xfc00, 0xffff000000000000, 0x0); + // zero + try test__extendhftf2(0x0000, 0x0000000000000000, 0x0); + try test__extendhftf2(0x8000, 0x8000000000000000, 0x0); + // denormal + try test__extendhftf2(0x0010, 0x3feb000000000000, 0x0); + try test__extendhftf2(0x0001, 0x3fe7000000000000, 0x0); + try test__extendhftf2(0x8001, 0xbfe7000000000000, 0x0); + + // pi + try test__extendhftf2(0x4248, 0x4000920000000000, 0x0); + try test__extendhftf2(0xc248, 0xc000920000000000, 0x0); + + try test__extendhftf2(0x508c, 0x4004230000000000, 0x0); + try test__extendhftf2(0x1bb7, 0x3ff6edc000000000, 0x0); +} diff --git a/lib/compiler_rt/extendhfsf2.zig b/lib/compiler_rt/extendhfsf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.gnu_f16_abi) { + @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = common.linkage }); + } else if (common.want_aeabi) { + @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage }); + } else { + @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage }); + } +} + +pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} + +fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} + +fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendhftf2.zig b/lib/compiler_rt/extendhftf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = common.linkage }); +} + +pub fn __extendhftf2(a: common.F16T) callconv(.C) f128 { + return extendf(f128, f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendhfxf2.zig b/lib/compiler_rt/extendhfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = common.linkage }); +} + +fn __extendhfxf2(a: common.F16T) callconv(.C) f80 { + return extend_f80(f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendsfdf2.zig b/lib/compiler_rt/extendsfdf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = common.linkage }); + } else { + @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = common.linkage }); + } +} + +fn __extendsfdf2(a: f32) callconv(.C) f64 { + return extendf(f64, f32, @bitCast(u32, a)); +} + +fn __aeabi_f2d(a: f32) callconv(.AAPCS) f64 { + return extendf(f64, f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendsftf2.zig b/lib/compiler_rt/extendsftf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = common.linkage }); + } else { + @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = common.linkage }); + } +} + +pub fn __extendsftf2(a: f32) callconv(.C) f128 { + return extendf(f128, f32, @bitCast(u32, a)); +} + +fn __extendsfkf2(a: f32) callconv(.C) f128 { + return extendf(f128, f32, @bitCast(u32, a)); +} + +fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void { + c.* = extendf(f128, f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendsfxf2.zig b/lib/compiler_rt/extendsfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = common.linkage }); +} + +fn __extendsfxf2(a: f32) callconv(.C) f80 { + return extend_f80(f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendxftf2.zig b/lib/compiler_rt/extendxftf2.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = common.linkage }); +} + +fn __extendxftf2(a: f80) callconv(.C) f128 { + const src_int_bit: u64 = 0x8000000000000000; + const src_sig_mask = ~src_int_bit; + const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + const dst_sig_bits = std.math.floatMantissaBits(f128); + + const dst_bits = @bitSizeOf(f128); + + const dst_min_normal = @as(u128, 1) << dst_sig_bits; + + // Break a into a sign and representation of the absolute value + var a_rep = std.math.break_f80(a); + const sign = a_rep.exp & 0x8000; + a_rep.exp &= 0x7FFF; + var abs_result: u128 = undefined; + + if (a_rep.exp == 0 and a_rep.fraction == 0) { + // zero + abs_result = 0; + } else if (a_rep.exp == 0x7FFF) { + // a is nan or infinite + abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else if (a_rep.fraction & src_int_bit != 0) { + // a is a normal value + abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else { + // a is denormal + // renormalize the significand and clear the leading bit and integer part, + // then insert the correct adjusted exponent in the destination type. + const scale: u32 = @clz(u64, a_rep.fraction); + abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); + abs_result ^= dst_min_normal; + abs_result |= @as(u128, scale + 1) << dst_sig_bits; + } + + // Apply the signbit to (dst_t)abs(a). + const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); + return @bitCast(f128, result); +} diff --git a/lib/compiler_rt/fabs.zig b/lib/compiler_rt/fabs.zig @@ -1,4 +1,19 @@ const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__fabsh, .{ .name = "__fabsh", .linkage = common.linkage }); + @export(fabsf, .{ .name = "fabsf", .linkage = common.linkage }); + @export(fabs, .{ .name = "fabs", .linkage = common.linkage }); + @export(__fabsx, .{ .name = "__fabsx", .linkage = common.linkage }); + const fabsq_sym_name = if (common.want_ppc_abi) "fabsf128" else "fabsq"; + @export(fabsq, .{ .name = fabsq_sym_name, .linkage = common.linkage }); + @export(fabsl, .{ .name = "fabsl", .linkage = common.linkage }); +} pub fn __fabsh(a: f16) callconv(.C) f16 { return generic_fabs(a); diff --git a/lib/compiler_rt/fixXfYi.zig b/lib/compiler_rt/fixXfYi.zig @@ -1,224 +0,0 @@ -const std = @import("std"); -const math = std.math; -const Log2Int = math.Log2Int; -const is_test = @import("builtin").is_test; - -pub inline fn fixXfYi(comptime I: type, a: anytype) I { - @setRuntimeSafety(is_test); - - const F = @TypeOf(a); - const float_bits = @typeInfo(F).Float.bits; - const int_bits = @typeInfo(I).Int.bits; - const rep_t = std.meta.Int(.unsigned, float_bits); - const sig_bits = math.floatMantissaBits(F); - const exp_bits = math.floatExponentBits(F); - const fractional_bits = math.floatFractionalBits(F); - - const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; - const max_exp = (1 << (exp_bits - 1)); - const exp_bias = max_exp - 1; - const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; - - // Break a into sign, exponent, significand - const a_rep: rep_t = @bitCast(rep_t, a); - const negative = (a_rep >> (float_bits - 1)) != 0; - const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; - const significand: rep_t = (a_rep & sig_mask) | implicit_bit; - - // If the exponent is negative, the result rounds to zero. - if (exponent < 0) return 0; - - // If the value is too large for the integer type, saturate. - switch (@typeInfo(I).Int.signedness) { - .unsigned => { - if (negative) return 0; - if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); - }, - .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { - return if (negative) math.minInt(I) else math.maxInt(I); - }, - } - - // If 0 <= exponent < sig_bits, right shift to get the result. - // Otherwise, shift left. - var result: I = undefined; - if (exponent < fractional_bits) { - result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); - } else { - result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); - } - - if ((@typeInfo(I).Int.signedness == .signed) and negative) - return ~result +% 1; - return result; -} - -// Conversion from f16 - -pub fn __fixhfsi(a: f16) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunshfsi(a: f16) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixhfdi(a: f16) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunshfdi(a: f16) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixhfti(a: f16) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunshfti(a: f16) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f32 - -pub fn __fixsfsi(a: f32) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunssfsi(a: f32) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixsfdi(a: f32) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunssfdi(a: f32) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixsfti(a: f32) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunssfti(a: f32) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f64 - -pub fn __fixdfsi(a: f64) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunsdfsi(a: f64) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixdfdi(a: f64) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunsdfdi(a: f64) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixdfti(a: f64) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunsdfti(a: f64) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f80 - -pub fn __fixxfsi(a: f80) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunsxfsi(a: f80) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixxfdi(a: f80) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunsxfdi(a: f80) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixxfti(a: f80) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunsxfti(a: f80) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f128 - -pub fn __fixtfsi(a: f128) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunstfsi(a: f128) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixtfdi(a: f128) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunstfdi(a: f128) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixtfti(a: f128) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunstfti(a: f128) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f32 - -pub fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { - return fixXfYi(i32, a); -} - -pub fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { - return fixXfYi(u32, a); -} - -pub fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { - return fixXfYi(i64, a); -} - -pub fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { - return fixXfYi(u64, a); -} - -// Conversion from f64 - -pub fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { - return fixXfYi(i32, a); -} - -pub fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { - return fixXfYi(u32, a); -} - -pub fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { - return fixXfYi(i64, a); -} - -pub fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { - return fixXfYi(u64, a); -} - -test { - _ = @import("fixXfYi_test.zig"); -} diff --git a/lib/compiler_rt/fixXfYi_test.zig b/lib/compiler_rt/fixXfYi_test.zig @@ -1,948 +0,0 @@ -const std = @import("std"); -const testing = std.testing; -const math = std.math; -const fixXfYi = @import("fixXfYi.zig").fixXfYi; - -// Conversion from f32 -const __fixsfsi = @import("fixXfYi.zig").__fixsfsi; -const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi; -const __fixsfdi = @import("fixXfYi.zig").__fixsfdi; -const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi; -const __fixsfti = @import("fixXfYi.zig").__fixsfti; -const __fixunssfti = @import("fixXfYi.zig").__fixunssfti; - -// Conversion from f64 -const __fixdfsi = @import("fixXfYi.zig").__fixdfsi; -const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi; -const __fixdfdi = @import("fixXfYi.zig").__fixdfdi; -const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi; -const __fixdfti = @import("fixXfYi.zig").__fixdfti; -const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti; - -// Conversion from f128 -const __fixtfsi = @import("fixXfYi.zig").__fixtfsi; -const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi; -const __fixtfdi = @import("fixXfYi.zig").__fixtfdi; -const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi; -const __fixtfti = @import("fixXfYi.zig").__fixtfti; -const __fixunstfti = @import("fixXfYi.zig").__fixunstfti; - -fn test__fixsfsi(a: f32, expected: i32) !void { - const x = __fixsfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunssfsi(a: f32, expected: u32) !void { - const x = __fixunssfsi(a); - try testing.expect(x == expected); -} - -test "fixsfsi" { - try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); - - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixsfsi(-0x1.000000p+31, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfsi(-2.01, -2); - try test__fixsfsi(-2.0, -2); - try test__fixsfsi(-1.99, -1); - try test__fixsfsi(-1.0, -1); - try test__fixsfsi(-0.99, 0); - try test__fixsfsi(-0.5, 0); - try test__fixsfsi(-math.floatMin(f32), 0); - try test__fixsfsi(0.0, 0); - try test__fixsfsi(math.floatMin(f32), 0); - try test__fixsfsi(0.5, 0); - try test__fixsfsi(0.99, 0); - try test__fixsfsi(1.0, 1); - try test__fixsfsi(1.5, 1); - try test__fixsfsi(1.99, 1); - try test__fixsfsi(2.0, 2); - try test__fixsfsi(2.01, 2); - - try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); - try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); -} - -test "fixunssfsi" { - try test__fixunssfsi(0.0, 0); - - try test__fixunssfsi(0.5, 0); - try test__fixunssfsi(0.99, 0); - try test__fixunssfsi(1.0, 1); - try test__fixunssfsi(1.5, 1); - try test__fixunssfsi(1.99, 1); - try test__fixunssfsi(2.0, 2); - try test__fixunssfsi(2.01, 2); - try test__fixunssfsi(-0.5, 0); - try test__fixunssfsi(-0.99, 0); - - try test__fixunssfsi(-1.0, 0); - try test__fixunssfsi(-1.5, 0); - try test__fixunssfsi(-1.99, 0); - try test__fixunssfsi(-2.0, 0); - try test__fixunssfsi(-2.01, 0); - - try test__fixunssfsi(0x1.000000p+31, 0x80000000); - try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunssfsi(-0x1.FFFFFEp+30, 0); - try test__fixunssfsi(-0x1.FFFFFCp+30, 0); -} - -fn test__fixsfdi(a: f32, expected: i64) !void { - const x = __fixsfdi(a); - try testing.expect(x == expected); -} - -fn test__fixunssfdi(a: f32, expected: u64) !void { - const x = __fixunssfdi(a); - try testing.expect(x == expected); -} - -test "fixsfdi" { - try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); - - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfdi(-2.01, -2); - try test__fixsfdi(-2.0, -2); - try test__fixsfdi(-1.99, -1); - try test__fixsfdi(-1.0, -1); - try test__fixsfdi(-0.99, 0); - try test__fixsfdi(-0.5, 0); - try test__fixsfdi(-math.floatMin(f32), 0); - try test__fixsfdi(0.0, 0); - try test__fixsfdi(math.floatMin(f32), 0); - try test__fixsfdi(0.5, 0); - try test__fixsfdi(0.99, 0); - try test__fixsfdi(1.0, 1); - try test__fixsfdi(1.5, 1); - try test__fixsfdi(1.99, 1); - try test__fixsfdi(2.0, 2); - try test__fixsfdi(2.01, 2); - - try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); -} - -test "fixunssfdi" { - try test__fixunssfdi(0.0, 0); - - try test__fixunssfdi(0.5, 0); - try test__fixunssfdi(0.99, 0); - try test__fixunssfdi(1.0, 1); - try test__fixunssfdi(1.5, 1); - try test__fixunssfdi(1.99, 1); - try test__fixunssfdi(2.0, 2); - try test__fixunssfdi(2.01, 2); - try test__fixunssfdi(-0.5, 0); - try test__fixunssfdi(-0.99, 0); - - try test__fixunssfdi(-1.0, 0); - try test__fixunssfdi(-1.5, 0); - try test__fixunssfdi(-1.99, 0); - try test__fixunssfdi(-2.0, 0); - try test__fixunssfdi(-2.01, 0); - - try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); -} - -fn test__fixsfti(a: f32, expected: i128) !void { - const x = __fixsfti(a); - try testing.expect(x == expected); -} - -fn test__fixunssfti(a: f32, expected: u128) !void { - const x = __fixunssfti(a); - try testing.expect(x == expected); -} - -test "fixsfti" { - try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); - - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); - try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); - - try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfti(-0x1.000000p+31, -0x80000000); - try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfti(-2.01, -2); - try test__fixsfti(-2.0, -2); - try test__fixsfti(-1.99, -1); - try test__fixsfti(-1.0, -1); - try test__fixsfti(-0.99, 0); - try test__fixsfti(-0.5, 0); - try test__fixsfti(-math.floatMin(f32), 0); - try test__fixsfti(0.0, 0); - try test__fixsfti(math.floatMin(f32), 0); - try test__fixsfti(0.5, 0); - try test__fixsfti(0.99, 0); - try test__fixsfti(1.0, 1); - try test__fixsfti(1.5, 1); - try test__fixsfti(1.99, 1); - try test__fixsfti(2.0, 2); - try test__fixsfti(2.01, 2); - - try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); - try test__fixsfti(0x1.000000p+31, 0x80000000); - - try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); - try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); - try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); - try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); -} - -test "fixunssfti" { - try test__fixunssfti(0.0, 0); - - try test__fixunssfti(0.5, 0); - try test__fixunssfti(0.99, 0); - try test__fixunssfti(1.0, 1); - try test__fixunssfti(1.5, 1); - try test__fixunssfti(1.99, 1); - try test__fixunssfti(2.0, 2); - try test__fixunssfti(2.01, 2); - try test__fixunssfti(-0.5, 0); - try test__fixunssfti(-0.99, 0); - - try test__fixunssfti(-1.0, 0); - try test__fixunssfti(-1.5, 0); - try test__fixunssfti(-1.99, 0); - try test__fixunssfti(-2.0, 0); - try test__fixunssfti(-2.01, 0); - - try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); - try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); - try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); - try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); - - try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); - try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); - try test__fixunssfti(math.inf(f32), math.maxInt(u128)); -} - -fn test__fixdfsi(a: f64, expected: i32) !void { - const x = __fixdfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunsdfsi(a: f64, expected: u32) !void { - const x = __fixunsdfsi(a); - try testing.expect(x == expected); -} - -test "fixdfsi" { - try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); - - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixdfsi(-0x1.000000p+31, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - - try test__fixdfsi(-2.01, -2); - try test__fixdfsi(-2.0, -2); - try test__fixdfsi(-1.99, -1); - try test__fixdfsi(-1.0, -1); - try test__fixdfsi(-0.99, 0); - try test__fixdfsi(-0.5, 0); - try test__fixdfsi(-math.floatMin(f64), 0); - try test__fixdfsi(0.0, 0); - try test__fixdfsi(math.floatMin(f64), 0); - try test__fixdfsi(0.5, 0); - try test__fixdfsi(0.99, 0); - try test__fixdfsi(1.0, 1); - try test__fixdfsi(1.5, 1); - try test__fixdfsi(1.99, 1); - try test__fixdfsi(2.0, 2); - try test__fixdfsi(2.01, 2); - - try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); -} - -test "fixunsdfsi" { - try test__fixunsdfsi(0.0, 0); - - try test__fixunsdfsi(0.5, 0); - try test__fixunsdfsi(0.99, 0); - try test__fixunsdfsi(1.0, 1); - try test__fixunsdfsi(1.5, 1); - try test__fixunsdfsi(1.99, 1); - try test__fixunsdfsi(2.0, 2); - try test__fixunsdfsi(2.01, 2); - try test__fixunsdfsi(-0.5, 0); - try test__fixunsdfsi(-0.99, 0); - try test__fixunsdfsi(-1.0, 0); - try test__fixunsdfsi(-1.5, 0); - try test__fixunsdfsi(-1.99, 0); - try test__fixunsdfsi(-2.0, 0); - try test__fixunsdfsi(-2.01, 0); - - try test__fixunsdfsi(0x1.000000p+31, 0x80000000); - try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); - try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); - - try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); -} - -fn test__fixdfdi(a: f64, expected: i64) !void { - const x = __fixdfdi(a); - try testing.expect(x == expected); -} - -fn test__fixunsdfdi(a: f64, expected: u64) !void { - const x = __fixunsdfdi(a); - try testing.expect(x == expected); -} - -test "fixdfdi" { - try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); - - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfdi(-2.01, -2); - try test__fixdfdi(-2.0, -2); - try test__fixdfdi(-1.99, -1); - try test__fixdfdi(-1.0, -1); - try test__fixdfdi(-0.99, 0); - try test__fixdfdi(-0.5, 0); - try test__fixdfdi(-math.floatMin(f64), 0); - try test__fixdfdi(0.0, 0); - try test__fixdfdi(math.floatMin(f64), 0); - try test__fixdfdi(0.5, 0); - try test__fixdfdi(0.99, 0); - try test__fixdfdi(1.0, 1); - try test__fixdfdi(1.5, 1); - try test__fixdfdi(1.99, 1); - try test__fixdfdi(2.0, 2); - try test__fixdfdi(2.01, 2); - - try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); -} - -test "fixunsdfdi" { - try test__fixunsdfdi(0.0, 0); - try test__fixunsdfdi(0.5, 0); - try test__fixunsdfdi(0.99, 0); - try test__fixunsdfdi(1.0, 1); - try test__fixunsdfdi(1.5, 1); - try test__fixunsdfdi(1.99, 1); - try test__fixunsdfdi(2.0, 2); - try test__fixunsdfdi(2.01, 2); - try test__fixunsdfdi(-0.5, 0); - try test__fixunsdfdi(-0.99, 0); - try test__fixunsdfdi(-1.0, 0); - try test__fixunsdfdi(-1.5, 0); - try test__fixunsdfdi(-1.99, 0); - try test__fixunsdfdi(-2.0, 0); - try test__fixunsdfdi(-2.01, 0); - - try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test__fixdfti(a: f64, expected: i128) !void { - const x = __fixdfti(a); - try testing.expect(x == expected); -} - -fn test__fixunsdfti(a: f64, expected: u128) !void { - const x = __fixunsdfti(a); - try testing.expect(x == expected); -} - -test "fixdfti" { - try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); - - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfti(-2.01, -2); - try test__fixdfti(-2.0, -2); - try test__fixdfti(-1.99, -1); - try test__fixdfti(-1.0, -1); - try test__fixdfti(-0.99, 0); - try test__fixdfti(-0.5, 0); - try test__fixdfti(-math.floatMin(f64), 0); - try test__fixdfti(0.0, 0); - try test__fixdfti(math.floatMin(f64), 0); - try test__fixdfti(0.5, 0); - try test__fixdfti(0.99, 0); - try test__fixdfti(1.0, 1); - try test__fixdfti(1.5, 1); - try test__fixdfti(1.99, 1); - try test__fixdfti(2.0, 2); - try test__fixdfti(2.01, 2); - - try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); -} - -test "fixunsdfti" { - try test__fixunsdfti(0.0, 0); - - try test__fixunsdfti(0.5, 0); - try test__fixunsdfti(0.99, 0); - try test__fixunsdfti(1.0, 1); - try test__fixunsdfti(1.5, 1); - try test__fixunsdfti(1.99, 1); - try test__fixunsdfti(2.0, 2); - try test__fixunsdfti(2.01, 2); - try test__fixunsdfti(-0.5, 0); - try test__fixunsdfti(-0.99, 0); - try test__fixunsdfti(-1.0, 0); - try test__fixunsdfti(-1.5, 0); - try test__fixunsdfti(-1.99, 0); - try test__fixunsdfti(-2.0, 0); - try test__fixunsdfti(-2.01, 0); - - try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfti(-0x1.FFFFFEp+62, 0); - try test__fixunsdfti(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test__fixtfsi(a: f128, expected: i32) !void { - const x = __fixtfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunstfsi(a: f128, expected: u32) !void { - const x = __fixunstfsi(a); - try testing.expect(x == expected); -} - -test "fixtfsi" { - try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); - - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixtfsi(-0x1.000000p+31, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfsi(-2.01, -2); - try test__fixtfsi(-2.0, -2); - try test__fixtfsi(-1.99, -1); - try test__fixtfsi(-1.0, -1); - try test__fixtfsi(-0.99, 0); - try test__fixtfsi(-0.5, 0); - try test__fixtfsi(-math.floatMin(f32), 0); - try test__fixtfsi(0.0, 0); - try test__fixtfsi(math.floatMin(f32), 0); - try test__fixtfsi(0.5, 0); - try test__fixtfsi(0.99, 0); - try test__fixtfsi(1.0, 1); - try test__fixtfsi(1.5, 1); - try test__fixtfsi(1.99, 1); - try test__fixtfsi(2.0, 2); - try test__fixtfsi(2.01, 2); - - try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); -} - -test "fixunstfsi" { - try test__fixunstfsi(math.inf(f128), 0xffffffff); - try test__fixunstfsi(0, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); - try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); - try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); - try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); - try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); - - try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); -} - -fn test__fixtfdi(a: f128, expected: i64) !void { - const x = __fixtfdi(a); - try testing.expect(x == expected); -} - -fn test__fixunstfdi(a: f128, expected: u64) !void { - const x = __fixunstfdi(a); - try testing.expect(x == expected); -} - -test "fixtfdi" { - try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); - - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); - try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); - - try test__fixtfdi(-0x1.000000p+31, -0x80000000); - try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfdi(-2.01, -2); - try test__fixtfdi(-2.0, -2); - try test__fixtfdi(-1.99, -1); - try test__fixtfdi(-1.0, -1); - try test__fixtfdi(-0.99, 0); - try test__fixtfdi(-0.5, 0); - try test__fixtfdi(-math.floatMin(f64), 0); - try test__fixtfdi(0.0, 0); - try test__fixtfdi(math.floatMin(f64), 0); - try test__fixtfdi(0.5, 0); - try test__fixtfdi(0.99, 0); - try test__fixtfdi(1.0, 1); - try test__fixtfdi(1.5, 1); - try test__fixtfdi(1.99, 1); - try test__fixtfdi(2.0, 2); - try test__fixtfdi(2.01, 2); - - try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfdi(0x1.000000p+31, 0x80000000); - - try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); -} - -test "fixunstfdi" { - try test__fixunstfdi(0.0, 0); - - try test__fixunstfdi(0.5, 0); - try test__fixunstfdi(0.99, 0); - try test__fixunstfdi(1.0, 1); - try test__fixunstfdi(1.5, 1); - try test__fixunstfdi(1.99, 1); - try test__fixunstfdi(2.0, 2); - try test__fixunstfdi(2.01, 2); - try test__fixunstfdi(-0.5, 0); - try test__fixunstfdi(-0.99, 0); - try test__fixunstfdi(-1.0, 0); - try test__fixunstfdi(-1.5, 0); - try test__fixunstfdi(-1.99, 0); - try test__fixunstfdi(-2.0, 0); - try test__fixunstfdi(-2.01, 0); - - try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunstfdi(-0x1.FFFFFEp+62, 0); - try test__fixunstfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); - try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); - try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); - - try test__fixunstfdi(-0x1.0000000000000000p+63, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); -} - -fn test__fixtfti(a: f128, expected: i128) !void { - const x = __fixtfti(a); - try testing.expect(x == expected); -} - -fn test__fixunstfti(a: f128, expected: u128) !void { - const x = __fixunstfti(a); - try testing.expect(x == expected); -} - -test "fixtfti" { - try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); - - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixtfti(-2.01, -2); - try test__fixtfti(-2.0, -2); - try test__fixtfti(-1.99, -1); - try test__fixtfti(-1.0, -1); - try test__fixtfti(-0.99, 0); - try test__fixtfti(-0.5, 0); - try test__fixtfti(-math.floatMin(f128), 0); - try test__fixtfti(0.0, 0); - try test__fixtfti(math.floatMin(f128), 0); - try test__fixtfti(0.5, 0); - try test__fixtfti(0.99, 0); - try test__fixtfti(1.0, 1); - try test__fixtfti(1.5, 1); - try test__fixtfti(1.99, 1); - try test__fixtfti(2.0, 2); - try test__fixtfti(2.01, 2); - - try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); - - try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); -} - -test "fixunstfti" { - try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); - - try test__fixunstfti(0.0, 0); - - try test__fixunstfti(0.5, 0); - try test__fixunstfti(0.99, 0); - try test__fixunstfti(1.0, 1); - try test__fixunstfti(1.5, 1); - try test__fixunstfti(1.99, 1); - try test__fixunstfti(2.0, 2); - try test__fixunstfti(2.01, 2); - try test__fixunstfti(-0.01, 0); - try test__fixunstfti(-0.99, 0); - - try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); - - try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); -} - -fn test__fixunshfti(a: f16, expected: u128) !void { - const x = fixXfYi(u128, a); - try testing.expect(x == expected); -} - -test "fixXfYi for f16" { - try test__fixunshfti(math.inf(f16), math.maxInt(u128)); - try test__fixunshfti(math.floatMax(f16), 65504); -} - -fn test__fixunsxfti(a: f80, expected: u128) !void { - const x = fixXfYi(u128, a); - try testing.expect(x == expected); -} - -test "fixXfYi for f80" { - try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); - try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); - try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); -} diff --git a/lib/compiler_rt/fixdfdi.zig b/lib/compiler_rt/fixdfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = common.linkage }); + } else { + @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = common.linkage }); + } +} + +pub fn __fixdfdi(a: f64) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixdfsi.zig b/lib/compiler_rt/fixdfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = common.linkage }); + } else { + @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = common.linkage }); + } +} + +pub fn __fixdfsi(a: f64) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixdfti.zig b/lib/compiler_rt/fixdfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixdfti, .{ .name = "__fixdfti", .linkage = common.linkage }); +} + +pub fn __fixdfti(a: f64) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixhfdi.zig b/lib/compiler_rt/fixhfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfdi, .{ .name = "__fixhfdi", .linkage = common.linkage }); +} + +fn __fixhfdi(a: f16) callconv(.C) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixhfsi.zig b/lib/compiler_rt/fixhfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfsi, .{ .name = "__fixhfsi", .linkage = common.linkage }); +} + +fn __fixhfsi(a: f16) callconv(.C) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixhfti.zig b/lib/compiler_rt/fixhfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfti, .{ .name = "__fixhfti", .linkage = common.linkage }); +} + +fn __fixhfti(a: f16) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixsfdi.zig b/lib/compiler_rt/fixsfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = common.linkage }); + } else { + @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = common.linkage }); + } +} + +pub fn __fixsfdi(a: f32) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixsfsi.zig b/lib/compiler_rt/fixsfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = common.linkage }); + } else { + @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = common.linkage }); + } +} + +pub fn __fixsfsi(a: f32) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixsfti.zig b/lib/compiler_rt/fixsfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixsfti, .{ .name = "__fixsfti", .linkage = common.linkage }); +} + +pub fn __fixsfti(a: f32) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixtfdi.zig b/lib/compiler_rt/fixtfdi.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = common.linkage }); + } else { + @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = common.linkage }); + } +} + +pub fn __fixtfdi(a: f128) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __fixkfdi(a: f128) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn _Qp_qtox(a: *const f128) callconv(.C) i64 { + return floatToInt(i64, a.*); +} diff --git a/lib/compiler_rt/fixtfsi.zig b/lib/compiler_rt/fixtfsi.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = common.linkage }); + } else { + @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = common.linkage }); + } +} + +pub fn __fixtfsi(a: f128) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __fixkfsi(a: f128) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn _Qp_qtoi(a: *const f128) callconv(.C) i32 { + return floatToInt(i32, a.*); +} diff --git a/lib/compiler_rt/fixtfti.zig b/lib/compiler_rt/fixtfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixtfti, .{ .name = "__fixtfti", .linkage = common.linkage }); +} + +pub fn __fixtfti(a: f128) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixunsdfdi.zig b/lib/compiler_rt/fixunsdfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = common.linkage }); + } else { + @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = common.linkage }); + } +} + +pub fn __fixunsdfdi(a: f64) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunsdfsi.zig b/lib/compiler_rt/fixunsdfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = common.linkage }); + } else { + @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = common.linkage }); + } +} + +pub fn __fixunsdfsi(a: f64) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunsdfti.zig b/lib/compiler_rt/fixunsdfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = common.linkage }); +} + +pub fn __fixunsdfti(a: f64) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunshfdi.zig b/lib/compiler_rt/fixunshfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfdi, .{ .name = "__fixunshfdi", .linkage = common.linkage }); +} + +fn __fixunshfdi(a: f16) callconv(.C) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunshfsi.zig b/lib/compiler_rt/fixunshfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfsi, .{ .name = "__fixunshfsi", .linkage = common.linkage }); +} + +fn __fixunshfsi(a: f16) callconv(.C) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunshfti.zig b/lib/compiler_rt/fixunshfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfti, .{ .name = "__fixunshfti", .linkage = common.linkage }); +} + +pub fn __fixunshfti(a: f16) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunssfdi.zig b/lib/compiler_rt/fixunssfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = common.linkage }); + } else { + @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = common.linkage }); + } +} + +pub fn __fixunssfdi(a: f32) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunssfsi.zig b/lib/compiler_rt/fixunssfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = common.linkage }); + } else { + @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = common.linkage }); + } +} + +pub fn __fixunssfsi(a: f32) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunssfti.zig b/lib/compiler_rt/fixunssfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = common.linkage }); +} + +pub fn __fixunssfti(a: f32) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunstfdi.zig b/lib/compiler_rt/fixunstfdi.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = common.linkage }); + } else { + @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = common.linkage }); + } +} + +pub fn __fixunstfdi(a: f128) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __fixunskfdi(a: f128) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn _Qp_qtoux(a: *const f128) callconv(.C) u64 { + return floatToInt(u64, a.*); +} diff --git a/lib/compiler_rt/fixunstfsi.zig b/lib/compiler_rt/fixunstfsi.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = common.linkage }); + } else { + @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = common.linkage }); + } +} + +pub fn __fixunstfsi(a: f128) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __fixunskfsi(a: f128) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn _Qp_qtoui(a: *const f128) callconv(.C) u32 { + return floatToInt(u32, a.*); +} diff --git a/lib/compiler_rt/fixunstfti.zig b/lib/compiler_rt/fixunstfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = common.linkage }); +} + +pub fn __fixunstfti(a: f128) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunsxfdi.zig b/lib/compiler_rt/fixunsxfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = common.linkage }); +} + +fn __fixunsxfdi(a: f80) callconv(.C) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunsxfsi.zig b/lib/compiler_rt/fixunsxfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = common.linkage }); +} + +fn __fixunsxfsi(a: f80) callconv(.C) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunsxfti.zig b/lib/compiler_rt/fixunsxfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = common.linkage }); +} + +pub fn __fixunsxfti(a: f80) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixxfdi.zig b/lib/compiler_rt/fixxfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = common.linkage }); +} + +fn __fixxfdi(a: f80) callconv(.C) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixxfsi.zig b/lib/compiler_rt/fixxfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = common.linkage }); +} + +fn __fixxfsi(a: f80) callconv(.C) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixxfti.zig b/lib/compiler_rt/fixxfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfti, .{ .name = "__fixxfti", .linkage = common.linkage }); +} + +fn __fixxfti(a: f80) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/floatXiYf.zig b/lib/compiler_rt/floatXiYf.zig @@ -1,222 +0,0 @@ -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const std = @import("std"); -const math = std.math; -const expect = std.testing.expect; - -pub fn floatXiYf(comptime T: type, x: anytype) T { - @setRuntimeSafety(is_test); - - if (x == 0) return 0; - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const Z = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(x))); - const uT = std.meta.Int(.unsigned, @bitSizeOf(T)); - const inf = math.inf(T); - const float_bits = @bitSizeOf(T); - const int_bits = @bitSizeOf(@TypeOf(x)); - const exp_bits = math.floatExponentBits(T); - const fractional_bits = math.floatFractionalBits(T); - const exp_bias = math.maxInt(std.meta.Int(.unsigned, exp_bits - 1)); - const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; - const max_exp = exp_bias; - - // Sign - var abs_val = math.absCast(x); - const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; - var result: uT = sign_bit; - - // Compute significand - var exp = int_bits - @clz(Z, abs_val) - 1; - if (int_bits <= fractional_bits or exp <= fractional_bits) { - const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); - - // Shift up result to line up with the significand - no rounding required - result = (@intCast(uT, abs_val) << shift_amt); - result ^= implicit_bit; // Remove implicit integer bit - } else { - var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); - const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; - - // Shift down result and remove implicit integer bit - result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); - - // Round result, including round-to-even for exact ties - result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); - } - - // Compute exponent - if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity - return @bitCast(T, sign_bit | @bitCast(uT, inf)); - - result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); - - // If the result included a carry, we need to restore the explicit integer bit - if (T == f80) result |= 1 << fractional_bits; - - return @bitCast(T, sign_bit | result); -} - -// Conversion to f16 -pub fn __floatsihf(a: i32) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatunsihf(a: u32) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatdihf(a: i64) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatundihf(a: u64) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floattihf(a: i128) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatuntihf(a: u128) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -// Conversion to f32 -pub fn __floatsisf(a: i32) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatunsisf(a: u32) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatdisf(a: i64) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatundisf(a: u64) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floattisf(a: i128) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatuntisf(a: u128) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -// Conversion to f64 -pub fn __floatsidf(a: i32) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatunsidf(a: u32) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatdidf(a: i64) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatundidf(a: u64) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floattidf(a: i128) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatuntidf(a: u128) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -// Conversion to f80 -pub fn __floatsixf(a: i32) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatunsixf(a: u32) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatdixf(a: i64) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatundixf(a: u64) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floattixf(a: i128) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatuntixf(a: u128) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -// Conversion to f128 -pub fn __floatsitf(a: i32) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatunsitf(a: u32) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatditf(a: i64) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatunditf(a: u64) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floattitf(a: i128) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatuntitf(a: u128) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -// Conversion to f32 -pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_i2f(arg: i32) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_ul2f(arg: u64) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_l2f(arg: i64) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -// Conversion to f64 -pub fn __aeabi_ui2d(arg: u32) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_i2d(arg: i32) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_ul2d(arg: u64) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_l2d(arg: i64) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -test { - _ = @import("floatXiYf_test.zig"); -} diff --git a/lib/compiler_rt/floatXiYf_test.zig b/lib/compiler_rt/floatXiYf_test.zig @@ -1,835 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const testing = std.testing; -const math = std.math; -const floatXiYf = @import("floatXiYf.zig").floatXiYf; - -// Conversion to f32 -const __floatsisf = @import("floatXiYf.zig").__floatsisf; -const __floatunsisf = @import("floatXiYf.zig").__floatunsisf; -const __floatdisf = @import("floatXiYf.zig").__floatdisf; -const __floatundisf = @import("floatXiYf.zig").__floatundisf; -const __floattisf = @import("floatXiYf.zig").__floattisf; -const __floatuntisf = @import("floatXiYf.zig").__floatuntisf; - -// Conversion to f64 -const __floatsidf = @import("floatXiYf.zig").__floatsidf; -const __floatunsidf = @import("floatXiYf.zig").__floatunsidf; -const __floatdidf = @import("floatXiYf.zig").__floatdidf; -const __floatundidf = @import("floatXiYf.zig").__floatundidf; -const __floattidf = @import("floatXiYf.zig").__floattidf; -const __floatuntidf = @import("floatXiYf.zig").__floatuntidf; - -// Conversion to f128 -const __floatsitf = @import("floatXiYf.zig").__floatsitf; -const __floatunsitf = @import("floatXiYf.zig").__floatunsitf; -const __floatditf = @import("floatXiYf.zig").__floatditf; -const __floatunditf = @import("floatXiYf.zig").__floatunditf; -const __floattitf = @import("floatXiYf.zig").__floattitf; -const __floatuntitf = @import("floatXiYf.zig").__floatuntitf; - -fn test__floatsisf(a: i32, expected: u32) !void { - const r = __floatsisf(a); - try std.testing.expect(@bitCast(u32, r) == expected); -} - -fn test_one_floatunsisf(a: u32, expected: u32) !void { - const r = __floatunsisf(a); - try std.testing.expect(@bitCast(u32, r) == expected); -} - -test "floatsisf" { - try test__floatsisf(0, 0x00000000); - try test__floatsisf(1, 0x3f800000); - try test__floatsisf(-1, 0xbf800000); - try test__floatsisf(0x7FFFFFFF, 0x4f000000); - try test__floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000); -} - -test "floatunsisf" { - // Test the produced bit pattern - try test_one_floatunsisf(0, 0); - try test_one_floatunsisf(1, 0x3f800000); - try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000); - try test_one_floatunsisf(0x80000000, 0x4f000000); - try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000); -} - -fn test__floatdisf(a: i64, expected: f32) !void { - const x = __floatdisf(a); - try testing.expect(x == expected); -} - -fn test__floatundisf(a: u64, expected: f32) !void { - try std.testing.expectEqual(expected, __floatundisf(a)); -} - -test "floatdisf" { - try test__floatdisf(0, 0.0); - try test__floatdisf(1, 1.0); - try test__floatdisf(2, 2.0); - try test__floatdisf(-1, -1.0); - try test__floatdisf(-2, -2.0); - try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(i64, @as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); - try test__floatdisf(@bitCast(i64, @as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000000)), -0x1.000000p+63); - try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000001)), -0x1.000000p+63); - try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); -} - -test "floatundisf" { - try test__floatundisf(0, 0.0); - try test__floatundisf(1, 1.0); - try test__floatundisf(2, 2.0); - try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundisf(0x8000008000000000, 0x1p+63); - try test__floatundisf(0x8000010000000000, 0x1.000002p+63); - try test__floatundisf(0x8000000000000000, 0x1p+63); - try test__floatundisf(0x8000000000000001, 0x1p+63); - try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); - try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); -} - -fn test__floattisf(a: i128, expected: f32) !void { - const x = __floattisf(a); - try testing.expect(x == expected); -} - -fn test__floatuntisf(a: u128, expected: f32) !void { - const x = __floatuntisf(a); - try testing.expect(x == expected); -} - -test "floattisf" { - try test__floattisf(0, 0.0); - - try test__floattisf(1, 1.0); - try test__floattisf(2, 2.0); - try test__floattisf(-1, -1.0); - try test__floattisf(-2, -2.0); - - try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); - - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); - - try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - - try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); - - try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); - - try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); - try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); - - try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); -} - -test "floatuntisf" { - try test__floatuntisf(0, 0.0); - - try test__floatuntisf(1, 1.0); - try test__floatuntisf(2, 2.0); - try test__floatuntisf(20, 20.0); - - try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - - try test__floatuntisf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntisf(make_uti(0x8000000000000800, 0), 0x1.0p+127); - try test__floatuntisf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - - try test__floatuntisf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); - - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); - - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); - - // Test overflow to infinity - try test__floatuntisf(@as(u128, math.maxInt(u128)), @bitCast(f32, math.inf(f32))); -} - -fn test_one_floatsidf(a: i32, expected: u64) !void { - const r = __floatsidf(a); - try std.testing.expect(@bitCast(u64, r) == expected); -} - -fn test_one_floatunsidf(a: u32, expected: u64) !void { - const r = __floatunsidf(a); - try std.testing.expect(@bitCast(u64, r) == expected); -} - -test "floatsidf" { - try test_one_floatsidf(0, 0x0000000000000000); - try test_one_floatsidf(1, 0x3ff0000000000000); - try test_one_floatsidf(-1, 0xbff0000000000000); - try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000); -} - -test "floatunsidf" { - try test_one_floatunsidf(0, 0x0000000000000000); - try test_one_floatunsidf(1, 0x3ff0000000000000); - try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatunsidf(@intCast(u32, 0x80000000), 0x41e0000000000000); - try test_one_floatunsidf(@intCast(u32, 0xFFFFFFFF), 0x41efffffffe00000); -} - -fn test__floatdidf(a: i64, expected: f64) !void { - const r = __floatdidf(a); - try testing.expect(r == expected); -} - -fn test__floatundidf(a: u64, expected: f64) !void { - const r = __floatundidf(a); - try testing.expect(r == expected); -} - -test "floatdidf" { - try test__floatdidf(0, 0.0); - try test__floatdidf(1, 1.0); - try test__floatdidf(2, 2.0); - try test__floatdidf(20, 20.0); - try test__floatdidf(-1, -1.0); - try test__floatdidf(-2, -2.0); - try test__floatdidf(-20, -20.0); - try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000800)), -0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000001000)), -0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000000)), -0x1.000000p+63); - try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000001)), -0x1.000000p+63); // 0x8000000000000001 - try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); -} - -test "floatundidf" { - try test__floatundidf(0, 0.0); - try test__floatundidf(1, 1.0); - try test__floatundidf(2, 2.0); - try test__floatundidf(20, 20.0); - try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatundidf(0x8000008000000000, 0x1.000001p+63); - try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63); - try test__floatundidf(0x8000010000000000, 0x1.000002p+63); - try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63); - try test__floatundidf(0x8000000000000000, 0x1p+63); - try test__floatundidf(0x8000000000000001, 0x1p+63); - try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); -} - -fn test__floattidf(a: i128, expected: f64) !void { - const x = __floattidf(a); - try testing.expect(x == expected); -} - -fn test__floatuntidf(a: u128, expected: f64) !void { - const x = __floatuntidf(a); - try testing.expect(x == expected); -} - -test "floattidf" { - try test__floattidf(0, 0.0); - - try test__floattidf(1, 1.0); - try test__floattidf(2, 2.0); - try test__floattidf(20, 20.0); - try test__floattidf(-1, -1.0); - try test__floattidf(-2, -2.0); - try test__floattidf(-20, -20.0); - - try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127); - - try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); -} - -test "floatuntidf" { - try test__floatuntidf(0, 0.0); - - try test__floatuntidf(1, 1.0); - try test__floatuntidf(2, 2.0); - try test__floatuntidf(20, 20.0); - - try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floatuntidf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntidf(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); - try test__floatuntidf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - try test__floatuntidf(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); - - try test__floatuntidf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - try test__floatuntidf(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); - - try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntidf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); -} - -fn test__floatsitf(a: i32, expected: u128) !void { - const r = __floatsitf(a); - try std.testing.expect(@bitCast(u128, r) == expected); -} - -test "floatsitf" { - try test__floatsitf(0, 0); - try test__floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); - try test__floatsitf(0x12345678, 0x401b2345678000000000000000000000); - try test__floatsitf(-0x12345678, 0xc01b2345678000000000000000000000); - try test__floatsitf(@bitCast(i32, @intCast(u32, 0xffffffff)), 0xbfff0000000000000000000000000000); - try test__floatsitf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc01e0000000000000000000000000000); -} - -fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunsitf(a); - - const x_repr = @bitCast(u128, x); - const x_hi = @intCast(u64, x_repr >> 64); - const x_lo = @truncate(u64, x_repr); - - if (x_hi == expected_hi and x_lo == expected_lo) { - return; - } - // nan repr - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { - return; - } - } - - @panic("__floatunsitf test failure"); -} - -test "floatunsitf" { - try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0); - try test__floatunsitf(0, 0x0, 0x0); - try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0); - try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0); -} - -fn test__floatditf(a: i64, expected: f128) !void { - const x = __floatditf(a); - try testing.expect(x == expected); -} - -fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunditf(a); - - const x_repr = @bitCast(u128, x); - const x_hi = @intCast(u64, x_repr >> 64); - const x_lo = @truncate(u64, x_repr); - - if (x_hi == expected_hi and x_lo == expected_lo) { - return; - } - // nan repr - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { - return; - } - } - - @panic("__floatunditf test failure"); -} - -test "floatditf" { - try test__floatditf(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); - try test__floatditf(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); - try test__floatditf(0x2, make_tf(0x4000000000000000, 0x0)); - try test__floatditf(0x1, make_tf(0x3fff000000000000, 0x0)); - try test__floatditf(0x0, make_tf(0x0, 0x0)); - try test__floatditf(@bitCast(i64, @as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); - try test__floatditf(@bitCast(i64, @as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); - try test__floatditf(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); - try test__floatditf(@bitCast(i64, @as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); -} - -test "floatunditf" { - try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); - try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); - try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0); - try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); - try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); - try test__floatunditf(0x2, 0x4000000000000000, 0x0); - try test__floatunditf(0x1, 0x3fff000000000000, 0x0); - try test__floatunditf(0x0, 0x0, 0x0); -} - -fn test__floattitf(a: i128, expected: f128) !void { - const x = __floattitf(a); - try testing.expect(x == expected); -} - -fn test__floatuntitf(a: u128, expected: f128) !void { - const x = __floatuntitf(a); - try testing.expect(x == expected); -} - -test "floattitf" { - try test__floattitf(0, 0.0); - - try test__floattitf(1, 1.0); - try test__floattitf(2, 2.0); - try test__floattitf(20, 20.0); - try test__floattitf(-1, -1.0); - try test__floattitf(-2, -2.0); - try test__floattitf(-20, -20.0); - - try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); - - try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); -} - -test "floatuntitf" { - try test__floatuntitf(0, 0.0); - - try test__floatuntitf(1, 1.0); - try test__floatuntitf(2, 2.0); - try test__floatuntitf(20, 20.0); - - try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); - try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); - try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); - - try test__floatuntitf(0x8000008000000000, 0x8.000008p+60); - try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60); - try test__floatuntitf(0x8000010000000000, 0x8.00001p+60); - try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60); - - try test__floatuntitf(0x8000000000000000, 0x8p+60); - try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60); - - try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntitf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntitf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floatuntitf(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); - - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); -} - -fn make_ti(high: u64, low: u64) i128 { - var result: u128 = high; - result <<= 64; - result |= low; - return @bitCast(i128, result); -} - -fn make_uti(high: u64, low: u64) u128 { - var result: u128 = high; - result <<= 64; - result |= low; - return result; -} - -fn make_tf(high: u64, low: u64) f128 { - var result: u128 = high; - result <<= 64; - result |= low; - return @bitCast(f128, result); -} - -test "conversion to f16" { - try testing.expect(floatXiYf(f16, @as(u32, 0)) == 0.0); - try testing.expect(floatXiYf(f16, @as(u32, 1)) == 1.0); - try testing.expect(floatXiYf(f16, @as(u32, 65504)) == 65504); - try testing.expect(floatXiYf(f16, @as(u32, 65504 + (1 << 4))) == math.inf(f16)); -} - -test "conversion to f32" { - try testing.expect(floatXiYf(f32, @as(u32, 0)) == 0.0); - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u32))) != 1.0); - try testing.expect(floatXiYf(f32, @as(i32, math.minInt(i32))) != 1.0); - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24))) == math.maxInt(u24)); - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even - try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact -} - -test "conversion to f80" { - if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64) - return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408 - - try testing.expect(floatXiYf(f80, @as(i80, -12)) == -12); - try testing.expect(@floatToInt(u80, floatXiYf(f80, @as(u64, math.maxInt(u64)) + 0)) == math.maxInt(u64) + 0); - try testing.expect(@floatToInt(u80, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1); - - try testing.expect(floatXiYf(f80, @as(u32, 0)) == 0.0); - try testing.expect(floatXiYf(f80, @as(u32, 1)) == 1.0); - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u32, math.maxInt(u24)) + 0)) == math.maxInt(u24)); - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 0)) == math.maxInt(u64)); - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1); // Exact - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 2)) == math.maxInt(u64) + 1); // Rounds down - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 3)) == math.maxInt(u64) + 3); // Tie - Exact - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 4)) == math.maxInt(u64) + 5); // Rounds up - - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 0)) == math.maxInt(u65) + 1); // Rounds up - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 1)) == math.maxInt(u65) + 1); // Exact - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 2)) == math.maxInt(u65) + 1); // Rounds down - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 3)) == math.maxInt(u65) + 1); // Tie - Rounds down - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 4)) == math.maxInt(u65) + 5); // Rounds up - try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 5)) == math.maxInt(u65) + 5); // Exact -} diff --git a/lib/compiler_rt/float_to_int.zig b/lib/compiler_rt/float_to_int.zig @@ -0,0 +1,55 @@ +const Int = @import("std").meta.Int; +const math = @import("std").math; +const Log2Int = math.Log2Int; + +pub inline fn floatToInt(comptime I: type, a: anytype) I { + const F = @TypeOf(a); + const float_bits = @typeInfo(F).Float.bits; + const int_bits = @typeInfo(I).Int.bits; + const rep_t = Int(.unsigned, float_bits); + const sig_bits = math.floatMantissaBits(F); + const exp_bits = math.floatExponentBits(F); + const fractional_bits = math.floatFractionalBits(F); + + const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; + const max_exp = (1 << (exp_bits - 1)); + const exp_bias = max_exp - 1; + const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; + + // Break a into sign, exponent, significand + const a_rep: rep_t = @bitCast(rep_t, a); + const negative = (a_rep >> (float_bits - 1)) != 0; + const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; + const significand: rep_t = (a_rep & sig_mask) | implicit_bit; + + // If the exponent is negative, the result rounds to zero. + if (exponent < 0) return 0; + + // If the value is too large for the integer type, saturate. + switch (@typeInfo(I).Int.signedness) { + .unsigned => { + if (negative) return 0; + if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); + }, + .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { + return if (negative) math.minInt(I) else math.maxInt(I); + }, + } + + // If 0 <= exponent < sig_bits, right shift to get the result. + // Otherwise, shift left. + var result: I = undefined; + if (exponent < fractional_bits) { + result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); + } else { + result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); + } + + if ((@typeInfo(I).Int.signedness == .signed) and negative) + return ~result +% 1; + return result; +} + +test { + _ = @import("float_to_int_test.zig"); +} diff --git a/lib/compiler_rt/float_to_int_test.zig b/lib/compiler_rt/float_to_int_test.zig @@ -0,0 +1,950 @@ +const std = @import("std"); +const testing = std.testing; +const math = std.math; + +const __fixunshfti = @import("fixunshfti.zig").__fixunshfti; +const __fixunsxfti = @import("fixunsxfti.zig").__fixunsxfti; + +// Conversion from f32 +const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; +const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; +const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; +const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; +const __fixsfti = @import("fixsfti.zig").__fixsfti; +const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; + +// Conversion from f64 +const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; +const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; +const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; +const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; +const __fixdfti = @import("fixdfti.zig").__fixdfti; +const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; + +// Conversion from f128 +const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; +const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; +const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; +const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; +const __fixtfti = @import("fixtfti.zig").__fixtfti; +const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; + +fn test__fixsfsi(a: f32, expected: i32) !void { + const x = __fixsfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunssfsi(a: f32, expected: u32) !void { + const x = __fixunssfsi(a); + try testing.expect(x == expected); +} + +test "fixsfsi" { + try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); + + try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); + try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); + try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); + try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); + try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); + + try test__fixsfsi(-0x1.000000p+31, -0x80000000); + try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); + try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test__fixsfsi(-2.01, -2); + try test__fixsfsi(-2.0, -2); + try test__fixsfsi(-1.99, -1); + try test__fixsfsi(-1.0, -1); + try test__fixsfsi(-0.99, 0); + try test__fixsfsi(-0.5, 0); + try test__fixsfsi(-math.floatMin(f32), 0); + try test__fixsfsi(0.0, 0); + try test__fixsfsi(math.floatMin(f32), 0); + try test__fixsfsi(0.5, 0); + try test__fixsfsi(0.99, 0); + try test__fixsfsi(1.0, 1); + try test__fixsfsi(1.5, 1); + try test__fixsfsi(1.99, 1); + try test__fixsfsi(2.0, 2); + try test__fixsfsi(2.01, 2); + + try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); + try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); + + try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); +} + +test "fixunssfsi" { + try test__fixunssfsi(0.0, 0); + + try test__fixunssfsi(0.5, 0); + try test__fixunssfsi(0.99, 0); + try test__fixunssfsi(1.0, 1); + try test__fixunssfsi(1.5, 1); + try test__fixunssfsi(1.99, 1); + try test__fixunssfsi(2.0, 2); + try test__fixunssfsi(2.01, 2); + try test__fixunssfsi(-0.5, 0); + try test__fixunssfsi(-0.99, 0); + + try test__fixunssfsi(-1.0, 0); + try test__fixunssfsi(-1.5, 0); + try test__fixunssfsi(-1.99, 0); + try test__fixunssfsi(-2.0, 0); + try test__fixunssfsi(-2.01, 0); + + try test__fixunssfsi(0x1.000000p+31, 0x80000000); + try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); + try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); + try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test__fixunssfsi(-0x1.FFFFFEp+30, 0); + try test__fixunssfsi(-0x1.FFFFFCp+30, 0); +} + +fn test__fixsfdi(a: f32, expected: i64) !void { + const x = __fixsfdi(a); + try testing.expect(x == expected); +} + +fn test__fixunssfdi(a: f32, expected: u64) !void { + const x = __fixunssfdi(a); + try testing.expect(x == expected); +} + +test "fixsfdi" { + try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); + + try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); + try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); + try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); + try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test__fixsfdi(-2.01, -2); + try test__fixsfdi(-2.0, -2); + try test__fixsfdi(-1.99, -1); + try test__fixsfdi(-1.0, -1); + try test__fixsfdi(-0.99, 0); + try test__fixsfdi(-0.5, 0); + try test__fixsfdi(-math.floatMin(f32), 0); + try test__fixsfdi(0.0, 0); + try test__fixsfdi(math.floatMin(f32), 0); + try test__fixsfdi(0.5, 0); + try test__fixsfdi(0.99, 0); + try test__fixsfdi(1.0, 1); + try test__fixsfdi(1.5, 1); + try test__fixsfdi(1.99, 1); + try test__fixsfdi(2.0, 2); + try test__fixsfdi(2.01, 2); + + try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); +} + +test "fixunssfdi" { + try test__fixunssfdi(0.0, 0); + + try test__fixunssfdi(0.5, 0); + try test__fixunssfdi(0.99, 0); + try test__fixunssfdi(1.0, 1); + try test__fixunssfdi(1.5, 1); + try test__fixunssfdi(1.99, 1); + try test__fixunssfdi(2.0, 2); + try test__fixunssfdi(2.01, 2); + try test__fixunssfdi(-0.5, 0); + try test__fixunssfdi(-0.99, 0); + + try test__fixunssfdi(-1.0, 0); + try test__fixunssfdi(-1.5, 0); + try test__fixunssfdi(-1.99, 0); + try test__fixunssfdi(-2.0, 0); + try test__fixunssfdi(-2.01, 0); + + try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); + try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); + try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); +} + +fn test__fixsfti(a: f32, expected: i128) !void { + const x = __fixsfti(a); + try testing.expect(x == expected); +} + +fn test__fixunssfti(a: f32, expected: u128) !void { + const x = __fixunssfti(a); + try testing.expect(x == expected); +} + +test "fixsfti" { + try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); + + try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); + try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); + try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test__fixsfti(-0x1.000000p+31, -0x80000000); + try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); + try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test__fixsfti(-2.01, -2); + try test__fixsfti(-2.0, -2); + try test__fixsfti(-1.99, -1); + try test__fixsfti(-1.0, -1); + try test__fixsfti(-0.99, 0); + try test__fixsfti(-0.5, 0); + try test__fixsfti(-math.floatMin(f32), 0); + try test__fixsfti(0.0, 0); + try test__fixsfti(math.floatMin(f32), 0); + try test__fixsfti(0.5, 0); + try test__fixsfti(0.99, 0); + try test__fixsfti(1.0, 1); + try test__fixsfti(1.5, 1); + try test__fixsfti(1.99, 1); + try test__fixsfti(2.0, 2); + try test__fixsfti(2.01, 2); + + try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); + try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); + try test__fixsfti(0x1.000000p+31, 0x80000000); + + try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); + + try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); + try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); + + try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); +} + +test "fixunssfti" { + try test__fixunssfti(0.0, 0); + + try test__fixunssfti(0.5, 0); + try test__fixunssfti(0.99, 0); + try test__fixunssfti(1.0, 1); + try test__fixunssfti(1.5, 1); + try test__fixunssfti(1.99, 1); + try test__fixunssfti(2.0, 2); + try test__fixunssfti(2.01, 2); + try test__fixunssfti(-0.5, 0); + try test__fixunssfti(-0.99, 0); + + try test__fixunssfti(-1.0, 0); + try test__fixunssfti(-1.5, 0); + try test__fixunssfti(-1.99, 0); + try test__fixunssfti(-2.0, 0); + try test__fixunssfti(-2.01, 0); + + try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); + try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); + try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); + try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); + try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); + + try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); + try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); + try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); + try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); + try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); + try test__fixunssfti(math.inf(f32), math.maxInt(u128)); +} + +fn test__fixdfsi(a: f64, expected: i32) !void { + const x = __fixdfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunsdfsi(a: f64, expected: u32) !void { + const x = __fixunsdfsi(a); + try testing.expect(x == expected); +} + +test "fixdfsi" { + try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); + + try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); + try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); + try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); + try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); + try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); + + try test__fixdfsi(-0x1.000000p+31, -0x80000000); + try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + + try test__fixdfsi(-2.01, -2); + try test__fixdfsi(-2.0, -2); + try test__fixdfsi(-1.99, -1); + try test__fixdfsi(-1.0, -1); + try test__fixdfsi(-0.99, 0); + try test__fixdfsi(-0.5, 0); + try test__fixdfsi(-math.floatMin(f64), 0); + try test__fixdfsi(0.0, 0); + try test__fixdfsi(math.floatMin(f64), 0); + try test__fixdfsi(0.5, 0); + try test__fixdfsi(0.99, 0); + try test__fixdfsi(1.0, 1); + try test__fixdfsi(1.5, 1); + try test__fixdfsi(1.99, 1); + try test__fixdfsi(2.0, 2); + try test__fixdfsi(2.01, 2); + + try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); + + try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); +} + +test "fixunsdfsi" { + try test__fixunsdfsi(0.0, 0); + + try test__fixunsdfsi(0.5, 0); + try test__fixunsdfsi(0.99, 0); + try test__fixunsdfsi(1.0, 1); + try test__fixunsdfsi(1.5, 1); + try test__fixunsdfsi(1.99, 1); + try test__fixunsdfsi(2.0, 2); + try test__fixunsdfsi(2.01, 2); + try test__fixunsdfsi(-0.5, 0); + try test__fixunsdfsi(-0.99, 0); + try test__fixunsdfsi(-1.0, 0); + try test__fixunsdfsi(-1.5, 0); + try test__fixunsdfsi(-1.99, 0); + try test__fixunsdfsi(-2.0, 0); + try test__fixunsdfsi(-2.01, 0); + + try test__fixunsdfsi(0x1.000000p+31, 0x80000000); + try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); + try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); + try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); + try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); + + try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); + try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); + try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); +} + +fn test__fixdfdi(a: f64, expected: i64) !void { + const x = __fixdfdi(a); + try testing.expect(x == expected); +} + +fn test__fixunsdfdi(a: f64, expected: u64) !void { + const x = __fixunsdfdi(a); + try testing.expect(x == expected); +} + +test "fixdfdi" { + try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); + + try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); + try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); + try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test__fixdfdi(-2.01, -2); + try test__fixdfdi(-2.0, -2); + try test__fixdfdi(-1.99, -1); + try test__fixdfdi(-1.0, -1); + try test__fixdfdi(-0.99, 0); + try test__fixdfdi(-0.5, 0); + try test__fixdfdi(-math.floatMin(f64), 0); + try test__fixdfdi(0.0, 0); + try test__fixdfdi(math.floatMin(f64), 0); + try test__fixdfdi(0.5, 0); + try test__fixdfdi(0.99, 0); + try test__fixdfdi(1.0, 1); + try test__fixdfdi(1.5, 1); + try test__fixdfdi(1.99, 1); + try test__fixdfdi(2.0, 2); + try test__fixdfdi(2.01, 2); + + try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); +} + +test "fixunsdfdi" { + try test__fixunsdfdi(0.0, 0); + try test__fixunsdfdi(0.5, 0); + try test__fixunsdfdi(0.99, 0); + try test__fixunsdfdi(1.0, 1); + try test__fixunsdfdi(1.5, 1); + try test__fixunsdfdi(1.99, 1); + try test__fixunsdfdi(2.0, 2); + try test__fixunsdfdi(2.01, 2); + try test__fixunsdfdi(-0.5, 0); + try test__fixunsdfdi(-0.99, 0); + try test__fixunsdfdi(-1.0, 0); + try test__fixunsdfdi(-1.5, 0); + try test__fixunsdfdi(-1.99, 0); + try test__fixunsdfdi(-2.0, 0); + try test__fixunsdfdi(-2.01, 0); + + try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); + try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); + + try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); + try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); + try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test__fixdfti(a: f64, expected: i128) !void { + const x = __fixdfti(a); + try testing.expect(x == expected); +} + +fn test__fixunsdfti(a: f64, expected: u128) !void { + const x = __fixunsdfti(a); + try testing.expect(x == expected); +} + +test "fixdfti" { + try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); + + try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); + try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test__fixdfti(-2.01, -2); + try test__fixdfti(-2.0, -2); + try test__fixdfti(-1.99, -1); + try test__fixdfti(-1.0, -1); + try test__fixdfti(-0.99, 0); + try test__fixdfti(-0.5, 0); + try test__fixdfti(-math.floatMin(f64), 0); + try test__fixdfti(0.0, 0); + try test__fixdfti(math.floatMin(f64), 0); + try test__fixdfti(0.5, 0); + try test__fixdfti(0.99, 0); + try test__fixdfti(1.0, 1); + try test__fixdfti(1.5, 1); + try test__fixdfti(1.99, 1); + try test__fixdfti(2.0, 2); + try test__fixdfti(2.01, 2); + + try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); + try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); + + try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); +} + +test "fixunsdfti" { + try test__fixunsdfti(0.0, 0); + + try test__fixunsdfti(0.5, 0); + try test__fixunsdfti(0.99, 0); + try test__fixunsdfti(1.0, 1); + try test__fixunsdfti(1.5, 1); + try test__fixunsdfti(1.99, 1); + try test__fixunsdfti(2.0, 2); + try test__fixunsdfti(2.01, 2); + try test__fixunsdfti(-0.5, 0); + try test__fixunsdfti(-0.99, 0); + try test__fixunsdfti(-1.0, 0); + try test__fixunsdfti(-1.5, 0); + try test__fixunsdfti(-1.99, 0); + try test__fixunsdfti(-2.0, 0); + try test__fixunsdfti(-2.01, 0); + + try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test__fixunsdfti(-0x1.FFFFFEp+62, 0); + try test__fixunsdfti(-0x1.FFFFFCp+62, 0); + + try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); + try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); + try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); + try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); + try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test__fixtfsi(a: f128, expected: i32) !void { + const x = __fixtfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunstfsi(a: f128, expected: u32) !void { + const x = __fixunstfsi(a); + try testing.expect(x == expected); +} + +test "fixtfsi" { + try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); + + try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); + try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); + try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); + try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); + try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); + + try test__fixtfsi(-0x1.000000p+31, -0x80000000); + try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test__fixtfsi(-2.01, -2); + try test__fixtfsi(-2.0, -2); + try test__fixtfsi(-1.99, -1); + try test__fixtfsi(-1.0, -1); + try test__fixtfsi(-0.99, 0); + try test__fixtfsi(-0.5, 0); + try test__fixtfsi(-math.floatMin(f32), 0); + try test__fixtfsi(0.0, 0); + try test__fixtfsi(math.floatMin(f32), 0); + try test__fixtfsi(0.5, 0); + try test__fixtfsi(0.99, 0); + try test__fixtfsi(1.0, 1); + try test__fixtfsi(1.5, 1); + try test__fixtfsi(1.99, 1); + try test__fixtfsi(2.0, 2); + try test__fixtfsi(2.01, 2); + + try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); + + try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); +} + +test "fixunstfsi" { + try test__fixunstfsi(math.inf(f128), 0xffffffff); + try test__fixunstfsi(0, 0x0); + try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); + try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); + try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); + try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); + try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); + try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); + + try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); +} + +fn test__fixtfdi(a: f128, expected: i64) !void { + const x = __fixtfdi(a); + try testing.expect(x == expected); +} + +fn test__fixunstfdi(a: f128, expected: u64) !void { + const x = __fixunstfdi(a); + try testing.expect(x == expected); +} + +test "fixtfdi" { + try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); + + try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); + try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); + try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + try test__fixtfdi(-0x1.000000p+31, -0x80000000); + try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test__fixtfdi(-2.01, -2); + try test__fixtfdi(-2.0, -2); + try test__fixtfdi(-1.99, -1); + try test__fixtfdi(-1.0, -1); + try test__fixtfdi(-0.99, 0); + try test__fixtfdi(-0.5, 0); + try test__fixtfdi(-math.floatMin(f64), 0); + try test__fixtfdi(0.0, 0); + try test__fixtfdi(math.floatMin(f64), 0); + try test__fixtfdi(0.5, 0); + try test__fixtfdi(0.99, 0); + try test__fixtfdi(1.0, 1); + try test__fixtfdi(1.5, 1); + try test__fixtfdi(1.99, 1); + try test__fixtfdi(2.0, 2); + try test__fixtfdi(2.01, 2); + + try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); + try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); + try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test__fixtfdi(0x1.000000p+31, 0x80000000); + + try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); +} + +test "fixunstfdi" { + try test__fixunstfdi(0.0, 0); + + try test__fixunstfdi(0.5, 0); + try test__fixunstfdi(0.99, 0); + try test__fixunstfdi(1.0, 1); + try test__fixunstfdi(1.5, 1); + try test__fixunstfdi(1.99, 1); + try test__fixunstfdi(2.0, 2); + try test__fixunstfdi(2.01, 2); + try test__fixunstfdi(-0.5, 0); + try test__fixunstfdi(-0.99, 0); + try test__fixunstfdi(-1.0, 0); + try test__fixunstfdi(-1.5, 0); + try test__fixunstfdi(-1.99, 0); + try test__fixunstfdi(-2.0, 0); + try test__fixunstfdi(-2.01, 0); + + try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test__fixunstfdi(-0x1.FFFFFEp+62, 0); + try test__fixunstfdi(-0x1.FFFFFCp+62, 0); + + try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); + try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); + + try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); + try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); + try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); + try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); + try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); + try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); + + try test__fixunstfdi(-0x1.0000000000000000p+63, 0); + try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); + try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); +} + +fn test__fixtfti(a: f128, expected: i128) !void { + const x = __fixtfti(a); + try testing.expect(x == expected); +} + +fn test__fixunstfti(a: f128, expected: u128) !void { + const x = __fixunstfti(a); + try testing.expect(x == expected); +} + +test "fixtfti" { + try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); + + try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); + try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); + try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test__fixtfti(-2.01, -2); + try test__fixtfti(-2.0, -2); + try test__fixtfti(-1.99, -1); + try test__fixtfti(-1.0, -1); + try test__fixtfti(-0.99, 0); + try test__fixtfti(-0.5, 0); + try test__fixtfti(-math.floatMin(f128), 0); + try test__fixtfti(0.0, 0); + try test__fixtfti(math.floatMin(f128), 0); + try test__fixtfti(0.5, 0); + try test__fixtfti(0.99, 0); + try test__fixtfti(1.0, 1); + try test__fixtfti(1.5, 1); + try test__fixtfti(1.99, 1); + try test__fixtfti(2.0, 2); + try test__fixtfti(2.01, 2); + + try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); + try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); + + try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); +} + +test "fixunstfti" { + try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); + + try test__fixunstfti(0.0, 0); + + try test__fixunstfti(0.5, 0); + try test__fixunstfti(0.99, 0); + try test__fixunstfti(1.0, 1); + try test__fixunstfti(1.5, 1); + try test__fixunstfti(1.99, 1); + try test__fixunstfti(2.0, 2); + try test__fixunstfti(2.01, 2); + try test__fixunstfti(-0.01, 0); + try test__fixunstfti(-0.99, 0); + + try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); + + try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); + try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); + try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); + try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); +} + +fn test__fixunshfti(a: f16, expected: u128) !void { + const x = __fixunshfti(a); + try testing.expect(x == expected); +} + +test "fixunshfti for f16" { + try test__fixunshfti(math.inf(f16), math.maxInt(u128)); + try test__fixunshfti(math.floatMax(f16), 65504); +} + +fn test__fixunsxfti(a: f80, expected: u128) !void { + const x = __fixunsxfti(a); + try testing.expect(x == expected); +} + +test "fixunsxfti for f80" { + try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); + try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); + try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); +} diff --git a/lib/compiler_rt/floatdidf.zig b/lib/compiler_rt/floatdidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = common.linkage }); + } else { + @export(__floatdidf, .{ .name = "__floatdidf", .linkage = common.linkage }); + } +} + +pub fn __floatdidf(a: i64) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_l2d(a: i64) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatdihf.zig b/lib/compiler_rt/floatdihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatdihf, .{ .name = "__floatdihf", .linkage = common.linkage }); +} + +fn __floatdihf(a: i64) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatdisf.zig b/lib/compiler_rt/floatdisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = common.linkage }); + } else { + @export(__floatdisf, .{ .name = "__floatdisf", .linkage = common.linkage }); + } +} + +pub fn __floatdisf(a: i64) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_l2f(a: i64) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatditf.zig b/lib/compiler_rt/floatditf.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatdikf, .{ .name = "__floatdikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = common.linkage }); + } else { + @export(__floatditf, .{ .name = "__floatditf", .linkage = common.linkage }); + } +} + +pub fn __floatditf(a: i64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatdikf(a: i64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatdixf.zig b/lib/compiler_rt/floatdixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatdixf, .{ .name = "__floatdixf", .linkage = common.linkage }); +} + +fn __floatdixf(a: i64) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatsidf.zig b/lib/compiler_rt/floatsidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = common.linkage }); + } else { + @export(__floatsidf, .{ .name = "__floatsidf", .linkage = common.linkage }); + } +} + +pub fn __floatsidf(a: i32) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_i2d(a: i32) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatsihf.zig b/lib/compiler_rt/floatsihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatsihf, .{ .name = "__floatsihf", .linkage = common.linkage }); +} + +fn __floatsihf(a: i32) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatsisf.zig b/lib/compiler_rt/floatsisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = common.linkage }); + } else { + @export(__floatsisf, .{ .name = "__floatsisf", .linkage = common.linkage }); + } +} + +pub fn __floatsisf(a: i32) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_i2f(a: i32) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatsitf.zig b/lib/compiler_rt/floatsitf.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatsikf, .{ .name = "__floatsikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = common.linkage }); + } else { + @export(__floatsitf, .{ .name = "__floatsitf", .linkage = common.linkage }); + } +} + +pub fn __floatsitf(a: i32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatsikf(a: i32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatsixf.zig b/lib/compiler_rt/floatsixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatsixf, .{ .name = "__floatsixf", .linkage = common.linkage }); +} + +fn __floatsixf(a: i32) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floattidf.zig b/lib/compiler_rt/floattidf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattidf, .{ .name = "__floattidf", .linkage = common.linkage }); +} + +pub fn __floattidf(a: i128) callconv(.C) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floattihf.zig b/lib/compiler_rt/floattihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattihf, .{ .name = "__floattihf", .linkage = common.linkage }); +} + +fn __floattihf(a: i128) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floattisf.zig b/lib/compiler_rt/floattisf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattisf, .{ .name = "__floattisf", .linkage = common.linkage }); +} + +pub fn __floattisf(a: i128) callconv(.C) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floattitf.zig b/lib/compiler_rt/floattitf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattitf, .{ .name = "__floattitf", .linkage = common.linkage }); +} + +pub fn __floattitf(a: i128) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floattixf.zig b/lib/compiler_rt/floattixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattixf, .{ .name = "__floattixf", .linkage = common.linkage }); +} + +fn __floattixf(a: i128) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatundidf.zig b/lib/compiler_rt/floatundidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = common.linkage }); + } else { + @export(__floatundidf, .{ .name = "__floatundidf", .linkage = common.linkage }); + } +} + +pub fn __floatundidf(a: u64) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_ul2d(a: u64) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatundihf.zig b/lib/compiler_rt/floatundihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatundihf, .{ .name = "__floatundihf", .linkage = common.linkage }); +} + +fn __floatundihf(a: u64) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatundisf.zig b/lib/compiler_rt/floatundisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = common.linkage }); + } else { + @export(__floatundisf, .{ .name = "__floatundisf", .linkage = common.linkage }); + } +} + +pub fn __floatundisf(a: u64) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_ul2f(a: u64) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatunditf.zig b/lib/compiler_rt/floatunditf.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatundikf, .{ .name = "__floatundikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = common.linkage }); + } else { + @export(__floatunditf, .{ .name = "__floatunditf", .linkage = common.linkage }); + } +} + +pub fn __floatunditf(a: u64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatundikf(a: u64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatundixf.zig b/lib/compiler_rt/floatundixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatundixf, .{ .name = "__floatundixf", .linkage = common.linkage }); +} + +fn __floatundixf(a: u64) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatunsidf.zig b/lib/compiler_rt/floatunsidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = common.linkage }); + } else { + @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = common.linkage }); + } +} + +pub fn __floatunsidf(a: u32) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_ui2d(a: u32) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatunsihf.zig b/lib/compiler_rt/floatunsihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatunsihf, .{ .name = "__floatunsihf", .linkage = common.linkage }); +} + +pub fn __floatunsihf(a: u32) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatunsisf.zig b/lib/compiler_rt/floatunsisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = common.linkage }); + } else { + @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = common.linkage }); + } +} + +pub fn __floatunsisf(a: u32) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_ui2f(a: u32) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatunsitf.zig b/lib/compiler_rt/floatunsitf.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = common.linkage }); + } else { + @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = common.linkage }); + } +} + +pub fn __floatunsitf(a: u32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatunsikf(a: u32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatunsixf.zig b/lib/compiler_rt/floatunsixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = common.linkage }); +} + +fn __floatunsixf(a: u32) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatuntidf.zig b/lib/compiler_rt/floatuntidf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = common.linkage }); +} + +pub fn __floatuntidf(a: u128) callconv(.C) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatuntihf.zig b/lib/compiler_rt/floatuntihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntihf, .{ .name = "__floatuntihf", .linkage = common.linkage }); +} + +fn __floatuntihf(a: u128) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatuntisf.zig b/lib/compiler_rt/floatuntisf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = common.linkage }); +} + +pub fn __floatuntisf(a: u128) callconv(.C) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatuntitf.zig b/lib/compiler_rt/floatuntitf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatuntikf, .{ .name = "__floatuntikf", .linkage = common.linkage }); + } else { + @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = common.linkage }); + } +} + +pub fn __floatuntitf(a: u128) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatuntikf(a: u128) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatuntixf.zig b/lib/compiler_rt/floatuntixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = common.linkage }); +} + +pub fn __floatuntixf(a: u128) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floor.zig b/lib/compiler_rt/floor.zig @@ -1,12 +1,27 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__floorh, .{ .name = "__floorh", .linkage = common.linkage }); + @export(floorf, .{ .name = "floorf", .linkage = common.linkage }); + @export(floor, .{ .name = "floor", .linkage = common.linkage }); + @export(__floorx, .{ .name = "__floorx", .linkage = common.linkage }); + const floorq_sym_name = if (common.want_ppc_abi) "floorf128" else "floorq"; + @export(floorq, .{ .name = floorq_sym_name, .linkage = common.linkage }); + @export(floorl, .{ .name = "floorl", .linkage = common.linkage }); +} pub fn __floorh(x: f16) callconv(.C) f16 { var u = @bitCast(u16, x); diff --git a/lib/compiler_rt/fma.zig b/lib/compiler_rt/fma.zig @@ -1,13 +1,28 @@ -// Ported from musl, which is MIT licensed: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c +//! Ported from musl, which is MIT licensed: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__fmah, .{ .name = "__fmah", .linkage = common.linkage }); + @export(fmaf, .{ .name = "fmaf", .linkage = common.linkage }); + @export(fma, .{ .name = "fma", .linkage = common.linkage }); + @export(__fmax, .{ .name = "__fmax", .linkage = common.linkage }); + const fmaq_sym_name = if (common.want_ppc_abi) "fmaf128" else "fmaq"; + @export(fmaq, .{ .name = fmaq_sym_name, .linkage = common.linkage }); + @export(fmal, .{ .name = "fmal", .linkage = common.linkage }); +} pub fn __fmah(x: f16, y: f16, z: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/fmax.zig b/lib/compiler_rt/fmax.zig @@ -1,5 +1,20 @@ const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__fmaxh, .{ .name = "__fmaxh", .linkage = common.linkage }); + @export(fmaxf, .{ .name = "fmaxf", .linkage = common.linkage }); + @export(fmax, .{ .name = "fmax", .linkage = common.linkage }); + @export(__fmaxx, .{ .name = "__fmaxx", .linkage = common.linkage }); + const fmaxq_sym_name = if (common.want_ppc_abi) "fmaxf128" else "fmaxq"; + @export(fmaxq, .{ .name = fmaxq_sym_name, .linkage = common.linkage }); + @export(fmaxl, .{ .name = "fmaxl", .linkage = common.linkage }); +} pub fn __fmaxh(x: f16, y: f16) callconv(.C) f16 { return generic_fmax(f16, x, y); diff --git a/lib/compiler_rt/fmin.zig b/lib/compiler_rt/fmin.zig @@ -1,5 +1,20 @@ const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__fminh, .{ .name = "__fminh", .linkage = common.linkage }); + @export(fminf, .{ .name = "fminf", .linkage = common.linkage }); + @export(fmin, .{ .name = "fmin", .linkage = common.linkage }); + @export(__fminx, .{ .name = "__fminx", .linkage = common.linkage }); + const fminq_sym_name = if (common.want_ppc_abi) "fminf128" else "fminq"; + @export(fminq, .{ .name = fminq_sym_name, .linkage = common.linkage }); + @export(fminl, .{ .name = "fminl", .linkage = common.linkage }); +} pub fn __fminh(x: f16, y: f16) callconv(.C) f16 { return generic_fmin(f16, x, y); diff --git a/lib/compiler_rt/fmod.zig b/lib/compiler_rt/fmod.zig @@ -2,7 +2,21 @@ const builtin = @import("builtin"); const std = @import("std"); const math = std.math; const assert = std.debug.assert; -const normalize = @import("divdf3.zig").normalize; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); +const normalize = common.normalize; + +pub const panic = common.panic; + +comptime { + @export(__fmodh, .{ .name = "__fmodh", .linkage = common.linkage }); + @export(fmodf, .{ .name = "fmodf", .linkage = common.linkage }); + @export(fmod, .{ .name = "fmod", .linkage = common.linkage }); + @export(__fmodx, .{ .name = "__fmodx", .linkage = common.linkage }); + const fmodq_sym_name = if (common.want_ppc_abi) "fmodf128" else "fmodq"; + @export(fmodq, .{ .name = fmodq_sym_name, .linkage = common.linkage }); + @export(fmodl, .{ .name = "fmodl", .linkage = common.linkage }); +} pub fn __fmodh(x: f16, y: f16) callconv(.C) f16 { // TODO: more efficient implementation @@ -20,8 +34,6 @@ pub fn fmod(x: f64, y: f64) callconv(.C) f64 { /// fmodx - floating modulo large, returns the remainder of division for f80 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits pub fn __fmodx(a: f80, b: f80) callconv(.C) f80 { - @setRuntimeSafety(builtin.is_test); - const T = f80; const Z = std.meta.Int(.unsigned, @bitSizeOf(T)); @@ -120,7 +132,6 @@ pub fn __fmodx(a: f80, b: f80) callconv(.C) f80 { /// fmodq - floating modulo large, returns the remainder of division for f128 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits pub fn fmodq(a: f128, b: f128) callconv(.C) f128 { - @setRuntimeSafety(builtin.is_test); var amod = a; var bmod = b; const aPtr_u64 = @ptrCast([*]u64, &amod); @@ -249,8 +260,6 @@ pub fn fmodl(a: c_longdouble, b: c_longdouble) callconv(.C) c_longdouble { } inline fn generic_fmod(comptime T: type, x: T, y: T) T { - @setRuntimeSafety(false); - const bits = @typeInfo(T).Float.bits; const uint = std.meta.Int(.unsigned, bits); const log2uint = math.Log2Int(uint); diff --git a/lib/compiler_rt/gedf2.zig b/lib/compiler_rt/gedf2.zig @@ -0,0 +1,36 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = common.linkage }); + @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = common.linkage }); + } else { + @export(__gedf2, .{ .name = "__gedf2", .linkage = common.linkage }); + @export(__gtdf2, .{ .name = "__gtdf2", .linkage = common.linkage }); + } +} + +/// "These functions return a value greater than or equal to zero if neither +/// argument is NaN, and a is greater than or equal to b." +pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f64, comparef.GE, a, b)); +} + +/// "These functions return a value greater than zero if neither argument is NaN, +/// and a is strictly greater than b." +pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { + return __gedf2(a, b); +} + +fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.GE, a, b) != .Less); +} + +fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.GE, a, b) == .Greater); +} diff --git a/lib/compiler_rt/gesf2.zig b/lib/compiler_rt/gesf2.zig @@ -0,0 +1,36 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = common.linkage }); + @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = common.linkage }); + } else { + @export(__gesf2, .{ .name = "__gesf2", .linkage = common.linkage }); + @export(__gtsf2, .{ .name = "__gtsf2", .linkage = common.linkage }); + } +} + +/// "These functions return a value greater than or equal to zero if neither +/// argument is NaN, and a is greater than or equal to b." +pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f32, comparef.GE, a, b)); +} + +/// "These functions return a value greater than zero if neither argument is NaN, +/// and a is strictly greater than b." +pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { + return __gesf2(a, b); +} + +fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.GE, a, b) != .Less); +} + +fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Greater); +} diff --git a/lib/compiler_rt/getf2.zig b/lib/compiler_rt/getf2.zig @@ -0,0 +1,39 @@ +///! The quoted behavior definitions are from +///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__gekf2, .{ .name = "__gekf2", .linkage = common.linkage }); + @export(__gtkf2, .{ .name = "__gtkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + // These exports are handled in cmptf2.zig because gt and ge on sparc + // are based on calling _Qp_cmp. + } else { + @export(__getf2, .{ .name = "__getf2", .linkage = common.linkage }); + @export(__gttf2, .{ .name = "__gttf2", .linkage = common.linkage }); + } +} + +/// "These functions return a value greater than or equal to zero if neither +/// argument is NaN, and a is greater than or equal to b." +fn __getf2(a: f128, b: f128) callconv(.C) i32 { + return @enumToInt(comparef.cmpf2(f128, comparef.GE, a, b)); +} + +/// "These functions return a value greater than zero if neither argument is NaN, +/// and a is strictly greater than b." +fn __gttf2(a: f128, b: f128) callconv(.C) i32 { + return __getf2(a, b); +} + +fn __gekf2(a: f128, b: f128) callconv(.C) i32 { + return __getf2(a, b); +} + +fn __gtkf2(a: f128, b: f128) callconv(.C) i32 { + return __getf2(a, b); +} diff --git a/lib/compiler_rt/gexf2.zig b/lib/compiler_rt/gexf2.zig @@ -0,0 +1,17 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + @export(__gexf2, .{ .name = "__gexf2", .linkage = common.linkage }); + @export(__gtxf2, .{ .name = "__gtxf2", .linkage = common.linkage }); +} + +fn __gexf2(a: f80, b: f80) callconv(.C) i32 { + return @enumToInt(comparef.cmp_f80(comparef.GE, a, b)); +} + +fn __gtxf2(a: f80, b: f80) callconv(.C) i32 { + return __gexf2(a, b); +} diff --git a/lib/compiler_rt/int.zig b/lib/compiler_rt/int.zig @@ -1,22 +1,45 @@ -// Builtin functions that operate on integer types +//! Builtin functions that operate on integer types + const builtin = @import("builtin"); const std = @import("std"); const testing = std.testing; const maxInt = std.math.maxInt; const minInt = std.math.minInt; - +const arch = builtin.cpu.arch; +const is_test = builtin.is_test; +const common = @import("common.zig"); const udivmod = @import("udivmod.zig").udivmod; -pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.C) i64 { - @setRuntimeSafety(builtin.is_test); +pub const panic = common.panic; + +comptime { + @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage }); + @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage }); + @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage }); + if (common.want_aeabi) { + @export(__aeabi_idiv, .{ .name = "__aeabi_idiv", .linkage = common.linkage }); + @export(__aeabi_uidiv, .{ .name = "__aeabi_uidiv", .linkage = common.linkage }); + } else { + @export(__divsi3, .{ .name = "__divsi3", .linkage = common.linkage }); + @export(__udivsi3, .{ .name = "__udivsi3", .linkage = common.linkage }); + } + @export(__divdi3, .{ .name = "__divdi3", .linkage = common.linkage }); + @export(__udivdi3, .{ .name = "__udivdi3", .linkage = common.linkage }); + @export(__modsi3, .{ .name = "__modsi3", .linkage = common.linkage }); + @export(__moddi3, .{ .name = "__moddi3", .linkage = common.linkage }); + @export(__umodsi3, .{ .name = "__umodsi3", .linkage = common.linkage }); + @export(__umoddi3, .{ .name = "__umoddi3", .linkage = common.linkage }); + @export(__divmodsi4, .{ .name = "__divmodsi4", .linkage = common.linkage }); + @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = common.linkage }); +} +pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.C) i64 { const d = __divdi3(a, b); rem.* = a -% (d *% b); return d; } pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.C) u64 { - @setRuntimeSafety(builtin.is_test); return udivmod(u64, a, b, maybe_rem); } @@ -25,8 +48,6 @@ test "test_udivmoddi4" { } pub fn __divdi3(a: i64, b: i64) callconv(.C) i64 { - @setRuntimeSafety(builtin.is_test); - // Set aside the sign of the quotient. const sign = @bitCast(u64, (a ^ b) >> 63); // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63). @@ -64,8 +85,6 @@ fn test_one_divdi3(a: i64, b: i64, expected_q: i64) !void { } pub fn __moddi3(a: i64, b: i64) callconv(.C) i64 { - @setRuntimeSafety(builtin.is_test); - // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63). const abs_a = (a ^ (a >> 63)) -% (a >> 63); const abs_b = (b ^ (b >> 63)) -% (b >> 63); @@ -104,13 +123,10 @@ fn test_one_moddi3(a: i64, b: i64, expected_r: i64) !void { } pub fn __udivdi3(a: u64, b: u64) callconv(.C) u64 { - @setRuntimeSafety(builtin.is_test); return __udivmoddi4(a, b, null); } pub fn __umoddi3(a: u64, b: u64) callconv(.C) u64 { - @setRuntimeSafety(builtin.is_test); - var r: u64 = undefined; _ = __udivmoddi4(a, b, &r); return r; @@ -130,8 +146,6 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) !void { } pub fn __divmodsi4(a: i32, b: i32, rem: *i32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const d = __divsi3(a, b); rem.* = a -% (d * b); return d; @@ -166,16 +180,20 @@ fn test_one_divmodsi4(a: i32, b: i32, expected_q: i32, expected_r: i32) !void { } pub fn __udivmodsi4(a: u32, b: u32, rem: *u32) callconv(.C) u32 { - @setRuntimeSafety(builtin.is_test); - const d = __udivsi3(a, b); rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b))); return d; } pub fn __divsi3(n: i32, d: i32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); + return div_i32(n, d); +} +fn __aeabi_idiv(n: i32, d: i32) callconv(.AAPCS) i32 { + return div_i32(n, d); +} + +inline fn div_i32(n: i32, d: i32) i32 { // Set aside the sign of the quotient. const sign = @bitCast(u32, (n ^ d) >> 31); // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). @@ -213,8 +231,14 @@ fn test_one_divsi3(a: i32, b: i32, expected_q: i32) !void { } pub fn __udivsi3(n: u32, d: u32) callconv(.C) u32 { - @setRuntimeSafety(builtin.is_test); + return div_u32(n, d); +} +fn __aeabi_uidiv(n: u32, d: u32) callconv(.AAPCS) u32 { + return div_u32(n, d); +} + +inline fn div_u32(n: u32, d: u32) u32 { const n_uword_bits: c_uint = 32; // special cases if (d == 0) return 0; // ?! @@ -400,8 +424,6 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) !void { } pub fn __modsi3(n: i32, d: i32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return n -% __divsi3(n, d) *% d; } @@ -431,8 +453,6 @@ fn test_one_modsi3(a: i32, b: i32, expected_r: i32) !void { } pub fn __umodsi3(n: u32, d: u32) callconv(.C) u32 { - @setRuntimeSafety(builtin.is_test); - return n -% __udivsi3(n, d) *% d; } @@ -583,8 +603,6 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void { } pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - var ua = @bitCast(u32, a); var ub = @bitCast(u32, b); var r: u32 = 0; diff --git a/lib/compiler_rt/int_to_float.zig b/lib/compiler_rt/int_to_float.zig @@ -0,0 +1,58 @@ +const Int = @import("std").meta.Int; +const math = @import("std").math; + +pub fn intToFloat(comptime T: type, x: anytype) T { + if (x == 0) return 0; + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const Z = Int(.unsigned, @bitSizeOf(@TypeOf(x))); + const uT = Int(.unsigned, @bitSizeOf(T)); + const inf = math.inf(T); + const float_bits = @bitSizeOf(T); + const int_bits = @bitSizeOf(@TypeOf(x)); + const exp_bits = math.floatExponentBits(T); + const fractional_bits = math.floatFractionalBits(T); + const exp_bias = math.maxInt(Int(.unsigned, exp_bits - 1)); + const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; + const max_exp = exp_bias; + + // Sign + var abs_val = math.absCast(x); + const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; + var result: uT = sign_bit; + + // Compute significand + var exp = int_bits - @clz(Z, abs_val) - 1; + if (int_bits <= fractional_bits or exp <= fractional_bits) { + const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); + + // Shift up result to line up with the significand - no rounding required + result = (@intCast(uT, abs_val) << shift_amt); + result ^= implicit_bit; // Remove implicit integer bit + } else { + var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); + const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; + + // Shift down result and remove implicit integer bit + result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); + + // Round result, including round-to-even for exact ties + result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); + } + + // Compute exponent + if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity + return @bitCast(T, sign_bit | @bitCast(uT, inf)); + + result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); + + // If the result included a carry, we need to restore the explicit integer bit + if (T == f80) result |= 1 << fractional_bits; + + return @bitCast(T, sign_bit | result); +} + +test { + _ = @import("int_to_float_test.zig"); +} diff --git a/lib/compiler_rt/int_to_float_test.zig b/lib/compiler_rt/int_to_float_test.zig @@ -0,0 +1,838 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const testing = std.testing; +const math = std.math; + +const __floatunsihf = @import("floatunsihf.zig").__floatunsihf; + +// Conversion to f32 +const __floatsisf = @import("floatsisf.zig").__floatsisf; +const __floatunsisf = @import("floatunsisf.zig").__floatunsisf; +const __floatdisf = @import("floatdisf.zig").__floatdisf; +const __floatundisf = @import("floatundisf.zig").__floatundisf; +const __floattisf = @import("floattisf.zig").__floattisf; +const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; + +// Conversion to f64 +const __floatsidf = @import("floatsidf.zig").__floatsidf; +const __floatunsidf = @import("floatunsidf.zig").__floatunsidf; +const __floatdidf = @import("floatdidf.zig").__floatdidf; +const __floatundidf = @import("floatundidf.zig").__floatundidf; +const __floattidf = @import("floattidf.zig").__floattidf; +const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; + +// Conversion to f128 +const __floatsitf = @import("floatsitf.zig").__floatsitf; +const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; +const __floatditf = @import("floatditf.zig").__floatditf; +const __floatunditf = @import("floatunditf.zig").__floatunditf; +const __floattitf = @import("floattitf.zig").__floattitf; +const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; + +fn test__floatsisf(a: i32, expected: u32) !void { + const r = __floatsisf(a); + try std.testing.expect(@bitCast(u32, r) == expected); +} + +fn test_one_floatunsisf(a: u32, expected: u32) !void { + const r = __floatunsisf(a); + try std.testing.expect(@bitCast(u32, r) == expected); +} + +test "floatsisf" { + try test__floatsisf(0, 0x00000000); + try test__floatsisf(1, 0x3f800000); + try test__floatsisf(-1, 0xbf800000); + try test__floatsisf(0x7FFFFFFF, 0x4f000000); + try test__floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000); +} + +test "floatunsisf" { + // Test the produced bit pattern + try test_one_floatunsisf(0, 0); + try test_one_floatunsisf(1, 0x3f800000); + try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000); + try test_one_floatunsisf(0x80000000, 0x4f000000); + try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000); +} + +fn test__floatdisf(a: i64, expected: f32) !void { + const x = __floatdisf(a); + try testing.expect(x == expected); +} + +fn test__floatundisf(a: u64, expected: f32) !void { + try std.testing.expectEqual(expected, __floatundisf(a)); +} + +test "floatdisf" { + try test__floatdisf(0, 0.0); + try test__floatdisf(1, 1.0); + try test__floatdisf(2, 2.0); + try test__floatdisf(-1, -1.0); + try test__floatdisf(-2, -2.0); + try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatdisf(@bitCast(i64, @as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); + try test__floatdisf(@bitCast(i64, @as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); + try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000000)), -0x1.000000p+63); + try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000001)), -0x1.000000p+63); + try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +} + +test "floatundisf" { + try test__floatundisf(0, 0.0); + try test__floatundisf(1, 1.0); + try test__floatundisf(2, 2.0); + try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatundisf(0x8000008000000000, 0x1p+63); + try test__floatundisf(0x8000010000000000, 0x1.000002p+63); + try test__floatundisf(0x8000000000000000, 0x1p+63); + try test__floatundisf(0x8000000000000001, 0x1p+63); + try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +} + +fn test__floattisf(a: i128, expected: f32) !void { + const x = __floattisf(a); + try testing.expect(x == expected); +} + +fn test__floatuntisf(a: u128, expected: f32) !void { + const x = __floatuntisf(a); + try testing.expect(x == expected); +} + +test "floattisf" { + try test__floattisf(0, 0.0); + + try test__floattisf(1, 1.0); + try test__floattisf(2, 2.0); + try test__floattisf(-1, -1.0); + try test__floattisf(-2, -2.0); + + try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + + try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); + try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); + + try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); + try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); + + try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + + try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + + try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); + + try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); + try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); + + try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); + try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); +} + +test "floatuntisf" { + try test__floatuntisf(0, 0.0); + + try test__floatuntisf(1, 1.0); + try test__floatuntisf(2, 2.0); + try test__floatuntisf(20, 20.0); + + try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + + try test__floatuntisf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test__floatuntisf(make_uti(0x8000000000000800, 0), 0x1.0p+127); + try test__floatuntisf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + + try test__floatuntisf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + + try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + + try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + + try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + + try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + + try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); + try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); + + // Test overflow to infinity + try test__floatuntisf(@as(u128, math.maxInt(u128)), @bitCast(f32, math.inf(f32))); +} + +fn test_one_floatsidf(a: i32, expected: u64) !void { + const r = __floatsidf(a); + try std.testing.expect(@bitCast(u64, r) == expected); +} + +fn test_one_floatunsidf(a: u32, expected: u64) !void { + const r = __floatunsidf(a); + try std.testing.expect(@bitCast(u64, r) == expected); +} + +test "floatsidf" { + try test_one_floatsidf(0, 0x0000000000000000); + try test_one_floatsidf(1, 0x3ff0000000000000); + try test_one_floatsidf(-1, 0xbff0000000000000); + try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); + try test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000); +} + +test "floatunsidf" { + try test_one_floatunsidf(0, 0x0000000000000000); + try test_one_floatunsidf(1, 0x3ff0000000000000); + try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000); + try test_one_floatunsidf(@intCast(u32, 0x80000000), 0x41e0000000000000); + try test_one_floatunsidf(@intCast(u32, 0xFFFFFFFF), 0x41efffffffe00000); +} + +fn test__floatdidf(a: i64, expected: f64) !void { + const r = __floatdidf(a); + try testing.expect(r == expected); +} + +fn test__floatundidf(a: u64, expected: f64) !void { + const r = __floatundidf(a); + try testing.expect(r == expected); +} + +test "floatdidf" { + try test__floatdidf(0, 0.0); + try test__floatdidf(1, 1.0); + try test__floatdidf(2, 2.0); + try test__floatdidf(20, 20.0); + try test__floatdidf(-1, -1.0); + try test__floatdidf(-2, -2.0); + try test__floatdidf(-20, -20.0); + try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000800)), -0x1.FFFFFFFFFFFFEp+62); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000001000)), -0x1.FFFFFFFFFFFFCp+62); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000000)), -0x1.000000p+63); + try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000001)), -0x1.000000p+63); // 0x8000000000000001 + try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +} + +test "floatundidf" { + try test__floatundidf(0, 0.0); + try test__floatundidf(1, 1.0); + try test__floatundidf(2, 2.0); + try test__floatundidf(20, 20.0); + try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test__floatundidf(0x8000008000000000, 0x1.000001p+63); + try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63); + try test__floatundidf(0x8000010000000000, 0x1.000002p+63); + try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63); + try test__floatundidf(0x8000000000000000, 0x1p+63); + try test__floatundidf(0x8000000000000001, 0x1p+63); + try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +} + +fn test__floattidf(a: i128, expected: f64) !void { + const x = __floattidf(a); + try testing.expect(x == expected); +} + +fn test__floatuntidf(a: u128, expected: f64) !void { + const x = __floatuntidf(a); + try testing.expect(x == expected); +} + +test "floattidf" { + try test__floattidf(0, 0.0); + + try test__floattidf(1, 1.0); + try test__floattidf(2, 2.0); + try test__floattidf(20, 20.0); + try test__floattidf(-1, -1.0); + try test__floattidf(-2, -2.0); + try test__floattidf(-20, -20.0); + + try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127); + + try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +} + +test "floatuntidf" { + try test__floatuntidf(0, 0.0); + + try test__floatuntidf(1, 1.0); + try test__floatuntidf(2, 2.0); + try test__floatuntidf(20, 20.0); + + try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test__floatuntidf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test__floatuntidf(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); + try test__floatuntidf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + try test__floatuntidf(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); + + try test__floatuntidf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + try test__floatuntidf(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); + + try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test__floatuntidf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test__floatuntidf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test__floatuntidf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test__floatuntidf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test__floatuntidf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test__floatuntidf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +} + +fn test__floatsitf(a: i32, expected: u128) !void { + const r = __floatsitf(a); + try std.testing.expect(@bitCast(u128, r) == expected); +} + +test "floatsitf" { + try test__floatsitf(0, 0); + try test__floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); + try test__floatsitf(0x12345678, 0x401b2345678000000000000000000000); + try test__floatsitf(-0x12345678, 0xc01b2345678000000000000000000000); + try test__floatsitf(@bitCast(i32, @intCast(u32, 0xffffffff)), 0xbfff0000000000000000000000000000); + try test__floatsitf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc01e0000000000000000000000000000); +} + +fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { + const x = __floatunsitf(a); + + const x_repr = @bitCast(u128, x); + const x_hi = @intCast(u64, x_repr >> 64); + const x_lo = @truncate(u64, x_repr); + + if (x_hi == expected_hi and x_lo == expected_lo) { + return; + } + // nan repr + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { + return; + } + } + + @panic("__floatunsitf test failure"); +} + +test "floatunsitf" { + try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0); + try test__floatunsitf(0, 0x0, 0x0); + try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0); + try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0); +} + +fn test__floatditf(a: i64, expected: f128) !void { + const x = __floatditf(a); + try testing.expect(x == expected); +} + +fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { + const x = __floatunditf(a); + + const x_repr = @bitCast(u128, x); + const x_hi = @intCast(u64, x_repr >> 64); + const x_lo = @truncate(u64, x_repr); + + if (x_hi == expected_hi and x_lo == expected_lo) { + return; + } + // nan repr + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { + return; + } + } + + @panic("__floatunditf test failure"); +} + +test "floatditf" { + try test__floatditf(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); + try test__floatditf(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); + try test__floatditf(0x2, make_tf(0x4000000000000000, 0x0)); + try test__floatditf(0x1, make_tf(0x3fff000000000000, 0x0)); + try test__floatditf(0x0, make_tf(0x0, 0x0)); + try test__floatditf(@bitCast(i64, @as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); + try test__floatditf(@bitCast(i64, @as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); + try test__floatditf(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); + try test__floatditf(@bitCast(i64, @as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); +} + +test "floatunditf" { + try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); + try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); + try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0); + try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); + try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); + try test__floatunditf(0x2, 0x4000000000000000, 0x0); + try test__floatunditf(0x1, 0x3fff000000000000, 0x0); + try test__floatunditf(0x0, 0x0, 0x0); +} + +fn test__floattitf(a: i128, expected: f128) !void { + const x = __floattitf(a); + try testing.expect(x == expected); +} + +fn test__floatuntitf(a: u128, expected: f128) !void { + const x = __floatuntitf(a); + try testing.expect(x == expected); +} + +test "floattitf" { + try test__floattitf(0, 0.0); + + try test__floattitf(1, 1.0); + try test__floattitf(2, 2.0); + try test__floattitf(20, 20.0); + try test__floattitf(-1, -1.0); + try test__floattitf(-2, -2.0); + try test__floattitf(-20, -20.0); + + try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); + + try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +} + +test "floatuntitf" { + try test__floatuntitf(0, 0.0); + + try test__floatuntitf(1, 1.0); + try test__floatuntitf(2, 2.0); + try test__floatuntitf(20, 20.0); + + try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); + try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); + try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); + + try test__floatuntitf(0x8000008000000000, 0x8.000008p+60); + try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60); + try test__floatuntitf(0x8000010000000000, 0x8.00001p+60); + try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60); + + try test__floatuntitf(0x8000000000000000, 0x8p+60); + try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60); + + try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test__floatuntitf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test__floatuntitf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test__floatuntitf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test__floatuntitf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test__floatuntitf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test__floatuntitf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test__floatuntitf(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); + try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); + + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +} + +fn make_ti(high: u64, low: u64) i128 { + var result: u128 = high; + result <<= 64; + result |= low; + return @bitCast(i128, result); +} + +fn make_uti(high: u64, low: u64) u128 { + var result: u128 = high; + result <<= 64; + result |= low; + return result; +} + +fn make_tf(high: u64, low: u64) f128 { + var result: u128 = high; + result <<= 64; + result |= low; + return @bitCast(f128, result); +} + +test "conversion to f16" { + try testing.expect(__floatunsihf(@as(u32, 0)) == 0.0); + try testing.expect(__floatunsihf(@as(u32, 1)) == 1.0); + try testing.expect(__floatunsihf(@as(u32, 65504)) == 65504); + try testing.expect(__floatunsihf(@as(u32, 65504 + (1 << 4))) == math.inf(f16)); +} + +test "conversion to f32" { + try testing.expect(__floatunsisf(@as(u32, 0)) == 0.0); + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u32))) != 1.0); + try testing.expect(__floatsisf(@as(i32, math.minInt(i32))) != 1.0); + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24))) == math.maxInt(u24)); + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even + try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact +} + +test "conversion to f80" { + if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64) + return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408 + + const intToFloat = @import("./int_to_float.zig").intToFloat; + + try testing.expect(intToFloat(f80, @as(i80, -12)) == -12); + try testing.expect(@floatToInt(u80, intToFloat(f80, @as(u64, math.maxInt(u64)) + 0)) == math.maxInt(u64) + 0); + try testing.expect(@floatToInt(u80, intToFloat(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1); + + try testing.expect(intToFloat(f80, @as(u32, 0)) == 0.0); + try testing.expect(intToFloat(f80, @as(u32, 1)) == 1.0); + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u32, math.maxInt(u24)) + 0)) == math.maxInt(u24)); + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u64)) + 0)) == math.maxInt(u64)); + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1); // Exact + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u64)) + 2)) == math.maxInt(u64) + 1); // Rounds down + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u64)) + 3)) == math.maxInt(u64) + 3); // Tie - Exact + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u64)) + 4)) == math.maxInt(u64) + 5); // Rounds up + + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 0)) == math.maxInt(u65) + 1); // Rounds up + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 1)) == math.maxInt(u65) + 1); // Exact + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 2)) == math.maxInt(u65) + 1); // Rounds down + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 3)) == math.maxInt(u65) + 1); // Tie - Rounds down + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 4)) == math.maxInt(u65) + 5); // Rounds up + try testing.expect(@floatToInt(u128, intToFloat(f80, @as(u80, math.maxInt(u65)) + 5)) == math.maxInt(u65) + 5); // Exact +} diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig @@ -1,12 +1,27 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/lnf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/lnf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const testing = std.testing; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__logh, .{ .name = "__logh", .linkage = common.linkage }); + @export(logf, .{ .name = "logf", .linkage = common.linkage }); + @export(log, .{ .name = "log", .linkage = common.linkage }); + @export(__logx, .{ .name = "__logx", .linkage = common.linkage }); + const logq_sym_name = if (common.want_ppc_abi) "logf128" else "logq"; + @export(logq, .{ .name = logq_sym_name, .linkage = common.linkage }); + @export(logl, .{ .name = "logl", .linkage = common.linkage }); +} pub fn __logh(a: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig @@ -1,13 +1,28 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/log10f.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/log10f.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const testing = std.testing; const maxInt = std.math.maxInt; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__log10h, .{ .name = "__log10h", .linkage = common.linkage }); + @export(log10f, .{ .name = "log10f", .linkage = common.linkage }); + @export(log10, .{ .name = "log10", .linkage = common.linkage }); + @export(__log10x, .{ .name = "__log10x", .linkage = common.linkage }); + const log10q_sym_name = if (common.want_ppc_abi) "log10f128" else "log10q"; + @export(log10q, .{ .name = log10q_sym_name, .linkage = common.linkage }); + @export(log10l, .{ .name = "log10l", .linkage = common.linkage }); +} pub fn __log10h(a: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig @@ -1,13 +1,28 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; const maxInt = std.math.maxInt; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__log2h, .{ .name = "__log2h", .linkage = common.linkage }); + @export(log2f, .{ .name = "log2f", .linkage = common.linkage }); + @export(log2, .{ .name = "log2", .linkage = common.linkage }); + @export(__log2x, .{ .name = "__log2x", .linkage = common.linkage }); + const log2q_sym_name = if (common.want_ppc_abi) "log2f128" else "log2q"; + @export(log2q, .{ .name = log2q_sym_name, .linkage = common.linkage }); + @export(log2l, .{ .name = "log2l", .linkage = common.linkage }); +} pub fn __log2h(a: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/modti3.zig b/lib/compiler_rt/modti3.zig @@ -1,14 +1,47 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c +//! Ported from: +//! +//! https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c -const udivmod = @import("udivmod.zig").udivmod; +const std = @import("std"); const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); +const udivmod = @import("udivmod.zig").udivmod; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__modti3, .{ .name = "__modti3", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__modti3_windows_x86_64, .{ .name = "__modti3", .linkage = common.linkage }); + }, + else => {}, + } + if (arch.isAARCH64()) { + @export(__modti3, .{ .name = "__modti3", .linkage = common.linkage }); + } + } else { + @export(__modti3, .{ .name = "__modti3", .linkage = common.linkage }); + } +} pub fn __modti3(a: i128, b: i128) callconv(.C) i128 { - @setRuntimeSafety(builtin.is_test); + return mod(a, b); +} +const v128 = @import("std").meta.Vector(2, u64); + +fn __modti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { + return @bitCast(v128, mod(@bitCast(i128, a), @bitCast(i128, b))); +} + +inline fn mod(a: i128, b: i128) i128 { const s_a = a >> (128 - 1); // s = a < 0 ? -1 : 0 const s_b = b >> (128 - 1); // s = b < 0 ? -1 : 0 @@ -20,14 +53,6 @@ pub fn __modti3(a: i128, b: i128) callconv(.C) i128 { return (@bitCast(i128, r) ^ s_a) -% s_a; // negate if s == -1 } -const v128 = @import("std").meta.Vector(2, u64); -pub fn __modti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { - return @bitCast(v128, @call(.{ .modifier = .always_inline }, __modti3, .{ - @bitCast(i128, a), - @bitCast(i128, b), - })); -} - test { _ = @import("modti3_test.zig"); } diff --git a/lib/compiler_rt/mulXf3.zig b/lib/compiler_rt/mulXf3.zig @@ -1,344 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc - -const std = @import("std"); -const math = std.math; -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); - -pub fn __multf3(a: f128, b: f128) callconv(.C) f128 { - return mulXf3(f128, a, b); -} -pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { - return mulXf3(f80, a, b); -} -pub fn __muldf3(a: f64, b: f64) callconv(.C) f64 { - return mulXf3(f64, a, b); -} -pub fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { - return mulXf3(f32, a, b); -} - -pub fn __aeabi_fmul(a: f32, b: f32) callconv(.C) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __mulsf3, .{ a, b }); -} - -pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __muldf3, .{ a, b }); -} - -fn mulXf3(comptime T: type, a: T, b: T) T { - @setRuntimeSafety(builtin.is_test); - const typeWidth = @typeInfo(T).Float.bits; - const significandBits = math.floatMantissaBits(T); - const fractionalBits = math.floatFractionalBits(T); - const exponentBits = math.floatExponentBits(T); - - const Z = std.meta.Int(.unsigned, typeWidth); - - // ZSignificand is large enough to contain the significand, including an explicit integer bit - const ZSignificand = PowerOfTwoSignificandZ(T); - const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; - - const roundBit = (1 << (ZSignificandBits - 1)); - const signBit = (@as(Z, 1) << (significandBits + exponentBits)); - const maxExponent = ((1 << exponentBits) - 1); - const exponentBias = (maxExponent >> 1); - - const integerBit = (@as(ZSignificand, 1) << fractionalBits); - const quietBit = integerBit >> 1; - const significandMask = (@as(Z, 1) << significandBits) - 1; - - const absMask = signBit - 1; - const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; - const infRep = @bitCast(Z, math.inf(T)); - const minNormalRep = @bitCast(Z, math.floatMin(T)); - - const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); - const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); - const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; - - var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); - var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); - var scale: i32 = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { - const aAbs: Z = @bitCast(Z, a) & absMask; - const bAbs: Z = @bitCast(Z, b) & absMask; - - // NaN * anything = qNaN - if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); - // anything * NaN = qNaN - if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); - - if (aAbs == infRep) { - // infinity * non-zero = +/- infinity - if (bAbs != 0) { - return @bitCast(T, aAbs | productSign); - } else { - // infinity * zero = NaN - return @bitCast(T, qnanRep); - } - } - - if (bAbs == infRep) { - //? non-zero * infinity = +/- infinity - if (aAbs != 0) { - return @bitCast(T, bAbs | productSign); - } else { - // zero * infinity = NaN - return @bitCast(T, qnanRep); - } - } - - // zero * anything = +/- zero - if (aAbs == 0) return @bitCast(T, productSign); - // anything * zero = +/- zero - if (bAbs == 0) return @bitCast(T, productSign); - - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); - if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); - } - - // Or in the implicit significand bit. (If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) - aSignificand |= integerBit; - bSignificand |= integerBit; - - // Get the significand of a*b. Before multiplying the significands, shift - // one of them left to left-align it in the field. Thus, the product will - // have (exponentBits + 2) integral digits, all but two of which must be - // zero. Normalizing this result is just a conditional left-shift by one - // and bumping the exponent accordingly. - var productHi: ZSignificand = undefined; - var productLo: ZSignificand = undefined; - const left_align_shift = ZSignificandBits - fractionalBits - 1; - wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); - - var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; - - // Normalize the significand, adjust exponent if needed. - if ((productHi & integerBit) != 0) { - productExponent +%= 1; - } else { - productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); - productLo = productLo << 1; - } - - // If we have overflowed the type, return +/- infinity. - if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); - - var result: Z = undefined; - if (productExponent <= 0) { - // Result is denormal before rounding - // - // If the result is so small that it just underflows to zero, return - // a zero of the appropriate sign. Mathematically there is no need to - // handle this case separately, but we make it a special case to - // simplify the shift logic. - const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); - if (shift >= ZSignificandBits) return @bitCast(T, productSign); - - // Otherwise, shift the significand of the result so that the round - // bit is the high bit of productLo. - const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); - productLo |= @boolToInt(sticky); - result = productHi; - - // We include the integer bit so that rounding will carry to the exponent, - // but it will be removed later if the result is still denormal - if (significandBits != fractionalBits) result |= integerBit; - } else { - // Result is normal before rounding; insert the exponent. - result = productHi & significandMask; - result |= @intCast(Z, productExponent) << significandBits; - } - - // Final rounding. The final result may overflow to infinity, or underflow - // to zero, but those are the correct results in those cases. We use the - // default IEEE-754 round-to-nearest, ties-to-even rounding mode. - if (productLo > roundBit) result +%= 1; - if (productLo == roundBit) result +%= result & 1; - - // Restore any explicit integer bit, if it was rounded off - if (significandBits != fractionalBits) { - if ((result >> significandBits) != 0) { - result |= integerBit; - } else { - result &= ~integerBit; - } - } - - // Insert the sign of the result: - result |= productSign; - - return @bitCast(T, result); -} - -fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { - @setRuntimeSafety(builtin.is_test); - switch (Z) { - u16 => { - // 16x16 --> 32 bit multiply - const product = @as(u32, a) * @as(u32, b); - hi.* = @intCast(u16, product >> 16); - lo.* = @truncate(u16, product); - }, - u32 => { - // 32x32 --> 64 bit multiply - const product = @as(u64, a) * @as(u64, b); - hi.* = @intCast(u32, product >> 32); - lo.* = @truncate(u32, product); - }, - u64 => { - const S = struct { - fn loWord(x: u64) u64 { - return @truncate(u32, x); - } - fn hiWord(x: u64) u64 { - return @intCast(u32, x >> 32); - } - }; - // 64x64 -> 128 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - // Each of the component 32x32 -> 64 products - const plolo: u64 = S.loWord(a) * S.loWord(b); - const plohi: u64 = S.loWord(a) * S.hiWord(b); - const philo: u64 = S.hiWord(a) * S.loWord(b); - const phihi: u64 = S.hiWord(a) * S.hiWord(b); - // Sum terms that contribute to lo in a way that allows us to get the carry - const r0: u64 = S.loWord(plolo); - const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); - lo.* = r0 +% (r1 << 32); - // Sum terms contributing to hi with the carry from lo - hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; - }, - u128 => { - const Word_LoMask = @as(u64, 0x00000000ffffffff); - const Word_HiMask = @as(u64, 0xffffffff00000000); - const Word_FullMask = @as(u64, 0xffffffffffffffff); - const S = struct { - fn Word_1(x: u128) u64 { - return @truncate(u32, x >> 96); - } - fn Word_2(x: u128) u64 { - return @truncate(u32, x >> 64); - } - fn Word_3(x: u128) u64 { - return @truncate(u32, x >> 32); - } - fn Word_4(x: u128) u64 { - return @truncate(u32, x); - } - }; - // 128x128 -> 256 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - - const product11: u64 = S.Word_1(a) * S.Word_1(b); - const product12: u64 = S.Word_1(a) * S.Word_2(b); - const product13: u64 = S.Word_1(a) * S.Word_3(b); - const product14: u64 = S.Word_1(a) * S.Word_4(b); - const product21: u64 = S.Word_2(a) * S.Word_1(b); - const product22: u64 = S.Word_2(a) * S.Word_2(b); - const product23: u64 = S.Word_2(a) * S.Word_3(b); - const product24: u64 = S.Word_2(a) * S.Word_4(b); - const product31: u64 = S.Word_3(a) * S.Word_1(b); - const product32: u64 = S.Word_3(a) * S.Word_2(b); - const product33: u64 = S.Word_3(a) * S.Word_3(b); - const product34: u64 = S.Word_3(a) * S.Word_4(b); - const product41: u64 = S.Word_4(a) * S.Word_1(b); - const product42: u64 = S.Word_4(a) * S.Word_2(b); - const product43: u64 = S.Word_4(a) * S.Word_3(b); - const product44: u64 = S.Word_4(a) * S.Word_4(b); - - const sum0: u128 = @as(u128, product44); - const sum1: u128 = @as(u128, product34) +% - @as(u128, product43); - const sum2: u128 = @as(u128, product24) +% - @as(u128, product33) +% - @as(u128, product42); - const sum3: u128 = @as(u128, product14) +% - @as(u128, product23) +% - @as(u128, product32) +% - @as(u128, product41); - const sum4: u128 = @as(u128, product13) +% - @as(u128, product22) +% - @as(u128, product31); - const sum5: u128 = @as(u128, product12) +% - @as(u128, product21); - const sum6: u128 = @as(u128, product11); - - const r0: u128 = (sum0 & Word_FullMask) +% - ((sum1 & Word_LoMask) << 32); - const r1: u128 = (sum0 >> 64) +% - ((sum1 >> 32) & Word_FullMask) +% - (sum2 & Word_FullMask) +% - ((sum3 << 32) & Word_HiMask); - - lo.* = r0 +% (r1 << 64); - hi.* = (r1 >> 64) +% - (sum1 >> 96) +% - (sum2 >> 64) +% - (sum3 >> 32) +% - sum4 +% - (sum5 << 32) +% - (sum6 << 64); - }, - else => @compileError("unsupported"), - } -} - -/// Returns a power-of-two integer type that is large enough to contain -/// the significand of T, including an explicit integer bit -fn PowerOfTwoSignificandZ(comptime T: type) type { - const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); - return std.meta.Int(.unsigned, bits); -} - -fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { - @setRuntimeSafety(builtin.is_test); - const Z = PowerOfTwoSignificandZ(T); - const integerBit = @as(Z, 1) << math.floatFractionalBits(T); - - const shift = @clz(Z, significand.*) - @clz(Z, integerBit); - significand.* <<= @intCast(math.Log2Int(Z), shift); - return @as(i32, 1) - shift; -} - -// Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) -// -// This is analogous to an shr version of `@shlWithOverflow` -fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { - @setRuntimeSafety(builtin.is_test); - const typeWidth = @typeInfo(Z).Int.bits; - const S = math.Log2Int(Z); - var inexact = false; - if (count < typeWidth) { - inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; - lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); - hi.* = hi.* >> @intCast(S, count); - } else if (count < 2 * typeWidth) { - inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; - lo.* = hi.* >> @intCast(S, count -% typeWidth); - hi.* = 0; - } else { - inexact = (hi.* | lo.*) != 0; - lo.* = 0; - hi.* = 0; - } - return inexact; -} - -test { - _ = @import("mulXf3_test.zig"); -} diff --git a/lib/compiler_rt/mulXf3_test.zig b/lib/compiler_rt/mulXf3_test.zig @@ -1,171 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c - -const std = @import("std"); -const math = std.math; -const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); -const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); - -const __multf3 = @import("mulXf3.zig").__multf3; -const __mulxf3 = @import("mulXf3.zig").__mulxf3; -const __muldf3 = @import("mulXf3.zig").__muldf3; -const __mulsf3 = @import("mulXf3.zig").__mulsf3; - -// return true if equal -// use two 64-bit integers intead of one 128-bit integer -// because 128-bit integer constant can't be assigned directly -fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { - const rep = @bitCast(u128, result); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expectedHi and lo == expectedLo) { - return true; - } - // test other possible NaN representation(signal NaN) - if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return true; - } - } - return false; -} - -fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __multf3(a, b); - - if (compareResultLD(x, expected_hi, expected_lo)) - return; - - @panic("__multf3 test failure"); -} - -fn makeNaN128(rand: u64) f128 { - const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; - const float_result = @bitCast(f128, int_result); - return float_result; -} -test "multf3" { - // qNaN * any = qNaN - try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN * any = NaN - const a = makeNaN128(0x800030000000); - try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - // inf * any = inf - try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); - - // any * any - try test__multf3( - @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), - @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), - 0x400423e7f9e3c9fc, - 0xd906c2c2a85777c4, - ); - - try test__multf3( - @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), - @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), - 0x3fc52a163c6223fc, - 0xc94c4bf0430768b4, - ); - - try test__multf3( - 0x1.234425696abcad34a35eeffefdcbap+456, - 0x451.ed98d76e5d46e5f24323dff21ffp+600, - 0x44293a91de5e0e94, - 0xe8ed17cc2cdf64ac, - ); - - try test__multf3( - @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), - @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), - 0x3d4f37c1a3137cae, - 0xfc6807048bc2836a, - ); - - try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); - - // Denormal operands. - try test__multf3( - 0x0.0000000000000000000000000001p-16382, - 0x1p16383, - 0x3f90000000000000, - 0x0, - ); - try test__multf3( - 0x1p16383, - 0x0.0000000000000000000000000001p-16382, - 0x3f90000000000000, - 0x0, - ); - - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); - try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); -} - -const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); - -fn test__mulxf3(a: f80, b: f80, expected: u80) !void { - const x = __mulxf3(a, b); - const rep = @bitCast(u80, x); - - if (rep == expected) - return; - - if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) - return; // We don't currently test NaN payload propagation - - return error.TestFailed; -} - -test "mulxf3" { - // NaN * any = NaN - try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - - // any * NaN = NaN - try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); - try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); - - // NaN * inf = NaN - try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); - - // inf * NaN = NaN - try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); - - // inf * inf = inf - try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); - - // inf * -inf = -inf - try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); - - // -inf + inf = -inf - try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); - - // inf * any = inf - try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); - - // any * inf = inf - try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); - - // any * any - try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); - try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact - - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact - - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up - try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal -} diff --git a/lib/compiler_rt/muldf3.zig b/lib/compiler_rt/muldf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = common.linkage }); + } else { + @export(__muldf3, .{ .name = "__muldf3", .linkage = common.linkage }); + } +} + +pub fn __muldf3(a: f64, b: f64) callconv(.C) f64 { + return mulf3(f64, a, b); +} + +fn __aeabi_dmul(a: f64, b: f64) callconv(.AAPCS) f64 { + return mulf3(f64, a, b); +} diff --git a/lib/compiler_rt/muldi3.zig b/lib/compiler_rt/muldi3.zig @@ -1,10 +1,36 @@ +//! Ported from +//! https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c + const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const native_endian = builtin.cpu.arch.endian(); +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_lmul, .{ .name = "__aeabi_lmul", .linkage = common.linkage }); + } else { + @export(__muldi3, .{ .name = "__muldi3", .linkage = common.linkage }); + } +} + +pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { + return mul(a, b); +} -// Ported from -// https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c +fn __aeabi_lmul(a: i64, b: i64) callconv(.AAPCS) i64 { + return mul(a, b); +} + +inline fn mul(a: i64, b: i64) i64 { + const x = dwords{ .all = a }; + const y = dwords{ .all = b }; + var r = dwords{ .all = muldsi3(x.s.low, y.s.low) }; + r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; + return r.all; +} const dwords = extern union { all: i64, @@ -20,9 +46,7 @@ const dwords = extern union { }, }; -fn __muldsi3(a: u32, b: u32) i64 { - @setRuntimeSafety(is_test); - +fn muldsi3(a: u32, b: u32) i64 { const bits_in_word_2 = @sizeOf(i32) * 8 / 2; const lower_mask = (~@as(u32, 0)) >> bits_in_word_2; @@ -42,16 +66,6 @@ fn __muldsi3(a: u32, b: u32) i64 { return r.all; } -pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { - @setRuntimeSafety(is_test); - - const x = dwords{ .all = a }; - const y = dwords{ .all = b }; - var r = dwords{ .all = __muldsi3(x.s.low, y.s.low) }; - r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; - return r.all; -} - test { _ = @import("muldi3_test.zig"); } diff --git a/lib/compiler_rt/mulf3.zig b/lib/compiler_rt/mulf3.zig @@ -0,0 +1,203 @@ +const std = @import("std"); +const math = std.math; +const builtin = @import("builtin"); +const common = @import("./common.zig"); + +/// Ported from: +/// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc +pub inline fn mulf3(comptime T: type, a: T, b: T) T { + @setRuntimeSafety(builtin.is_test); + const typeWidth = @typeInfo(T).Float.bits; + const significandBits = math.floatMantissaBits(T); + const fractionalBits = math.floatFractionalBits(T); + const exponentBits = math.floatExponentBits(T); + + const Z = std.meta.Int(.unsigned, typeWidth); + + // ZSignificand is large enough to contain the significand, including an explicit integer bit + const ZSignificand = PowerOfTwoSignificandZ(T); + const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; + + const roundBit = (1 << (ZSignificandBits - 1)); + const signBit = (@as(Z, 1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const integerBit = (@as(ZSignificand, 1) << fractionalBits); + const quietBit = integerBit >> 1; + const significandMask = (@as(Z, 1) << significandBits) - 1; + + const absMask = signBit - 1; + const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; + const infRep = @bitCast(Z, math.inf(T)); + const minNormalRep = @bitCast(Z, math.floatMin(T)); + + const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); + const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); + const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; + + var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); + var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); + var scale: i32 = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { + const aAbs: Z = @bitCast(Z, a) & absMask; + const bAbs: Z = @bitCast(Z, b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs != 0) { + return @bitCast(T, aAbs | productSign); + } else { + // infinity * zero = NaN + return @bitCast(T, qnanRep); + } + } + + if (bAbs == infRep) { + //? non-zero * infinity = +/- infinity + if (aAbs != 0) { + return @bitCast(T, bAbs | productSign); + } else { + // zero * infinity = NaN + return @bitCast(T, qnanRep); + } + } + + // zero * anything = +/- zero + if (aAbs == 0) return @bitCast(T, productSign); + // anything * zero = +/- zero + if (bAbs == 0) return @bitCast(T, productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); + if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= integerBit; + bSignificand |= integerBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + var productHi: ZSignificand = undefined; + var productLo: ZSignificand = undefined; + const left_align_shift = ZSignificandBits - fractionalBits - 1; + common.wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); + + var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if ((productHi & integerBit) != 0) { + productExponent +%= 1; + } else { + productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); + productLo = productLo << 1; + } + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); + + var result: Z = undefined; + if (productExponent <= 0) { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); + if (shift >= ZSignificandBits) return @bitCast(T, productSign); + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); + productLo |= @boolToInt(sticky); + result = productHi; + + // We include the integer bit so that rounding will carry to the exponent, + // but it will be removed later if the result is still denormal + if (significandBits != fractionalBits) result |= integerBit; + } else { + // Result is normal before rounding; insert the exponent. + result = productHi & significandMask; + result |= @intCast(Z, productExponent) << significandBits; + } + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if (productLo > roundBit) result +%= 1; + if (productLo == roundBit) result +%= result & 1; + + // Restore any explicit integer bit, if it was rounded off + if (significandBits != fractionalBits) { + if ((result >> significandBits) != 0) { + result |= integerBit; + } else { + result &= ~integerBit; + } + } + + // Insert the sign of the result: + result |= productSign; + + return @bitCast(T, result); +} + +/// Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) +/// +/// This is analogous to an shr version of `@shlWithOverflow` +fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { + @setRuntimeSafety(builtin.is_test); + const typeWidth = @typeInfo(Z).Int.bits; + const S = math.Log2Int(Z); + var inexact = false; + if (count < typeWidth) { + inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; + lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); + hi.* = hi.* >> @intCast(S, count); + } else if (count < 2 * typeWidth) { + inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; + lo.* = hi.* >> @intCast(S, count -% typeWidth); + hi.* = 0; + } else { + inexact = (hi.* | lo.*) != 0; + lo.* = 0; + hi.* = 0; + } + return inexact; +} + +fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { + const Z = PowerOfTwoSignificandZ(T); + const integerBit = @as(Z, 1) << math.floatFractionalBits(T); + + const shift = @clz(Z, significand.*) - @clz(Z, integerBit); + significand.* <<= @intCast(math.Log2Int(Z), shift); + return @as(i32, 1) - shift; +} + +/// Returns a power-of-two integer type that is large enough to contain +/// the significand of T, including an explicit integer bit +fn PowerOfTwoSignificandZ(comptime T: type) type { + const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); + return std.meta.Int(.unsigned, bits); +} + +test { + _ = @import("mulf3_test.zig"); +} diff --git a/lib/compiler_rt/mulf3_test.zig b/lib/compiler_rt/mulf3_test.zig @@ -0,0 +1,171 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c + +const std = @import("std"); +const math = std.math; +const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); +const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); + +const __multf3 = @import("multf3.zig").__multf3; +const __mulxf3 = @import("mulxf3.zig").__mulxf3; +const __muldf3 = @import("muldf3.zig").__muldf3; +const __mulsf3 = @import("mulsf3.zig").__mulsf3; + +// return true if equal +// use two 64-bit integers intead of one 128-bit integer +// because 128-bit integer constant can't be assigned directly +fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { + const rep = @bitCast(u128, result); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expectedHi and lo == expectedLo) { + return true; + } + // test other possible NaN representation(signal NaN) + if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return true; + } + } + return false; +} + +fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __multf3(a, b); + + if (compareResultLD(x, expected_hi, expected_lo)) + return; + + @panic("__multf3 test failure"); +} + +fn makeNaN128(rand: u64) f128 { + const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; + const float_result = @bitCast(f128, int_result); + return float_result; +} +test "multf3" { + // qNaN * any = qNaN + try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN * any = NaN + const a = makeNaN128(0x800030000000); + try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + // inf * any = inf + try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + + // any * any + try test__multf3( + @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), + @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), + 0x400423e7f9e3c9fc, + 0xd906c2c2a85777c4, + ); + + try test__multf3( + @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), + @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), + 0x3fc52a163c6223fc, + 0xc94c4bf0430768b4, + ); + + try test__multf3( + 0x1.234425696abcad34a35eeffefdcbap+456, + 0x451.ed98d76e5d46e5f24323dff21ffp+600, + 0x44293a91de5e0e94, + 0xe8ed17cc2cdf64ac, + ); + + try test__multf3( + @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), + @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), + 0x3d4f37c1a3137cae, + 0xfc6807048bc2836a, + ); + + try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); + + // Denormal operands. + try test__multf3( + 0x0.0000000000000000000000000001p-16382, + 0x1p16383, + 0x3f90000000000000, + 0x0, + ); + try test__multf3( + 0x1p16383, + 0x0.0000000000000000000000000001p-16382, + 0x3f90000000000000, + 0x0, + ); + + try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); + try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); + try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); +} + +const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); + +fn test__mulxf3(a: f80, b: f80, expected: u80) !void { + const x = __mulxf3(a, b); + const rep = @bitCast(u80, x); + + if (rep == expected) + return; + + if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) + return; // We don't currently test NaN payload propagation + + return error.TestFailed; +} + +test "mulxf3" { + // NaN * any = NaN + try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + + // any * NaN = NaN + try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); + try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); + + // NaN * inf = NaN + try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); + + // inf * NaN = NaN + try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); + + // inf * inf = inf + try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); + + // inf * -inf = -inf + try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); + + // -inf + inf = -inf + try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); + + // inf * any = inf + try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); + + // any * inf = inf + try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); + + // any * any + try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); + try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact + + try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact + try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down + try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even + try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up + try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact + + try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even + try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up + try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal +} diff --git a/lib/compiler_rt/mulo.zig b/lib/compiler_rt/mulo.zig @@ -1,6 +1,15 @@ -const builtin = @import("builtin"); const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__mulosi4, .{ .name = "__mulosi4", .linkage = common.linkage }); + @export(__mulodi4, .{ .name = "__mulodi4", .linkage = common.linkage }); + @export(__muloti4, .{ .name = "__muloti4", .linkage = common.linkage }); +} // mulo - multiplication overflow // * return a*%b. @@ -9,7 +18,6 @@ const math = std.math; // - muloXi4_genericFast for 2*bitsize <= usize inline fn muloXi4_genericSmall(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - @setRuntimeSafety(builtin.is_test); overflow.* = 0; const min = math.minInt(ST); var res: ST = a *% b; @@ -24,7 +32,6 @@ inline fn muloXi4_genericSmall(comptime ST: type, a: ST, b: ST, overflow: *c_int } inline fn muloXi4_genericFast(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - @setRuntimeSafety(builtin.is_test); overflow.* = 0; const EST = switch (ST) { i32 => i64, diff --git a/lib/compiler_rt/mulsf3.zig b/lib/compiler_rt/mulsf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = common.linkage }); + } else { + @export(__mulsf3, .{ .name = "__mulsf3", .linkage = common.linkage }); + } +} + +pub fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { + return mulf3(f32, a, b); +} + +fn __aeabi_fmul(a: f32, b: f32) callconv(.AAPCS) f32 { + return mulf3(f32, a, b); +} diff --git a/lib/compiler_rt/multf3.zig b/lib/compiler_rt/multf3.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__mulkf3, .{ .name = "__mulkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = common.linkage }); + } else { + @export(__multf3, .{ .name = "__multf3", .linkage = common.linkage }); + } +} + +pub fn __multf3(a: f128, b: f128) callconv(.C) f128 { + return mulf3(f128, a, b); +} + +fn __mulkf3(a: f128, b: f128) callconv(.C) f128 { + return mulf3(f128, a, b); +} + +fn _Qp_mul(c: *f128, a: *const f128, b: *const f128) callconv(.C) void { + c.* = mulf3(f128, a.*, b.*); +} diff --git a/lib/compiler_rt/multi3.zig b/lib/compiler_rt/multi3.zig @@ -1,31 +1,52 @@ -const compiler_rt = @import("../compiler_rt.zig"); +//! Ported from git@github.com:llvm-project/llvm-project-20170507.git +//! ae684fad6d34858c014c94da69c15e7774a633c3 +//! 2018-08-13 + const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; +const arch = builtin.cpu.arch; const native_endian = builtin.cpu.arch.endian(); +const common = @import("common.zig"); + +pub const panic = common.panic; -// Ported from git@github.com:llvm-project/llvm-project-20170507.git -// ae684fad6d34858c014c94da69c15e7774a633c3 -// 2018-08-13 +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = common.linkage }); + }, + else => {}, + } + } else { + @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage }); + } +} pub fn __multi3(a: i128, b: i128) callconv(.C) i128 { - @setRuntimeSafety(is_test); + return mul(a, b); +} + +const v128 = @Vector(2, u64); + +fn __multi3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { + return @bitCast(v128, mul(@bitCast(i128, a), @bitCast(i128, b))); +} + +inline fn mul(a: i128, b: i128) i128 { const x = twords{ .all = a }; const y = twords{ .all = b }; - var r = twords{ .all = __mulddi3(x.s.low, y.s.low) }; + var r = twords{ .all = mulddi3(x.s.low, y.s.low) }; r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; return r.all; } -const v128 = @Vector(2, u64); -pub fn __multi3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { - return @bitCast(v128, @call(.{ .modifier = .always_inline }, __multi3, .{ - @bitCast(i128, a), - @bitCast(i128, b), - })); -} - -fn __mulddi3(a: u64, b: u64) i128 { +fn mulddi3(a: u64, b: u64) i128 { const bits_in_dword_2 = (@sizeOf(i64) * 8) / 2; const lower_mask = ~@as(u64, 0) >> bits_in_dword_2; var r: twords = undefined; diff --git a/lib/compiler_rt/mulxf3.zig b/lib/compiler_rt/mulxf3.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + @export(__mulxf3, .{ .name = "__mulxf3", .linkage = common.linkage }); +} + +pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { + return mulf3(f80, a, b); +} diff --git a/lib/compiler_rt/negXf2.zig b/lib/compiler_rt/negXf2.zig @@ -1,24 +1,36 @@ const std = @import("std"); +const builtin = @import("builtin"); +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = common.linkage }); + @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = common.linkage }); + } else { + @export(__negsf2, .{ .name = "__negsf2", .linkage = common.linkage }); + @export(__negdf2, .{ .name = "__negdf2", .linkage = common.linkage }); + } +} pub fn __negsf2(a: f32) callconv(.C) f32 { return negXf2(f32, a); } -pub fn __negdf2(a: f64) callconv(.C) f64 { - return negXf2(f64, a); +fn __aeabi_fneg(a: f32) callconv(.AAPCS) f32 { + return negXf2(f32, a); } -pub fn __aeabi_fneg(arg: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __negsf2, .{arg}); +pub fn __negdf2(a: f64) callconv(.C) f64 { + return negXf2(f64, a); } -pub fn __aeabi_dneg(arg: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __negdf2, .{arg}); +fn __aeabi_dneg(a: f64) callconv(.AAPCS) f64 { + return negXf2(f64, a); } -fn negXf2(comptime T: type, a: T) T { +inline fn negXf2(comptime T: type, a: T) T { const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); const significandBits = std.math.floatMantissaBits(T); diff --git a/lib/compiler_rt/negXi2.zig b/lib/compiler_rt/negXi2.zig @@ -1,19 +1,21 @@ +//! neg - negate (the number) +//! - negXi2 for unoptimized little and big endian +//! sfffffff = 2^31-1 +//! two's complement inverting bits and add 1 would result in -INT_MIN == 0 +//! => -INT_MIN = -2^31 forbidden +//! * size optimized builds +//! * machines that dont support carry operations + const std = @import("std"); const builtin = @import("builtin"); +const common = @import("common.zig"); -// neg - negate (the number) -// - negXi2 for unoptimized little and big endian - -// sfffffff = 2^31-1 -// two's complement inverting bits and add 1 would result in -INT_MIN == 0 -// => -INT_MIN = -2^31 forbidden - -// * size optimized builds -// * machines that dont support carry operations +pub const panic = common.panic; -inline fn negXi2(comptime T: type, a: T) T { - @setRuntimeSafety(builtin.is_test); - return -a; +comptime { + @export(__negsi2, .{ .name = "__negsi2", .linkage = common.linkage }); + @export(__negdi2, .{ .name = "__negdi2", .linkage = common.linkage }); + @export(__negti2, .{ .name = "__negti2", .linkage = common.linkage }); } pub fn __negsi2(a: i32) callconv(.C) i32 { @@ -28,6 +30,10 @@ pub fn __negti2(a: i128) callconv(.C) i128 { return negXi2(i128, a); } +inline fn negXi2(comptime T: type, a: T) T { + return -a; +} + test { _ = @import("negsi2_test.zig"); _ = @import("negdi2_test.zig"); diff --git a/lib/compiler_rt/negv.zig b/lib/compiler_rt/negv.zig @@ -1,20 +1,16 @@ -// negv - negate oVerflow -// * @panic, if result can not be represented -// - negvXi4_generic for unoptimized version +//! negv - negate oVerflow +//! * @panic, if result can not be represented +//! - negvXi4_generic for unoptimized version +const std = @import("std"); +const builtin = @import("builtin"); +const common = @import("common.zig"); -// assume -0 == 0 is gracefully handled by the hardware -inline fn negvXi(comptime ST: type, a: ST) ST { - const UT = switch (ST) { - i32 => u32, - i64 => u64, - i128 => u128, - else => unreachable, - }; - const N: UT = @bitSizeOf(ST); - const min: ST = @bitCast(ST, (@as(UT, 1) << (N - 1))); - if (a == min) - @panic("compiler_rt negv: overflow"); - return -a; +pub const panic = common.panic; + +comptime { + @export(__negvsi2, .{ .name = "__negvsi2", .linkage = common.linkage }); + @export(__negvdi2, .{ .name = "__negvdi2", .linkage = common.linkage }); + @export(__negvti2, .{ .name = "__negvti2", .linkage = common.linkage }); } pub fn __negvsi2(a: i32) callconv(.C) i32 { @@ -29,6 +25,20 @@ pub fn __negvti2(a: i128) callconv(.C) i128 { return negvXi(i128, a); } +inline fn negvXi(comptime ST: type, a: ST) ST { + const UT = switch (ST) { + i32 => u32, + i64 => u64, + i128 => u128, + else => unreachable, + }; + const N: UT = @bitSizeOf(ST); + const min: ST = @bitCast(ST, (@as(UT, 1) << (N - 1))); + if (a == min) + @panic("compiler_rt negv: overflow"); + return -a; +} + test { _ = @import("negvsi2_test.zig"); _ = @import("negvdi2_test.zig"); diff --git a/lib/compiler_rt/os_version_check.zig b/lib/compiler_rt/os_version_check.zig @@ -1,5 +1,14 @@ -const testing = @import("std").testing; +const std = @import("std"); +const testing = std.testing; const builtin = @import("builtin"); +const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +pub const panic = @import("common.zig").panic; + +comptime { + if (builtin.os.tag.isDarwin()) { + @export(__isPlatformVersionAtLeast, .{ .name = "__isPlatformVersionAtLeast", .linkage = linkage }); + } +} // Ported from llvm-project 13.0.0 d7b669b3a30345cfcdb2fde2af6f48aa4b94845d // @@ -16,30 +25,32 @@ const builtin = @import("builtin"); // the newer codepath, which merely calls out to the Darwin _availability_version_check API which is // available on macOS 10.15+, iOS 13+, tvOS 13+ and watchOS 6+. -inline fn constructVersion(major: u32, minor: u32, subminor: u32) u32 { - return ((major & 0xffff) << 16) | ((minor & 0xff) << 8) | (subminor & 0xff); -} +const __isPlatformVersionAtLeast = if (builtin.os.tag.isDarwin()) struct { + inline fn constructVersion(major: u32, minor: u32, subminor: u32) u32 { + return ((major & 0xffff) << 16) | ((minor & 0xff) << 8) | (subminor & 0xff); + } -// Darwin-only -pub fn __isPlatformVersionAtLeast(platform: u32, major: u32, minor: u32, subminor: u32) callconv(.C) i32 { - const build_version = dyld_build_version_t{ - .platform = platform, - .version = constructVersion(major, minor, subminor), - }; - return @boolToInt(_availability_version_check(1, &[_]dyld_build_version_t{build_version})); -} + // Darwin-only + fn __isPlatformVersionAtLeast(platform: u32, major: u32, minor: u32, subminor: u32) callconv(.C) i32 { + const build_version = dyld_build_version_t{ + .platform = platform, + .version = constructVersion(major, minor, subminor), + }; + return @boolToInt(_availability_version_check(1, &[_]dyld_build_version_t{build_version})); + } -// _availability_version_check darwin API support. -const dyld_platform_t = u32; -const dyld_build_version_t = extern struct { - platform: dyld_platform_t, - version: u32, -}; -// Darwin-only -extern "c" fn _availability_version_check(count: u32, versions: [*c]const dyld_build_version_t) bool; + // _availability_version_check darwin API support. + const dyld_platform_t = u32; + const dyld_build_version_t = extern struct { + platform: dyld_platform_t, + version: u32, + }; + // Darwin-only + extern "c" fn _availability_version_check(count: u32, versions: [*c]const dyld_build_version_t) bool; +}.__isPlatformVersionAtLeast else struct {}; test "isPlatformVersionAtLeast" { - if (!builtin.os.tag.isDarwin()) return error.SkipZigTest; + if (!comptime builtin.os.tag.isDarwin()) return error.SkipZigTest; // Note: this test depends on the actual host OS version since it is merely calling into the // native Darwin API. diff --git a/lib/compiler_rt/parity.zig b/lib/compiler_rt/parity.zig @@ -1,12 +1,31 @@ +//! parity - if number of bits set is even => 0, else => 1 +//! - pariytXi2_generic for big and little endian + const std = @import("std"); const builtin = @import("builtin"); +const common = @import("common.zig"); -// parity - if number of bits set is even => 0, else => 1 -// - pariytXi2_generic for big and little endian +pub const panic = common.panic; -inline fn parityXi2(comptime T: type, a: T) i32 { - @setRuntimeSafety(builtin.is_test); +comptime { + @export(__paritysi2, .{ .name = "__paritysi2", .linkage = common.linkage }); + @export(__paritydi2, .{ .name = "__paritydi2", .linkage = common.linkage }); + @export(__parityti2, .{ .name = "__parityti2", .linkage = common.linkage }); +} + +pub fn __paritysi2(a: i32) callconv(.C) i32 { + return parityXi2(i32, a); +} + +pub fn __paritydi2(a: i64) callconv(.C) i32 { + return parityXi2(i64, a); +} + +pub fn __parityti2(a: i128) callconv(.C) i32 { + return parityXi2(i128, a); +} +inline fn parityXi2(comptime T: type, a: T) i32 { var x = switch (@bitSizeOf(T)) { 32 => @bitCast(u32, a), 64 => @bitCast(u64, a), @@ -23,18 +42,6 @@ inline fn parityXi2(comptime T: type, a: T) i32 { return (@intCast(u16, 0x6996) >> @intCast(u4, x)) & 1; // optimization for >>2 and >>1 } -pub fn __paritysi2(a: i32) callconv(.C) i32 { - return parityXi2(i32, a); -} - -pub fn __paritydi2(a: i64) callconv(.C) i32 { - return parityXi2(i64, a); -} - -pub fn __parityti2(a: i128) callconv(.C) i32 { - return parityXi2(i128, a); -} - test { _ = @import("paritysi2_test.zig"); _ = @import("paritydi2_test.zig"); diff --git a/lib/compiler_rt/popcount.zig b/lib/compiler_rt/popcount.zig @@ -1,17 +1,36 @@ +//! popcount - population count +//! counts the number of 1 bits +//! SWAR-Popcount: count bits of duos, aggregate to nibbles, and bytes inside +//! x-bit register in parallel to sum up all bytes +//! SWAR-Masks and factors can be defined as 2-adic fractions +//! TAOCP: Combinational Algorithms, Bitwise Tricks And Techniques, +//! subsubsection "Working with the rightmost bits" and "Sideways addition". + const builtin = @import("builtin"); const std = @import("std"); +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__popcountsi2, .{ .name = "__popcountsi2", .linkage = common.linkage }); + @export(__popcountdi2, .{ .name = "__popcountdi2", .linkage = common.linkage }); + @export(__popcountti2, .{ .name = "__popcountti2", .linkage = common.linkage }); +} -// popcount - population count -// counts the number of 1 bits +pub fn __popcountsi2(a: i32) callconv(.C) i32 { + return popcountXi2(i32, a); +} -// SWAR-Popcount: count bits of duos, aggregate to nibbles, and bytes inside -// x-bit register in parallel to sum up all bytes -// SWAR-Masks and factors can be defined as 2-adic fractions -// TAOCP: Combinational Algorithms, Bitwise Tricks And Techniques, -// subsubsection "Working with the rightmost bits" and "Sideways addition". +pub fn __popcountdi2(a: i64) callconv(.C) i32 { + return popcountXi2(i64, a); +} + +pub fn __popcountti2(a: i128) callconv(.C) i32 { + return popcountXi2(i128, a); +} inline fn popcountXi2(comptime ST: type, a: ST) i32 { - @setRuntimeSafety(builtin.is_test); const UT = switch (ST) { i32 => u32, i64 => u64, @@ -30,18 +49,6 @@ inline fn popcountXi2(comptime ST: type, a: ST) i32 { return @intCast(i32, x); } -pub fn __popcountsi2(a: i32) callconv(.C) i32 { - return popcountXi2(i32, a); -} - -pub fn __popcountdi2(a: i64) callconv(.C) i32 { - return popcountXi2(i64, a); -} - -pub fn __popcountti2(a: i128) callconv(.C) i32 { - return popcountXi2(i128, a); -} - test { _ = @import("popcountsi2_test.zig"); _ = @import("popcountdi2_test.zig"); diff --git a/lib/compiler_rt/round.zig b/lib/compiler_rt/round.zig @@ -1,12 +1,27 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/round.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/round.c const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__roundh, .{ .name = "__roundh", .linkage = common.linkage }); + @export(roundf, .{ .name = "roundf", .linkage = common.linkage }); + @export(round, .{ .name = "round", .linkage = common.linkage }); + @export(__roundx, .{ .name = "__roundx", .linkage = common.linkage }); + const roundq_sym_name = if (common.want_ppc_abi) "roundf128" else "roundq"; + @export(roundq, .{ .name = roundq_sym_name, .linkage = common.linkage }); + @export(roundl, .{ .name = "roundl", .linkage = common.linkage }); +} pub fn __roundh(x: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/shift.zig b/lib/compiler_rt/shift.zig @@ -1,13 +1,33 @@ const std = @import("std"); +const builtin = @import("builtin"); const Log2Int = std.math.Log2Int; -const native_endian = @import("builtin").cpu.arch.endian(); +const native_endian = builtin.cpu.arch.endian(); +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__ashlti3, .{ .name = "__ashlti3", .linkage = common.linkage }); + @export(__ashrti3, .{ .name = "__ashrti3", .linkage = common.linkage }); + @export(__lshrti3, .{ .name = "__lshrti3", .linkage = common.linkage }); + + if (common.want_aeabi) { + @export(__aeabi_llsl, .{ .name = "__aeabi_llsl", .linkage = common.linkage }); + @export(__aeabi_lasr, .{ .name = "__aeabi_lasr", .linkage = common.linkage }); + @export(__aeabi_llsr, .{ .name = "__aeabi_llsr", .linkage = common.linkage }); + } else { + @export(__ashldi3, .{ .name = "__ashldi3", .linkage = common.linkage }); + @export(__ashrdi3, .{ .name = "__ashrdi3", .linkage = common.linkage }); + @export(__lshrdi3, .{ .name = "__lshrdi3", .linkage = common.linkage }); + } +} fn Dwords(comptime T: type, comptime signed_half: bool) type { return extern union { - pub const bits = @divExact(@typeInfo(T).Int.bits, 2); - pub const HalfTU = std.meta.Int(.unsigned, bits); - pub const HalfTS = std.meta.Int(.signed, bits); - pub const HalfT = if (signed_half) HalfTS else HalfTU; + const bits = @divExact(@typeInfo(T).Int.bits, 2); + const HalfTU = std.meta.Int(.unsigned, bits); + const HalfTS = std.meta.Int(.signed, bits); + const HalfT = if (signed_half) HalfTS else HalfTU; all: T, s: if (native_endian == .Little) @@ -19,7 +39,7 @@ fn Dwords(comptime T: type, comptime signed_half: bool) type { // Arithmetic shift left // Precondition: 0 <= b < bits_in_dword -pub inline fn ashlXi3(comptime T: type, a: T, b: i32) T { +inline fn ashlXi3(comptime T: type, a: T, b: i32) T { const dwords = Dwords(T, false); const S = Log2Int(dwords.HalfT); @@ -42,7 +62,7 @@ pub inline fn ashlXi3(comptime T: type, a: T, b: i32) T { // Arithmetic shift right // Precondition: 0 <= b < T.bit_count -pub inline fn ashrXi3(comptime T: type, a: T, b: i32) T { +inline fn ashrXi3(comptime T: type, a: T, b: i32) T { const dwords = Dwords(T, true); const S = Log2Int(dwords.HalfT); @@ -69,7 +89,7 @@ pub inline fn ashrXi3(comptime T: type, a: T, b: i32) T { // Logical shift right // Precondition: 0 <= b < T.bit_count -pub inline fn lshrXi3(comptime T: type, a: T, b: i32) T { +inline fn lshrXi3(comptime T: type, a: T, b: i32) T { const dwords = Dwords(T, false); const S = Log2Int(dwords.HalfT); @@ -93,30 +113,34 @@ pub inline fn lshrXi3(comptime T: type, a: T, b: i32) T { pub fn __ashldi3(a: i64, b: i32) callconv(.C) i64 { return ashlXi3(i64, a, b); } +fn __aeabi_llsl(a: i64, b: i32) callconv(.AAPCS) i64 { + return ashlXi3(i64, a, b); +} + pub fn __ashlti3(a: i128, b: i32) callconv(.C) i128 { return ashlXi3(i128, a, b); } + pub fn __ashrdi3(a: i64, b: i32) callconv(.C) i64 { return ashrXi3(i64, a, b); } +fn __aeabi_lasr(a: i64, b: i32) callconv(.AAPCS) i64 { + return ashrXi3(i64, a, b); +} + pub fn __ashrti3(a: i128, b: i32) callconv(.C) i128 { return ashrXi3(i128, a, b); } + pub fn __lshrdi3(a: i64, b: i32) callconv(.C) i64 { return lshrXi3(i64, a, b); } -pub fn __lshrti3(a: i128, b: i32) callconv(.C) i128 { - return lshrXi3(i128, a, b); +fn __aeabi_llsr(a: i64, b: i32) callconv(.AAPCS) i64 { + return lshrXi3(i64, a, b); } -pub fn __aeabi_llsl(a: i64, b: i32) callconv(.AAPCS) i64 { - return ashlXi3(i64, a, b); -} -pub fn __aeabi_lasr(a: i64, b: i32) callconv(.AAPCS) i64 { - return ashrXi3(i64, a, b); -} -pub fn __aeabi_llsr(a: i64, b: i32) callconv(.AAPCS) i64 { - return lshrXi3(i64, a, b); +pub fn __lshrti3(a: i128, b: i32) callconv(.C) i128 { + return lshrXi3(i128, a, b); } test { diff --git a/lib/compiler_rt/sin.zig b/lib/compiler_rt/sin.zig @@ -1,17 +1,32 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/sinf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/sinf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; +pub const panic = common.panic; + +comptime { + @export(__sinh, .{ .name = "__sinh", .linkage = common.linkage }); + @export(sinf, .{ .name = "sinf", .linkage = common.linkage }); + @export(sin, .{ .name = "sin", .linkage = common.linkage }); + @export(__sinx, .{ .name = "__sinx", .linkage = common.linkage }); + const sinq_sym_name = if (common.want_ppc_abi) "sinf128" else "sinq"; + @export(sinq, .{ .name = sinq_sym_name, .linkage = common.linkage }); + @export(sinl, .{ .name = "sinl", .linkage = common.linkage }); +} + pub fn __sinh(x: f16) callconv(.C) f16 { // TODO: more efficient implementation return @floatCast(f16, sinf(x)); diff --git a/lib/compiler_rt/sincos.zig b/lib/compiler_rt/sincos.zig @@ -1,10 +1,23 @@ const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; -const sin = @import("sin.zig"); -const cos = @import("cos.zig"); const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__sincosh, .{ .name = "__sincosh", .linkage = common.linkage }); + @export(sincosf, .{ .name = "sincosf", .linkage = common.linkage }); + @export(sincos, .{ .name = "sincos", .linkage = common.linkage }); + @export(__sincosx, .{ .name = "__sincosx", .linkage = common.linkage }); + const sincosq_sym_name = if (common.want_ppc_abi) "sincosf128" else "sincosq"; + @export(sincosq, .{ .name = sincosq_sym_name, .linkage = common.linkage }); + @export(sincosl, .{ .name = "sincosl", .linkage = common.linkage }); +} pub fn __sincosh(x: f16, r_sin: *f16, r_cos: *f16) callconv(.C) void { // TODO: more efficient implementation @@ -192,7 +205,7 @@ pub fn sincosl(x: c_longdouble, r_sin: *c_longdouble, r_cos: *c_longdouble) call } } -const rem_pio2_generic = @compileError("TODO"); +pub const rem_pio2_generic = @compileError("TODO"); /// Ported from musl sincosl.c. Needs the following dependencies to be complete: /// * rem_pio2_generic ported from __rem_pio2l.c diff --git a/lib/compiler_rt/sparc.zig b/lib/compiler_rt/sparc.zig @@ -1,114 +0,0 @@ -// -// SPARC uses a different naming scheme for its support routines so we map it here to the x86 name. - -const std = @import("std"); -const builtin = @import("builtin"); - -// The SPARC Architecture Manual, Version 9: -// A.13 Floating-Point Compare -const FCMP = enum(i32) { - Equal = 0, - Less = 1, - Greater = 2, - Unordered = 3, -}; - -// Basic arithmetic - -pub fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addXf3.zig").__addtf3(a.*, b.*); -} - -pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("divtf3.zig").__divtf3(a.*, b.*); -} - -pub fn _Qp_mul(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("mulXf3.zig").__multf3(a.*, b.*); -} - -pub fn _Qp_sub(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addXf3.zig").__subtf3(a.*, b.*); -} - -// Comparison - -pub fn _Qp_cmp(a: *f128, b: *f128) callconv(.C) i32 { - return @enumToInt(@import("compareXf2.zig").cmp(f128, FCMP, a.*, b.*)); -} - -pub fn _Qp_feq(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Equal); -} - -pub fn _Qp_fne(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) != @enumToInt(FCMP.Equal); -} - -pub fn _Qp_flt(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Less); -} - -pub fn _Qp_fle(a: *f128, b: *f128) callconv(.C) bool { - const cmp = _Qp_cmp(a, b); - return cmp == @enumToInt(FCMP.Less) or cmp == @enumToInt(FCMP.Equal); -} - -pub fn _Qp_fgt(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Greater); -} - -pub fn _Qp_fge(a: *f128, b: *f128) callconv(.C) bool { - const cmp = _Qp_cmp(a, b); - return cmp == @enumToInt(FCMP.Greater) or cmp == @enumToInt(FCMP.Equal); -} - -// Conversion - -pub fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatsitf(a); -} - -pub fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatunsitf(a); -} - -pub fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatditf(a); -} - -pub fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatunditf(a); -} - -pub fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void { - c.* = @import("extendXfYf2.zig").__extendsftf2(a); -} - -pub fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void { - c.* = @import("extendXfYf2.zig").__extenddftf2(a); -} - -pub fn _Qp_qtoi(a: *f128) callconv(.C) i32 { - return @import("fixXfYi.zig").__fixtfsi(a.*); -} - -pub fn _Qp_qtoui(a: *f128) callconv(.C) u32 { - return @import("fixXfYi.zig").__fixunstfsi(a.*); -} - -pub fn _Qp_qtox(a: *f128) callconv(.C) i64 { - return @import("fixXfYi.zig").__fixtfdi(a.*); -} - -pub fn _Qp_qtoux(a: *f128) callconv(.C) u64 { - return @import("fixXfYi.zig").__fixunstfdi(a.*); -} - -pub fn _Qp_qtos(a: *f128) callconv(.C) f32 { - return @import("truncXfYf2.zig").__trunctfsf2(a.*); -} - -pub fn _Qp_qtod(a: *f128) callconv(.C) f64 { - return @import("truncXfYf2.zig").__trunctfdf2(a.*); -} diff --git a/lib/compiler_rt/sqrt.zig b/lib/compiler_rt/sqrt.zig @@ -1,5 +1,20 @@ const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__sqrth, .{ .name = "__sqrth", .linkage = common.linkage }); + @export(sqrtf, .{ .name = "sqrtf", .linkage = common.linkage }); + @export(sqrt, .{ .name = "sqrt", .linkage = common.linkage }); + @export(__sqrtx, .{ .name = "__sqrtx", .linkage = common.linkage }); + const sqrtq_sym_name = if (common.want_ppc_abi) "sqrtf128" else "sqrtq"; + @export(sqrtq, .{ .name = sqrtq_sym_name, .linkage = common.linkage }); + @export(sqrtl, .{ .name = "sqrtl", .linkage = common.linkage }); +} pub fn __sqrth(x: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/stack_probe.zig b/lib/compiler_rt/stack_probe.zig @@ -1,4 +1,43 @@ -const native_arch = @import("builtin").cpu.arch; +const std = @import("std"); +const builtin = @import("builtin"); +const os_tag = builtin.os.tag; +const arch = builtin.cpu.arch; +const abi = builtin.abi; +const is_test = builtin.is_test; + +const is_gnu = abi.isGnu(); +const is_mingw = os_tag == .windows and is_gnu; + +const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +const strong_linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Strong; +pub const panic = @import("common.zig").panic; + +comptime { + if (builtin.os.tag == .windows) { + // Default stack-probe functions emitted by LLVM + if (is_mingw) { + @export(_chkstk, .{ .name = "_alloca", .linkage = strong_linkage }); + @export(___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = strong_linkage }); + } else if (!builtin.link_libc) { + // This symbols are otherwise exported by MSVCRT.lib + @export(_chkstk, .{ .name = "_chkstk", .linkage = strong_linkage }); + @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); + } + + if (arch.isAARCH64()) { + @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); + } + } + + switch (arch) { + .i386, + .x86_64, + => { + @export(zig_probe_stack, .{ .name = "__zig_probe_stack", .linkage = linkage }); + }, + else => {}, + } +} // Zig's own stack-probe routine (available only on x86 and x86_64) pub fn zig_probe_stack() callconv(.Naked) void { @@ -8,7 +47,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { // invalid so let's update it on the go, otherwise we'll get a segfault // instead of triggering the stack growth. - switch (native_arch) { + switch (arch) { .x86_64 => { // %rax = probe length, %rsp = stack pointer asm volatile ( @@ -60,7 +99,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { fn win_probe_stack_only() void { @setRuntimeSafety(false); - switch (native_arch) { + switch (arch) { .x86_64 => { asm volatile ( \\ push %%rcx @@ -105,7 +144,7 @@ fn win_probe_stack_only() void { }, else => {}, } - if (comptime native_arch.isAARCH64()) { + if (comptime arch.isAARCH64()) { // NOTE: page size hardcoded to 4096 for now asm volatile ( \\ lsl x16, x15, #4 @@ -127,7 +166,7 @@ fn win_probe_stack_only() void { fn win_probe_stack_adjust_sp() void { @setRuntimeSafety(false); - switch (native_arch) { + switch (arch) { .x86_64 => { asm volatile ( \\ push %%rcx @@ -201,9 +240,9 @@ pub fn _chkstk() callconv(.Naked) void { } pub fn __chkstk() callconv(.Naked) void { @setRuntimeSafety(false); - if (comptime native_arch.isAARCH64()) { + if (comptime arch.isAARCH64()) { @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}); - } else switch (native_arch) { + } else switch (arch) { .i386 => @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}), .x86_64 => @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}), else => unreachable, diff --git a/lib/compiler_rt/subdf3.zig b/lib/compiler_rt/subdf3.zig @@ -0,0 +1,21 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = common.linkage }); + } else { + @export(__subdf3, .{ .name = "__subdf3", .linkage = common.linkage }); + } +} + +fn __subdf3(a: f64, b: f64) callconv(.C) f64 { + const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); + return a + neg_b; +} + +fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { + const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subo.zig b/lib/compiler_rt/subo.zig @@ -1,12 +1,31 @@ +//! subo - subtract overflow +//! * return a-%b. +//! * return if a-b overflows => 1 else => 0 +//! - suboXi4_generic as default + +const std = @import("std"); const builtin = @import("builtin"); +const common = @import("common.zig"); + +pub const panic = common.panic; -// subo - subtract overflow -// * return a-%b. -// * return if a-b overflows => 1 else => 0 -// - suboXi4_generic as default +comptime { + @export(__subosi4, .{ .name = "__subosi4", .linkage = common.linkage }); + @export(__subodi4, .{ .name = "__subodi4", .linkage = common.linkage }); + @export(__suboti4, .{ .name = "__suboti4", .linkage = common.linkage }); +} + +pub fn __subosi4(a: i32, b: i32, overflow: *c_int) callconv(.C) i32 { + return suboXi4_generic(i32, a, b, overflow); +} +pub fn __subodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 { + return suboXi4_generic(i64, a, b, overflow); +} +pub fn __suboti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { + return suboXi4_generic(i128, a, b, overflow); +} inline fn suboXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - @setRuntimeSafety(builtin.is_test); overflow.* = 0; var sum: ST = a -% b; // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract @@ -21,16 +40,6 @@ inline fn suboXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST return sum; } -pub fn __subosi4(a: i32, b: i32, overflow: *c_int) callconv(.C) i32 { - return suboXi4_generic(i32, a, b, overflow); -} -pub fn __subodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 { - return suboXi4_generic(i64, a, b, overflow); -} -pub fn __suboti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { - return suboXi4_generic(i128, a, b, overflow); -} - test { _ = @import("subosi4_test.zig"); _ = @import("subodi4_test.zig"); diff --git a/lib/compiler_rt/subsf3.zig b/lib/compiler_rt/subsf3.zig @@ -0,0 +1,21 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = common.linkage }); + } else { + @export(__subsf3, .{ .name = "__subsf3", .linkage = common.linkage }); + } +} + +fn __subsf3(a: f32, b: f32) callconv(.C) f32 { + const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); + return a + neg_b; +} + +fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { + const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subtf3.zig b/lib/compiler_rt/subtf3.zig @@ -0,0 +1,30 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__subkf3, .{ .name = "__subkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = common.linkage }); + } else { + @export(__subtf3, .{ .name = "__subtf3", .linkage = common.linkage }); + } +} + +pub fn __subtf3(a: f128, b: f128) callconv(.C) f128 { + return sub(a, b); +} + +fn __subkf3(a: f128, b: f128) callconv(.C) f128 { + return sub(a, b); +} + +fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.C) void { + c.* = sub(a.*, b.*); +} + +inline fn sub(a: f128, b: f128) f128 { + const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subxf3.zig b/lib/compiler_rt/subxf3.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__subxf3, .{ .name = "__subxf3", .linkage = common.linkage }); +} + +fn __subxf3(a: f80, b: f80) callconv(.C) f80 { + var b_rep = std.math.break_f80(b); + b_rep.exp ^= 0x8000; + const neg_b = std.math.make_f80(b_rep); + return a + neg_b; +} diff --git a/lib/compiler_rt/tan.zig b/lib/compiler_rt/tan.zig @@ -1,11 +1,12 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/tanf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c -// https://golang.org/src/math/tan.go +//! Ported from musl, which is licensed under the MIT license: +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/tanf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c +//! https://golang.org/src/math/tan.go const std = @import("std"); +const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; @@ -13,6 +14,21 @@ const kernel = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__tanh, .{ .name = "__tanh", .linkage = common.linkage }); + @export(tanf, .{ .name = "tanf", .linkage = common.linkage }); + @export(tan, .{ .name = "tan", .linkage = common.linkage }); + @export(__tanx, .{ .name = "__tanx", .linkage = common.linkage }); + const tanq_sym_name = if (common.want_ppc_abi) "tanf128" else "tanq"; + @export(tanq, .{ .name = tanq_sym_name, .linkage = common.linkage }); + @export(tanl, .{ .name = "tanl", .linkage = common.linkage }); +} + pub fn __tanh(x: f16) callconv(.C) f16 { // TODO: more efficient implementation return @floatCast(f16, tanf(x)); diff --git a/lib/compiler_rt/trunc.zig b/lib/compiler_rt/trunc.zig @@ -1,12 +1,27 @@ -// Ported from musl, which is licensed under the MIT license: -// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT -// -// https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c -// https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c +//! Ported from musl, which is MIT licensed. +//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT +//! +//! https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c +//! https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c const std = @import("std"); +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; const math = std.math; const expect = std.testing.expect; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__trunch, .{ .name = "__trunch", .linkage = common.linkage }); + @export(truncf, .{ .name = "truncf", .linkage = common.linkage }); + @export(trunc, .{ .name = "trunc", .linkage = common.linkage }); + @export(__truncx, .{ .name = "__truncx", .linkage = common.linkage }); + const truncq_sym_name = if (common.want_ppc_abi) "truncf128" else "truncq"; + @export(truncq, .{ .name = truncq_sym_name, .linkage = common.linkage }); + @export(truncl, .{ .name = "truncl", .linkage = common.linkage }); +} pub fn __trunch(x: f16) callconv(.C) f16 { // TODO: more efficient implementation diff --git a/lib/compiler_rt/truncXfYf2.zig b/lib/compiler_rt/truncXfYf2.zig @@ -1,152 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const native_arch = builtin.cpu.arch; - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -// TODO remove this; do this type selection in the language rather than -// here in compiler-rt. -pub const F16T = if (native_arch.isAARCH64()) f16 else u16; - -pub fn __truncsfhf2(a: f32) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f32, a)); -} - -pub fn __truncdfhf2(a: f64) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f64, a)); -} - -pub fn __trunctfhf2(a: f128) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f128, a)); -} - -pub fn __trunctfsf2(a: f128) callconv(.C) f32 { - return truncXfYf2(f32, f128, a); -} - -pub fn __trunctfdf2(a: f128) callconv(.C) f64 { - return truncXfYf2(f64, f128, a); -} - -pub fn __truncdfsf2(a: f64) callconv(.C) f32 { - return truncXfYf2(f32, f64, a); -} - -pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return truncXfYf2(f32, f64, a); -} - -pub fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { - @setRuntimeSafety(false); - return @bitCast(F16T, truncXfYf2(f16, f64, a)); -} - -pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { - @setRuntimeSafety(false); - return @bitCast(F16T, truncXfYf2(f16, f32, a)); -} - -inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); - const srcSigBits = std.math.floatMantissaBits(src_t); - const dstSigBits = std.math.floatMantissaBits(dst_t); - const SrcShift = std.math.Log2Int(src_rep_t); - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const srcBits = @typeInfo(src_t).Float.bits; - const srcExpBits = srcBits - srcSigBits - 1; - const srcInfExp = (1 << srcExpBits) - 1; - const srcExpBias = srcInfExp >> 1; - - const srcMinNormal = 1 << srcSigBits; - const srcSignificandMask = srcMinNormal - 1; - const srcInfinity = srcInfExp << srcSigBits; - const srcSignMask = 1 << (srcSigBits + srcExpBits); - const srcAbsMask = srcSignMask - 1; - const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; - const halfway = 1 << (srcSigBits - dstSigBits - 1); - const srcQNaN = 1 << (srcSigBits - 1); - const srcNaNCode = srcQNaN - 1; - - const dstBits = @typeInfo(dst_t).Float.bits; - const dstExpBits = dstBits - dstSigBits - 1; - const dstInfExp = (1 << dstExpBits) - 1; - const dstExpBias = dstInfExp >> 1; - - const underflowExponent = srcExpBias + 1 - dstExpBias; - const overflowExponent = srcExpBias + dstInfExp - dstExpBias; - const underflow = underflowExponent << srcSigBits; - const overflow = overflowExponent << srcSigBits; - - const dstQNaN = 1 << (dstSigBits - 1); - const dstNaNCode = dstQNaN - 1; - - // Break a into a sign and representation of the absolute value - const aRep: src_rep_t = @bitCast(src_rep_t, a); - const aAbs: src_rep_t = aRep & srcAbsMask; - const sign: src_rep_t = aRep & srcSignMask; - var absResult: dst_rep_t = undefined; - - if (aAbs -% underflow < aAbs -% overflow) { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding and adjusting the exponent. - absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); - absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; - - const roundBits: src_rep_t = aAbs & roundMask; - if (roundBits > halfway) { - // Round to nearest - absResult += 1; - } else if (roundBits == halfway) { - // Ties to even - absResult += absResult & 1; - } - } else if (aAbs > srcInfinity) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; - absResult |= dstQNaN; - absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); - } else if (aAbs >= overflow) { - // a overflows to infinity. - absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - const aExp = @intCast(u32, aAbs >> srcSigBits); - const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); - - const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; - - // Right shift by the denormalization amount with sticky. - if (shift > srcSigBits) { - absResult = 0; - } else { - const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); - const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; - absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); - const roundBits: src_rep_t = denormalizedSignificand & roundMask; - if (roundBits > halfway) { - // Round to nearest - absResult += 1; - } else if (roundBits == halfway) { - // Ties to even - absResult += absResult & 1; - } - } - } - - const result: dst_rep_t align(@alignOf(dst_t)) = absResult | - @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); - return @bitCast(dst_t, result); -} - -test { - _ = @import("truncXfYf2_test.zig"); -} diff --git a/lib/compiler_rt/truncXfYf2_test.zig b/lib/compiler_rt/truncXfYf2_test.zig @@ -1,296 +0,0 @@ -const std = @import("std"); -const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; - -fn test__truncsfhf2(a: u32, expected: u16) !void { - const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); - - if (actual == expected) { - return; - } - - return error.TestFailure; -} - -test "truncsfhf2" { - try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN - try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN - - try test__truncsfhf2(0, 0); // 0 - try test__truncsfhf2(0x80000000, 0x8000); // -0 - - try test__truncsfhf2(0x7f800000, 0x7c00); // inf - try test__truncsfhf2(0xff800000, 0xfc00); // -inf - - try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf - try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf - - try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf - try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf - - try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 - try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 - - try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 - try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 - - try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 - try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 - - try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 - try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 - - try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 - try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 - - try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 - try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 - - try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 - try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 - - try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 - - try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 - try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 - - try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 - try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 - - try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 - try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 - - try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 - try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 - try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero -} - -const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; - -fn test__truncdfhf2(a: f64, expected: u16) void { - const rep = @bitCast(u16, __truncdfhf2(a)); - - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7e00) { - if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { - return; - } - } - - @panic("__truncdfhf2 test failure"); -} - -fn test__truncdfhf2_raw(a: u64, expected: u16) void { - const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); - - if (actual == expected) { - return; - } - - @panic("__truncdfhf2 test failure"); -} - -test "truncdfhf2" { - test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN - test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN - - test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf - test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf - - test__truncdfhf2(0.0, 0x0); // zero - test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero - - test__truncdfhf2(3.1415926535, 0x4248); - test__truncdfhf2(-3.1415926535, 0xc248); - - test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); - test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); - test__truncdfhf2(0x1.0p+0, 0x3c00); - test__truncdfhf2(0x1.0p-14, 0x0400); - - // denormal - test__truncdfhf2(0x1.0p-20, 0x0010); - test__truncdfhf2(0x1.0p-24, 0x0001); - test__truncdfhf2(-0x1.0p-24, 0x8001); - test__truncdfhf2(0x1.5p-25, 0x0001); - - // and back to zero - test__truncdfhf2(0x1.0p-25, 0x0000); - test__truncdfhf2(-0x1.0p-25, 0x8000); - - // max (precise) - test__truncdfhf2(65504.0, 0x7bff); - - // max (rounded) - test__truncdfhf2(65519.0, 0x7bff); - - // max (to +inf) - test__truncdfhf2(65520.0, 0x7c00); - test__truncdfhf2(-65520.0, 0xfc00); - test__truncdfhf2(65536.0, 0x7c00); -} - -const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; - -fn test__trunctfsf2(a: f128, expected: u32) void { - const x = __trunctfsf2(a); - - const rep = @bitCast(u32, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { - if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { - return; - } - } - - @panic("__trunctfsf2 test failure"); -} - -test "trunctfsf2" { - // qnan - test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); - // nan - test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); - // inf - test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); - // zero - test__trunctfsf2(0.0, 0x0); - - test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); - test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); - test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); - test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); -} - -const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2; - -fn test__trunctfdf2(a: f128, expected: u64) void { - const x = __trunctfdf2(a); - - const rep = @bitCast(u64, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7ff8000000000000) { - if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { - return; - } - } - - @panic("__trunctfsf2 test failure"); -} - -test "trunctfdf2" { - // qnan - test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); - // nan - test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); - // inf - test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); - // zero - test__trunctfdf2(0.0, 0x0); - - test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); - test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); - test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); - test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); -} - -const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; - -fn test__truncdfsf2(a: f64, expected: u32) void { - const x = __truncdfsf2(a); - - const rep = @bitCast(u32, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { - if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { - return; - } - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfsf2 test failure"); -} - -test "truncdfsf2" { - // nan & qnan - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); - // inf - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); - test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); - - test__truncdfsf2(0.0, 0x0); - test__truncdfsf2(1.0, 0x3f800000); - test__truncdfsf2(-1.0, 0xbf800000); - - // huge number becomes inf - test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); -} - -const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; - -fn test__trunctfhf2(a: f128, expected: u16) void { - const x = __trunctfhf2(a); - - const rep = @bitCast(u16, x); - if (rep == expected) { - return; - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfhf2 test failure"); -} - -test "trunctfhf2" { - // qNaN - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); - // NaN - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); - // inf - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); - test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); - // zero - test__trunctfhf2(0.0, 0x0); - test__trunctfhf2(-0.0, 0x8000); - - test__trunctfhf2(3.1415926535, 0x4248); - test__trunctfhf2(-3.1415926535, 0xc248); - test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); - test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); - test__trunctfhf2(0x1.0p+0, 0x3c00); - test__trunctfhf2(0x1.0p-14, 0x0400); - // denormal - test__trunctfhf2(0x1.0p-20, 0x0010); - test__trunctfhf2(0x1.0p-24, 0x0001); - test__trunctfhf2(-0x1.0p-24, 0x8001); - test__trunctfhf2(0x1.5p-25, 0x0001); - // and back to zero - test__trunctfhf2(0x1.0p-25, 0x0000); - test__trunctfhf2(-0x1.0p-25, 0x8000); - // max (precise) - test__trunctfhf2(65504.0, 0x7bff); - // max (rounded) - test__trunctfhf2(65519.0, 0x7bff); - // max (to +inf) - test__trunctfhf2(65520.0, 0x7c00); - test__trunctfhf2(65536.0, 0x7c00); - test__trunctfhf2(-65520.0, 0xfc00); - - test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); - test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); - test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); - test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); -} diff --git a/lib/compiler_rt/trunc_f80.zig b/lib/compiler_rt/trunc_f80.zig @@ -1,173 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const native_arch = builtin.cpu.arch; -const testing = std.testing; - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -pub const F16T = if (native_arch.isAARCH64()) f16 else u16; - -pub fn __truncxfhf2(a: f80) callconv(.C) F16T { - return @bitCast(F16T, trunc(f16, a)); -} - -pub fn __truncxfsf2(a: f80) callconv(.C) f32 { - return trunc(f32, a); -} - -pub fn __truncxfdf2(a: f80) callconv(.C) f64 { - return trunc(f64, a); -} - -inline fn trunc(comptime dst_t: type, a: f80) dst_t { - @setRuntimeSafety(builtin.is_test); - - const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); - const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - const dst_sig_bits = std.math.floatMantissaBits(dst_t); - - const src_exp_bias = 16383; - - const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; - const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); - - const dst_bits = @typeInfo(dst_t).Float.bits; - const dst_exp_bits = dst_bits - dst_sig_bits - 1; - const dst_inf_exp = (1 << dst_exp_bits) - 1; - const dst_exp_bias = dst_inf_exp >> 1; - - const underflow = src_exp_bias + 1 - dst_exp_bias; - const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; - - const dst_qnan = 1 << (dst_sig_bits - 1); - const dst_nan_mask = dst_qnan - 1; - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.break_f80(a); - const sign = a_rep.exp & 0x8000; - a_rep.exp &= 0x7FFF; - a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; - var abs_result: dst_rep_t = undefined; - - if (a_rep.exp -% underflow < a_rep.exp -% overflow) { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding and adjusting the exponent. - abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; - abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); - abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; - - const round_bits = a_rep.fraction & round_mask; - if (round_bits > halfway) { - // Round to nearest - abs_result += 1; - } else if (round_bits == halfway) { - // Ties to even - abs_result += abs_result & 1; - } - } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; - abs_result |= dst_qnan; - abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); - } else if (a_rep.exp >= overflow) { - // a overflows to infinity. - abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - const shift = src_exp_bias - dst_exp_bias - a_rep.exp; - - // Right shift by the denormalization amount with sticky. - if (shift > src_sig_bits) { - abs_result = 0; - } else { - const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); - const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; - abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); - const round_bits = denormalized_significand & round_mask; - if (round_bits > halfway) { - // Round to nearest - abs_result += 1; - } else if (round_bits == halfway) { - // Ties to even - abs_result += abs_result & 1; - } - } - } - - const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; - return @bitCast(dst_t, result); -} - -pub fn __trunctfxf2(a: f128) callconv(.C) f80 { - const src_sig_bits = std.math.floatMantissaBits(f128); - const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const src_bits = @typeInfo(f128).Float.bits; - const src_exp_bits = src_bits - src_sig_bits - 1; - const src_inf_exp = 0x7FFF; - - const src_inf = src_inf_exp << src_sig_bits; - const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); - const src_abs_mask = src_sign_mask - 1; - const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; - const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); - - // Break a into a sign and representation of the absolute value - const a_rep = @bitCast(u128, a); - const a_abs = a_rep & src_abs_mask; - const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; - const integer_bit = 1 << 63; - - var res: std.math.F80 = undefined; - - if (a_abs > src_inf) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - res.exp = 0x7fff; - res.fraction = 0x8000000000000000; - res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)); - } else { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding, adding the explicit integer bit, and adjusting the exponent - res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; - res.exp = @truncate(u16, a_abs >> src_sig_bits); - - const round_bits = a_abs & round_mask; - if (round_bits > halfway) { - // Round to nearest - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry - } else if (round_bits == halfway) { - // Ties to even - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry - } - if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals - } - - res.exp |= sign; - return std.math.make_f80(res); -} - -fn test__trunctfxf2(a: f128, expected: f80) !void { - const x = __trunctfxf2(a); - try testing.expect(x == expected); -} - -test { - try test__trunctfxf2(1.5, 1.5); - try test__trunctfxf2(2.5, 2.5); - try test__trunctfxf2(-2.5, -2.5); - try test__trunctfxf2(0.0, 0.0); -} diff --git a/lib/compiler_rt/truncdfhf2.zig b/lib/compiler_rt/truncdfhf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = common.linkage }); + } else { + @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage }); + } +} + +pub fn __truncdfhf2(a: f64) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f64, a)); +} + +fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { + return @bitCast(common.F16T, truncf(f16, f64, a)); +} diff --git a/lib/compiler_rt/truncdfsf2.zig b/lib/compiler_rt/truncdfsf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = common.linkage }); + } else { + @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = common.linkage }); + } +} + +pub fn __truncdfsf2(a: f64) callconv(.C) f32 { + return truncf(f32, f64, a); +} + +fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { + return truncf(f32, f64, a); +} diff --git a/lib/compiler_rt/truncf.zig b/lib/compiler_rt/truncf.zig @@ -0,0 +1,187 @@ +const std = @import("std"); + +pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); + const srcSigBits = std.math.floatMantissaBits(src_t); + const dstSigBits = std.math.floatMantissaBits(dst_t); + const SrcShift = std.math.Log2Int(src_rep_t); + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const srcBits = @typeInfo(src_t).Float.bits; + const srcExpBits = srcBits - srcSigBits - 1; + const srcInfExp = (1 << srcExpBits) - 1; + const srcExpBias = srcInfExp >> 1; + + const srcMinNormal = 1 << srcSigBits; + const srcSignificandMask = srcMinNormal - 1; + const srcInfinity = srcInfExp << srcSigBits; + const srcSignMask = 1 << (srcSigBits + srcExpBits); + const srcAbsMask = srcSignMask - 1; + const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; + const halfway = 1 << (srcSigBits - dstSigBits - 1); + const srcQNaN = 1 << (srcSigBits - 1); + const srcNaNCode = srcQNaN - 1; + + const dstBits = @typeInfo(dst_t).Float.bits; + const dstExpBits = dstBits - dstSigBits - 1; + const dstInfExp = (1 << dstExpBits) - 1; + const dstExpBias = dstInfExp >> 1; + + const underflowExponent = srcExpBias + 1 - dstExpBias; + const overflowExponent = srcExpBias + dstInfExp - dstExpBias; + const underflow = underflowExponent << srcSigBits; + const overflow = overflowExponent << srcSigBits; + + const dstQNaN = 1 << (dstSigBits - 1); + const dstNaNCode = dstQNaN - 1; + + // Break a into a sign and representation of the absolute value + const aRep: src_rep_t = @bitCast(src_rep_t, a); + const aAbs: src_rep_t = aRep & srcAbsMask; + const sign: src_rep_t = aRep & srcSignMask; + var absResult: dst_rep_t = undefined; + + if (aAbs -% underflow < aAbs -% overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); + absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; + + const roundBits: src_rep_t = aAbs & roundMask; + if (roundBits > halfway) { + // Round to nearest + absResult += 1; + } else if (roundBits == halfway) { + // Ties to even + absResult += absResult & 1; + } + } else if (aAbs > srcInfinity) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; + absResult |= dstQNaN; + absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); + } else if (aAbs >= overflow) { + // a overflows to infinity. + absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const aExp = @intCast(u32, aAbs >> srcSigBits); + const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); + + const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; + + // Right shift by the denormalization amount with sticky. + if (shift > srcSigBits) { + absResult = 0; + } else { + const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); + const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; + absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); + const roundBits: src_rep_t = denormalizedSignificand & roundMask; + if (roundBits > halfway) { + // Round to nearest + absResult += 1; + } else if (roundBits == halfway) { + // Ties to even + absResult += absResult & 1; + } + } + } + + const result: dst_rep_t align(@alignOf(dst_t)) = absResult | + @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); + return @bitCast(dst_t, result); +} + +pub inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { + const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); + const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + const dst_sig_bits = std.math.floatMantissaBits(dst_t); + + const src_exp_bias = 16383; + + const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; + const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); + + const dst_bits = @typeInfo(dst_t).Float.bits; + const dst_exp_bits = dst_bits - dst_sig_bits - 1; + const dst_inf_exp = (1 << dst_exp_bits) - 1; + const dst_exp_bias = dst_inf_exp >> 1; + + const underflow = src_exp_bias + 1 - dst_exp_bias; + const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; + + const dst_qnan = 1 << (dst_sig_bits - 1); + const dst_nan_mask = dst_qnan - 1; + + // Break a into a sign and representation of the absolute value + var a_rep = std.math.break_f80(a); + const sign = a_rep.exp & 0x8000; + a_rep.exp &= 0x7FFF; + a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; + var abs_result: dst_rep_t = undefined; + + if (a_rep.exp -% underflow < a_rep.exp -% overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; + abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); + abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; + + const round_bits = a_rep.fraction & round_mask; + if (round_bits > halfway) { + // Round to nearest + abs_result += 1; + } else if (round_bits == halfway) { + // Ties to even + abs_result += abs_result & 1; + } + } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; + abs_result |= dst_qnan; + abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); + } else if (a_rep.exp >= overflow) { + // a overflows to infinity. + abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const shift = src_exp_bias - dst_exp_bias - a_rep.exp; + + // Right shift by the denormalization amount with sticky. + if (shift > src_sig_bits) { + abs_result = 0; + } else { + const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); + const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; + abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); + const round_bits = denormalized_significand & round_mask; + if (round_bits > halfway) { + // Round to nearest + abs_result += 1; + } else if (round_bits == halfway) { + // Ties to even + abs_result += abs_result & 1; + } + } + } + + const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; + return @bitCast(dst_t, result); +} + +test { + _ = @import("truncf_test.zig"); +} diff --git a/lib/compiler_rt/truncf_test.zig b/lib/compiler_rt/truncf_test.zig @@ -0,0 +1,306 @@ +const std = @import("std"); +const testing = std.testing; + +const __truncsfhf2 = @import("truncsfhf2.zig").__truncsfhf2; +const __truncdfhf2 = @import("truncdfhf2.zig").__truncdfhf2; +const __truncdfsf2 = @import("truncdfsf2.zig").__truncdfsf2; +const __trunctfhf2 = @import("trunctfhf2.zig").__trunctfhf2; +const __trunctfsf2 = @import("trunctfsf2.zig").__trunctfsf2; +const __trunctfdf2 = @import("trunctfdf2.zig").__trunctfdf2; +const __trunctfxf2 = @import("trunctfxf2.zig").__trunctfxf2; + +fn test__truncsfhf2(a: u32, expected: u16) !void { + const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); + + if (actual == expected) { + return; + } + + return error.TestFailure; +} + +test "truncsfhf2" { + try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN + try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN + + try test__truncsfhf2(0, 0); // 0 + try test__truncsfhf2(0x80000000, 0x8000); // -0 + + try test__truncsfhf2(0x7f800000, 0x7c00); // inf + try test__truncsfhf2(0xff800000, 0xfc00); // -inf + + try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf + try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf + + try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf + try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf + + try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 + try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 + + try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 + try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 + + try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 + try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 + + try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 + try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 + + try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 + try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 + + try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 + try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 + + try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 + try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 + + try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 + + try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 + try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 + + try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 + try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 + + try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 + try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 + + try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 + try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 + try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero +} + +fn test__truncdfhf2(a: f64, expected: u16) void { + const rep = @bitCast(u16, __truncdfhf2(a)); + + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7e00) { + if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { + return; + } + } + + @panic("__truncdfhf2 test failure"); +} + +fn test__truncdfhf2_raw(a: u64, expected: u16) void { + const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); + + if (actual == expected) { + return; + } + + @panic("__truncdfhf2 test failure"); +} + +test "truncdfhf2" { + test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN + test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN + + test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf + test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf + + test__truncdfhf2(0.0, 0x0); // zero + test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero + + test__truncdfhf2(3.1415926535, 0x4248); + test__truncdfhf2(-3.1415926535, 0xc248); + + test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); + test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); + test__truncdfhf2(0x1.0p+0, 0x3c00); + test__truncdfhf2(0x1.0p-14, 0x0400); + + // denormal + test__truncdfhf2(0x1.0p-20, 0x0010); + test__truncdfhf2(0x1.0p-24, 0x0001); + test__truncdfhf2(-0x1.0p-24, 0x8001); + test__truncdfhf2(0x1.5p-25, 0x0001); + + // and back to zero + test__truncdfhf2(0x1.0p-25, 0x0000); + test__truncdfhf2(-0x1.0p-25, 0x8000); + + // max (precise) + test__truncdfhf2(65504.0, 0x7bff); + + // max (rounded) + test__truncdfhf2(65519.0, 0x7bff); + + // max (to +inf) + test__truncdfhf2(65520.0, 0x7c00); + test__truncdfhf2(-65520.0, 0xfc00); + test__truncdfhf2(65536.0, 0x7c00); +} + +fn test__trunctfsf2(a: f128, expected: u32) void { + const x = __trunctfsf2(a); + + const rep = @bitCast(u32, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7fc00000) { + if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { + return; + } + } + + @panic("__trunctfsf2 test failure"); +} + +test "trunctfsf2" { + // qnan + test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); + // nan + test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); + // inf + test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); + // zero + test__trunctfsf2(0.0, 0x0); + + test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); + test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); + test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); + test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); +} + +fn test__trunctfdf2(a: f128, expected: u64) void { + const x = __trunctfdf2(a); + + const rep = @bitCast(u64, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7ff8000000000000) { + if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { + return; + } + } + + @panic("__trunctfsf2 test failure"); +} + +test "trunctfdf2" { + // qnan + test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); + // nan + test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); + // inf + test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); + // zero + test__trunctfdf2(0.0, 0x0); + + test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); + test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); + test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); + test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); +} + +fn test__truncdfsf2(a: f64, expected: u32) void { + const x = __truncdfsf2(a); + + const rep = @bitCast(u32, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7fc00000) { + if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { + return; + } + } + + std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); + + @panic("__trunctfsf2 test failure"); +} + +test "truncdfsf2" { + // nan & qnan + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); + // inf + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); + test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); + + test__truncdfsf2(0.0, 0x0); + test__truncdfsf2(1.0, 0x3f800000); + test__truncdfsf2(-1.0, 0xbf800000); + + // huge number becomes inf + test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); +} + +fn test__trunctfhf2(a: f128, expected: u16) void { + const x = __trunctfhf2(a); + + const rep = @bitCast(u16, x); + if (rep == expected) { + return; + } + + std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); + + @panic("__trunctfhf2 test failure"); +} + +test "trunctfhf2" { + // qNaN + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); + // NaN + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); + // inf + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); + test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); + // zero + test__trunctfhf2(0.0, 0x0); + test__trunctfhf2(-0.0, 0x8000); + + test__trunctfhf2(3.1415926535, 0x4248); + test__trunctfhf2(-3.1415926535, 0xc248); + test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); + test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); + test__trunctfhf2(0x1.0p+0, 0x3c00); + test__trunctfhf2(0x1.0p-14, 0x0400); + // denormal + test__trunctfhf2(0x1.0p-20, 0x0010); + test__trunctfhf2(0x1.0p-24, 0x0001); + test__trunctfhf2(-0x1.0p-24, 0x8001); + test__trunctfhf2(0x1.5p-25, 0x0001); + // and back to zero + test__trunctfhf2(0x1.0p-25, 0x0000); + test__trunctfhf2(-0x1.0p-25, 0x8000); + // max (precise) + test__trunctfhf2(65504.0, 0x7bff); + // max (rounded) + test__trunctfhf2(65519.0, 0x7bff); + // max (to +inf) + test__trunctfhf2(65520.0, 0x7c00); + test__trunctfhf2(65536.0, 0x7c00); + test__trunctfhf2(-65520.0, 0xfc00); + + test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); + test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); + test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); + test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); +} + +test "trunctfxf2" { + try test__trunctfxf2(1.5, 1.5); + try test__trunctfxf2(2.5, 2.5); + try test__trunctfxf2(-2.5, -2.5); + try test__trunctfxf2(0.0, 0.0); +} + +fn test__trunctfxf2(a: f128, expected: f80) !void { + const x = __trunctfxf2(a); + try testing.expect(x == expected); +} diff --git a/lib/compiler_rt/truncsfhf2.zig b/lib/compiler_rt/truncsfhf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.gnu_f16_abi) { + @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = common.linkage }); + } else if (common.want_aeabi) { + @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage }); + } else { + @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage }); + } +} + +pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} + +fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} + +fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} diff --git a/lib/compiler_rt/trunctfdf2.zig b/lib/compiler_rt/trunctfdf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = common.linkage }); + } else { + @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = common.linkage }); + } +} + +pub fn __trunctfdf2(a: f128) callconv(.C) f64 { + return truncf(f64, f128, a); +} + +fn __trunckfdf2(a: f128) callconv(.C) f64 { + return truncf(f64, f128, a); +} + +fn _Qp_qtod(a: *const f128) callconv(.C) f64 { + return truncf(f64, f128, a.*); +} diff --git a/lib/compiler_rt/trunctfhf2.zig b/lib/compiler_rt/trunctfhf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = common.linkage }); +} + +pub fn __trunctfhf2(a: f128) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f128, a)); +} diff --git a/lib/compiler_rt/trunctfsf2.zig b/lib/compiler_rt/trunctfsf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = common.linkage }); + } else { + @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = common.linkage }); + } +} + +pub fn __trunctfsf2(a: f128) callconv(.C) f32 { + return truncf(f32, f128, a); +} + +fn __trunckfsf2(a: f128) callconv(.C) f32 { + return truncf(f32, f128, a); +} + +fn _Qp_qtos(a: *const f128) callconv(.C) f32 { + return truncf(f32, f128, a.*); +} diff --git a/lib/compiler_rt/trunctfxf2.zig b/lib/compiler_rt/trunctfxf2.zig @@ -0,0 +1,66 @@ +const math = @import("std").math; +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage }); +} + +pub fn __trunctfxf2(a: f128) callconv(.C) f80 { + const src_sig_bits = math.floatMantissaBits(f128); + const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const src_bits = @typeInfo(f128).Float.bits; + const src_exp_bits = src_bits - src_sig_bits - 1; + const src_inf_exp = 0x7FFF; + + const src_inf = src_inf_exp << src_sig_bits; + const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); + const src_abs_mask = src_sign_mask - 1; + const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; + const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); + + // Break a into a sign and representation of the absolute value + const a_rep = @bitCast(u128, a); + const a_abs = a_rep & src_abs_mask; + const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; + const integer_bit = 1 << 63; + + var res: math.F80 = undefined; + + if (a_abs > src_inf) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + res.exp = 0x7fff; + res.fraction = 0x8000000000000000; + res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)); + } else { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding, adding the explicit integer bit, and adjusting the exponent + res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; + res.exp = @truncate(u16, a_abs >> src_sig_bits); + + const round_bits = a_abs & round_mask; + if (round_bits > halfway) { + // Round to nearest + const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); + res.exp += carry; + res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry + } else if (round_bits == halfway) { + // Ties to even + const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); + res.exp += carry; + res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry + } + if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals + } + + res.exp |= sign; + return math.make_f80(res); +} diff --git a/lib/compiler_rt/truncxfdf2.zig b/lib/compiler_rt/truncxfdf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = common.linkage }); +} + +fn __truncxfdf2(a: f80) callconv(.C) f64 { + return trunc_f80(f64, a); +} diff --git a/lib/compiler_rt/truncxfhf2.zig b/lib/compiler_rt/truncxfhf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = common.linkage }); +} + +fn __truncxfhf2(a: f80) callconv(.C) common.F16T { + return @bitCast(common.F16T, trunc_f80(f16, a)); +} diff --git a/lib/compiler_rt/truncxfsf2.zig b/lib/compiler_rt/truncxfsf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = common.linkage }); +} + +fn __truncxfsf2(a: f80) callconv(.C) f32 { + return trunc_f80(f32, a); +} diff --git a/lib/compiler_rt/udivmodti4.zig b/lib/compiler_rt/udivmodti4.zig @@ -1,15 +1,36 @@ -const udivmod = @import("udivmod.zig").udivmod; +const std = @import("std"); const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); +const udivmod = @import("udivmod.zig").udivmod; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__udivmodti4_windows_x86_64, .{ .name = "__udivmodti4", .linkage = common.linkage }); + }, + else => {}, + } + } else { + @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = common.linkage }); + } +} pub fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) callconv(.C) u128 { - @setRuntimeSafety(builtin.is_test); return udivmod(u128, a, b, maybe_rem); } -const v128 = @import("std").meta.Vector(2, u64); -pub fn __udivmodti4_windows_x86_64(a: v128, b: v128, maybe_rem: ?*u128) callconv(.C) v128 { - @setRuntimeSafety(builtin.is_test); +const v128 = std.meta.Vector(2, u64); + +fn __udivmodti4_windows_x86_64(a: v128, b: v128, maybe_rem: ?*u128) callconv(.C) v128 { return @bitCast(v128, udivmod(u128, @bitCast(u128, a), @bitCast(u128, b), maybe_rem)); } diff --git a/lib/compiler_rt/udivti3.zig b/lib/compiler_rt/udivti3.zig @@ -1,13 +1,38 @@ -const udivmodti4 = @import("udivmodti4.zig"); +const std = @import("std"); const builtin = @import("builtin"); +const udivmod = @import("udivmod.zig").udivmod; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__udivti3, .{ .name = "__udivti3", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__udivti3_windows_x86_64, .{ .name = "__udivti3", .linkage = common.linkage }); + }, + else => {}, + } + if (arch.isAARCH64()) { + @export(__udivti3, .{ .name = "__udivti3", .linkage = common.linkage }); + } + } else { + @export(__udivti3, .{ .name = "__udivti3", .linkage = common.linkage }); + } +} pub fn __udivti3(a: u128, b: u128) callconv(.C) u128 { - @setRuntimeSafety(builtin.is_test); - return udivmodti4.__udivmodti4(a, b, null); + return udivmod(u128, a, b, null); } -const v128 = @import("std").meta.Vector(2, u64); -pub fn __udivti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { - @setRuntimeSafety(builtin.is_test); - return udivmodti4.__udivmodti4_windows_x86_64(a, b, null); +const v128 = std.meta.Vector(2, u64); + +fn __udivti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { + return @bitCast(v128, udivmod(u128, @bitCast(u128, a), @bitCast(u128, b), null)); } diff --git a/lib/compiler_rt/umodti3.zig b/lib/compiler_rt/umodti3.zig @@ -1,18 +1,42 @@ -const udivmodti4 = @import("udivmodti4.zig"); +const std = @import("std"); const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); +const udivmod = @import("udivmod.zig").udivmod; +const arch = builtin.cpu.arch; +const common = @import("common.zig"); + +pub const panic = common.panic; + +comptime { + if (builtin.os.tag == .windows) { + switch (arch) { + .i386 => { + @export(__umodti3, .{ .name = "__umodti3", .linkage = common.linkage }); + }, + .x86_64 => { + // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI + // that LLVM expects compiler-rt to have. + @export(__umodti3_windows_x86_64, .{ .name = "__umodti3", .linkage = common.linkage }); + }, + else => {}, + } + if (arch.isAARCH64()) { + @export(__umodti3, .{ .name = "__umodti3", .linkage = common.linkage }); + } + } else { + @export(__umodti3, .{ .name = "__umodti3", .linkage = common.linkage }); + } +} pub fn __umodti3(a: u128, b: u128) callconv(.C) u128 { - @setRuntimeSafety(builtin.is_test); var r: u128 = undefined; - _ = udivmodti4.__udivmodti4(a, b, &r); + _ = udivmod(u128, a, b, &r); return r; } -const v128 = @import("std").meta.Vector(2, u64); -pub fn __umodti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { - return @bitCast(v128, @call(.{ .modifier = .always_inline }, __umodti3, .{ - @bitCast(u128, a), - @bitCast(u128, b), - })); +const v128 = std.meta.Vector(2, u64); + +fn __umodti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { + var r: u128 = undefined; + _ = udivmod(u128, @bitCast(u128, a), @bitCast(u128, b), &r); + return @bitCast(v128, r); } diff --git a/lib/compiler_rt/unorddf2.zig b/lib/compiler_rt/unorddf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = common.linkage }); + } else { + @export(__unorddf2, .{ .name = "__unorddf2", .linkage = common.linkage }); + } +} + +pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { + return comparef.unordcmp(f64, a, b); +} + +fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { + return comparef.unordcmp(f64, a, b); +} diff --git a/lib/compiler_rt/unordsf2.zig b/lib/compiler_rt/unordsf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = common.linkage }); + } else { + @export(__unordsf2, .{ .name = "__unordsf2", .linkage = common.linkage }); + } +} + +pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { + return comparef.unordcmp(f32, a, b); +} + +fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { + return comparef.unordcmp(f32, a, b); +} diff --git a/lib/compiler_rt/unordtf2.zig b/lib/compiler_rt/unordtf2.zig @@ -0,0 +1,23 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__unordkf2, .{ .name = "__unordkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + // These exports are handled in cmptf2.zig because unordered comparisons + // are based on calling _Qp_cmp. + } else { + @export(__unordtf2, .{ .name = "__unordtf2", .linkage = common.linkage }); + } +} + +fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { + return comparef.unordcmp(f128, a, b); +} + +fn __unordkf2(a: f128, b: f128) callconv(.C) i32 { + return comparef.unordcmp(f128, a, b); +} diff --git a/src/Compilation.zig b/src/Compilation.zig @@ -92,6 +92,9 @@ unwind_tables: bool, test_evented_io: bool, debug_compiler_runtime_libs: bool, debug_compile_errors: bool, +job_queued_compiler_rt_lib: bool = false, +job_queued_compiler_rt_obj: bool = false, +alloc_failure_occurred: bool = false, c_source_files: []const CSourceFile, clang_argv: []const []const u8, @@ -129,11 +132,11 @@ libssp_static_lib: ?CRTFile = null, /// Populated when we build the libc static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libc_static_lib: ?CRTFile = null, -/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue -/// and resolved before calling linker.flush(). -compiler_rt_static_lib: ?CRTFile = null, -/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue -/// and resolved before calling linker.flush(). +/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated +/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush(). +compiler_rt_lib: ?CRTFile = null, +/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated +/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush(). compiler_rt_obj: ?CRTFile = null, glibc_so_files: ?glibc.BuiltSharedObjects = null, @@ -175,7 +178,7 @@ pub const CRTFile = struct { lock: Cache.Lock, full_object_path: []const u8, - fn deinit(self: *CRTFile, gpa: Allocator) void { + pub fn deinit(self: *CRTFile, gpa: Allocator) void { self.lock.release(); gpa.free(self.full_object_path); self.* = undefined; @@ -223,8 +226,6 @@ const Job = union(enum) { libcxxabi: void, libtsan: void, libssp: void, - compiler_rt_lib: void, - compiler_rt_obj: void, /// needed when not linking libc and using LLVM for code generation because it generates /// calls to, for example, memcpy and memset. zig_libc: void, @@ -1924,13 +1925,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { if (is_exe_or_dyn_lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); - try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} }); + comp.job_queued_compiler_rt_lib = true; } else if (options.output_mode != .Obj) { log.debug("queuing a job to build compiler_rt_obj", .{}); // If build-obj with -fcompiler-rt is requested, that is handled specially // elsewhere. In this case we are making a static library, so we ask // for a compiler-rt object to put in it. - try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} }); + comp.job_queued_compiler_rt_obj = true; } } if (needs_c_symbols) { @@ -1978,7 +1979,7 @@ pub fn destroy(self: *Compilation) void { if (self.libcxxabi_static_lib) |*crt_file| { crt_file.deinit(gpa); } - if (self.compiler_rt_static_lib) |*crt_file| { + if (self.compiler_rt_lib) |*crt_file| { crt_file.deinit(gpa); } if (self.compiler_rt_obj) |*crt_file| { @@ -2020,6 +2021,7 @@ pub fn destroy(self: *Compilation) void { } pub fn clearMiscFailures(comp: *Compilation) void { + comp.alloc_failure_occurred = false; for (comp.misc_failures.values()) |*value| { value.deinit(comp.gpa); } @@ -2532,8 +2534,10 @@ pub fn makeBinFileWritable(self: *Compilation) !void { return self.bin_file.makeWritable(); } +/// This function is temporally single-threaded. pub fn totalErrorCount(self: *Compilation) usize { - var total: usize = self.failed_c_objects.count() + self.misc_failures.count(); + var total: usize = self.failed_c_objects.count() + self.misc_failures.count() + + @boolToInt(self.alloc_failure_occurred); if (self.bin_file.options.module) |module| { total += module.failed_exports.count(); @@ -2590,6 +2594,7 @@ pub fn totalErrorCount(self: *Compilation) usize { return total; } +/// This function is temporally single-threaded. pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { var arena = std.heap.ArenaAllocator.init(self.gpa); errdefer arena.deinit(); @@ -2622,6 +2627,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { for (self.misc_failures.values()) |*value| { try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children); } + if (self.alloc_failure_occurred) { + try AllErrors.addPlain(&arena, &errors, "memory allocation failure"); + } if (self.bin_file.options.module) |module| { { var it = module.failed_files.iterator(); @@ -2739,6 +2747,8 @@ pub fn performAllTheWork( comp.work_queue_wait_group.reset(); defer comp.work_queue_wait_group.wait(); + const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; + { const astgen_frame = tracy.namedFrame("astgen"); defer astgen_frame.end(); @@ -2783,7 +2793,6 @@ pub fn performAllTheWork( } } - const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; if (!use_stage1) { const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls"); defer outdated_and_deleted_decls_frame.end(); @@ -2826,6 +2835,16 @@ pub fn performAllTheWork( } break; } + + if (comp.job_queued_compiler_rt_lib) { + comp.job_queued_compiler_rt_lib = false; + buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib); + } + + if (comp.job_queued_compiler_rt_obj) { + comp.job_queued_compiler_rt_obj = false; + buildCompilerRtOneShot(comp, .Obj, &comp.compiler_rt_obj); + } } fn processOneJob(comp: *Compilation, job: Job) !void { @@ -2996,7 +3015,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { module.semaPkg(pkg) catch |err| switch (err) { error.CurrentWorkingDirectoryUnlinked, error.Unexpected, - => try comp.setMiscFailure( + => comp.lockAndSetMiscFailure( .analyze_pkg, "unexpected problem analyzing package '{s}'", .{pkg.root_src_path}, @@ -3011,7 +3030,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { glibc.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{ + comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{ @errorName(err), }); }; @@ -3022,7 +3041,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { glibc.buildSharedObjects(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .glibc_shared_objects, "unable to build glibc shared objects: {s}", .{@errorName(err)}, @@ -3035,7 +3054,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { musl.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .musl_crt_file, "unable to build musl CRT file: {s}", .{@errorName(err)}, @@ -3048,7 +3067,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { mingw.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .mingw_crt_file, "unable to build mingw-w64 CRT file: {s}", .{@errorName(err)}, @@ -3062,7 +3081,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { const link_lib = comp.bin_file.options.system_libs.keys()[index]; mingw.buildImportLib(comp, link_lib) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .windows_import_lib, "unable to generate DLL import .lib file: {s}", .{@errorName(err)}, @@ -3075,7 +3094,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libunwind.buildStaticLib(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libunwind, "unable to build libunwind: {s}", .{@errorName(err)}, @@ -3088,7 +3107,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libcxx.buildLibCXX(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libcxx, "unable to build libcxx: {s}", .{@errorName(err)}, @@ -3101,7 +3120,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libcxx.buildLibCXXABI(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libcxxabi, "unable to build libcxxabi: {s}", .{@errorName(err)}, @@ -3114,7 +3133,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libtsan.buildTsan(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libtsan, "unable to build TSAN library: {s}", .{@errorName(err)}, @@ -3127,51 +3146,13 @@ fn processOneJob(comp: *Compilation, job: Job) !void { wasi_libc.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .wasi_libc_crt_file, "unable to build WASI libc CRT file: {s}", .{@errorName(err)}, ); }; }, - .compiler_rt_lib => { - const named_frame = tracy.namedFrame("compiler_rt_lib"); - defer named_frame.end(); - - comp.buildOutputFromZig( - "compiler_rt.zig", - .Lib, - &comp.compiler_rt_static_lib, - .compiler_rt, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; - }, - .compiler_rt_obj => { - const named_frame = tracy.namedFrame("compiler_rt_obj"); - defer named_frame.end(); - - comp.buildOutputFromZig( - "compiler_rt.zig", - .Obj, - &comp.compiler_rt_obj, - .compiler_rt, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; - }, .libssp => { const named_frame = tracy.namedFrame("libssp"); defer named_frame.end(); @@ -3184,7 +3165,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( + else => comp.lockAndSetMiscFailure( .libssp, "unable to build libssp: {s}", .{@errorName(err)}, @@ -3203,7 +3184,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( + else => comp.lockAndSetMiscFailure( .zig_libc, "unable to build zig's multitarget libc: {s}", .{@errorName(err)}, @@ -3307,11 +3288,7 @@ fn workerUpdateBuiltinZigFile( comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{ dir_path, @errorName(err), - }) catch |oom| switch (oom) { - error.OutOfMemory => log.err("unable to write builtin.zig to {s}: {s}", .{ - dir_path, @errorName(err), - }), - }; + }); }; } @@ -3525,6 +3502,21 @@ fn workerUpdateCObject( }; } +fn buildCompilerRtOneShot( + comp: *Compilation, + output_mode: std.builtin.OutputMode, + out: *?CRTFile, +) void { + comp.buildOutputFromZig("compiler_rt.zig", output_mode, out, .compiler_rt) catch |err| switch (err) { + error.SubCompilationFailed => return, // error reported already + else => comp.lockAndSetMiscFailure( + .compiler_rt, + "unable to build compiler_rt: {s}", + .{@errorName(err)}, + ), + }; +} + fn reportRetryableCObjectError( comp: *Compilation, c_object: *CObject, @@ -4623,14 +4615,21 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { comp.bin_file.options.object_format != .c; } -fn setMiscFailure( +fn setAllocFailure(comp: *Compilation) void { + log.debug("memory allocation failure", .{}); + comp.alloc_failure_occurred = true; +} + +/// Assumes that Compilation mutex is locked. +/// See also `lockAndSetMiscFailure`. +pub fn setMiscFailure( comp: *Compilation, tag: MiscTask, comptime format: []const u8, args: anytype, -) Allocator.Error!void { - try comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1); - const msg = try std.fmt.allocPrint(comp.gpa, format, args); +) void { + comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1) catch return comp.setAllocFailure(); + const msg = std.fmt.allocPrint(comp.gpa, format, args) catch return comp.setAllocFailure(); const gop = comp.misc_failures.getOrPutAssumeCapacity(tag); if (gop.found_existing) { gop.value_ptr.deinit(comp.gpa); @@ -4638,6 +4637,19 @@ fn setMiscFailure( gop.value_ptr.* = .{ .msg = msg }; } +/// See also `setMiscFailure`. +pub fn lockAndSetMiscFailure( + comp: *Compilation, + tag: MiscTask, + comptime format: []const u8, + args: anytype, +) void { + comp.mutex.lock(); + defer comp.mutex.unlock(); + + return setMiscFailure(comp, tag, format, args); +} + pub fn dump_argv(argv: []const []const u8) void { for (argv[0 .. argv.len - 1]) |arg| { std.debug.print("{s} ", .{arg}); diff --git a/src/ThreadPool.zig b/src/ThreadPool.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const ThreadPool = @This(); +const WaitGroup = @import("WaitGroup.zig"); mutex: std.Thread.Mutex = .{}, cond: std.Thread.Condition = .{}, @@ -19,8 +20,8 @@ const RunProto = switch (builtin.zig_backend) { else => *const fn (*Runnable) void, }; -pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { - self.* = .{ +pub fn init(pool: *ThreadPool, allocator: std.mem.Allocator) !void { + pool.* = .{ .allocator = allocator, .threads = &[_]std.Thread{}, }; @@ -30,48 +31,48 @@ pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { } const thread_count = std.math.max(1, std.Thread.getCpuCount() catch 1); - self.threads = try allocator.alloc(std.Thread, thread_count); - errdefer allocator.free(self.threads); + pool.threads = try allocator.alloc(std.Thread, thread_count); + errdefer allocator.free(pool.threads); // kill and join any threads we spawned previously on error. var spawned: usize = 0; - errdefer self.join(spawned); + errdefer pool.join(spawned); - for (self.threads) |*thread| { - thread.* = try std.Thread.spawn(.{}, worker, .{self}); + for (pool.threads) |*thread| { + thread.* = try std.Thread.spawn(.{}, worker, .{pool}); spawned += 1; } } -pub fn deinit(self: *ThreadPool) void { - self.join(self.threads.len); // kill and join all threads. - self.* = undefined; +pub fn deinit(pool: *ThreadPool) void { + pool.join(pool.threads.len); // kill and join all threads. + pool.* = undefined; } -fn join(self: *ThreadPool, spawned: usize) void { +fn join(pool: *ThreadPool, spawned: usize) void { if (builtin.single_threaded) { return; } { - self.mutex.lock(); - defer self.mutex.unlock(); + pool.mutex.lock(); + defer pool.mutex.unlock(); // ensure future worker threads exit the dequeue loop - self.is_running = false; + pool.is_running = false; } // wake up any sleeping threads (this can be done outside the mutex) // then wait for all the threads we know are spawned to complete. - self.cond.broadcast(); - for (self.threads[0..spawned]) |thread| { + pool.cond.broadcast(); + for (pool.threads[0..spawned]) |thread| { thread.join(); } - self.allocator.free(self.threads); + pool.allocator.free(pool.threads); } -pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { +pub fn spawn(pool: *ThreadPool, comptime func: anytype, args: anytype) !void { if (builtin.single_threaded) { @call(.{}, func, args); return; @@ -98,41 +99,57 @@ pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { }; { - self.mutex.lock(); - defer self.mutex.unlock(); + pool.mutex.lock(); + defer pool.mutex.unlock(); - const closure = try self.allocator.create(Closure); + const closure = try pool.allocator.create(Closure); closure.* = .{ .arguments = args, - .pool = self, + .pool = pool, }; - self.run_queue.prepend(&closure.run_node); + pool.run_queue.prepend(&closure.run_node); } // Notify waiting threads outside the lock to try and keep the critical section small. - self.cond.signal(); + pool.cond.signal(); } -fn worker(self: *ThreadPool) void { - self.mutex.lock(); - defer self.mutex.unlock(); +fn worker(pool: *ThreadPool) void { + pool.mutex.lock(); + defer pool.mutex.unlock(); while (true) { - while (self.run_queue.popFirst()) |run_node| { + while (pool.run_queue.popFirst()) |run_node| { // Temporarily unlock the mutex in order to execute the run_node - self.mutex.unlock(); - defer self.mutex.lock(); + pool.mutex.unlock(); + defer pool.mutex.lock(); const runFn = run_node.data.runFn; runFn(&run_node.data); } // Stop executing instead of waiting if the thread pool is no longer running. - if (self.is_running) { - self.cond.wait(&self.mutex); + if (pool.is_running) { + pool.cond.wait(&pool.mutex); } else { break; } } } + +pub fn waitAndWork(pool: *ThreadPool, wait_group: *WaitGroup) void { + while (!wait_group.isDone()) { + if (blk: { + pool.mutex.lock(); + defer pool.mutex.unlock(); + break :blk pool.run_queue.popFirst(); + }) |run_node| { + run_node.data.runFn(&run_node.data); + continue; + } + + wait_group.wait(); + return; + } +} diff --git a/src/WaitGroup.zig b/src/WaitGroup.zig @@ -37,3 +37,10 @@ pub fn reset(self: *WaitGroup) void { self.state.store(0, .Monotonic); self.event.reset(); } + +pub fn isDone(wg: *WaitGroup) bool { + const state = wg.state.load(.Acquire); + assert(state & is_waiting == 0); + + return (state / one_pending) == 0; +} diff --git a/src/link.zig b/src/link.zig @@ -792,11 +792,8 @@ pub const File = struct { }), } } - if (base.options.object_format == .macho) { - try base.cast(MachO).?.flushObject(comp, prog_node); - } else { - try base.flushModule(comp, prog_node); - } + try base.flushModule(comp, prog_node); + const dirname = fs.path.dirname(full_out_path_z) orelse "."; break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? }); } else null; diff --git a/src/link/Coff.zig b/src/link/Coff.zig @@ -1354,7 +1354,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! } // MSVC compiler_rt is missing some stuff, so we build it unconditionally but // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. - if (comp.compiler_rt_static_lib) |lib| { + if (comp.compiler_rt_lib) |lib| { try argv.append(lib.full_object_path); } } diff --git a/src/link/Elf.zig b/src/link/Elf.zig @@ -1272,7 +1272,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const stack_size = self.base.options.stack_size_override orelse 16777216; const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; const compiler_rt_path: ?[]const u8 = blk: { - if (comp.compiler_rt_static_lib) |x| break :blk x.full_object_path; + if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; break :blk null; }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig @@ -436,7 +436,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !v return error.TODOImplementWritingStaticLibFiles; } } - try self.flushModule(comp, prog_node); + return self.flushModule(comp, prog_node); } pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { @@ -444,8 +444,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No defer tracy.end(); const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; - if (!use_stage1 and self.base.options.output_mode == .Obj) - return self.flushObject(comp, prog_node); + + if (build_options.have_llvm and !use_stage1) { + if (self.llvm_object) |llvm_object| { + try llvm_object.flushModule(comp, prog_node); + + llvm_object.destroy(self.base.allocator); + self.llvm_object = null; + + if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { + return; + } + } + } + + var sub_prog_node = prog_node.start("MachO Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); defer arena_allocator.deinit(); @@ -454,12 +469,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); - if (self.d_sym) |*d_sym| { - if (self.base.options.module) |module| { - try d_sym.dwarf.flushModule(&self.base, module); - } - } - // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { @@ -482,8 +491,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const obj_basename = self.base.intermediary_basename orelse break :blk null; - try self.flushObject(comp, prog_node); - if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, obj_basename }); } else { @@ -491,9 +498,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No } } else null; - var sub_prog_node = prog_node.start("MachO Flush", 0); - sub_prog_node.activate(); - defer sub_prog_node.end(); + if (self.d_sym) |*d_sym| { + if (self.base.options.module) |module| { + try d_sym.dwarf.flushModule(&self.base, module); + } + } const is_lib = self.base.options.output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; @@ -738,7 +747,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try positionals.append(p); } - if (comp.compiler_rt_static_lib) |lib| { + if (comp.compiler_rt_lib) |lib| { try positionals.append(lib.full_object_path); } @@ -1119,17 +1128,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No self.cold_start = false; } -pub fn flushObject(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { - const tracy = trace(@src()); - defer tracy.end(); - - if (build_options.have_llvm) - if (self.llvm_object) |llvm_object| - return llvm_object.flushModule(comp, prog_node); - - return error.TODOImplementWritingObjFiles; -} - fn resolveSearchDir( arena: Allocator, dir: []const u8, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig @@ -2255,7 +2255,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const is_obj = self.base.options.output_mode == .Obj; const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj) - comp.compiler_rt_static_lib.?.full_object_path + comp.compiler_rt_lib.?.full_object_path else null; diff --git a/src/musl.zig b/src/musl.zig @@ -4,7 +4,6 @@ const mem = std.mem; const path = std.fs.path; const assert = std.debug.assert; -const target_util = @import("target.zig"); const Compilation = @import("Compilation.zig"); const build_options = @import("build_options");