Merge remote-tracking branch 'origin/master' into llvm14

This commit is contained in:
Andrew Kelley 2022-07-01 15:52:54 -07:00
commit c89dd15e1b
2552 changed files with 159639 additions and 67915 deletions

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,7 @@
contact_links:
- name: Language Proposal
about: Propose to improve the Zig language
url: https://github.com/ziglang/zig/wiki/Language-Proposals
- name: Question
about: Please use one of the community spaces for questions or general discussions.
url: https://github.com/ziglang/zig/wiki/Community

View File

@ -1,16 +0,0 @@
name: Language Proposal
description: Propose to improve the Zig language
labels: ["proposal"]
body:
- type: markdown
attributes:
value: |
Thank you for your interest in improving the Zig language. However, we are
not accepting new proposals to change the language at this time.
- type: checkboxes
id: trash
attributes:
label: Please do not file a proposal to change the language
options:
- label: "I understand, thank you. I will not submit a new proposal at this time"
required: true

View File

@ -1,20 +0,0 @@
name: Question
description: Ask a Zig-related question
labels: ["question"]
body:
- type: markdown
attributes:
value: |
Welcome! There are a bunch of great places to ask Zig-related questions.
Please take a look at
[The Community Wiki Page](https://github.com/ziglang/zig/wiki/Community) and
find a comfy place to ask questions. You will find plenty of helpful people in
these spaces. However, this issue tracker is not for questions. It is for
more actionable items such as bug reports and enhancements.
- type: checkboxes
id: trash
attributes:
label: Please do not open a question issue on the bug tracker
options:
- label: "I understand, thank you. I will take my question to one of the community spaces instead"
required: true

View File

@ -12,7 +12,7 @@ if(NOT CMAKE_BUILD_TYPE)
endif()
if(NOT CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE STRING
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage1" CACHE STRING
"Directory to install zig to" FORCE)
endif()
@ -63,7 +63,7 @@ if("${ZIG_VERSION}" STREQUAL "")
endif()
endif()
endif()
message("Configuring zig version ${ZIG_VERSION}")
message(STATUS "Configuring zig version ${ZIG_VERSION}")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
@ -398,6 +398,9 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/debug.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/AT.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/ATE.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/FORM.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/LANG.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/OP.zig"
"${CMAKE_SOURCE_DIR}/lib/std/dwarf/TAG.zig"
"${CMAKE_SOURCE_DIR}/lib/std/elf.zig"
@ -441,9 +444,8 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/math.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/big.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/big/int.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/floor.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/float.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/frexp.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/inf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/isinf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/isnan.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/ln.zig"
@ -460,12 +462,14 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/meta/trait.zig"
"${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/darwin.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/errno/generic.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/io_uring.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/posix_spawn.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/ntstatus.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/windows/win32error.zig"
@ -474,74 +478,180 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/process.zig"
"${CMAKE_SOURCE_DIR}/lib/std/rand.zig"
"${CMAKE_SOURCE_DIR}/lib/std/sort.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/absv.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/clear_cache.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/cmp.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/compareXf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/count0bits.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divdf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divsf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divtf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extendXfYf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixdfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixint.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixsfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixtfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixuint.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunsdfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunssfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfdi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfsi.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixunstfti.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatXisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatdidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatditf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatsiXf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floattidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floattitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatundidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatundisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunditf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatunsitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntidf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntisf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatuntitf.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/int.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulo.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXi2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negv.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/parity.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcount.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/shift.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/stack_probe.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/truncXfYf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmod.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmodti4.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivti3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/umodti3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/absv.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"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/aullrem.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/bswap.zig"
"${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/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"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/divsf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/divtf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/divti3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/divxf3.zig"
"${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/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/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/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/negXi2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/os_version_check.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/parity.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/popcount.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/rem_pio2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/rem_pio2_large.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/rem_pio2f.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/round.zig"
"${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/sqrt.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negsf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negdf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negtf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negxf2.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/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"
@ -561,16 +671,16 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/target/wasm.zig"
"${CMAKE_SOURCE_DIR}/lib/std/target/x86.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/AutoResetEvent.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/Futex.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/Mutex.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/ResetEvent.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/StaticResetEvent.zig"
"${CMAKE_SOURCE_DIR}/lib/std/time.zig"
"${CMAKE_SOURCE_DIR}/lib/std/treap.zig"
"${CMAKE_SOURCE_DIR}/lib/std/unicode.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/CrossTarget.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/parse.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/string_literal.zig"
@ -597,14 +707,22 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/sparc64/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/sparc64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/sparc64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/sparc64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/sparc64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"
@ -612,6 +730,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/clang.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
@ -655,6 +774,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/print_env.zig"
"${CMAKE_SOURCE_DIR}/src/print_targets.zig"
"${CMAKE_SOURCE_DIR}/src/print_zir.zig"
"${CMAKE_SOURCE_DIR}/src/register_manager.zig"
"${CMAKE_SOURCE_DIR}/src/stage1.zig"
"${CMAKE_SOURCE_DIR}/src/target.zig"
"${CMAKE_SOURCE_DIR}/src/tracy.zig"
@ -791,6 +911,9 @@ add_library(opt_c_util STATIC ${OPTIMIZED_C_SOURCES})
set_target_properties(opt_c_util PROPERTIES
COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}"
)
target_include_directories(opt_c_util PRIVATE
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e-prebuilt"
)
add_library(zigstage1 STATIC ${STAGE1_SOURCES})
set_target_properties(zigstage1 PROPERTIES
@ -834,7 +957,7 @@ else()
set(ZIG1_RELEASE_ARG -OReleaseFast --strip)
endif()
if(ZIG_SINGLE_THREADED)
set(ZIG1_SINGLE_THREADED_ARG "--single-threaded")
set(ZIG1_SINGLE_THREADED_ARG "-fsingle-threaded")
else()
set(ZIG1_SINGLE_THREADED_ARG "")
endif()
@ -852,7 +975,7 @@ set(BUILD_ZIG1_ARGS
-lc
--pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
--pkg-end
--pkg-begin compiler_rt "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
--pkg-begin compiler_rt "${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig"
--pkg-end
)

View File

@ -9,8 +9,8 @@ A general-purpose programming language and toolchain for maintaining
* [Download & Documentation](https://ziglang.org/download)
* [Chapter 0 - Getting Started | ZigLearn.org](https://ziglearn.org/)
* [Community](https://github.com/ziglang/zig/wiki/Community)
* [Contributing](https://github.com/ziglang/zig/blob/master/CONTRIBUTING.md)
* [Code of Conduct](https://github.com/ziglang/zig/blob/master/CODE_OF_CONDUCT.md)
* [Contributing](https://github.com/ziglang/zig/blob/master/.github/CONTRIBUTING.md)
* [Code of Conduct](https://github.com/ziglang/zig/blob/master/.github/CODE_OF_CONDUCT.md)
* [Frequently Asked Questions](https://github.com/ziglang/zig/wiki/FAQ)
* [Community Projects](https://github.com/ziglang/zig/wiki/Community-Projects)

312
build.zig
View File

@ -19,7 +19,7 @@ pub fn build(b: *Builder) !void {
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false;
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
docgen_exe.single_threaded = single_threaded;
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
@ -27,7 +27,7 @@ pub fn build(b: *Builder) !void {
b.allocator,
&[_][]const u8{ b.cache_root, "langref.html" },
) catch unreachable;
var docgen_cmd = docgen_exe.run();
const docgen_cmd = docgen_exe.run();
docgen_cmd.addArgs(&[_][]const u8{
rel_zig_exe,
"doc" ++ fs.path.sep_str ++ "langref.html.in",
@ -40,10 +40,10 @@ pub fn build(b: *Builder) !void {
const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
var test_stage2 = b.addTest("src/test.zig");
test_stage2.setBuildMode(mode);
test_stage2.addPackagePath("test_cases", "test/cases.zig");
test_stage2.single_threaded = single_threaded;
var test_cases = b.addTest("src/test.zig");
test_cases.setBuildMode(mode);
test_cases.addPackagePath("test_cases", "test/cases.zig");
test_cases.single_threaded = single_threaded;
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
@ -54,12 +54,14 @@ pub fn build(b: *Builder) !void {
const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false;
const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false;
const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false;
const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
const skip_stage1 = b.option(bool, "skip-stage1", "Main test suite skips stage1 compile error tests") orelse false;
const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
const skip_stage2_tests = b.option(bool, "skip-stage2-tests", "Main test suite skips self-hosted compiler tests") orelse false;
const skip_install_lib_files = b.option(bool, "skip-install-lib-files", "Do not copy lib/ files to installation prefix") orelse false;
const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;
const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
@ -128,6 +130,8 @@ pub fn build(b: *Builder) !void {
const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false;
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
const use_zig0 = b.option(bool, "zig0", "Bootstrap using zig0") orelse false;
const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
if (strip) break :blk @as(u32, 0);
@ -135,23 +139,29 @@ pub fn build(b: *Builder) !void {
break :blk 4;
};
const main_file = if (is_stage1) "src/stage1.zig" else "src/main.zig";
const main_file: ?[]const u8 = mf: {
if (!is_stage1) break :mf "src/main.zig";
if (use_zig0) break :mf null;
break :mf "src/stage1.zig";
};
var exe = b.addExecutable("zig", main_file);
const exe = b.addExecutable("zig", main_file);
exe.strip = strip;
exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false;
exe.install();
exe.setBuildMode(mode);
exe.setTarget(target);
if (!skip_stage2_tests) {
toolchain_step.dependOn(&exe.step);
}
b.default_step.dependOn(&exe.step);
exe.single_threaded = single_threaded;
if (target.isWindows() and target.getAbi() == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
test_stage2.want_lto = false;
test_cases.want_lto = false;
}
const exe_options = b.addOptions();
@ -166,59 +176,9 @@ pub fn build(b: *Builder) !void {
exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
exe_options.addOption(bool, "force_gpa", force_gpa);
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
if (is_stage1) {
exe.addIncludePath("src");
exe.addIncludePath("deps/SoftFloat-3e/source/include");
test_stage2.addIncludePath("src");
test_stage2.addIncludePath("deps/SoftFloat-3e/source/include");
// This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
// of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
// is pointless.
exe.addPackagePath("compiler_rt", "src/empty.zig");
exe.defineCMacro("ZIG_LINK_MODE", "Static");
test_stage2.defineCMacro("ZIG_LINK_MODE", "Static");
const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast);
softfloat.setTarget(target);
softfloat.addIncludePath("deps/SoftFloat-3e-prebuilt");
softfloat.addIncludePath("deps/SoftFloat-3e/source/8086");
softfloat.addIncludePath("deps/SoftFloat-3e/source/include");
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
softfloat.single_threaded = single_threaded;
exe.linkLibrary(softfloat);
test_stage2.linkLibrary(softfloat);
exe.addCSourceFiles(&stage1_sources, &exe_cflags);
exe.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
test_stage2.addCSourceFiles(&stage1_sources, &exe_cflags);
test_stage2.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
// That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
// the information passed on to us from cmake.
if (cfg.cmake_prefix_path.len > 0) {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
try addCmakeCfgOptionsToExe(b, cfg, test_stage2, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
try addStaticLlvmOptionsToExe(test_stage2);
}
}
if (link_libc) {
exe.linkLibC();
test_stage2.linkLibC();
test_cases.linkLibC();
}
const is_debug = mode == .Debug;
@ -227,6 +187,10 @@ pub fn build(b: *Builder) !void {
const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
const version = if (opt_version_string) |version| version else v: {
if (!std.process.can_spawn) {
std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{});
std.process.exit(1);
}
const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
var code: u8 = undefined;
@ -276,6 +240,112 @@ pub fn build(b: *Builder) !void {
};
exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
if (is_stage1) {
const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast);
softfloat.setTarget(target);
softfloat.addIncludePath("deps/SoftFloat-3e-prebuilt");
softfloat.addIncludePath("deps/SoftFloat-3e/source/8086");
softfloat.addIncludePath("deps/SoftFloat-3e/source/include");
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
softfloat.single_threaded = single_threaded;
const zig0 = b.addExecutable("zig0", null);
zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags);
zig0.addIncludePath("zig-cache/tmp"); // for config.h
zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major}));
zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor}));
zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
for ([_]*std.build.LibExeObjStep{ zig0, exe, test_cases }) |artifact| {
artifact.addIncludePath("src");
artifact.addIncludePath("deps/SoftFloat-3e/source/include");
artifact.addIncludePath("deps/SoftFloat-3e-prebuilt");
artifact.defineCMacro("ZIG_LINK_MODE", "Static");
artifact.addCSourceFiles(&stage1_sources, &exe_cflags);
artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
artifact.linkLibrary(softfloat);
artifact.linkLibCpp();
}
try addStaticLlvmOptionsToExe(zig0);
const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch());
const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) });
const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" });
const zig1_obj = zig0.run();
zig1_obj.addArgs(&.{
"src/stage1.zig",
"-target",
try target.zigTriple(b.allocator),
"-mcpu=baseline",
"--name",
"zig1",
"--zig-lib-dir",
b.pathFromRoot("lib"),
b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}),
"-fcompiler-rt",
"-lc",
});
{
zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" });
zig1_obj.addFileSourceArg(exe_options.getSource());
zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" });
}
switch (mode) {
.Debug => {},
.ReleaseFast => {
zig1_obj.addArg("-OReleaseFast");
zig1_obj.addArg("--strip");
},
.ReleaseSafe => {
zig1_obj.addArg("-OReleaseSafe");
zig1_obj.addArg("--strip");
},
.ReleaseSmall => {
zig1_obj.addArg("-OReleaseSmall");
zig1_obj.addArg("--strip");
},
}
if (single_threaded orelse false) {
zig1_obj.addArg("-fsingle-threaded");
}
if (use_zig0) {
exe.step.dependOn(&zig1_obj.step);
exe.addObjectFile(zig1_obj_path);
}
// This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
// of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
// is pointless.
exe.addPackagePath("compiler_rt", "src/empty.zig");
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
// That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
// the information passed on to us from cmake.
if (cfg.cmake_prefix_path.len > 0) {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
try addStaticLlvmOptionsToExe(test_cases);
}
}
const semver = try std.SemanticVersion.parse(version);
exe_options.addOption(std.SemanticVersion, "semver", semver);
@ -284,6 +354,7 @@ pub fn build(b: *Builder) !void {
exe_options.addOption(bool, "enable_tracy", tracy != null);
exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
exe_options.addOption(bool, "value_tracing", value_tracing);
exe_options.addOption(bool, "is_stage1", is_stage1);
exe_options.addOption(bool, "omit_stage2", omit_stage2);
if (tracy) |tracy_path| {
@ -313,34 +384,37 @@ pub fn build(b: *Builder) !void {
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
const test_stage2_options = b.addOptions();
test_stage2.addOptions("build_options", test_stage2_options);
const test_cases_options = b.addOptions();
test_cases.addOptions("build_options", test_cases_options);
test_stage2_options.addOption(bool, "enable_logging", enable_logging);
test_stage2_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
test_stage2_options.addOption(bool, "skip_non_native", skip_non_native);
test_stage2_options.addOption(bool, "skip_compile_errors", skip_compile_errors);
test_stage2_options.addOption(bool, "is_stage1", is_stage1);
test_stage2_options.addOption(bool, "omit_stage2", omit_stage2);
test_stage2_options.addOption(bool, "have_llvm", enable_llvm);
test_stage2_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
test_stage2_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
test_stage2_options.addOption(bool, "llvm_has_ve", llvm_has_ve);
test_stage2_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
test_stage2_options.addOption(bool, "enable_qemu", b.enable_qemu);
test_stage2_options.addOption(bool, "enable_wine", b.enable_wine);
test_stage2_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
test_stage2_options.addOption(bool, "enable_rosetta", b.enable_rosetta);
test_stage2_options.addOption(bool, "enable_darling", b.enable_darling);
test_stage2_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2);
test_stage2_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir);
test_stage2_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
test_stage2_options.addOption(std.SemanticVersion, "semver", semver);
test_cases_options.addOption(bool, "enable_logging", enable_logging);
test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
test_cases_options.addOption(bool, "is_stage1", is_stage1);
test_cases_options.addOption(bool, "omit_stage2", omit_stage2);
test_cases_options.addOption(bool, "have_llvm", enable_llvm);
test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
test_cases_options.addOption(bool, "llvm_has_ve", llvm_has_ve);
test_cases_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
test_cases_options.addOption(bool, "force_gpa", force_gpa);
test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu);
test_cases_options.addOption(bool, "enable_wine", b.enable_wine);
test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
test_cases_options.addOption(bool, "enable_rosetta", b.enable_rosetta);
test_cases_options.addOption(bool, "enable_darling", b.enable_darling);
test_cases_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2);
test_cases_options.addOption(bool, "value_tracing", value_tracing);
test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir);
test_cases_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
test_cases_options.addOption(std.SemanticVersion, "semver", semver);
test_cases_options.addOption(?[]const u8, "test_filter", test_filter);
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
test_stage2_step.dependOn(&test_stage2.step);
const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
test_cases_step.dependOn(&test_cases.step);
if (!skip_stage2_tests) {
toolchain_step.dependOn(test_stage2_step);
toolchain_step.dependOn(test_cases_step);
}
var chosen_modes: [4]builtin.Mode = undefined;
@ -375,41 +449,50 @@ pub fn build(b: *Builder) !void {
"behavior",
"Run the behavior tests",
modes,
false, // skip_single_threaded
skip_single_threaded,
skip_non_native,
skip_libc,
skip_stage1,
omit_stage2,
is_stage1,
));
toolchain_step.dependOn(tests.addPkgTests(
b,
test_filter,
"lib/std/special/compiler_rt.zig",
"lib/compiler_rt.zig",
"compiler-rt",
"Run the compiler_rt tests",
modes,
true, // skip_single_threaded
skip_non_native,
true, // skip_libc
skip_stage1,
omit_stage2 or true, // TODO get these all passing
is_stage1,
));
toolchain_step.dependOn(tests.addPkgTests(
b,
test_filter,
"lib/std/special/c.zig",
"minilibc",
"Run the mini libc tests",
"lib/c.zig",
"universal-libc",
"Run the universal libc tests",
modes,
true, // skip_single_threaded
skip_non_native,
true, // skip_libc
skip_stage1,
omit_stage2 or true, // TODO get these all passing
is_stage1,
));
toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addStandaloneTests(b, test_filter, modes, skip_non_native, enable_macos_sdk, target));
toolchain_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk));
toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
if (!skip_run_translated_c) {
toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
@ -424,9 +507,12 @@ pub fn build(b: *Builder) !void {
"std",
"Run the standard library tests",
modes,
false,
skip_single_threaded,
skip_non_native,
skip_libc,
skip_stage1,
omit_stage2 or true, // TODO get these all passing
is_stage1,
);
const test_step = b.step("test", "Run all the tests");
@ -499,9 +585,7 @@ fn addCmakeCfgOptionsToExe(
}
}
fn addStaticLlvmOptionsToExe(
exe: *std.build.LibExeObjStep,
) !void {
fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
// Adds the Zig C++ sources which both stage1 and stage2 need.
//
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
@ -542,11 +626,14 @@ fn addCxxKnownPath(
errtxt: ?[]const u8,
need_cpp_includes: bool,
) !void {
if (!std.process.can_spawn)
return error.RequiredLibraryNotFound;
const path_padded = try b.exec(&[_][]const u8{
ctx.cxx_compiler,
b.fmt("-print-file-name={s}", .{objname}),
});
const path_unpadded = mem.tokenize(u8, path_padded, "\r\n").next().?;
var tokenizer = mem.tokenize(u8, path_padded, "\r\n");
const path_unpadded = tokenizer.next().?;
if (mem.eql(u8, path_unpadded, objname)) {
if (errtxt) |msg| {
std.debug.print("{s}", .{msg});
@ -688,15 +775,19 @@ fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c",
"deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c",
"deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c",
"deps/SoftFloat-3e/source/f128M_add.c",
@ -716,6 +807,7 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/f128M_to_f16.c",
"deps/SoftFloat-3e/source/f128M_to_f32.c",
"deps/SoftFloat-3e/source/f128M_to_f64.c",
"deps/SoftFloat-3e/source/f128M_to_extF80M.c",
"deps/SoftFloat-3e/source/f128M_to_i32.c",
"deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_i64.c",
@ -724,6 +816,20 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_ui64.c",
"deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c",
"deps/SoftFloat-3e/source/extF80M_add.c",
"deps/SoftFloat-3e/source/extF80M_div.c",
"deps/SoftFloat-3e/source/extF80M_eq.c",
"deps/SoftFloat-3e/source/extF80M_le.c",
"deps/SoftFloat-3e/source/extF80M_lt.c",
"deps/SoftFloat-3e/source/extF80M_mul.c",
"deps/SoftFloat-3e/source/extF80M_rem.c",
"deps/SoftFloat-3e/source/extF80M_roundToInt.c",
"deps/SoftFloat-3e/source/extF80M_sqrt.c",
"deps/SoftFloat-3e/source/extF80M_sub.c",
"deps/SoftFloat-3e/source/extF80M_to_f16.c",
"deps/SoftFloat-3e/source/extF80M_to_f32.c",
"deps/SoftFloat-3e/source/extF80M_to_f64.c",
"deps/SoftFloat-3e/source/extF80M_to_f128M.c",
"deps/SoftFloat-3e/source/f16_add.c",
"deps/SoftFloat-3e/source/f16_div.c",
"deps/SoftFloat-3e/source/f16_eq.c",
@ -735,9 +841,12 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/f16_roundToInt.c",
"deps/SoftFloat-3e/source/f16_sqrt.c",
"deps/SoftFloat-3e/source/f16_sub.c",
"deps/SoftFloat-3e/source/f16_to_extF80M.c",
"deps/SoftFloat-3e/source/f16_to_f128M.c",
"deps/SoftFloat-3e/source/f16_to_f64.c",
"deps/SoftFloat-3e/source/f32_to_extF80M.c",
"deps/SoftFloat-3e/source/f32_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_extF80M.c",
"deps/SoftFloat-3e/source/f64_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_f16.c",
"deps/SoftFloat-3e/source/i32_to_f128M.c",
@ -745,6 +854,7 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/s_addCarryM.c",
"deps/SoftFloat-3e/source/s_addComplCarryM.c",
"deps/SoftFloat-3e/source/s_addF128M.c",
"deps/SoftFloat-3e/source/s_addExtF80M.c",
"deps/SoftFloat-3e/source/s_addM.c",
"deps/SoftFloat-3e/source/s_addMagsF16.c",
"deps/SoftFloat-3e/source/s_addMagsF32.c",
@ -755,12 +865,14 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/s_approxRecip_1Ks.c",
"deps/SoftFloat-3e/source/s_compare128M.c",
"deps/SoftFloat-3e/source/s_compare96M.c",
"deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros16.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros32.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros64.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros8.c",
"deps/SoftFloat-3e/source/s_eq128.c",
"deps/SoftFloat-3e/source/s_invalidF128M.c",
"deps/SoftFloat-3e/source/s_invalidExtF80M.c",
"deps/SoftFloat-3e/source/s_isNaNF128M.c",
"deps/SoftFloat-3e/source/s_le128.c",
"deps/SoftFloat-3e/source/s_lt128.c",
@ -771,7 +883,9 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/s_mulAddF32.c",
"deps/SoftFloat-3e/source/s_mulAddF64.c",
"deps/SoftFloat-3e/source/s_negXM.c",
"deps/SoftFloat-3e/source/s_normExtF80SigM.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF16.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF32.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF64.c",
@ -782,6 +896,7 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/s_remStepMBy32.c",
"deps/SoftFloat-3e/source/s_roundMToI64.c",
"deps/SoftFloat-3e/source/s_roundMToUI64.c",
"deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_roundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_roundPackToF16.c",
"deps/SoftFloat-3e/source/s_roundPackToF32.c",
@ -810,9 +925,12 @@ const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/s_subMagsF32.c",
"deps/SoftFloat-3e/source/s_subMagsF64.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/softfloat_state.c",
"deps/SoftFloat-3e/source/ui32_to_f128M.c",
"deps/SoftFloat-3e/source/ui64_to_f128M.c",
"deps/SoftFloat-3e/source/ui32_to_extF80M.c",
"deps/SoftFloat-3e/source/ui64_to_extF80M.c",
};
const stage1_sources = [_][]const u8{

980
ci/azure/build.zig Normal file
View File

@ -0,0 +1,980 @@
const std = @import("std");
const builtin = std.builtin;
const Builder = std.build.Builder;
const BufMap = std.BufMap;
const mem = std.mem;
const ArrayList = std.ArrayList;
const io = std.io;
const fs = std.fs;
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
const assert = std.debug.assert;
const zig_version = std.builtin.Version{ .major = 0, .minor = 10, .patch = 0 };
pub fn build(b: *Builder) !void {
b.setPreferredReleaseMode(.ReleaseFast);
const mode = b.standardReleaseOptions();
const target = b.standardTargetOptions(.{});
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false;
const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
docgen_exe.single_threaded = single_threaded;
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
const langref_out_path = fs.path.join(
b.allocator,
&[_][]const u8{ b.cache_root, "langref.html" },
) catch unreachable;
const docgen_cmd = docgen_exe.run();
docgen_cmd.addArgs(&[_][]const u8{
rel_zig_exe,
"doc" ++ fs.path.sep_str ++ "langref.html.in",
langref_out_path,
});
docgen_cmd.step.dependOn(&docgen_exe.step);
const docs_step = b.step("docs", "Build documentation");
docs_step.dependOn(&docgen_cmd.step);
const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;
const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm);
const llvm_has_m68k = b.option(
bool,
"llvm-has-m68k",
"Whether LLVM has the experimental target m68k enabled",
) orelse false;
const llvm_has_csky = b.option(
bool,
"llvm-has-csky",
"Whether LLVM has the experimental target csky enabled",
) orelse false;
const llvm_has_ve = b.option(
bool,
"llvm-has-ve",
"Whether LLVM has the experimental target ve enabled",
) orelse false;
const llvm_has_arc = b.option(
bool,
"llvm-has-arc",
"Whether LLVM has the experimental target arc enabled",
) orelse false;
const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h");
b.installDirectory(InstallDirectoryOptions{
.source_dir = "lib",
.install_dir = .lib,
.install_subdir = "zig",
.exclude_extensions = &[_][]const u8{
// exclude files from lib/std/compress/
".gz",
".z.0",
".z.9",
"rfc1951.txt",
"rfc1952.txt",
// exclude files from lib/std/compress/deflate/testdata
".expect",
".expect-noinput",
".golden",
".input",
"compress-e.txt",
"compress-gettysburg.txt",
"compress-pi.txt",
"rfc1951.txt",
// exclude files from lib/std/tz/
".tzif",
// others
"README.md",
},
.blank_extensions = &[_][]const u8{
"test.zig",
},
});
const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false;
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
if (strip) break :blk @as(u32, 0);
if (mode != .Debug) break :blk 0;
break :blk 4;
};
const main_file: ?[]const u8 = if (is_stage1) null else "src/main.zig";
const exe = b.addExecutable("zig", main_file);
exe.strip = strip;
exe.install();
exe.setBuildMode(mode);
exe.setTarget(target);
b.default_step.dependOn(&exe.step);
exe.single_threaded = single_threaded;
if (target.isWindows() and target.getAbi() == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
}
const exe_options = b.addOptions();
exe.addOptions("build_options", exe_options);
exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames);
exe_options.addOption(bool, "skip_non_native", false);
exe_options.addOption(bool, "have_llvm", enable_llvm);
exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
exe_options.addOption(bool, "llvm_has_ve", llvm_has_ve);
exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
exe_options.addOption(bool, "force_gpa", force_gpa);
if (link_libc) {
exe.linkLibC();
}
const is_debug = mode == .Debug;
const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false;
const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
const version = if (opt_version_string) |version| version else v: {
const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
var code: u8 = undefined;
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
"git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
}, &code, .Ignore) catch {
break :v version_string;
};
const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
switch (mem.count(u8, git_describe, "-")) {
0 => {
// Tagged release version (e.g. 0.9.0).
if (!mem.eql(u8, git_describe, version_string)) {
std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe });
std.process.exit(1);
}
break :v version_string;
},
2 => {
// Untagged development build (e.g. 0.9.0-dev.2025+ecf0050a9).
var it = mem.split(u8, git_describe, "-");
const tagged_ancestor = it.next() orelse unreachable;
const commit_height = it.next() orelse unreachable;
const commit_id = it.next() orelse unreachable;
const ancestor_ver = try std.builtin.Version.parse(tagged_ancestor);
if (zig_version.order(ancestor_ver) != .gt) {
std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
std.process.exit(1);
}
// Check that the commit hash is prefixed with a 'g' (a Git convention).
if (commit_id.len < 1 or commit_id[0] != 'g') {
std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
break :v version_string;
}
// The version is reformatted in accordance with the https://semver.org specification.
break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] });
},
else => {
std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
break :v version_string;
},
}
};
exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
if (is_stage1) {
const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast);
softfloat.setTarget(target);
softfloat.addIncludeDir("deps/SoftFloat-3e-prebuilt");
softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
softfloat.single_threaded = single_threaded;
const zig0 = b.addExecutable("zig0", null);
zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags);
zig0.addIncludeDir("zig-cache/tmp"); // for config.h
zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major}));
zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor}));
zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
for ([_]*std.build.LibExeObjStep{ zig0, exe }) |artifact| {
artifact.addIncludeDir("src");
artifact.addIncludeDir("deps/SoftFloat-3e/source/include");
artifact.addIncludeDir("deps/SoftFloat-3e-prebuilt");
artifact.defineCMacro("ZIG_LINK_MODE", "Static");
artifact.addCSourceFiles(&stage1_sources, &exe_cflags);
artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
artifact.linkLibrary(softfloat);
artifact.linkLibCpp();
}
try addStaticLlvmOptionsToExe(zig0);
const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch());
const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) });
const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" });
const zig1_obj = zig0.run();
zig1_obj.addArgs(&.{
"src/stage1.zig",
"-target",
try target.zigTriple(b.allocator),
"-mcpu=baseline",
"--name",
"zig1",
"--zig-lib-dir",
b.pathFromRoot("lib"),
b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}),
"-fcompiler-rt",
"-lc",
});
{
zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" });
zig1_obj.addFileSourceArg(exe_options.getSource());
zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" });
}
switch (mode) {
.Debug => {},
.ReleaseFast => {
zig1_obj.addArg("-OReleaseFast");
zig1_obj.addArg("--strip");
},
.ReleaseSafe => {
zig1_obj.addArg("-OReleaseSafe");
zig1_obj.addArg("--strip");
},
.ReleaseSmall => {
zig1_obj.addArg("-OReleaseSmall");
zig1_obj.addArg("--strip");
},
}
if (single_threaded orelse false) {
zig1_obj.addArg("-fsingle-threaded");
}
exe.step.dependOn(&zig1_obj.step);
exe.addObjectFile(zig1_obj_path);
// This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
// of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
// is pointless.
exe.addPackagePath("compiler_rt", "src/empty.zig");
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
// That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
// the information passed on to us from cmake.
if (cfg.cmake_prefix_path.len > 0) {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
}
}
const semver = try std.SemanticVersion.parse(version);
exe_options.addOption(std.SemanticVersion, "semver", semver);
exe_options.addOption(bool, "enable_logging", enable_logging);
exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
exe_options.addOption(bool, "enable_tracy", tracy != null);
exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
exe_options.addOption(bool, "value_tracing", value_tracing);
exe_options.addOption(bool, "is_stage1", is_stage1);
exe_options.addOption(bool, "omit_stage2", omit_stage2);
if (tracy) |tracy_path| {
const client_cpp = fs.path.join(
b.allocator,
&[_][]const u8{ tracy_path, "TracyClient.cpp" },
) catch unreachable;
// On mingw, we need to opt into windows 7+ to get some features required by tracy.
const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu)
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
else
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
exe.addIncludeDir(tracy_path);
exe.addCSourceFile(client_cpp, tracy_c_flags);
if (!enable_llvm) {
exe.linkSystemLibraryName("c++");
}
exe.linkLibC();
if (target.isWindows()) {
exe.linkSystemLibrary("dbghelp");
exe.linkSystemLibrary("ws2_32");
}
}
}
const exe_cflags = [_][]const u8{
"-std=c++14",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D__STDC_LIMIT_MACROS",
"-D_GNU_SOURCE",
"-fvisibility-inlines-hidden",
"-fno-exceptions",
"-fno-rtti",
"-Werror=type-limits",
"-Wno-missing-braces",
"-Wno-comment",
};
fn addCmakeCfgOptionsToExe(
b: *Builder,
cfg: CMakeConfig,
exe: *std.build.LibExeObjStep,
use_zig_libcxx: bool,
) !void {
exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
cfg.cmake_binary_dir,
"zigcpp",
b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
}) catch unreachable);
assert(cfg.lld_include_dir.len != 0);
exe.addIncludeDir(cfg.lld_include_dir);
addCMakeLibraryList(exe, cfg.clang_libraries);
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);
if (use_zig_libcxx) {
exe.linkLibCpp();
} else {
const need_cpp_includes = true;
// System -lc++ must be used because in this code path we are attempting to link
// against system-provided LLVM, Clang, LLD.
if (exe.target.getOsTag() == .linux) {
// First we try to static link against gcc libstdc++. If that doesn't work,
// we fall back to -lc++ and cross our fingers.
addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
error.RequiredLibraryNotFound => {
exe.linkSystemLibrary("c++");
},
else => |e| return e,
};
exe.linkSystemLibrary("unwind");
} else if (exe.target.isFreeBSD()) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
} else if (exe.target.getOsTag() == .openbsd) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
} else if (exe.target.isDarwin()) {
exe.linkSystemLibrary("c++");
}
}
if (cfg.dia_guids_lib.len != 0) {
exe.addObjectFile(cfg.dia_guids_lib);
}
}
fn addStaticLlvmOptionsToExe(
exe: *std.build.LibExeObjStep,
) !void {
// Adds the Zig C++ sources which both stage1 and stage2 need.
//
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
// in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
// unavailable when LLVM is compiled in Release mode.
const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
for (clang_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
for (lld_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
for (llvm_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
exe.linkSystemLibrary("z");
// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");
if (exe.target.getOs().tag == .windows) {
exe.linkSystemLibrary("version");
exe.linkSystemLibrary("uuid");
exe.linkSystemLibrary("ole32");
}
}
fn addCxxKnownPath(
b: *Builder,
ctx: CMakeConfig,
exe: *std.build.LibExeObjStep,
objname: []const u8,
errtxt: ?[]const u8,
need_cpp_includes: bool,
) !void {
const path_padded = try b.exec(&[_][]const u8{
ctx.cxx_compiler,
b.fmt("-print-file-name={s}", .{objname}),
});
const path_unpadded = mem.tokenize(u8, path_padded, "\r\n").next().?;
if (mem.eql(u8, path_unpadded, objname)) {
if (errtxt) |msg| {
std.debug.print("{s}", .{msg});
} else {
std.debug.print("Unable to determine path to {s}\n", .{objname});
}
return error.RequiredLibraryNotFound;
}
exe.addObjectFile(path_unpadded);
// TODO a way to integrate with system c++ include files here
// cc -E -Wp,-v -xc++ /dev/null
if (need_cpp_includes) {
// I used these temporarily for testing something but we obviously need a
// more general purpose solution here.
//exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0");
//exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/x86_64-unknown-linux-gnu");
//exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/backward");
}
}
fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
var it = mem.tokenize(u8, list, ";");
while (it.next()) |lib| {
if (mem.startsWith(u8, lib, "-l")) {
exe.linkSystemLibrary(lib["-l".len..]);
} else {
exe.addObjectFile(lib);
}
}
}
const CMakeConfig = struct {
cmake_binary_dir: []const u8,
cmake_prefix_path: []const u8,
cxx_compiler: []const u8,
lld_include_dir: []const u8,
lld_libraries: []const u8,
clang_libraries: []const u8,
llvm_libraries: []const u8,
dia_guids_lib: []const u8,
};
const max_config_h_bytes = 1 * 1024 * 1024;
fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig {
const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: {
break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
} else blk: {
// TODO this should stop looking for config.h once it detects we hit the
// zig source root directory.
var check_dir = fs.path.dirname(b.zig_exe).?;
while (true) {
var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
defer dir.close();
break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) {
error.FileNotFound => {
const new_check_dir = fs.path.dirname(check_dir);
if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
return null;
}
check_dir = new_check_dir.?;
continue;
},
else => unreachable,
};
} else unreachable; // TODO should not need `else unreachable`.
};
var ctx: CMakeConfig = .{
.cmake_binary_dir = undefined,
.cmake_prefix_path = undefined,
.cxx_compiler = undefined,
.lld_include_dir = undefined,
.lld_libraries = undefined,
.clang_libraries = undefined,
.llvm_libraries = undefined,
.dia_guids_lib = undefined,
};
const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
.{
.prefix = "#define ZIG_CMAKE_BINARY_DIR ",
.field = "cmake_binary_dir",
},
.{
.prefix = "#define ZIG_CMAKE_PREFIX_PATH ",
.field = "cmake_prefix_path",
},
.{
.prefix = "#define ZIG_CXX_COMPILER ",
.field = "cxx_compiler",
},
.{
.prefix = "#define ZIG_LLD_INCLUDE_PATH ",
.field = "lld_include_dir",
},
.{
.prefix = "#define ZIG_LLD_LIBRARIES ",
.field = "lld_libraries",
},
.{
.prefix = "#define ZIG_CLANG_LIBRARIES ",
.field = "clang_libraries",
},
.{
.prefix = "#define ZIG_LLVM_LIBRARIES ",
.field = "llvm_libraries",
},
.{
.prefix = "#define ZIG_DIA_GUIDS_LIB ",
.field = "dia_guids_lib",
},
};
var lines_it = mem.tokenize(u8, config_h_text, "\r\n");
while (lines_it.next()) |line| {
inline for (mappings) |mapping| {
if (mem.startsWith(u8, line, mapping.prefix)) {
var it = mem.split(u8, line, "\"");
_ = it.next().?; // skip the stuff before the quote
const quoted = it.next().?; // the stuff inside the quote
@field(ctx, mapping.field) = toNativePathSep(b, quoted);
}
}
}
return ctx;
}
fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
const duplicated = b.allocator.dupe(u8, s) catch unreachable;
for (duplicated) |*byte| switch (byte.*) {
'/' => byte.* = fs.path.sep,
else => {},
};
return duplicated;
}
const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c",
"deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c",
"deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c",
"deps/SoftFloat-3e/source/f128M_add.c",
"deps/SoftFloat-3e/source/f128M_div.c",
"deps/SoftFloat-3e/source/f128M_eq.c",
"deps/SoftFloat-3e/source/f128M_eq_signaling.c",
"deps/SoftFloat-3e/source/f128M_le.c",
"deps/SoftFloat-3e/source/f128M_le_quiet.c",
"deps/SoftFloat-3e/source/f128M_lt.c",
"deps/SoftFloat-3e/source/f128M_lt_quiet.c",
"deps/SoftFloat-3e/source/f128M_mul.c",
"deps/SoftFloat-3e/source/f128M_mulAdd.c",
"deps/SoftFloat-3e/source/f128M_rem.c",
"deps/SoftFloat-3e/source/f128M_roundToInt.c",
"deps/SoftFloat-3e/source/f128M_sqrt.c",
"deps/SoftFloat-3e/source/f128M_sub.c",
"deps/SoftFloat-3e/source/f128M_to_f16.c",
"deps/SoftFloat-3e/source/f128M_to_f32.c",
"deps/SoftFloat-3e/source/f128M_to_f64.c",
"deps/SoftFloat-3e/source/f128M_to_extF80M.c",
"deps/SoftFloat-3e/source/f128M_to_i32.c",
"deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_i64.c",
"deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_ui32.c",
"deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_ui64.c",
"deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c",
"deps/SoftFloat-3e/source/extF80M_add.c",
"deps/SoftFloat-3e/source/extF80M_div.c",
"deps/SoftFloat-3e/source/extF80M_eq.c",
"deps/SoftFloat-3e/source/extF80M_le.c",
"deps/SoftFloat-3e/source/extF80M_lt.c",
"deps/SoftFloat-3e/source/extF80M_mul.c",
"deps/SoftFloat-3e/source/extF80M_rem.c",
"deps/SoftFloat-3e/source/extF80M_roundToInt.c",
"deps/SoftFloat-3e/source/extF80M_sqrt.c",
"deps/SoftFloat-3e/source/extF80M_sub.c",
"deps/SoftFloat-3e/source/extF80M_to_f16.c",
"deps/SoftFloat-3e/source/extF80M_to_f32.c",
"deps/SoftFloat-3e/source/extF80M_to_f64.c",
"deps/SoftFloat-3e/source/extF80M_to_f128M.c",
"deps/SoftFloat-3e/source/f16_add.c",
"deps/SoftFloat-3e/source/f16_div.c",
"deps/SoftFloat-3e/source/f16_eq.c",
"deps/SoftFloat-3e/source/f16_isSignalingNaN.c",
"deps/SoftFloat-3e/source/f16_lt.c",
"deps/SoftFloat-3e/source/f16_mul.c",
"deps/SoftFloat-3e/source/f16_mulAdd.c",
"deps/SoftFloat-3e/source/f16_rem.c",
"deps/SoftFloat-3e/source/f16_roundToInt.c",
"deps/SoftFloat-3e/source/f16_sqrt.c",
"deps/SoftFloat-3e/source/f16_sub.c",
"deps/SoftFloat-3e/source/f16_to_extF80M.c",
"deps/SoftFloat-3e/source/f16_to_f128M.c",
"deps/SoftFloat-3e/source/f16_to_f64.c",
"deps/SoftFloat-3e/source/f32_to_extF80M.c",
"deps/SoftFloat-3e/source/f32_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_extF80M.c",
"deps/SoftFloat-3e/source/f64_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_f16.c",
"deps/SoftFloat-3e/source/i32_to_f128M.c",
"deps/SoftFloat-3e/source/s_add256M.c",
"deps/SoftFloat-3e/source/s_addCarryM.c",
"deps/SoftFloat-3e/source/s_addComplCarryM.c",
"deps/SoftFloat-3e/source/s_addF128M.c",
"deps/SoftFloat-3e/source/s_addExtF80M.c",
"deps/SoftFloat-3e/source/s_addM.c",
"deps/SoftFloat-3e/source/s_addMagsF16.c",
"deps/SoftFloat-3e/source/s_addMagsF32.c",
"deps/SoftFloat-3e/source/s_addMagsF64.c",
"deps/SoftFloat-3e/source/s_approxRecip32_1.c",
"deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c",
"deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c",
"deps/SoftFloat-3e/source/s_approxRecip_1Ks.c",
"deps/SoftFloat-3e/source/s_compare128M.c",
"deps/SoftFloat-3e/source/s_compare96M.c",
"deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros16.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros32.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros64.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros8.c",
"deps/SoftFloat-3e/source/s_eq128.c",
"deps/SoftFloat-3e/source/s_invalidF128M.c",
"deps/SoftFloat-3e/source/s_invalidExtF80M.c",
"deps/SoftFloat-3e/source/s_isNaNF128M.c",
"deps/SoftFloat-3e/source/s_le128.c",
"deps/SoftFloat-3e/source/s_lt128.c",
"deps/SoftFloat-3e/source/s_mul128MTo256M.c",
"deps/SoftFloat-3e/source/s_mul64To128M.c",
"deps/SoftFloat-3e/source/s_mulAddF128M.c",
"deps/SoftFloat-3e/source/s_mulAddF16.c",
"deps/SoftFloat-3e/source/s_mulAddF32.c",
"deps/SoftFloat-3e/source/s_mulAddF64.c",
"deps/SoftFloat-3e/source/s_negXM.c",
"deps/SoftFloat-3e/source/s_normExtF80SigM.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF16.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF32.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF64.c",
"deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c",
"deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c",
"deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c",
"deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c",
"deps/SoftFloat-3e/source/s_remStepMBy32.c",
"deps/SoftFloat-3e/source/s_roundMToI64.c",
"deps/SoftFloat-3e/source/s_roundMToUI64.c",
"deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_roundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_roundPackToF16.c",
"deps/SoftFloat-3e/source/s_roundPackToF32.c",
"deps/SoftFloat-3e/source/s_roundPackToF64.c",
"deps/SoftFloat-3e/source/s_roundToI32.c",
"deps/SoftFloat-3e/source/s_roundToI64.c",
"deps/SoftFloat-3e/source/s_roundToUI32.c",
"deps/SoftFloat-3e/source/s_roundToUI64.c",
"deps/SoftFloat-3e/source/s_shiftLeftM.c",
"deps/SoftFloat-3e/source/s_shiftNormSigF128M.c",
"deps/SoftFloat-3e/source/s_shiftRightJam256M.c",
"deps/SoftFloat-3e/source/s_shiftRightJam32.c",
"deps/SoftFloat-3e/source/s_shiftRightJam64.c",
"deps/SoftFloat-3e/source/s_shiftRightJamM.c",
"deps/SoftFloat-3e/source/s_shiftRightM.c",
"deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c",
"deps/SoftFloat-3e/source/s_shortShiftLeftM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightJam64.c",
"deps/SoftFloat-3e/source/s_shortShiftRightJamM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightM.c",
"deps/SoftFloat-3e/source/s_sub1XM.c",
"deps/SoftFloat-3e/source/s_sub256M.c",
"deps/SoftFloat-3e/source/s_subM.c",
"deps/SoftFloat-3e/source/s_subMagsF16.c",
"deps/SoftFloat-3e/source/s_subMagsF32.c",
"deps/SoftFloat-3e/source/s_subMagsF64.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/softfloat_state.c",
"deps/SoftFloat-3e/source/ui32_to_f128M.c",
"deps/SoftFloat-3e/source/ui64_to_f128M.c",
"deps/SoftFloat-3e/source/ui32_to_extF80M.c",
"deps/SoftFloat-3e/source/ui64_to_extF80M.c",
};
const stage1_sources = [_][]const u8{
"src/stage1/analyze.cpp",
"src/stage1/astgen.cpp",
"src/stage1/bigfloat.cpp",
"src/stage1/bigint.cpp",
"src/stage1/buffer.cpp",
"src/stage1/codegen.cpp",
"src/stage1/dump_analysis.cpp",
"src/stage1/errmsg.cpp",
"src/stage1/error.cpp",
"src/stage1/heap.cpp",
"src/stage1/ir.cpp",
"src/stage1/ir_print.cpp",
"src/stage1/mem.cpp",
"src/stage1/os.cpp",
"src/stage1/parser.cpp",
"src/stage1/range_set.cpp",
"src/stage1/stage1.cpp",
"src/stage1/target.cpp",
"src/stage1/tokenizer.cpp",
"src/stage1/util.cpp",
"src/stage1/softfloat_ext.cpp",
};
const optimized_c_sources = [_][]const u8{
"src/stage1/parse_f128.c",
};
const zig_cpp_sources = [_][]const u8{
// These are planned to stay even when we are self-hosted.
"src/zig_llvm.cpp",
"src/zig_clang.cpp",
"src/zig_llvm-ar.cpp",
"src/zig_clang_driver.cpp",
"src/zig_clang_cc1_main.cpp",
"src/zig_clang_cc1as_main.cpp",
// https://github.com/ziglang/zig/issues/6363
"src/windows_sdk.cpp",
};
const clang_libs = [_][]const u8{
"clangFrontendTool",
"clangCodeGen",
"clangFrontend",
"clangDriver",
"clangSerialization",
"clangSema",
"clangStaticAnalyzerFrontend",
"clangStaticAnalyzerCheckers",
"clangStaticAnalyzerCore",
"clangAnalysis",
"clangASTMatchers",
"clangAST",
"clangParse",
"clangSema",
"clangBasic",
"clangEdit",
"clangLex",
"clangARCMigrate",
"clangRewriteFrontend",
"clangRewrite",
"clangCrossTU",
"clangIndex",
"clangToolingCore",
};
const lld_libs = [_][]const u8{
"lldDriver",
"lldMinGW",
"lldELF",
"lldCOFF",
"lldMachO",
"lldWasm",
"lldReaderWriter",
"lldCore",
"lldYAML",
"lldCommon",
};
// This list can be re-generated with `llvm-config --libfiles` and then
// reformatting using your favorite text editor. Note we do not execute
// `llvm-config` here because we are cross compiling. Also omit LLVMTableGen
// from these libs.
const llvm_libs = [_][]const u8{
"LLVMWindowsManifest",
"LLVMXRay",
"LLVMLibDriver",
"LLVMDlltoolDriver",
"LLVMCoverage",
"LLVMLineEditor",
"LLVMXCoreDisassembler",
"LLVMXCoreCodeGen",
"LLVMXCoreDesc",
"LLVMXCoreInfo",
"LLVMX86Disassembler",
"LLVMX86AsmParser",
"LLVMX86CodeGen",
"LLVMX86Desc",
"LLVMX86Info",
"LLVMWebAssemblyDisassembler",
"LLVMWebAssemblyAsmParser",
"LLVMWebAssemblyCodeGen",
"LLVMWebAssemblyDesc",
"LLVMWebAssemblyUtils",
"LLVMWebAssemblyInfo",
"LLVMSystemZDisassembler",
"LLVMSystemZAsmParser",
"LLVMSystemZCodeGen",
"LLVMSystemZDesc",
"LLVMSystemZInfo",
"LLVMSparcDisassembler",
"LLVMSparcAsmParser",
"LLVMSparcCodeGen",
"LLVMSparcDesc",
"LLVMSparcInfo",
"LLVMRISCVDisassembler",
"LLVMRISCVAsmParser",
"LLVMRISCVCodeGen",
"LLVMRISCVDesc",
"LLVMRISCVInfo",
"LLVMPowerPCDisassembler",
"LLVMPowerPCAsmParser",
"LLVMPowerPCCodeGen",
"LLVMPowerPCDesc",
"LLVMPowerPCInfo",
"LLVMNVPTXCodeGen",
"LLVMNVPTXDesc",
"LLVMNVPTXInfo",
"LLVMMSP430Disassembler",
"LLVMMSP430AsmParser",
"LLVMMSP430CodeGen",
"LLVMMSP430Desc",
"LLVMMSP430Info",
"LLVMMipsDisassembler",
"LLVMMipsAsmParser",
"LLVMMipsCodeGen",
"LLVMMipsDesc",
"LLVMMipsInfo",
"LLVMLanaiDisassembler",
"LLVMLanaiCodeGen",
"LLVMLanaiAsmParser",
"LLVMLanaiDesc",
"LLVMLanaiInfo",
"LLVMHexagonDisassembler",
"LLVMHexagonCodeGen",
"LLVMHexagonAsmParser",
"LLVMHexagonDesc",
"LLVMHexagonInfo",
"LLVMBPFDisassembler",
"LLVMBPFAsmParser",
"LLVMBPFCodeGen",
"LLVMBPFDesc",
"LLVMBPFInfo",
"LLVMAVRDisassembler",
"LLVMAVRAsmParser",
"LLVMAVRCodeGen",
"LLVMAVRDesc",
"LLVMAVRInfo",
"LLVMARMDisassembler",
"LLVMARMAsmParser",
"LLVMARMCodeGen",
"LLVMARMDesc",
"LLVMARMUtils",
"LLVMARMInfo",
"LLVMAMDGPUDisassembler",
"LLVMAMDGPUAsmParser",
"LLVMAMDGPUCodeGen",
"LLVMAMDGPUDesc",
"LLVMAMDGPUUtils",
"LLVMAMDGPUInfo",
"LLVMAArch64Disassembler",
"LLVMAArch64AsmParser",
"LLVMAArch64CodeGen",
"LLVMAArch64Desc",
"LLVMAArch64Utils",
"LLVMAArch64Info",
"LLVMOrcJIT",
"LLVMMCJIT",
"LLVMJITLink",
"LLVMInterpreter",
"LLVMExecutionEngine",
"LLVMRuntimeDyld",
"LLVMOrcTargetProcess",
"LLVMOrcShared",
"LLVMDWP",
"LLVMSymbolize",
"LLVMDebugInfoPDB",
"LLVMDebugInfoGSYM",
"LLVMOption",
"LLVMObjectYAML",
"LLVMMCA",
"LLVMMCDisassembler",
"LLVMLTO",
"LLVMPasses",
"LLVMCFGuard",
"LLVMCoroutines",
"LLVMObjCARCOpts",
"LLVMipo",
"LLVMVectorize",
"LLVMLinker",
"LLVMInstrumentation",
"LLVMFrontendOpenMP",
"LLVMFrontendOpenACC",
"LLVMExtensions",
"LLVMDWARFLinker",
"LLVMGlobalISel",
"LLVMMIRParser",
"LLVMAsmPrinter",
"LLVMDebugInfoMSF",
"LLVMDebugInfoDWARF",
"LLVMSelectionDAG",
"LLVMCodeGen",
"LLVMIRReader",
"LLVMAsmParser",
"LLVMInterfaceStub",
"LLVMFileCheck",
"LLVMFuzzMutate",
"LLVMTarget",
"LLVMScalarOpts",
"LLVMInstCombine",
"LLVMAggressiveInstCombine",
"LLVMTransformUtils",
"LLVMBitWriter",
"LLVMAnalysis",
"LLVMProfileData",
"LLVMObject",
"LLVMTextAPI",
"LLVMMCParser",
"LLVMMC",
"LLVMDebugInfoCodeView",
"LLVMBitReader",
"LLVMCore",
"LLVMRemarks",
"LLVMBitstreamReader",
"LLVMBinaryFormat",
"LLVMSupport",
"LLVMDemangle",
};

View File

@ -8,15 +8,15 @@ brew update && brew install ncurses s3cmd
ZIGDIR="$(pwd)"
HOST_ARCH="x86_64"
HOST_TARGET="$HOST_ARCH-macos-gnu"
HOST_TARGET="$HOST_ARCH-macos-none"
HOST_MCPU="baseline"
HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.9.0-dev.1249+210ef5af8"
HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.10.0-dev.2348+d43761808"
HOST_PREFIX="$HOME/$HOST_CACHE_BASENAME"
ARCH="aarch64"
TARGET="$ARCH-macos-gnu"
TARGET="$ARCH-macos-none"
MCPU="apple_a14"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.9.0-dev.1249+210ef5af8"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.2348+d43761808"
PREFIX="$HOME/$CACHE_BASENAME"
JOBS="-j2"

View File

@ -7,9 +7,9 @@ brew update && brew install ncurses s3cmd
ZIGDIR="$(pwd)"
ARCH="x86_64"
TARGET="$ARCH-macos-gnu"
TARGET="$ARCH-macos-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.9.0-dev.1249+210ef5af8"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.2348+d43761808"
PREFIX="$HOME/$CACHE_BASENAME"
JOBS="-j2"
@ -55,12 +55,28 @@ make $JOBS install
cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
make $JOBS install
# TODO figure out why this causes a segmentation fault
# release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test
# Build stage2 standalone so that we can test stage2 against stage2 compiler-rt.
release/bin/zig build -p stage2 -Denable-llvm
release/bin/zig build test-toolchain -Denable-macos-sdk
release/bin/zig build test-std
release/bin/zig build docs
stage2/bin/zig build test-behavior
# TODO: upgrade these to test stage2 instead of stage1
# TODO: upgrade these to test stage3 instead of stage2
release/bin/zig build test-behavior -Denable-macos-sdk -Domit-stage2
release/bin/zig build test-compiler-rt -Denable-macos-sdk
release/bin/zig build test-std -Denable-macos-sdk
release/bin/zig build test-universal-libc -Denable-macos-sdk
release/bin/zig build test-compare-output -Denable-macos-sdk
release/bin/zig build test-standalone -Denable-macos-sdk
release/bin/zig build test-stack-traces -Denable-macos-sdk
release/bin/zig build test-cli -Denable-macos-sdk
release/bin/zig build test-asm-link -Denable-macos-sdk
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 -Dsingle-threaded
release/bin/zig build test-link -Denable-macos-sdk
if [ "${BUILD_REASON}" != "PullRequest" ]; then
mv ../LICENSE release/

View File

@ -22,29 +22,149 @@ jobs:
name: main
displayName: 'Build'
- job: BuildWindows
timeoutInMinutes: 360
pool:
vmImage: 'windows-2019'
timeoutInMinutes: 360
variables:
TARGET: 'x86_64-windows-gnu'
ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.9.1'
ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
steps:
- powershell: |
(New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2022-01-28/msys2-base-x86_64-20220128.sfx.exe", "sfx.exe")
.\sfx.exe -y -o\
displayName: Download/Extract/Install MSYS2
- script: |
@REM install updated filesystem package first without dependency checking
@REM because of: https://github.com/msys2/MSYS2-packages/issues/2021
%CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Sydd filesystem"
displayName: Workaround filesystem dash MSYS2 dependency issue
- script: |
%CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
%CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
displayName: Update MSYS2
- pwsh: |
(New-Object Net.WebClient).DownloadFile("$(ZIG_LLVM_CLANG_LLD_URL)", "${ZIG_LLVM_CLANG_LLD_NAME}.zip")
& 'C:\Program Files\7-Zip\7z.exe' x "${ZIG_LLVM_CLANG_LLD_NAME}.zip"
name: install
displayName: 'Install ZIG/LLVM/CLANG/LLD'
- pwsh: |
Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist"
Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)"
# Make the `zig version` number consistent.
# This will affect the `zig build` command below which uses `git describe`.
git config core.abbrev 9
git fetch --tags
if ((git rev-parse --is-shallow-repository) -eq "true") {
git fetch --unshallow # `git describe` won't work on a shallow repo
}
# The dev kit zip file that we have here is old, and may be incompatible with
# the build.zig script of master branch. So we keep an old version of build.zig
# here in the CI directory.
mv build.zig build.zig.master
mv ci/azure/build.zig build.zig
mkdir $ZIGBUILDDIR
cd $ZIGBUILDDIR
& "${ZIGPREFIXPATH}/bin/zig.exe" build `
--prefix "$ZIGINSTALLDIR" `
--search-prefix "$ZIGPREFIXPATH" `
-Dstage1 `
<# stage2 is omitted until we resolve https://github.com/ziglang/zig/issues/6485 #> `
-Domit-stage2 `
-Dstatic-llvm `
-Drelease `
-Dstrip `
-Duse-zig-libcxx `
-Dtarget=$(TARGET)
cd -
# Now that we have built an up-to-date zig.exe, we restore the original
# build script from master branch.
rm build.zig
mv build.zig.master build.zig
name: build
displayName: 'Build'
- pwsh: |
Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
# Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is
# built with itself and does not gobble as much memory, we can enable these tests.
#& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1
& "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1
& "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1
name: test
displayName: 'Test'
- pwsh: |
Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
& "$ZIGINSTALLDIR\bin\zig.exe" build docs
timeoutInMinutes: 60
name: doc
displayName: 'Documentation'
- task: DownloadSecureFile@1
inputs:
secureFile: s3cfg
- script: ci/azure/windows_msvc_script.bat
name: main
displayName: 'Build and test'
name: aws_credentials
secureFile: aws_credentials
- pwsh: |
Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
$Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH"
# Workaround Azure networking issue
# https://github.com/aws/aws-cli/issues/5749
$Env:AWS_EC2_METADATA_DISABLED = "true"
$Env:AWS_REGION = "us-west-2"
cd "$ZIGBUILDDIR"
mv ../LICENSE dist/
mv ../zig-cache/langref.html dist/
mv dist/bin/zig.exe dist/
rmdir dist/bin
# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
mv dist/lib/zig dist/lib2
rmdir dist/lib
mv dist/lib2 dist/lib
Set-Variable -Name VERSION -Value $(./dist/zig.exe version)
Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION"
Set-Variable -Name TARBALL -Value "$DIRNAME.zip"
mv dist "$DIRNAME"
7z a "$TARBALL" "$DIRNAME"
aws s3 cp `
"$TARBALL" `
s3://ziglang.org/builds/ `
--acl public-read `
--cache-control 'public, max-age=31536000, immutable'
Set-Variable -Name SHASUM -Value (Get-FileHash "$TARBALL" -Algorithm SHA256 | select-object -ExpandProperty Hash).ToLower()
Set-Variable -Name BYTESIZE -Value (Get-Item "$TARBALL").length
Set-Variable -Name JSONFILE -Value "windows-${Env:BUILD_SOURCEBRANCHNAME}.json"
echo $null > $JSONFILE
echo ('{"tarball": "' + $TARBALL + '",') >> $JSONFILE
echo ('"shasum": "' + $SHASUM + '",') >> $JSONFILE
echo ('"size": ' + $BYTESIZE + '}' ) >> $JSONFILE
aws s3 cp `
"$JSONFILE" `
s3://ziglang.org/builds/ `
--acl public-read `
--cache-control 'max-age=0, must-revalidate'
aws s3 cp `
"$JSONFILE" `
"s3://ziglang.org/builds/x86_64-windows-${VERSION}.json" `
--acl public-read
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
name: upload
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
displayName: 'Upload'
- job: OnMasterSuccess
dependsOn:
- BuildMacOS
@ -54,7 +174,7 @@ jobs:
strategy:
maxParallel: 1
pool:
vmImage: 'ubuntu-18.04'
vmImage: 'ubuntu-20.04'
variables:
version: $[ dependencies.BuildMacOS.outputs['main.version'] ]
steps:

View File

@ -1,16 +0,0 @@
#!/bin/sh
set -x
set -e
pacman -Suy --needed --noconfirm
pacman -S --needed --noconfirm wget p7zip python3-pip tar xz
TARBALL="llvm+clang+lld-13.0.0-x86_64-windows-msvc-release-mt.tar.xz"
pip install s3cmd
wget -nv "https://ziglang.org/deps/$TARBALL"
# If the first extraction fails, re-try it once; this can happen if the tarball
# contains symlinks that are in the table of contents before the files that
# they point to.
tar -xf $TARBALL || tar --overwrite -xf $TARBALL

View File

@ -1,39 +0,0 @@
@echo on
SET "SRCROOT=%cd%"
SET "PREVPATH=%PATH%"
SET "PREVMSYSTEM=%MSYSTEM%"
set "PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem"
SET "MSYSTEM=MINGW64"
bash -lc "cd ${SRCROOT} && ci/azure/windows_msvc_install" || exit /b
SET "PATH=%PREVPATH%"
SET "MSYSTEM=%PREVMSYSTEM%"
SET "ZIGBUILDDIR=%SRCROOT%\build"
SET "ZIGINSTALLDIR=%ZIGBUILDDIR%\dist"
SET "ZIGPREFIXPATH=%SRCROOT%\llvm+clang+lld-13.0.0-x86_64-windows-msvc-release-mt"
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
REM Make the `zig version` number consistent.
REM This will affect the cmake command below.
git.exe config core.abbrev 9
git.exe fetch --unshallow
git.exe fetch --tags
mkdir %ZIGBUILDDIR%
cd %ZIGBUILDDIR%
cmake.exe .. -Thost=x64 -G"Visual Studio 16 2019" -A x64 "-DCMAKE_INSTALL_PREFIX=%ZIGINSTALLDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release -DZIG_OMIT_STAGE2=ON || exit /b
msbuild /maxcpucount /p:Configuration=Release INSTALL.vcxproj || exit /b
REM Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is
REM built with itself and does not gobble as much memory, we can enable these tests.
REM "%ZIGINSTALLDIR%\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" || exit /b
"%ZIGINSTALLDIR%\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests || exit /b
"%ZIGINSTALLDIR%\bin\zig.exe" build test-std -Dskip-non-native || exit /b
"%ZIGINSTALLDIR%\bin\zig.exe" build docs || exit /b
set "PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem"
SET "MSYSTEM=MINGW64"
bash -lc "cd ${SRCROOT} && ci/azure/windows_upload" || exit /b

View File

@ -1,46 +0,0 @@
#!/bin/sh
set -x
set -e
if [ "${BUILD_REASON}" != "PullRequest" ]; then
cd "$ZIGBUILDDIR"
mv ../LICENSE dist/
mv ../zig-cache/langref.html dist/
mv dist/bin/zig.exe dist/
rmdir dist/bin
# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
mv dist/lib/zig dist/lib2
rmdir dist/lib
mv dist/lib2 dist/lib
VERSION=$(dist/zig.exe version)
DIRNAME="zig-windows-x86_64-$VERSION"
TARBALL="$DIRNAME.zip"
mv dist "$DIRNAME"
7z a "$TARBALL" "$DIRNAME"
# mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
s3cmd -c "$DOWNLOADSECUREFILE_SECUREFILEPATH" put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL)
JSONFILE="windows-$GITBRANCH.json"
touch $JSONFILE
echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
s3cmd -c "$DOWNLOADSECUREFILE_SECUREFILEPATH" put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
s3cmd -c "$DOWNLOADSECUREFILE_SECUREFILEPATH" put -P "$JSONFILE" "s3://ziglang.org/builds/x86_64-windows-$VERSION.json"
# `set -x` causes these variables to be mangled.
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
set +x
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
fi

View File

@ -17,29 +17,28 @@ case "$1" in
;;
3)
# ReleaseSafe
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
;;
4)
# Releasefast
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small
# ReleaseFast
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
;;
5)
# ReleaseSmall
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-fast
;;
6)
./build/zig build $BUILD_FLAGS test-minilibc
./build/zig build $BUILD_FLAGS test-universal-libc
./build/zig build $BUILD_FLAGS test-compare-output
./build/zig build $BUILD_FLAGS test-standalone -Dskip-release-safe
./build/zig build $BUILD_FLAGS test-stack-traces
./build/zig build $BUILD_FLAGS test-cli
./build/zig build $BUILD_FLAGS test-asm-link
./build/zig build $BUILD_FLAGS test-runtime-safety
./build/zig build $BUILD_FLAGS test-translate-c
;;
7)
./build/zig build $BUILD_FLAGS # test building self-hosted without LLVM
./build/zig build $BUILD_FLAGS test-stage2
./build/zig build $BUILD_FLAGS test-cases
;;
'')
echo "error: expecting test group argument"

View File

@ -4,10 +4,10 @@ set -x
set -e
sudo pkg update -fq
sudo pkg install -y cmake py38-s3cmd wget curl jq samurai
sudo pkg install -y cmake py39-s3cmd wget curl jq samurai
ZIGDIR="$(pwd)"
CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.9.0-dev.1243+456d7e5f5"
CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.9.1"
PREFIX="$HOME/$CACHE_BASENAME"
cd $HOME
@ -44,7 +44,7 @@ samu install
#release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test
# Here we skip some tests to save time.
release/bin/zig build test -Dskip-compile-errors -Dskip-non-native
release/bin/zig build test -Dskip-stage1 -Dskip-non-native
if [ -f ~/.s3cfg ]; then
mv ../LICENSE release/

View File

@ -40,6 +40,77 @@
"size": "{{AARCH64_LINUX_BYTESIZE}}"
}
},
"0.9.1": {
"date": "2022-02-14",
"docs": "https://ziglang.org/documentation/0.9.1/",
"stdDocs": "https://ziglang.org/documentation/0.9.1/std/",
"notes": "https://ziglang.org/download/0.9.1/release-notes.html",
"src": {
"tarball": "https://ziglang.org/download/0.9.1/zig-0.9.1.tar.xz",
"shasum": "38cf4e84481f5facc766ba72783e7462e08d6d29a5d47e3b75c8ee3142485210",
"size": "13940828"
},
"bootstrap": {
"tarball": "https://ziglang.org/download/0.9.1/zig-bootstrap-0.9.1.tar.xz",
"shasum": "0a8e221c71860d8975c15662b3ed3bd863e81c4fe383455a596e5e0e490d6109",
"size": "42488812"
},
"x86_64-freebsd": {
"tarball": "https://ziglang.org/download/0.9.1/zig-freebsd-x86_64-0.9.1.tar.xz",
"shasum": "4e06009bd3ede34b72757eec1b5b291b30aa0d5046dadd16ecb6b34a02411254",
"size": "39028848"
},
"aarch64-linux": {
"tarball": "https://ziglang.org/download/0.9.1/zig-linux-aarch64-0.9.1.tar.xz",
"shasum": "5d99a39cded1870a3fa95d4de4ce68ac2610cca440336cfd252ffdddc2b90e66",
"size": "37034860"
},
"armv7a-linux": {
"tarball": "https://ziglang.org/download/0.9.1/zig-linux-armv7a-0.9.1.tar.xz",
"shasum": "6de64456cb4757a555816611ea697f86fba7681d8da3e1863fa726a417de49be",
"size": "37974652"
},
"i386-linux": {
"tarball": "https://ziglang.org/download/0.9.1/zig-linux-i386-0.9.1.tar.xz",
"shasum": "e776844fecd2e62fc40d94718891057a1dbca1816ff6013369e9a38c874374ca",
"size": "44969172"
},
"riscv64-linux": {
"tarball": "https://ziglang.org/download/0.9.1/zig-linux-riscv64-0.9.1.tar.xz",
"shasum": "208dea53662c2c52777bd9e3076115d2126a4f71aed7f2ff3b8fe224dc3881aa",
"size": "39390868"
},
"x86_64-linux": {
"tarball": "https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz",
"shasum": "be8da632c1d3273f766b69244d80669fe4f5e27798654681d77c992f17c237d7",
"size": "41011464"
},
"aarch64-macos": {
"tarball": "https://ziglang.org/download/0.9.1/zig-macos-aarch64-0.9.1.tar.xz",
"shasum": "8c473082b4f0f819f1da05de2dbd0c1e891dff7d85d2c12b6ee876887d438287",
"size": "38995640"
},
"x86_64-macos": {
"tarball": "https://ziglang.org/download/0.9.1/zig-macos-x86_64-0.9.1.tar.xz",
"shasum": "2d94984972d67292b55c1eb1c00de46580e9916575d083003546e9a01166754c",
"size": "43713044"
},
"i386-windows": {
"tarball": "https://ziglang.org/download/0.9.1/zig-windows-i386-0.9.1.zip",
"shasum": "74a640ed459914b96bcc572183a8db687bed0af08c30d2ea2f8eba03ae930f69",
"size": "67929868"
},
"x86_64-windows": {
"tarball": "https://ziglang.org/download/0.9.1/zig-windows-x86_64-0.9.1.zip",
"shasum": "443da53387d6ae8ba6bac4b3b90e9fef4ecbe545e1c5fa3a89485c36f5c0e3a2",
"size": "65047697"
},
"aarch64-windows": {
"tarball": "https://ziglang.org/download/0.9.1/zig-windows-aarch64-0.9.1.zip",
"shasum": "621bf95f54dc3ff71466c5faae67479419951d7489e40e87fd26d195825fb842",
"size": "61478151"
}
},
"0.9.0": {
"date": "2021-12-20",
"docs": "https://ziglang.org/documentation/0.9.0/",

View File

@ -57,7 +57,7 @@ unset CXX
#release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test
# Here we skip some tests to save time.
release/bin/zig build test -Dskip-compile-errors -Dskip-non-native
release/bin/zig build test -Dskip-stage1 -Dskip-non-native
if [ -f ~/.s3cfg ]; then
mv ../LICENSE release/

View File

@ -9,20 +9,8 @@ workspace:
path: /workspace
steps:
- name: probe
image: ci/debian-amd64:11.1-2
commands:
- ./ci/zinc/linux_probe.sh
- name: build
image: ci/debian-amd64:11.1-2
commands:
- ./ci/zinc/linux_build.sh
- name: test
depends_on:
- build
image: ci/debian-amd64:11.1-2
image: ci/debian-amd64:11.1-3
commands:
- ./ci/zinc/linux_test.sh
@ -34,7 +22,7 @@ steps:
- master
event:
- push
image: ci/debian-amd64:11.1-2
image: ci/debian-amd64:11.1-3
environment:
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID

View File

@ -17,7 +17,6 @@ set -x
set -e
ARCH="$(uname -m)"
JOBS="-j$(nproc)"
DEPS_LOCAL="/deps/local"
WORKSPACE="$DRONE_WORKSPACE"

View File

@ -1,72 +0,0 @@
#!/bin/sh
. ./ci/zinc/linux_base.sh
ZIG="$DEPS_LOCAL/bin/zig"
TARGET="${ARCH}-linux-musl"
MCPU="baseline"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git config core.abbrev 9
# Build debug zig.
echo "BUILD debug zig with zig:$($ZIG version)"
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir _debug
cd _debug
cmake .. \
-DCMAKE_INSTALL_PREFIX="$DEBUG_STAGING" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja $JOBS install
ZIG=$DEBUG_STAGING/bin/zig
# Here we rebuild zig but this time using the Zig binary we just now produced to
# build zig1.o rather than relying on the one built with stage0. See
# https://github.com/ziglang/zig/issues/6830 for more details.
cmake .. -DZIG_EXECUTABLE="$ZIG"
ninja $JOBS install
cd $WORKSPACE
# Build release zig.
echo "BUILD release zig with zig:$($ZIG version)"
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir _release
cd _release
cmake .. \
-DCMAKE_INSTALL_PREFIX="$RELEASE_STAGING" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
unset CC
unset CXX
ninja $JOBS install
cd $WORKSPACE
# Look for non-conforming code formatting.
# Formatting errors can be fixed by running `zig fmt` on the files printed here.
$ZIG fmt --check .
# Explicit exit helps show last command duration.
exit

View File

@ -1,10 +0,0 @@
#!/bin/sh
. ./ci/zinc/linux_base.sh
# Probe CPU/brand details.
echo "lscpu:"
(lscpu | sed 's,^, : ,') 1>&2
# Explicit exit helps show last command duration.
exit

View File

@ -2,34 +2,82 @@
. ./ci/zinc/linux_base.sh
ZIG=$DEBUG_STAGING/bin/zig
ZIG="$DEPS_LOCAL/bin/zig"
TARGET="${ARCH}-linux-musl"
MCPU="baseline"
$ZIG test test/behavior.zig -fno-stage1 -I test -fLLVM
$ZIG test test/behavior.zig -fno-stage1 -I test -ofmt=c
$ZIG test test/behavior.zig -fno-stage1 -I test -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin
$ZIG test test/behavior.zig -fno-stage1 -I test -target arm-linux --test-cmd qemu-arm --test-cmd-bin
$ZIG test test/behavior.zig -fno-stage1 -I test
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git config core.abbrev 9
$ZIG build test-behavior -fqemu -fwasmtime
echo "BUILD debug zig with zig:$($ZIG version)"
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir _debug
cd _debug
cmake .. \
-DCMAKE_INSTALL_PREFIX="$DEBUG_STAGING" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
ZIG="$DEBUG_STAGING/bin/zig"
# Here we rebuild zig but this time using the Zig binary we just now produced to
# build zig1.o rather than relying on the one built with stage0. See
# https://github.com/ziglang/zig/issues/6830 for more details.
cmake .. -DZIG_EXECUTABLE="$ZIG"
ninja install
cd $WORKSPACE
# Look for non-conforming code formatting.
# Formatting errors can be fixed by running `zig fmt` on the files printed here.
$ZIG fmt --check . --exclude test/cases/
# Build stage2 standalone so that we can test stage2 against stage2 compiler-rt.
$ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
# Ensure that stage2 can build itself.
stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
stage2/bin/zig build # test building self-hosted without LLVM
stage2/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm
# Here we use stage2 instead of stage3 because of two bugs remaining:
# * https://github.com/ziglang/zig/issues/11367 (and corresponding workaround in compiler source)
# * https://github.com/ziglang/zig/pull/11492#issuecomment-1112871321
stage2/bin/zig build test-behavior -fqemu -fwasmtime
stage2/bin/zig test lib/std/std.zig --zig-lib-dir lib
$ZIG build test-behavior -fqemu -fwasmtime -Domit-stage2
$ZIG build test-compiler-rt -fqemu -fwasmtime
$ZIG build test-std -fqemu -fwasmtime
$ZIG build test-minilibc -fqemu -fwasmtime
$ZIG build test-universal-libc -fqemu -fwasmtime
$ZIG build test-compare-output -fqemu -fwasmtime
$ZIG build test-standalone -fqemu -fwasmtime
$ZIG build test-stack-traces -fqemu -fwasmtime
$ZIG build test-cli -fqemu -fwasmtime
$ZIG build test-asm-link -fqemu -fwasmtime
$ZIG build test-runtime-safety -fqemu -fwasmtime
$ZIG build test-translate-c -fqemu -fwasmtime
$ZIG build test-run-translated-c -fqemu -fwasmtime
$ZIG build docs -fqemu -fwasmtime
$ZIG build # test building self-hosted without LLVM
$ZIG build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm
$ZIG build test-fmt -fqemu -fwasmtime
$ZIG build test-stage2 -fqemu -fwasmtime
$ZIG build test-cases -fqemu -fwasmtime
# Produce the experimental std lib documentation.
mkdir -p $RELEASE_STAGING/docs/std
mkdir -p "$RELEASE_STAGING/docs/std"
$ZIG test lib/std/std.zig \
--zig-lib-dir lib \
-femit-docs=$RELEASE_STAGING/docs/std \
@ -38,5 +86,15 @@ $ZIG test lib/std/std.zig \
# Look for HTML errors.
tidy --drop-empty-elements no -qe zig-cache/langref.html
# Build release zig.
$ZIG build \
--prefix "$RELEASE_STAGING" \
--search-prefix "$DEPS_LOCAL" \
-Dstatic-llvm \
-Drelease \
-Dstrip \
-Dtarget="$TARGET" \
-Dstage1
# Explicit exit helps show last command duration.
exit

View File

@ -49,6 +49,7 @@ else()
FIND_AND_ADD_LLD_LIB(lldELF)
FIND_AND_ADD_LLD_LIB(lldCOFF)
FIND_AND_ADD_LLD_LIB(lldWasm)
FIND_AND_ADD_LLD_LIB(lldMachO)
FIND_AND_ADD_LLD_LIB(lldReaderWriter)
FIND_AND_ADD_LLD_LIB(lldCore)
FIND_AND_ADD_LLD_LIB(lldYAML)

View File

@ -12,6 +12,7 @@ find_path(LLVM_INCLUDE_DIRS NAMES llvm/IR/IRBuilder.h
/usr/lib/llvm/14/include
/usr/lib/llvm-14/include
/usr/lib/llvm-14.0/include
/usr/lib/llvm14/include
/usr/local/llvm14/include
/usr/local/llvm140/include
/usr/local/opt/llvm@14/include
@ -31,6 +32,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB)
/usr/lib/llvm/14/lib
/usr/lib/llvm/14/lib64
/usr/lib/llvm-14/lib
/usr/lib/llvm14/lib
/usr/local/llvm14/lib
/usr/local/llvm140/lib
/usr/local/opt/llvm@14/lib
@ -181,19 +183,7 @@ else()
macro(FIND_AND_ADD_LLVM_LIB _libname_)
string(TOUPPER ${_libname_} _prettylibname_)
find_library(LLVM_${_prettylibname_}_LIB NAMES ${_libname_}
PATHS
${LLVM_LIBDIRS}
/usr/lib/llvm/14/lib
/usr/lib/llvm-14/lib
/usr/lib/llvm-14.0/lib
/usr/local/llvm140/lib
/usr/local/llvm14/lib
/usr/local/opt/llvm@14/lib
/opt/homebrew/opt/llvm@14/lib
/mingw64/lib
/c/msys64/mingw64/lib
c:\\msys64\\mingw64\\lib)
find_library(LLVM_${_prettylibname_}_LIB NAMES ${_libname_} PATHS ${LLVM_LIBDIRS})
set(LLVM_LIBRARIES ${LLVM_LIBRARIES} ${LLVM_${_prettylibname_}_LIB})
endmacro(FIND_AND_ADD_LLVM_LIB)

View File

@ -17,8 +17,6 @@
#define BIGENDIAN 1
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define BIGENDIAN 1
#elif defined(_BIG_ENDIAN)
#define BIGENDIAN 1
#elif defined(__sparc)
#define BIGENDIAN 1
#elif defined(__sparc__)
@ -37,7 +35,9 @@
#define BIGENDIAN 1
#elif defined(__s390__)
#define BIGENDIAN 1
#elif defined(__LITTLE_ENDIAN__)
#endif
#if defined(__LITTLE_ENDIAN__)
#define LITTLEENDIAN 1
#elif defined(__ARMEL__)
#define LITTLEENDIAN 1
@ -53,8 +53,6 @@
#define LITTLEENDIAN 1
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define LITTLEENDIAN 1
#elif defined(_LITTLE_ENDIAN)
#define LITTLEENDIAN 1
#elif defined(__i386__)
#define LITTLEENDIAN 1
#elif defined(__alpha__)
@ -83,7 +81,11 @@
#define LITTLEENDIAN 1
#elif defined(__bfin__)
#define LITTLEENDIAN 1
#else
#endif
#if defined(LITTLEENDIAN) && defined(BIGENDIAN)
#error unable to detect endianness
#elif !defined(LITTLEENDIAN) && !defined(BIGENDIAN)
#error unable to detect endianness
#endif

View File

@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef primitiveTypes_h
#define primitiveTypes_h 1
#include "platform.h"
#include <stdint.h>
#ifdef SOFTFLOAT_FAST_INT64

View File

@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef softfloat_types_h
#define softfloat_types_h 1
#include "platform.h"
#include <stdint.h>
/*----------------------------------------------------------------------------

View File

@ -1196,7 +1196,7 @@ fn genHtml(
do_code_tests: bool,
) !void {
var progress = Progress{};
const root_node = try progress.start("Generating docgen examples", toc.nodes.len);
const root_node = progress.start("Generating docgen examples", toc.nodes.len);
defer root_node.end();
var env_map = try process.getEnvMap(allocator);
@ -1708,7 +1708,7 @@ fn genHtml(
}
}
fn exec(allocator: Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {
fn exec(allocator: Allocator, env_map: *process.EnvMap, args: []const []const u8) !ChildProcess.ExecResult {
const result = try ChildProcess.exec(.{
.allocator = allocator,
.argv = args,
@ -1732,7 +1732,7 @@ fn exec(allocator: Allocator, env_map: *std.BufMap, args: []const []const u8) !C
return result;
}
fn getBuiltinCode(allocator: Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
fn getBuiltinCode(allocator: Allocator, env_map: *process.EnvMap, zig_exe: []const u8) ![]const u8 {
const result = try exec(allocator, env_map, &[_][]const u8{ zig_exe, "build-obj", "--show-builtin" });
return result.stdout;
}

View File

@ -316,7 +316,7 @@
<a href="https://ziglang.org/documentation/0.6.0/">0.6.0</a> |
<a href="https://ziglang.org/documentation/0.7.1/">0.7.1</a> |
<a href="https://ziglang.org/documentation/0.8.1/">0.8.1</a> |
<a href="https://ziglang.org/documentation/0.9.0/">0.9.0</a> |
<a href="https://ziglang.org/documentation/0.9.1/">0.9.1</a> |
master
</nav>
<nav aria-labelledby="table-of-contents">
@ -392,7 +392,7 @@ pub fn main() !void {
The code sample begins by adding the {#link|Zig Standard Library#} to the build using the {#link|@import#} builtin function.
The {#syntax#}@import("std"){#endsyntax#} function call creates a structure that represents the Zig Standard Library.
The code then {#link|declares|Container Level Variables#} a
{#link|constant identifier|Assignment#}, named {#syntax#}std{#endsyntax#}, that gives access the features of the Zig Standard Library.
{#link|constant identifier|Assignment#}, named {#syntax#}std{#endsyntax#}, that gives access to the features of the Zig Standard Library.
</p>
<p>
Next, a {#link|public function|Functions#}, {#syntax#}pub fn{#endsyntax#}, named {#syntax#}main{#endsyntax#}
@ -535,8 +535,8 @@ const Timestamp = struct {
{#header_close#}
{#header_open|Top-Level Doc Comments#}
<p>User documentation that doesn't belong to whatever
immediately follows it, like package-level documentation, goes
in top-level doc comments. A top-level doc comment is one that
immediately follows it, like container level documentation, goes
in top level doc comments. A top level doc comment is one that
begins with two slashes and an exclamation point:
{#syntax#}//!{#endsyntax#}.</p>
{#code_begin|syntax|tldoc_comments#}
@ -672,8 +672,8 @@ pub fn main() void {
</tr>
<tr>
<th scope="row">{#syntax#}usize{#endsyntax#}</th>
<td><code class="c">uintptr_t</code></td>
<td>unsigned pointer sized integer</td>
<td><code class="c">uintptr_t</code>, <code class="c">size_t</code></td>
<td>unsigned pointer sized integer. Also see <a href="https://github.com/ziglang/zig/issues/5185">#5185</a></td>
</tr>
<tr>
@ -1040,7 +1040,7 @@ fn addOne(number: i32) i32 {
</p>
<aside>
This documentation discusses the features of the default test runner as provided by the Zig Standard Library.
Its source code is located in <code class="file">lib/std/special/test_runner.zig</code>.
Its source code is located in <code class="file">lib/test_runner.zig</code>.
</aside>
<p>
The shell output shown above displays two lines after the <kbd>zig test</kbd> command. These lines are
@ -1295,13 +1295,39 @@ test "expectError demo" {
A variable is a unit of {#link|Memory#} storage.
</p>
<p>
Variables are never allowed to shadow identifiers from an outer scope.
</p>
<p>
It is generally preferable to use {#syntax#}const{#endsyntax#} rather than
{#syntax#}var{#endsyntax#} when declaring a variable. This causes less work for both
humans and computers to do when reading code, and creates more optimization opportunities.
</p>
{#header_open|Identifiers#}
<p>
Variable identifiers are never allowed to shadow identifiers from an outer scope.
</p>
<p>
Identifiers must start with an alphabetic character or underscore and may be followed
by any number of alphanumeric characters or underscores.
They must not overlap with any keywords. See {#link|Keyword Reference#}.
</p>
<p>
If a name that does not fit these requirements is needed, such as for linking with external libraries, the {#syntax#}@""{#endsyntax#} syntax may be used.
</p>
{#code_begin|syntax#}
const @"identifier with spaces in it" = 0xff;
const @"1SmallStep4Man" = 112358;
const c = @import("std").c;
pub extern "c" fn @"error"() void;
pub extern "c" fn @"fstat$INODE64"(fd: c.fd_t, buf: *c.Stat) c_int;
const Color = enum {
red,
@"really red",
};
const color: Color = .@"really red";
{#code_end#}
{#header_close#}
{#header_open|Container Level Variables#}
<p>
Container level variables have static lifetime and are order-independent and lazily analyzed.
@ -2489,13 +2515,14 @@ test "null terminated array" {
{#header_open|Vectors#}
<p>
A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on
in parallel using SIMD instructions. Vector types are created with the builtin function {#link|@Type#},
or using the shorthand function {#syntax#}std.meta.Vector{#endsyntax#}.
A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or
{#link|Pointers#} which are operated on in parallel, using SIMD instructions if possible.
Vector types are created with the builtin function {#link|@Vector#}.
</p>
<p>
Vectors support the same builtin operators as their underlying base types. These operations are performed
element-wise, and return a vector of the same length as the input vectors. This includes:
Vectors support the same builtin operators as their underlying base types.
These operations are performed element-wise, and return a vector of the same length
as the input vectors. This includes:
</p>
<ul>
<li>Arithmetic ({#syntax#}+{#endsyntax#}, {#syntax#}-{#endsyntax#}, {#syntax#}/{#endsyntax#}, {#syntax#}*{#endsyntax#},
@ -2506,10 +2533,11 @@ test "null terminated array" {
<li>Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)</li>
</ul>
<p>
It is prohibited to use a math operator on a mixture of scalars (individual numbers) and vectors.
Zig provides the {#link|@splat#} builtin to easily convert from scalars to vectors, and it supports {#link|@reduce#}
and array indexing syntax to convert from vectors to scalars. Vectors also support assignment to and from
fixed-length arrays with comptime known length.
It is prohibited to use a math operator on a mixture of scalars (individual numbers)
and vectors. Zig provides the {#link|@splat#} builtin to easily convert from scalars
to vectors, and it supports {#link|@reduce#} and array indexing syntax to convert
from vectors to scalars. Vectors also support assignment to and from fixed-length
arrays with comptime known length.
</p>
<p>
For rearranging elements within and between vectors, Zig provides the {#link|@shuffle#} and {#link|@select#} functions.
@ -2524,16 +2552,14 @@ test "null terminated array" {
</p>
{#code_begin|test|vector_example#}
const std = @import("std");
const Vector = std.meta.Vector;
const expectEqual = std.testing.expectEqual;
test "Basic vector usage" {
// Vectors have a compile-time known length and base type,
// and can be assigned to using array literal syntax
const a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
const b: Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
// Vectors have a compile-time known length and base type.
const a = @Vector(4, i32){ 1, 2, 3, 4 };
const b = @Vector(4, i32){ 5, 6, 7, 8 };
// Math operations take place element-wise
// Math operations take place element-wise.
const c = a + b;
// Individual vector elements can be accessed using array indexing syntax.
@ -2546,19 +2572,19 @@ test "Basic vector usage" {
test "Conversion between vectors, arrays, and slices" {
// Vectors and fixed-length arrays can be automatically assigned back and forth
var arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 };
var vec: Vector(4, f32) = arr1;
var vec: @Vector(4, f32) = arr1;
var arr2: [4]f32 = vec;
try expectEqual(arr1, arr2);
// You can also assign from a slice with comptime-known length to a vector using .*
const vec2: Vector(2, f32) = arr1[1..3].*;
const vec2: @Vector(2, f32) = arr1[1..3].*;
var slice: []const f32 = &arr1;
var offset: u32 = 1;
// To extract a comptime-known length from a runtime-known offset,
// first extract a new slice from the starting offset, then an array of
// comptime known length
const vec3: Vector(2, f32) = slice[offset..][0..2].*;
const vec3: @Vector(2, f32) = slice[offset..][0..2].*;
try expectEqual(slice[offset], vec2[0]);
try expectEqual(slice[offset + 1], vec2[1]);
try expectEqual(vec2, vec3);
@ -3428,6 +3454,8 @@ test "aligned struct fields" {
<li>If the struct is in the {#syntax#}return{#endsyntax#} expression, it gets named after
the function it is returning from, with the parameter values serialized.</li>
<li>Otherwise, the struct gets a name such as <code>(anonymous struct at file.zig:7:38)</code>.</li>
<li>If the struct is declared inside another struct, it gets named after both the parent
struct and the name inferred by the previous rules, separated by a dot.</li>
</ul>
{#code_begin|exe|struct_name#}
const std = @import("std");
@ -3497,7 +3525,7 @@ fn dump(args: anytype) !void {
</p>
<p>
The fields are implicitly named using numbers starting from 0. Because their names are integers,
the {#syntax#}@"0"{#endsyntax#} syntax must be used to access them. Names inside {#syntax#}@""{#endsyntax#} are always recognised as identifiers.
the {#syntax#}@"0"{#endsyntax#} syntax must be used to access them. Names inside {#syntax#}@""{#endsyntax#} are always recognised as {#link|identifiers|Identifiers#}.
</p>
<p>
Like arrays, tuples have a .len field, can be indexed and work with the ++ and ** operators. They can also be iterated over with {#link|inline for#}.
@ -3986,7 +4014,7 @@ test "labeled break from labeled block expression" {
{#see_also|Labeled while|Labeled for#}
{#header_open|Shadowing#}
<p>Identifiers are never allowed to "hide" other identifiers by using the same name:</p>
<p>{#link|Identifiers#} are never allowed to "hide" other identifiers by using the same name:</p>
{#code_begin|test_err|local shadows declaration#}
const pi = 3.14;
@ -4037,7 +4065,7 @@ test "switch simple" {
1, 2, 3 => 0,
// Ranges can be specified using the ... syntax. These are inclusive
// both ends.
// of both ends.
5...100 => 1,
// Branches can be arbitrarily complex.
@ -4809,7 +4837,7 @@ test "errdefer unwinding" {
</p>
{#header_open|Basics#}
{#code_begin|test|test_unreachable#}
// unreachable is used to assert that control flow will never happen upon a
// unreachable is used to assert that control flow will never reach a
// particular location:
test "basic math" {
const x = 1;
@ -5309,6 +5337,179 @@ fn createFoo(param: i32) !Foo {
is covered. The deallocation code is always directly following the allocation code.
</p>
{#header_close#}
{#header_open|Common errdefer Slip-Ups#}
<p>
It should be noted that {#syntax#}errdefer{#endsyntax#} statements only last until the end of the block
they are written in, and therefore are not run if an error is returned outside of that block:
</p>
{#code_begin|test_err|1 tests leaked memory#}
const std = @import("std");
const Allocator = std.mem.Allocator;
const Foo = struct {
data: u32,
};
fn tryToAllocateFoo(allocator: Allocator) !*Foo {
return allocator.create(Foo);
}
fn deallocateFoo(allocator: Allocator, foo: *Foo) void {
allocator.destroy(foo);
}
fn getFooData() !u32 {
return 666;
}
fn createFoo(allocator: Allocator, param: i32) !*Foo {
const foo = getFoo: {
var foo = try tryToAllocateFoo(allocator);
errdefer deallocateFoo(allocator, foo); // Only lasts until the end of getFoo
// Calls deallocateFoo on error
foo.data = try getFooData();
break :getFoo foo;
};
// Outside of the scope of the errdefer, so
// deallocateFoo will not be called here
if (param > 1337) return error.InvalidParam;
return foo;
}
test "createFoo" {
try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468));
}
{#code_end#}
<p>
To ensure that {#syntax#}deallocateFoo{#endsyntax#} is properly called
when returning an error, you must add an {#syntax#}errdefer{#endsyntax#} outside of the block:
{#code_begin|test|test_errdefer_block#}
const std = @import("std");
const Allocator = std.mem.Allocator;
const Foo = struct {
data: u32,
};
fn tryToAllocateFoo(allocator: Allocator) !*Foo {
return allocator.create(Foo);
}
fn deallocateFoo(allocator: Allocator, foo: *Foo) void {
allocator.destroy(foo);
}
fn getFooData() !u32 {
return 666;
}
fn createFoo(allocator: Allocator, param: i32) !*Foo {
const foo = getFoo: {
var foo = try tryToAllocateFoo(allocator);
errdefer deallocateFoo(allocator, foo);
foo.data = try getFooData();
break :getFoo foo;
};
// This lasts for the rest of the function
errdefer deallocateFoo(allocator, foo);
// Error is now properly handled by errdefer
if (param > 1337) return error.InvalidParam;
return foo;
}
test "createFoo" {
try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468));
}
{#code_end#}
<p>
The fact that errdefers only last for the block they are declared in is
especially important when using loops:
</p>
{#code_begin|test_err|3 errors were logged#}
const std = @import("std");
const Allocator = std.mem.Allocator;
const Foo = struct {
data: *u32
};
fn getData() !u32 {
return 666;
}
fn genFoos(allocator: Allocator, num: usize) ![]Foo {
var foos = try allocator.alloc(Foo, num);
errdefer allocator.free(foos);
for(foos) |*foo, i| {
foo.data = try allocator.create(u32);
// This errdefer does not last between iterations
errdefer allocator.destroy(foo.data);
// The data for the first 3 foos will be leaked
if(i >= 3) return error.TooManyFoos;
foo.data.* = try getData();
}
return foos;
}
test "genFoos" {
try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5));
}
{#code_end#}
<p>
Special care must be taken with code that allocates in a loop
to make sure that no memory is leaked when returning an error:
</p>
{#code_begin|test|test_errdefer_loop#}
const std = @import("std");
const Allocator = std.mem.Allocator;
const Foo = struct {
data: *u32
};
fn getData() !u32 {
return 666;
}
fn genFoos(allocator: Allocator, num: usize) ![]Foo {
var foos = try allocator.alloc(Foo, num);
errdefer allocator.free(foos);
// Used to track how many foos have been initialized
// (including their data being allocated)
var num_allocated: usize = 0;
errdefer for(foos[0..num_allocated]) |foo| {
allocator.destroy(foo.data);
};
for(foos) |*foo, i| {
foo.data = try allocator.create(u32);
num_allocated += 1;
if(i >= 3) return error.TooManyFoos;
foo.data.* = try getData();
}
return foos;
}
test "genFoos" {
try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5));
}
{#code_end#}
{#header_close#}
<p>
A couple of other tidbits about error handling:
</p>
@ -6777,8 +6978,7 @@ test "variable values" {
generic data structure.
</p>
<p>
Here is an example of a generic {#syntax#}List{#endsyntax#} data structure, that we will instantiate with
the type {#syntax#}i32{#endsyntax#}. In Zig we refer to the type as {#syntax#}List(i32){#endsyntax#}.
Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.
</p>
{#code_begin|syntax#}
fn List(comptime T: type) type {
@ -6787,27 +6987,46 @@ fn List(comptime T: type) type {
len: usize,
};
}
{#code_end#}
<p>
That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}. For the purposes of error messages
and debugging, Zig infers the name {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating
the anonymous struct.
</p>
<p>
To keep the language small and uniform, all aggregate types in Zig are anonymous. To give a type
a name, we assign it to a constant:
</p>
{#code_begin|syntax#}
const Node = struct {
next: *Node,
name: []u8,
// The generic List data structure can be instantiated by passing in a type:
var buffer: [10]i32 = undefined;
var list = List(i32){
.items = &buffer,
.len = 0,
};
{#code_end#}
<p>
This works because all top level declarations are order-independent, and as long as there isn't
an actual infinite regression, values can refer to themselves, directly or indirectly. In this case,
{#syntax#}Node{#endsyntax#} refers to itself as a pointer, which is not actually an infinite regression, so
it works fine.
That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}.
To keep the language small and uniform, all aggregate types in Zig are anonymous.
For the purposes of error messages and debugging, Zig infers the name
{#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating
the anonymous struct.
</p>
<p>
To explicitly give a type a name, we assign it to a constant.
</p>
{#code_begin|syntax#}
const Node = struct {
next: ?*Node,
name: []const u8,
};
var node_a = Node{
.next = null,
.name = &"Node A",
};
var node_b = Node{
.next = &node_a,
.name = &"Node B",
};
{#code_end#}
<p>
In this example, the {#syntax#}Node{#endsyntax#} struct refers to itself.
This works because all top level declarations are order-independent.
As long as the compiler can determine the size of the struct, it is free to refer to itself.
In this case, {#syntax#}Node{#endsyntax#} refers to itself as a pointer, which has a
well-defined size at compile time, so it works fine.
</p>
{#header_close#}
{#header_open|Case Study: print in Zig#}
@ -7614,7 +7833,7 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {
for the current target to match the C ABI. When the child type of a pointer has
this alignment, the alignment can be omitted from the type.
</p>
<pre>{#syntax#}const expect = @import("std").debug.assert;
<pre>{#syntax#}const assert = @import("std").debug.assert;
comptime {
assert(*u32 == *align(@alignOf(u32)) u32);
}{#endsyntax#}</pre>
@ -7807,7 +8026,7 @@ fn func(y: *i32) void {
only rounds once, and is thus more accurate.
</p>
<p>
Supports Floats and Vectors of floats.
Supports {#link|Floats#} and {#link|Vectors#} of floats.
</p>
{#header_close#}
@ -8297,8 +8516,8 @@ fn internalName() callconv(.C) void {}
{#code_begin|obj#}
export fn foo() void {}
{#code_end#}
<p>Note that even when using {#syntax#}export{#endsyntax#}, {#syntax#}@"foo"{#endsyntax#} syntax can
be used to choose any string for the symbol name:</p>
<p>Note that even when using {#syntax#}export{#endsyntax#}, the {#syntax#}@"foo"{#endsyntax#} syntax for
{#link|identifiers|Identifiers#} can be used to choose any string for the symbol name:</p>
{#code_begin|obj#}
export fn @"A function name that is a complete sentence."() void {}
{#code_end#}
@ -8447,7 +8666,7 @@ fn func() void {
{#header_close#}
{#header_open|@frameSize#}
<pre>{#syntax#}@frameSize() usize{#endsyntax#}</pre>
<pre>{#syntax#}@frameSize(func: anytype) usize{#endsyntax#}</pre>
<p>
This is the same as {#syntax#}@sizeOf(@Frame(func)){#endsyntax#}, where {#syntax#}func{#endsyntax#}
may be runtime-known.
@ -8597,7 +8816,9 @@ test "integer cast panic" {
{#header_open|@intToPtr#}
<pre>{#syntax#}@intToPtr(comptime DestType: type, address: usize) DestType{#endsyntax#}</pre>
<p>
Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}.
Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}. Casting an address of 0 to a destination type
which in not {#link|optional|Optional Pointers#} and does not have the {#syntax#}allowzero{#endsyntax#} attribute will result in a
{#link|Pointer Cast Invalid Null#} panic when runtime safety checks are enabled.
</p>
<p>
If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}
@ -8711,7 +8932,8 @@ test "@wasmMemoryGrow" {
<pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
Modulus division. For unsigned integers this is the same as
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}.
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
</p>
<ul>
<li>{#syntax#}@mod(-5, 3) == 1{#endsyntax#}</li>
@ -8836,7 +9058,8 @@ pub const PrefetchOptions = struct {
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
Remainder division. For unsigned integers this is the same as
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}.
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
</p>
<ul>
<li>{#syntax#}@rem(-5, 3) == -2{#endsyntax#}</li>
@ -8863,7 +9086,7 @@ pub const PrefetchOptions = struct {
{#header_close#}
{#header_open|@select#}
<pre>{#syntax#}@select(comptime T: type, pred: std.meta.Vector(len, bool), a: std.meta.Vector(len, T), b: std.meta.Vector(len, T)) std.meta.Vector(len, T){#endsyntax#}</pre>
<pre>{#syntax#}@select(comptime T: type, pred: @Vector(len, bool), a: @Vector(len, T), b: @Vector(len, T)) @Vector(len, T){#endsyntax#}</pre>
<p>
Selects values element-wise from {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} based on {#syntax#}pred{#endsyntax#}. If {#syntax#}pred[i]{#endsyntax#} is {#syntax#}true{#endsyntax#}, the corresponding element in the result will be {#syntax#}a[i]{#endsyntax#} and otherwise {#syntax#}b[i]{#endsyntax#}.
</p>
@ -8878,14 +9101,14 @@ pub const PrefetchOptions = struct {
{#header_close#}
{#header_open|@setCold#}
<pre>{#syntax#}@setCold(is_cold: bool){#endsyntax#}</pre>
<pre>{#syntax#}@setCold(comptime is_cold: bool){#endsyntax#}</pre>
<p>
Tells the optimizer that a function is rarely called.
</p>
{#header_close#}
{#header_open|@setEvalBranchQuota#}
<pre>{#syntax#}@setEvalBranchQuota(new_quota: u32){#endsyntax#}</pre>
<pre>{#syntax#}@setEvalBranchQuota(comptime new_quota: u32){#endsyntax#}</pre>
<p>
Changes the maximum number of backwards branches that compile-time code
execution can use before giving up and making a compile error.
@ -8920,7 +9143,7 @@ test "foo" {
{#header_close#}
{#header_open|@setFloatMode#}
<pre>{#syntax#}@setFloatMode(mode: @import("std").builtin.FloatMode){#endsyntax#}</pre>
<pre>{#syntax#}@setFloatMode(comptime mode: @import("std").builtin.FloatMode){#endsyntax#}</pre>
<p>
Sets the floating point mode of the current scope. Possible values are:
</p>
@ -8955,7 +9178,7 @@ pub const FloatMode = enum {
{#header_close#}
{#header_open|@setRuntimeSafety#}
<pre>{#syntax#}@setRuntimeSafety(safety_on: bool) void{#endsyntax#}</pre>
<pre>{#syntax#}@setRuntimeSafety(comptime safety_on: bool) void{#endsyntax#}</pre>
<p>
Sets whether runtime safety checks are enabled for the scope that contains the function call.
</p>
@ -8997,8 +9220,8 @@ test "@setRuntimeSafety" {
any bits that disagree with the resultant sign bit are shifted out.
</p>
<p>
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior.
</p>
{#see_also|@shrExact|@shlWithOverflow#}
{#header_close#}
@ -9011,8 +9234,8 @@ test "@setRuntimeSafety" {
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
</p>
<p>
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior.
</p>
{#see_also|@shlExact|@shrExact#}
{#header_close#}
@ -9024,14 +9247,14 @@ test "@setRuntimeSafety" {
that the shift will not shift any 1 bits out.
</p>
<p>
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).Int.bits){#endsyntax#} bits.
This is because {#syntax#}shift_amt >= @typeInfo(T).Int.bits{#endsyntax#} is undefined behavior.
</p>
{#see_also|@shlExact|@shlWithOverflow#}
{#header_close#}
{#header_open|@shuffle#}
<pre>{#syntax#}@shuffle(comptime E: type, a: std.meta.Vector(a_len, E), b: std.meta.Vector(b_len, E), comptime mask: std.meta.Vector(mask_len, i32)) std.meta.Vector(mask_len, E){#endsyntax#}</pre>
<pre>{#syntax#}@shuffle(comptime E: type, a: @Vector(a_len, E), b: @Vector(b_len, E), comptime mask: @Vector(mask_len, i32)) @Vector(mask_len, E){#endsyntax#}</pre>
<p>
Constructs a new {#link|vector|Vectors#} by selecting elements from {#syntax#}a{#endsyntax#} and
{#syntax#}b{#endsyntax#} based on {#syntax#}mask{#endsyntax#}.
@ -9066,22 +9289,21 @@ test "@setRuntimeSafety" {
</p>
{#code_begin|test|vector_shuffle#}
const std = @import("std");
const Vector = std.meta.Vector;
const expect = std.testing.expect;
test "vector @shuffle" {
const a: Vector(7, u8) = [_]u8{ 'o', 'l', 'h', 'e', 'r', 'z', 'w' };
const b: Vector(4, u8) = [_]u8{ 'w', 'd', '!', 'x' };
const a = @Vector(7, u8){ 'o', 'l', 'h', 'e', 'r', 'z', 'w' };
const b = @Vector(4, u8){ 'w', 'd', '!', 'x' };
// To shuffle within a single vector, pass undefined as the second argument.
// Notice that we can re-order, duplicate, or omit elements of the input vector
const mask1: Vector(5, i32) = [_]i32{ 2, 3, 1, 1, 0 };
const res1: Vector(5, u8) = @shuffle(u8, a, undefined, mask1);
const mask1 = @Vector(5, i32){ 2, 3, 1, 1, 0 };
const res1: @Vector(5, u8) = @shuffle(u8, a, undefined, mask1);
try expect(std.mem.eql(u8, &@as([5]u8, res1), "hello"));
// Combining two vectors
const mask2: Vector(6, i32) = [_]i32{ -1, 0, 4, 1, -2, -3 };
const res2: Vector(6, u8) = @shuffle(u8, a, b, mask2);
const mask2 = @Vector(6, i32){ -1, 0, 4, 1, -2, -3 };
const res2: @Vector(6, u8) = @shuffle(u8, a, b, mask2);
try expect(std.mem.eql(u8, &@as([6]u8, res2), "world!"));
}
{#code_end#}
@ -9108,7 +9330,7 @@ test "vector @shuffle" {
{#header_close#}
{#header_open|@splat#}
<pre>{#syntax#}@splat(comptime len: u32, scalar: anytype) std.meta.Vector(len, @TypeOf(scalar)){#endsyntax#}</pre>
<pre>{#syntax#}@splat(comptime len: u32, scalar: anytype) @Vector(len, @TypeOf(scalar)){#endsyntax#}</pre>
<p>
Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value
{#syntax#}scalar{#endsyntax#}:
@ -9120,7 +9342,7 @@ const expect = std.testing.expect;
test "vector @splat" {
const scalar: u32 = 5;
const result = @splat(4, scalar);
comptime try expect(@TypeOf(result) == std.meta.Vector(4, u32));
comptime try expect(@TypeOf(result) == @Vector(4, u32));
try expect(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 }));
}
{#code_end#}
@ -9132,22 +9354,23 @@ test "vector @splat" {
{#header_close#}
{#header_open|@reduce#}
<pre>{#syntax#}@reduce(comptime op: std.builtin.ReduceOp, value: anytype) std.meta.Child(value){#endsyntax#}</pre>
<pre>{#syntax#}@reduce(comptime op: std.builtin.ReduceOp, value: anytype) E{#endsyntax#}</pre>
<p>
Transforms a {#link|vector|Vectors#} into a scalar value by performing a
sequential horizontal reduction of its elements using the specified operator {#syntax#}op{#endsyntax#}.
Transforms a {#link|vector|Vectors#} into a scalar value (of type <code>E</code>)
by performing a sequential horizontal reduction of its elements using the
specified operator {#syntax#}op{#endsyntax#}.
</p>
<p>
Not every operator is available for every vector element type:
</p>
<ul>
<li>Every operator is available for {#link|integer|Integers#} vectors.</li>
<li>{#syntax#}.And{#endsyntax#}, {#syntax#}.Or{#endsyntax#},
{#syntax#}.Xor{#endsyntax#} are available for
{#syntax#}.Xor{#endsyntax#} are additionally available for
{#syntax#}bool{#endsyntax#} vectors,</li>
<li>{#syntax#}.Min{#endsyntax#}, {#syntax#}.Max{#endsyntax#},
{#syntax#}.Add{#endsyntax#}, {#syntax#}.Mul{#endsyntax#} are
available for {#link|floating point|Floats#} vectors,</li>
<li>Every operator is available for {#link|integer|Integers#} vectors.</li>
additionally available for {#link|floating point|Floats#} vectors,</li>
</ul>
<p>
Note that {#syntax#}.Add{#endsyntax#} and {#syntax#}.Mul{#endsyntax#}
@ -9160,10 +9383,10 @@ const std = @import("std");
const expect = std.testing.expect;
test "vector @reduce" {
const value: std.meta.Vector(4, i32) = [_]i32{ 1, -1, 1, -1 };
const value = @Vector(4, i32){ 1, -1, 1, -1 };
const result = value > @splat(4, @as(i32, 0));
// result is { true, false, true, false };
comptime try expect(@TypeOf(result) == std.meta.Vector(4, bool));
comptime try expect(@TypeOf(result) == @Vector(4, bool));
const is_all_true = @reduce(.And, result);
comptime try expect(@TypeOf(is_all_true) == bool);
try expect(is_all_true == false);
@ -9217,6 +9440,7 @@ fn doTheTest() !void {
<a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
</p>
{#header_close#}
{#header_open|@cos#}
<pre>{#syntax#}@cos(value: anytype) @TypeOf(value){#endsyntax#}</pre>
<p>
@ -9228,6 +9452,19 @@ fn doTheTest() !void {
<a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
</p>
{#header_close#}
{#header_open|@tan#}
<pre>{#syntax#}@tan(value: anytype) @TypeOf(value){#endsyntax#}</pre>
<p>
Tangent trigonometric function on a floating point number.
Uses a dedicated hardware instruction when available.
</p>
<p>
Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that
<a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
</p>
{#header_close#}
{#header_open|@exp#}
<pre>{#syntax#}@exp(value: anytype) @TypeOf(value){#endsyntax#}</pre>
<p>
@ -9418,7 +9655,7 @@ test "integer truncation" {
{#header_close#}
{#header_open|@Type#}
<pre>{#syntax#}@Type(comptime info: std.builtin.TypeInfo) type{#endsyntax#}</pre>
<pre>{#syntax#}@Type(comptime info: std.builtin.Type) type{#endsyntax#}</pre>
<p>
This function is the inverse of {#link|@typeInfo#}. It reifies type information
into a {#syntax#}type{#endsyntax#}.
@ -9460,14 +9697,19 @@ test "integer truncation" {
</ul>
{#header_close#}
{#header_open|@typeInfo#}
<pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.TypeInfo{#endsyntax#}</pre>
<pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.Type{#endsyntax#}</pre>
<p>
Provides type reflection.
</p>
<p>
For {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and
{#link|error sets|Error Set Type#}, the fields are guaranteed to be in the same
order as declared. For declarations, the order is unspecified.
Type information of {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and
{#link|error sets|Error Set Type#} has fields which are are guaranteed to be in the same
order as appearance in the source file.
</p>
<p>
Type information of {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and
{#link|opaques|opaque#} has declarations, which are also guaranteed to be in the same
order as appearance in the source file.
</p>
{#header_close#}
@ -9476,8 +9718,9 @@ test "integer truncation" {
<p>
This function returns the string representation of a type, as
an array. It is equivalent to a string literal of the type name.
The returned type name is fully qualified with the parent namespace included
as part of the type name with a series of dots.
</p>
{#header_close#}
{#header_open|@TypeOf#}
@ -9517,6 +9760,12 @@ fn foo(comptime T: type, ptr: *T) T {
{#syntax#}@unionInit{#endsyntax#} forwards its {#link|result location|Result Location Semantics#} to {#syntax#}init_expr{#endsyntax#}.
</p>
{#header_close#}
{#header_open|@Vector#}
<pre>{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}</pre>
<p>Creates {#link|Vectors#}.</p>
{#header_close#}
{#header_close#}
{#header_open|Build Mode#}
@ -10352,7 +10601,7 @@ pub fn main() !void {
<p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
This is why it is an error to pass a string literal to a mutable slice, like this:
</p>
{#code_begin|test_err|expected type '[]u8'#}
{#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#}
fn foo(s: []u8) void {
_ = s;
}
@ -11044,7 +11293,7 @@ pub fn main() !void {
var preopens = PreopenList.init(gpa);
defer preopens.deinit();
try preopens.populate();
try preopens.populate(null);
for (preopens.asSlice()) |preopen, i| {
std.debug.print("{}: {}\n", .{ i, preopen });
@ -11143,7 +11392,7 @@ Architectures:
riscv32
riscv64
sparc
sparcv9
sparc64
sparcel
s390x
thumb
@ -11294,7 +11543,7 @@ Available libcs:
s390x-linux-gnu
s390x-linux-musl
sparc-linux-gnu
sparcv9-linux-gnu
sparc64-linux-gnu
wasm32-freestanding-musl
wasm32-wasi-musl
x86_64-linux-gnu
@ -11720,17 +11969,6 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}false{#endsyntax#}</pre>
</th>
<td>
The boolean value {#syntax#}false{#endsyntax#}.
<ul>
<li>See also {#link|Primitive Values#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}fn{#endsyntax#}</pre>
@ -11806,17 +12044,6 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}null{#endsyntax#}</pre>
</th>
<td>
The optional value {#syntax#}null{#endsyntax#}.
<ul>
<li>See also {#link|null#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}or{#endsyntax#}</pre>
@ -11955,17 +12182,6 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}true{#endsyntax#}</pre>
</th>
<td>
The boolean value {#syntax#}true{#endsyntax#}.
<ul>
<li>See also {#link|Primitive Values#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}try{#endsyntax#}</pre>
@ -11979,17 +12195,6 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}undefined{#endsyntax#}</pre>
</th>
<td>
{#syntax#}undefined{#endsyntax#} can be used to leave a value uninitialized.
<ul>
<li>See also {#link|undefined#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}union{#endsyntax#}</pre>

View File

@ -24,19 +24,19 @@ pub fn main() !void {
var arg_idx: usize = 1;
const zig_exe = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected first argument to be path to zig compiler\n", .{});
std.debug.print("Expected path to zig compiler\n", .{});
return error.InvalidArgs;
};
const build_root = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected second argument to be build root directory path\n", .{});
std.debug.print("Expected build root directory path\n", .{});
return error.InvalidArgs;
};
const cache_root = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected third argument to be cache root directory path\n", .{});
std.debug.print("Expected cache root directory path\n", .{});
return error.InvalidArgs;
};
const global_cache_root = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected third argument to be global cache root directory path\n", .{});
std.debug.print("Expected global cache root directory path\n", .{});
return error.InvalidArgs;
};
@ -147,10 +147,6 @@ pub fn main() !void {
std.debug.print("Expected argument after --glibc-runtimes\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--verbose-tokenize")) {
builder.verbose_tokenize = true;
} else if (mem.eql(u8, arg, "--verbose-ast")) {
builder.verbose_ast = true;
} else if (mem.eql(u8, arg, "--verbose-link")) {
builder.verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-air")) {
@ -185,6 +181,10 @@ pub fn main() !void {
builder.enable_darling = true;
} else if (mem.eql(u8, arg, "-fno-darling")) {
builder.enable_darling = false;
} else if (mem.eql(u8, arg, "-fstage1")) {
builder.use_stage1 = true;
} else if (mem.eql(u8, arg, "-fno-stage1")) {
builder.use_stage1 = false;
} else if (mem.eql(u8, arg, "--")) {
builder.args = argsRest(args, arg_idx);
break;
@ -306,12 +306,13 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
try out_stream.writeAll(
\\
\\Advanced Options:
\\ -fstage1 Force using bootstrap compiler as the codegen backend
\\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend
\\ --build-file [file] Override path to build.zig
\\ --cache-dir [path] Override path to zig cache directory
\\ --cache-dir [path] Override path to local Zig cache directory
\\ --global-cache-dir [path] Override path to global Zig cache directory
\\ --zig-lib-dir [arg] Override path to Zig lib directory
\\ --debug-log [scope] Enable debugging the compiler
\\ --verbose-tokenize Enable compiler debug output for tokenization
\\ --verbose-ast Enable compiler debug output for parsing into an AST
\\ --verbose-link Enable compiler debug output for linking
\\ --verbose-air Enable compiler debug output for Zig AIR
\\ --verbose-llvm-ir Enable compiler debug output for LLVM IR

View File

@ -1,11 +1,17 @@
//! This is Zig's multi-target implementation of libc.
//! When builtin.link_libc is true, we need to export all the functions and
//! provide an entire C API.
//! Otherwise, only the functions which LLVM generates calls to need to be generated,
//! such as memcpy, memset, and some math functions.
const std = @import("std");
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
const math = std.math;
const isNan = std.math.isNan;
const maxInt = std.math.maxInt;
const native_os = builtin.os.tag;
const native_arch = builtin.cpu.arch;
const native_abi = builtin.abi;
const native_os = builtin.os.tag;
const long_double_is_f128 = builtin.target.longDoubleIsF128();
const is_wasm = switch (native_arch) {
.wasm32, .wasm64 => true,
@ -19,10 +25,23 @@ const is_freestanding = switch (native_os) {
.freestanding => true,
else => false,
};
comptime {
if (is_freestanding and is_wasm and builtin.link_libc) {
@export(wasm_start, .{ .name = "_start", .linkage = .Strong });
}
if (native_os == .linux) {
@export(clone, .{ .name = "clone" });
}
@export(memset, .{ .name = "memset", .linkage = .Strong });
@export(__memset, .{ .name = "__memset", .linkage = .Strong });
@export(memcpy, .{ .name = "memcpy", .linkage = .Strong });
@export(memmove, .{ .name = "memmove", .linkage = .Strong });
@export(memcmp, .{ .name = "memcmp", .linkage = .Strong });
@export(bcmp, .{ .name = "bcmp", .linkage = .Strong });
if (builtin.link_libc) {
@export(strcmp, .{ .name = "strcmp", .linkage = .Strong });
@export(strncmp, .{ .name = "strncmp", .linkage = .Strong });
@ -37,13 +56,137 @@ comptime {
}
}
var _fltused: c_int = 1;
// 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 {
@setCold(true);
_ = error_return_trace;
if (builtin.is_test) {
std.debug.panic("{s}", .{msg});
}
if (native_os != .freestanding and native_os != .other) {
std.os.abort();
}
while (true) {}
}
extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
fn wasm_start() callconv(.C) void {
_ = main(0, undefined);
}
fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (len != 0) {
var d = dest.?;
var n = len;
while (true) {
d[0] = c;
n -= 1;
if (n == 0) break;
d += 1;
}
}
return dest;
}
fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
if (dest_n < n)
@panic("buffer overflow");
return memset(dest, c, n);
}
fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (len != 0) {
var d = dest.?;
var s = src.?;
var n = len;
while (true) {
d[0] = s[0];
n -= 1;
if (n == 0) break;
d += 1;
s += 1;
}
}
return dest;
}
fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (@ptrToInt(dest) < @ptrToInt(src)) {
var index: usize = 0;
while (index != n) : (index += 1) {
dest.?[index] = src.?[index];
}
} else {
var index = n;
while (index != 0) {
index -= 1;
dest.?[index] = src.?[index];
}
}
return dest;
}
fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1) {
const compare_val = @bitCast(i8, vl.?[index] -% vr.?[index]);
if (compare_val != 0) {
return compare_val;
}
}
return 0;
}
test "memcmp" {
const base_arr = &[_]u8{ 1, 1, 1 };
const arr1 = &[_]u8{ 1, 1, 1 };
const arr2 = &[_]u8{ 1, 0, 1 };
const arr3 = &[_]u8{ 1, 2, 1 };
try std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
try std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
}
fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1) {
if (vl[index] != vr[index]) {
return 1;
}
}
return 0;
}
test "bcmp" {
const base_arr = &[_]u8{ 1, 1, 1 };
const arr1 = &[_]u8{ 1, 1, 1 };
const arr2 = &[_]u8{ 1, 0, 1 };
const arr3 = &[_]u8{ 1, 2, 1 };
try std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
try std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
try std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
}
var _fltused: c_int = 1;
fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
var i: usize = 0;
while (src[i] != 0) : (i += 1) {
@ -161,106 +304,6 @@ test "strncmp" {
try std.testing.expect(strncmp("\xff", "\x02", 1) == 253);
}
export fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1)
dest.?[index] = c;
return dest;
}
export fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
if (dest_n < n)
@panic("buffer overflow");
return memset(dest, c, n);
}
export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1)
dest.?[index] = src.?[index];
return dest;
}
export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (@ptrToInt(dest) < @ptrToInt(src)) {
var index: usize = 0;
while (index != n) : (index += 1) {
dest.?[index] = src.?[index];
}
} else {
var index = n;
while (index != 0) {
index -= 1;
dest.?[index] = src.?[index];
}
}
return dest;
}
export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1) {
const compare_val = @bitCast(i8, vl.?[index] -% vr.?[index]);
if (compare_val != 0) {
return compare_val;
}
}
return 0;
}
test "memcmp" {
const base_arr = &[_]u8{ 1, 1, 1 };
const arr1 = &[_]u8{ 1, 1, 1 };
const arr2 = &[_]u8{ 1, 0, 1 };
const arr3 = &[_]u8{ 1, 2, 1 };
try std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
try std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
}
export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
@setRuntimeSafety(false);
var index: usize = 0;
while (index != n) : (index += 1) {
if (vl[index] != vr[index]) {
return 1;
}
}
return 0;
}
test "bcmp" {
const base_arr = &[_]u8{ 1, 1, 1 };
const arr1 = &[_]u8{ 1, 1, 1 };
const arr2 = &[_]u8{ 1, 0, 1 };
const arr3 = &[_]u8{ 1, 2, 1 };
try std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
try std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
try std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
}
comptime {
if (native_os == .linux) {
@export(clone, .{ .name = "clone" });
}
}
// TODO we should be able to put this directly in std/linux/x86_64.zig but
// it causes a segfault in release mode. this is a workaround of calling it
// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
@ -582,7 +625,7 @@ fn clone() callconv(.Naked) void {
\\ sc
);
},
.sparcv9 => {
.sparc64 => {
// __clone(func, stack, flags, arg, ptid, tls, ctid)
// i0, i1, i2, i3, i4, i5, sp
// syscall(SYS_clone, flags, stack, ptid, tls, ctid)
@ -629,568 +672,3 @@ fn clone() callconv(.Naked) void {
else => @compileError("Implement clone() for this arch."),
}
}
const math = std.math;
export fn fmodf(x: f32, y: f32) f32 {
return generic_fmod(f32, x, y);
}
export fn fmod(x: f64, y: f64) f64 {
return generic_fmod(f64, x, y);
}
export fn ceilf(x: f32) f32 {
return math.ceil(x);
}
export fn ceil(x: f64) f64 {
return math.ceil(x);
}
export fn ceill(x: c_longdouble) c_longdouble {
if (!long_double_is_f128) {
@panic("TODO implement this");
}
return math.ceil(x);
}
export fn fmaf(a: f32, b: f32, c: f32) f32 {
return math.fma(f32, a, b, c);
}
export fn fma(a: f64, b: f64, c: f64) f64 {
return math.fma(f64, a, b, c);
}
export fn fmal(a: c_longdouble, b: c_longdouble, c: c_longdouble) c_longdouble {
if (!long_double_is_f128) {
@panic("TODO implement this");
}
return math.fma(c_longdouble, a, b, c);
}
export fn sin(a: f64) f64 {
return math.sin(a);
}
export fn sinf(a: f32) f32 {
return math.sin(a);
}
export fn cos(a: f64) f64 {
return math.cos(a);
}
export fn cosf(a: f32) f32 {
return math.cos(a);
}
export fn sincos(a: f64, r_sin: *f64, r_cos: *f64) void {
r_sin.* = math.sin(a);
r_cos.* = math.cos(a);
}
export fn sincosf(a: f32, r_sin: *f32, r_cos: *f32) void {
r_sin.* = math.sin(a);
r_cos.* = math.cos(a);
}
export fn exp(a: f64) f64 {
return math.exp(a);
}
export fn expf(a: f32) f32 {
return math.exp(a);
}
export fn exp2(a: f64) f64 {
return math.exp2(a);
}
export fn exp2f(a: f32) f32 {
return math.exp2(a);
}
export fn log(a: f64) f64 {
return math.ln(a);
}
export fn logf(a: f32) f32 {
return math.ln(a);
}
export fn log2(a: f64) f64 {
return math.log2(a);
}
export fn log2f(a: f32) f32 {
return math.log2(a);
}
export fn log10(a: f64) f64 {
return math.log10(a);
}
export fn log10f(a: f32) f32 {
return math.log10(a);
}
export fn fabs(a: f64) f64 {
return math.fabs(a);
}
export fn fabsf(a: f32) f32 {
return math.fabs(a);
}
export fn trunc(a: f64) f64 {
return math.trunc(a);
}
export fn truncf(a: f32) f32 {
return math.trunc(a);
}
export fn truncl(a: c_longdouble) c_longdouble {
if (!long_double_is_f128) {
@panic("TODO implement this");
}
return math.trunc(a);
}
export fn round(a: f64) f64 {
return math.round(a);
}
export fn roundf(a: f32) f32 {
return math.round(a);
}
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);
const digits = if (T == f32) 23 else 52;
const exp_bits = if (T == f32) 9 else 12;
const bits_minus_1 = bits - 1;
const mask = if (T == f32) 0xff else 0x7ff;
var ux = @bitCast(uint, x);
var uy = @bitCast(uint, y);
var ex = @intCast(i32, (ux >> digits) & mask);
var ey = @intCast(i32, (uy >> digits) & mask);
const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1);
var i: uint = undefined;
if (uy << 1 == 0 or isNan(@bitCast(T, uy)) or ex == mask)
return (x * y) / (x * y);
if (ux << 1 <= uy << 1) {
if (ux << 1 == uy << 1)
return 0 * x;
return x;
}
// normalize x and y
if (ex == 0) {
i = ux << exp_bits;
while (i >> bits_minus_1 == 0) : ({
ex -= 1;
i <<= 1;
}) {}
ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1));
} else {
ux &= maxInt(uint) >> exp_bits;
ux |= 1 << digits;
}
if (ey == 0) {
i = uy << exp_bits;
while (i >> bits_minus_1 == 0) : ({
ey -= 1;
i <<= 1;
}) {}
uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1));
} else {
uy &= maxInt(uint) >> exp_bits;
uy |= 1 << digits;
}
// x mod y
while (ex > ey) : (ex -= 1) {
i = ux -% uy;
if (i >> bits_minus_1 == 0) {
if (i == 0)
return 0 * x;
ux = i;
}
ux <<= 1;
}
i = ux -% uy;
if (i >> bits_minus_1 == 0) {
if (i == 0)
return 0 * x;
ux = i;
}
while (ux >> digits == 0) : ({
ux <<= 1;
ex -= 1;
}) {}
// scale result up
if (ex > 0) {
ux -%= 1 << digits;
ux |= @as(uint, @bitCast(u32, ex)) << digits;
} else {
ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1));
}
if (T == f32) {
ux |= sx;
} else {
ux |= @intCast(uint, sx) << bits_minus_1;
}
return @bitCast(T, ux);
}
test "fmod, fmodf" {
inline for ([_]type{ f32, f64 }) |T| {
const nan_val = math.nan(T);
const inf_val = math.inf(T);
try std.testing.expect(isNan(generic_fmod(T, nan_val, 1.0)));
try std.testing.expect(isNan(generic_fmod(T, 1.0, nan_val)));
try std.testing.expect(isNan(generic_fmod(T, inf_val, 1.0)));
try std.testing.expect(isNan(generic_fmod(T, 0.0, 0.0)));
try std.testing.expect(isNan(generic_fmod(T, 1.0, 0.0)));
try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0));
try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0));
try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0));
try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0));
try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0));
try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0));
}
}
fn generic_fmin(comptime T: type, x: T, y: T) T {
if (isNan(x))
return y;
if (isNan(y))
return x;
return if (x < y) x else y;
}
export fn fminf(x: f32, y: f32) callconv(.C) f32 {
return generic_fmin(f32, x, y);
}
export fn fmin(x: f64, y: f64) callconv(.C) f64 {
return generic_fmin(f64, x, y);
}
test "fmin, fminf" {
inline for ([_]type{ f32, f64 }) |T| {
const nan_val = math.nan(T);
try std.testing.expect(isNan(generic_fmin(T, nan_val, nan_val)));
try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0));
try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val));
try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0));
try std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0));
}
}
fn generic_fmax(comptime T: type, x: T, y: T) T {
if (isNan(x))
return y;
if (isNan(y))
return x;
return if (x < y) y else x;
}
export fn fmaxf(x: f32, y: f32) callconv(.C) f32 {
return generic_fmax(f32, x, y);
}
export fn fmax(x: f64, y: f64) callconv(.C) f64 {
return generic_fmax(f64, x, y);
}
test "fmax, fmaxf" {
inline for ([_]type{ f32, f64 }) |T| {
const nan_val = math.nan(T);
try std.testing.expect(isNan(generic_fmax(T, nan_val, nan_val)));
try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0));
try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val));
try std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0));
try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0));
}
}
// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
// potentially some edge cases remaining that are not handled in the same way.
export fn sqrt(x: f64) f64 {
const tiny: f64 = 1.0e-300;
const sign: u32 = 0x80000000;
const u = @bitCast(u64, x);
var ix0 = @intCast(u32, u >> 32);
var ix1 = @intCast(u32, u & 0xFFFFFFFF);
// sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
if (ix0 & 0x7FF00000 == 0x7FF00000) {
return x * x + x;
}
// sqrt(+-0) = +-0
if (x == 0.0) {
return x;
}
// sqrt(-ve) = snan
if (ix0 & sign != 0) {
return math.snan(f64);
}
// normalize x
var m = @intCast(i32, ix0 >> 20);
if (m == 0) {
// subnormal
while (ix0 == 0) {
m -= 21;
ix0 |= ix1 >> 11;
ix1 <<= 21;
}
// subnormal
var i: u32 = 0;
while (ix0 & 0x00100000 == 0) : (i += 1) {
ix0 <<= 1;
}
m -= @intCast(i32, i) - 1;
ix0 |= ix1 >> @intCast(u5, 32 - i);
ix1 <<= @intCast(u5, i);
}
// unbias exponent
m -= 1023;
ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
if (m & 1 != 0) {
ix0 += ix0 + (ix1 >> 31);
ix1 = ix1 +% ix1;
}
m >>= 1;
// sqrt(x) bit by bit
ix0 += ix0 + (ix1 >> 31);
ix1 = ix1 +% ix1;
var q: u32 = 0;
var q1: u32 = 0;
var s0: u32 = 0;
var s1: u32 = 0;
var r: u32 = 0x00200000;
var t: u32 = undefined;
var t1: u32 = undefined;
while (r != 0) {
t = s0 +% r;
if (t <= ix0) {
s0 = t + r;
ix0 -= t;
q += r;
}
ix0 = ix0 +% ix0 +% (ix1 >> 31);
ix1 = ix1 +% ix1;
r >>= 1;
}
r = sign;
while (r != 0) {
t1 = s1 +% r;
t = s0;
if (t < ix0 or (t == ix0 and t1 <= ix1)) {
s1 = t1 +% r;
if (t1 & sign == sign and s1 & sign == 0) {
s0 += 1;
}
ix0 -= t;
if (ix1 < t1) {
ix0 -= 1;
}
ix1 = ix1 -% t1;
q1 += r;
}
ix0 = ix0 +% ix0 +% (ix1 >> 31);
ix1 = ix1 +% ix1;
r >>= 1;
}
// rounding direction
if (ix0 | ix1 != 0) {
var z = 1.0 - tiny; // raise inexact
if (z >= 1.0) {
z = 1.0 + tiny;
if (q1 == 0xFFFFFFFF) {
q1 = 0;
q += 1;
} else if (z > 1.0) {
if (q1 == 0xFFFFFFFE) {
q += 1;
}
q1 += 2;
} else {
q1 += q1 & 1;
}
}
}
ix0 = (q >> 1) + 0x3FE00000;
ix1 = q1 >> 1;
if (q & 1 != 0) {
ix1 |= 0x80000000;
}
// NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
// behaviour at least.
var iix0 = @intCast(i32, ix0);
iix0 = iix0 +% (m << 20);
const uz = (@intCast(u64, iix0) << 32) | ix1;
return @bitCast(f64, uz);
}
test "sqrt" {
const V = [_]f64{
0.0,
4.089288054930154,
7.538757127071935,
8.97780793672623,
5.304443821913729,
5.682408965311888,
0.5846878579110049,
3.650338664297043,
0.3178091951800732,
7.1505232436382835,
3.6589165881946464,
};
// Note that @sqrt will either generate the sqrt opcode (if supported by the
// target ISA) or a call to `sqrtf` otherwise.
for (V) |val|
try std.testing.expectEqual(@sqrt(val), sqrt(val));
}
test "sqrt special" {
try std.testing.expect(std.math.isPositiveInf(sqrt(std.math.inf(f64))));
try std.testing.expect(sqrt(0.0) == 0.0);
try std.testing.expect(sqrt(-0.0) == -0.0);
try std.testing.expect(isNan(sqrt(-1.0)));
try std.testing.expect(isNan(sqrt(std.math.nan(f64))));
}
export fn sqrtf(x: f32) f32 {
const tiny: f32 = 1.0e-30;
const sign: i32 = @bitCast(i32, @as(u32, 0x80000000));
var ix: i32 = @bitCast(i32, x);
if ((ix & 0x7F800000) == 0x7F800000) {
return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
}
// zero
if (ix <= 0) {
if (ix & ~sign == 0) {
return x; // sqrt (+-0) = +-0
}
if (ix < 0) {
return math.snan(f32);
}
}
// normalize
var m = ix >> 23;
if (m == 0) {
// subnormal
var i: i32 = 0;
while (ix & 0x00800000 == 0) : (i += 1) {
ix <<= 1;
}
m -= i - 1;
}
m -= 127; // unbias exponent
ix = (ix & 0x007FFFFF) | 0x00800000;
if (m & 1 != 0) { // odd m, double x to even
ix += ix;
}
m >>= 1; // m = [m / 2]
// sqrt(x) bit by bit
ix += ix;
var q: i32 = 0; // q = sqrt(x)
var s: i32 = 0;
var r: i32 = 0x01000000; // r = moving bit right -> left
while (r != 0) {
const t = s + r;
if (t <= ix) {
s = t + r;
ix -= t;
q += r;
}
ix += ix;
r >>= 1;
}
// floating add to find rounding direction
if (ix != 0) {
var z = 1.0 - tiny; // inexact
if (z >= 1.0) {
z = 1.0 + tiny;
if (z > 1.0) {
q += 2;
} else {
if (q & 1 != 0) {
q += 1;
}
}
}
}
ix = (q >> 1) + 0x3f000000;
ix += m << 23;
return @bitCast(f32, ix);
}
test "sqrtf" {
const V = [_]f32{
0.0,
4.089288054930154,
7.538757127071935,
8.97780793672623,
5.304443821913729,
5.682408965311888,
0.5846878579110049,
3.650338664297043,
0.3178091951800732,
7.1505232436382835,
3.6589165881946464,
};
// Note that @sqrt will either generate the sqrt opcode (if supported by the
// target ISA) or a call to `sqrtf` otherwise.
for (V) |val|
try std.testing.expectEqual(@sqrt(val), sqrtf(val));
}
test "sqrtf special" {
try std.testing.expect(std.math.isPositiveInf(sqrtf(std.math.inf(f32))));
try std.testing.expect(sqrtf(0.0) == 0.0);
try std.testing.expect(sqrtf(-0.0) == -0.0);
try std.testing.expect(isNan(sqrtf(-1.0)));
try std.testing.expect(isNan(sqrtf(std.math.nan(f32))));
}

187
lib/compiler_rt.zig Normal file
View File

@ -0,0 +1,187 @@
pub const panic = @import("compiler_rt/common.zig").panic;
comptime {
_ = @import("compiler_rt/atomics.zig");
_ = @import("compiler_rt/addf3.zig");
_ = @import("compiler_rt/addsf3.zig");
_ = @import("compiler_rt/adddf3.zig");
_ = @import("compiler_rt/addtf3.zig");
_ = @import("compiler_rt/addxf3.zig");
_ = @import("compiler_rt/subsf3.zig");
_ = @import("compiler_rt/subdf3.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/negsf2.zig");
_ = @import("compiler_rt/negdf2.zig");
_ = @import("compiler_rt/negtf2.zig");
_ = @import("compiler_rt/negxf2.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/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");
}

267
lib/compiler_rt/README.md Normal file
View File

@ -0,0 +1,267 @@
If hardware lacks basic or specialized functionality, compiler-rt adds such functionality
for basic arithmetic(s).
One such example is 64-bit integer multiplication on 32-bit x86.
Goals:
1. zig as linker for object files produced by other compilers
=> `function compatibility` to compiler-rt and libgcc for same-named functions
* compatibility conflict between compiler-rt and libgcc: prefer compiler-rt
2. `symbol-level compatibility` low-priority compared to emitted calls by llvm
* symbol-level compatibility: libgcc even lower priority
3. add zig-specific language runtime features, see #7265
* example: arbitrary bit width integer arithmetic
* lower to call those functions for e.g. multiplying two i12345 numbers together
* proper naming + documention for standardizing (allow languages to follow our exmaple)
Current status (tracking libgcc documentation):
- Integer library routines => almost implemented
- Soft float library routines => only f80 routines missing
- Decimal float library routines => unimplemented (~120 functions)
- Fixed-point fractional library routines => unimplemented (~300 functions)
- Exception handling routines => unclear, if supported (~32+x undocumented functions)
- Miscellaneous routines => unclear, if supported (cache control and stack function)
- No zig-specific language runtime features in compiler-rt yet
This library is automatically built as-needed for the compilation target and
then statically linked and therefore is a transparent dependency for the
programmer.
For details see `../compiler_rt.zig`.
The routines in this folder are listed below.
Routines are annotated as `type source routine // description`, with `routine`
being the name used in aforementioned `compiler_rt.zig`.
`dev` means deviating from compiler_rt, `port` ported, `source` is the
information source for the implementation, `none` means unimplemented.
Some examples for the naming convention are:
- dev source name_routine, name_routine2 various implementations for performance, simplicity etc
- port llvm compiler-rt library routines from [LLVM](http://compiler-rt.llvm.org/)
* LLVM emits library calls to compiler-rt, if the hardware lacks functionality
- port musl libc routines from [musl](https://musl.libc.org/)
If the library or information source is uncommon, use the entry `other` for `source`.
Please do not break the search by inserting entries in another format than `impl space source`.
Bugs should be solved by trying to duplicate the bug upstream, if possible.
* If the bug exists upstream, get it fixed upstream and port the fix downstream to Zig.
* If the bug only exists in Zig, use the corresponding C code and debug
both implementations side by side to figure out what is wrong.
## Integer library routines
#### Integer Bit operations
- dev HackersDelight __clzsi2 // count leading zeros
- dev HackersDelight __clzdi2 // count leading zeros
- dev HackersDelight __clzti2 // count leading zeros
- dev HackersDelight __ctzsi2 // count trailing zeros
- dev HackersDelight __ctzdi2 // count trailing zeros
- dev HackersDelight __ctzti2 // count trailing zeros
- dev __ctzsi2 __ffssi2 // find least significant 1 bit
- dev __ctzsi2 __ffsdi2 // find least significant 1 bit
- dev __ctzsi2 __ffsti2 // find least significant 1 bit
- dev BitTwiddlingHacks __paritysi2 // bit parity
- dev BitTwiddlingHacks __paritydi2 // bit parity
- dev BitTwiddlingHacks __parityti2 // bit parity
- dev TAOCP __popcountsi2 // bit population
- dev TAOCP __popcountdi2 // bit population
- dev TAOCP __popcountti2 // bit population
- dev other __bswapsi2 // a byteswapped
- dev other __bswapdi2 // a byteswapped
- dev other __bswapti2 // a byteswapped
#### Integer Comparison
- port llvm __cmpsi2 // (a<b)=>output=0, (a==b)=>output=1, (a>b)=>output=2
- port llvm __cmpdi2
- port llvm __cmpti2
- port llvm __ucmpsi2 // (a<b)=>output=0, (a==b)=>output=1, (a>b)=>output=2
- port llvm __ucmpdi2
- port llvm __ucmpti2
#### Integer Arithmetic
- none none __ashlsi3 // a << b unused in llvm, missing (e.g. used by rl78)
- port llvm __ashldi3 // a << b
- port llvm __ashlti3 // a << b
- none none __ashrsi3 // a >> b arithmetic (sign fill) missing (e.g. used by rl78)
- port llvm __ashrdi3 // a >> b arithmetic (sign fill)
- port llvm __ashrti3 // a >> b arithmetic (sign fill)
- none none __lshrsi3 // a >> b logical (zero fill) missing (e.g. used by rl78)
- port llvm __lshrdi3 // a >> b logical (zero fill)
- port llvm __lshrti3 // a >> b logical (zero fill)
- port llvm __negdi2 // -a symbol-level compatibility: libgcc
- port llvm __negti2 // -a unnecessary: unused in backends
- port llvm __mulsi3 // a * b signed
- port llvm __muldi3 // a * b signed
- port llvm __multi3 // a * b signed
- port llvm __divsi3 // a / b signed
- port llvm __divdi3 // a / b signed
- port llvm __divti3 // a / b signed
- port llvm __udivsi3 // a / b unsigned
- port llvm __udivdi3 // a / b unsigned
- port llvm __udivti3 // a / b unsigned
- port llvm __modsi3 // a % b signed
- port llvm __moddi3 // a % b signed
- port llvm __modti3 // a % b signed
- port llvm __umodsi3 // a % b unsigned
- port llvm __umoddi3 // a % b unsigned
- port llvm __umodti3 // a % b unsigned
- port llvm __udivmoddi4 // a / b, rem.* = a % b unsigned
- port llvm __udivmodti4 // a / b, rem.* = a % b unsigned
- port llvm __udivmodsi4 // a / b, rem.* = a % b unsigned
- port llvm __divmodsi4 // a / b, rem.* = a % b signed, ARM
#### Integer Arithmetic with trapping overflow
- dev BitTwiddlingHacks __absvsi2 // abs(a)
- dev BitTwiddlingHacks __absvdi2 // abs(a)
- dev BitTwiddlingHacks __absvti2 // abs(a)
- port llvm __negvsi2 // -a symbol-level compatibility: libgcc
- port llvm __negvdi2 // -a unnecessary: unused in backends
- port llvm __negvti2 // -a
- TODO upstreaming __addvsi3..__mulvti3 after testing panics works
- dev HackersDelight __addvsi3 // a + b
- dev HackersDelight __addvdi3 // a + b
- dev HackersDelight __addvti3 // a + b
- dev HackersDelight __subvsi3 // a - b
- dev HackersDelight __subvdi3 // a - b
- dev HackersDelight __subvti3 // a - b
- dev HackersDelight __mulvsi3 // a * b
- dev HackersDelight __mulvdi3 // a * b
- dev HackersDelight __mulvti3 // a * b
#### Integer Arithmetic which returns if overflow (would be faster without pointer)
- dev HackersDelight __addosi4 // a + b, overflow=>ov.*=1 else 0
- dev HackersDelight __addodi4 // (completeness + performance, llvm does not use them)
- dev HackersDelight __addoti4 //
- dev HackersDelight __subosi4 // a - b, overflow=>ov.*=1 else 0
- dev HackersDelight __subodi4 // (completeness + performance, llvm does not use them)
- dev HackersDelight __suboti4 //
- dev HackersDelight __mulosi4 // a * b, overflow=>ov.*=1 else 0
- dev HackersDelight __mulodi4 // (required by llvm)
- dev HackersDelight __muloti4 //
## Float library routines
#### Float Conversion
- todo todo __extendsfdf2 // extend a f32 => f64
- todo todo __extendsftf2 // extend a f32 => f128
- dev llvm __extendsfxf2 // extend a f32 => f80
- todo todo __extenddftf2 // extend a f64 => f128
- dev llvm __extenddfxf2 // extend a f64 => f80
- todo todo __truncdfsf2 // truncate a to narrower mode of return type, rounding towards zero
- todo todo __trunctfdf2 //
- todo todo __trunctfsf2 //
- dev llvm __truncxfsf2 //
- dev llvm __truncxfdf2 //
- todo todo __fixsfsi // convert a to i32, rounding towards zero
- todo todo __fixdfsi //
- todo todo __fixtfsi //
- todo todo __fixxfsi //
- todo todo __fixsfdi // convert a to i64, rounding towards zero
- todo todo __fixdfdi //
- todo todo __fixtfdi //
- todo todo __fixxfdi //
- todo todo __fixsfti // convert a to i128, rounding towards zero
- todo todo __fixdfti //
- todo todo __fixtfdi //
- todo todo __fixxfti //
- __fixunssfsi // convert to u32, rounding towards zero. negative values become 0.
- __fixunsdfsi //
- __fixunstfsi //
- __fixunsxfsi //
- __fixunssfdi // convert to u64, rounding towards zero. negative values become 0.
- __fixunsdfdi //
- __fixunstfdi //
- __fixunsxfdi //
- __fixunssfti // convert to u128, rounding towards zero. negative values become 0.
- __fixunsdfti //
- __fixunstfdi //
- __fixunsxfti //
- __floatsisf // convert i32 to floating point
- __floatsidf //
- __floatsitf //
- __floatsixf //
- __floatdisf // convert i64 to floating point
- __floatdidf //
- __floatditf //
- __floatdixf //
- __floattisf // convert i128 to floating point
- __floattidf //
- __floattixf //
- __floatunsisf // convert u32 to floating point
- __floatunsidf //
- __floatunsitf //
- __floatunsixf //
- __floatundisf // convert u64 to floating point
- __floatundidf //
- __floatunditf //
- __floatundixf //
- __floatuntisf // convert u128 to floating point
- __floatuntidf //
- __floatuntitf //
- __floatuntixf //
#### Float Comparison
- __cmpsf2 // return (a<b)=>-1,(a==b)=>0,(a>b)=>1,Nan=>1 dont rely on this
- __cmpdf2 // exported from __lesf2, __ledf2, __letf2 (below)
- __cmptf2 //
- __unordsf2 // (input==NaN) => out!=0 else out=0,
- __unorddf2 // __only reliable for (input!=Nan)__
- __unordtf2 //
- __eqsf2 // (a!=NaN) and (b!=Nan) and (a==b) => output=0
- __eqdf2 //
- __eqtf2 //
- __nesf2 // (a==NaN) or (b==Nan) or (a!=b) => output!=0
- __nedf2 //
- __netf2 //
- __gesf2 // (a!=Nan) and (b!=Nan) and (a>=b) => output>=0
- __gedf2 //
- __getf2 //
- __ltsf2 // (a!=Nan) and (b!=Nan) and (a<b) => output<0
- __ltdf2 //
- __lttf2 //
- __lesf2 // (a!=Nan) and (b!=Nan) and (a<=b) => output<=0
- __ledf2 //
- __letf2 //
- __gtsf2 // (a!=Nan) and (b!=Nan) and (a>b) => output>0
- __gtdf2 //
- __gttf2 //
#### Float Arithmetic
- __addsf3 // a + b f32
- __adddf3 // a + b f64
- __addtf3 // a + b f128
- __addxf3 // a + b f80
- __aeabi_fadd // a + b f64 ARM: AAPCS
- __aeabi_dadd // a + b f64 ARM: AAPCS
- __subsf3 // a - b
- __subdf3 // a - b
- __subtf3 // a - b
- __subxf3 // a - b f80
- __aeabi_fsub // a - b f64 ARM: AAPCS
- __aeabi_dsub // a - b f64 ARM: AAPCS
- __mulsf3 // a * b
- __muldf3 // a * b
- __multf3 // a * b
- __mulxf3 // a * b
- __divsf3 // a / b
- __divdf3 // a / b
- __divtf3 // a / b
- __divxf3 // a / b
- __negsf2 // -a symbol-level compatibility: libgcc uses this for the rl78
- __negdf2 // -a unnecessary: can be lowered directly to a xor
- __negtf2 // -a
- __negxf2 // -a
#### Floating point raised to integer power
- __powisf2 // unclear, if supported a ^ b
- __powidf2 //
- __powitf2 //
- __powixf2 //
- __mulsc3 // unsupported (a+ib) * (c+id)
- __muldc3 //
- __multc3 //
- __mulxc3 //
- __divsc3 // unsupported (a+ib) * / (c+id)
- __divdc3 //
- __divtc3 //
- __divxc3 //

View File

@ -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");

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,98 +1,37 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc
const std = @import("std");
const builtin = @import("builtin");
const compiler_rt = @import("../compiler_rt.zig");
const math = std.math;
const common = @import("./common.zig");
const normalize = common.normalize;
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 __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 significandBits = std.math.floatMantissaBits(T);
const implicitBit = @as(Z, 1) << significandBits;
const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, implicitBit);
significand.* <<= @intCast(S, shift);
return 1 - shift;
}
// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154
fn addXf3(comptime T: type, a: T, b: T) T {
/// 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 = std.math.floatMantissaBits(T);
const exponentBits = std.math.floatExponentBits(T);
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 implicitBit = (@as(Z, 1) << significandBits);
const quietBit = implicitBit >> 1;
const significandMask = implicitBit - 1;
const integerBit = (@as(Z, 1) << fractionalBits);
const quietBit = integerBit >> 1;
const significandMask = (@as(Z, 1) << significandBits) - 1;
const absMask = signBit - 1;
const exponentMask = absMask ^ significandMask;
const qnanRep = exponentMask | quietBit;
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, std.math.inf(T));
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
@ -157,12 +96,12 @@ fn addXf3(comptime T: type, a: T, b: T) T {
// 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 | implicitBit) << 3;
bSignificand = (bSignificand | implicitBit) << 3;
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(Z, aExponent - bExponent);
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;
@ -178,8 +117,8 @@ fn addXf3(comptime T: type, a: T, b: T) T {
// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < implicitBit << 3) {
const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), implicitBit << 3));
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;
}
@ -188,7 +127,7 @@ fn addXf3(comptime T: type, a: T, b: T) T {
// If the addition carried up, we need to right-shift the result and
// adjust the exponent:
if (aSignificand & (implicitBit << 4) != 0) {
if (aSignificand & (integerBit << 4) != 0) {
const sticky = aSignificand & 1;
aSignificand = aSignificand >> 1 | sticky;
aExponent += 1;
@ -199,18 +138,16 @@ fn addXf3(comptime T: type, a: T, b: T) T {
if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign);
if (aExponent <= 0) {
// Result is denormal before rounding; the exponent is zero and we
// need to shift the significand.
const shift = @intCast(Z, 1 - aExponent);
const sticky = if (aSignificand << @intCast(S, typeWidth - shift) != 0) @as(Z, 1) else 0;
aSignificand = aSignificand >> @intCast(S, shift | sticky);
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 implicit bit.
// 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.
@ -222,9 +159,14 @@ fn addXf3(comptime T: type, a: T, b: T) T {
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");
_ = @import("addf3_test.zig");
}

View File

@ -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
}

48
lib/compiler_rt/addo.zig Normal file
View File

@ -0,0 +1,48 @@
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.
// * return if a+b overflows => 1 else => 0
// - addoXi4_generic as default
inline fn addoXi4_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
// Let sum = a +% b == a + b + carry == wraparound addition.
// Overflow in a+b+carry occurs, iff a and b have opposite signs
// and the sign of a+b+carry is the same as a (or equivalently b).
// Slower routine: res = ~(a ^ b) & ((sum ^ a)
// Faster routine: res = (sum ^ a) & (sum ^ b)
// Overflow occured, iff (res < 0)
if (((sum ^ a) & (sum ^ b)) < 0)
overflow.* = 1;
return sum;
}
pub fn __addosi4(a: i32, b: i32, overflow: *c_int) callconv(.C) i32 {
return addoXi4_generic(i32, a, b, overflow);
}
pub fn __addodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 {
return addoXi4_generic(i64, a, b, overflow);
}
pub fn __addoti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 {
return addoXi4_generic(i128, a, b, overflow);
}
test {
_ = @import("addosi4_test.zig");
_ = @import("addodi4_test.zig");
_ = @import("addoti4_test.zig");
}

View File

@ -0,0 +1,77 @@
const addv = @import("addo.zig");
const std = @import("std");
const testing = std.testing;
const math = std.math;
fn test__addodi4(a: i64, b: i64) !void {
var result_ov: c_int = undefined;
var expected_ov: c_int = undefined;
var result = addv.__addodi4(a, b, &result_ov);
var expected: i64 = simple_addodi4(a, b, &expected_ov);
try testing.expectEqual(expected, result);
try testing.expectEqual(expected_ov, result_ov);
}
fn simple_addodi4(a: i64, b: i64, overflow: *c_int) i64 {
overflow.* = 0;
const min: i64 = math.minInt(i64);
const max: i64 = math.maxInt(i64);
if (((a > 0) and (b > max - a)) or
((a < 0) and (b < min - a)))
overflow.* = 1;
return a +% b;
}
test "addodi4" {
const min: i64 = math.minInt(i64);
const max: i64 = math.maxInt(i64);
var i: i64 = 1;
while (i < max) : (i *|= 2) {
try test__addodi4(i, i);
try test__addodi4(-i, -i);
try test__addodi4(i, -i);
try test__addodi4(-i, i);
}
// edge cases
// 0 + 0 = 0
// MIN + MIN overflow
// MAX + MAX overflow
// 0 + MIN MIN
// 0 + MAX MAX
// MIN + 0 MIN
// MAX + 0 MAX
// MIN + MAX -1
// MAX + MIN -1
try test__addodi4(0, 0);
try test__addodi4(min, min);
try test__addodi4(max, max);
try test__addodi4(0, min);
try test__addodi4(0, max);
try test__addodi4(min, 0);
try test__addodi4(max, 0);
try test__addodi4(min, max);
try test__addodi4(max, min);
// derived edge cases
// MIN+1 + MIN overflow
// MAX-1 + MAX overflow
// 1 + MIN = MIN+1
// -1 + MIN overflow
// -1 + MAX = MAX-1
// +1 + MAX overflow
// MIN + 1 = MIN+1
// MIN + -1 overflow
// MAX + 1 overflow
// MAX + -1 = MAX-1
try test__addodi4(min + 1, min);
try test__addodi4(max - 1, max);
try test__addodi4(1, min);
try test__addodi4(-1, min);
try test__addodi4(-1, max);
try test__addodi4(1, max);
try test__addodi4(min, 1);
try test__addodi4(min, -1);
try test__addodi4(max, -1);
try test__addodi4(max, 1);
}

View File

@ -0,0 +1,78 @@
const addv = @import("addo.zig");
const testing = @import("std").testing;
fn test__addosi4(a: i32, b: i32) !void {
var result_ov: c_int = undefined;
var expected_ov: c_int = undefined;
var result = addv.__addosi4(a, b, &result_ov);
var expected: i32 = simple_addosi4(a, b, &expected_ov);
try testing.expectEqual(expected, result);
try testing.expectEqual(expected_ov, result_ov);
}
fn simple_addosi4(a: i32, b: i32, overflow: *c_int) i32 {
overflow.* = 0;
const min: i32 = -2147483648;
const max: i32 = 2147483647;
if (((a > 0) and (b > max - a)) or
((a < 0) and (b < min - a)))
overflow.* = 1;
return a +% b;
}
test "addosi4" {
// -2^31 <= i32 <= 2^31-1
// 2^31 = 2147483648
// 2^31-1 = 2147483647
const min: i32 = -2147483648;
const max: i32 = 2147483647;
var i: i32 = 1;
while (i < max) : (i *|= 2) {
try test__addosi4(i, i);
try test__addosi4(-i, -i);
try test__addosi4(i, -i);
try test__addosi4(-i, i);
}
// edge cases
// 0 + 0 = 0
// MIN + MIN overflow
// MAX + MAX overflow
// 0 + MIN MIN
// 0 + MAX MAX
// MIN + 0 MIN
// MAX + 0 MAX
// MIN + MAX -1
// MAX + MIN -1
try test__addosi4(0, 0);
try test__addosi4(min, min);
try test__addosi4(max, max);
try test__addosi4(0, min);
try test__addosi4(0, max);
try test__addosi4(min, 0);
try test__addosi4(max, 0);
try test__addosi4(min, max);
try test__addosi4(max, min);
// derived edge cases
// MIN+1 + MIN overflow
// MAX-1 + MAX overflow
// 1 + MIN = MIN+1
// -1 + MIN overflow
// -1 + MAX = MAX-1
// +1 + MAX overflow
// MIN + 1 = MIN+1
// MIN + -1 overflow
// MAX + 1 overflow
// MAX + -1 = MAX-1
try test__addosi4(min + 1, min);
try test__addosi4(max - 1, max);
try test__addosi4(1, min);
try test__addosi4(-1, min);
try test__addosi4(-1, max);
try test__addosi4(1, max);
try test__addosi4(min, 1);
try test__addosi4(min, -1);
try test__addosi4(max, -1);
try test__addosi4(max, 1);
}

View File

@ -0,0 +1,77 @@
const addv = @import("addo.zig");
const std = @import("std");
const testing = std.testing;
const math = std.math;
fn test__addoti4(a: i128, b: i128) !void {
var result_ov: c_int = undefined;
var expected_ov: c_int = undefined;
var result = addv.__addoti4(a, b, &result_ov);
var expected: i128 = simple_addoti4(a, b, &expected_ov);
try testing.expectEqual(expected, result);
try testing.expectEqual(expected_ov, result_ov);
}
fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
overflow.* = 0;
const min: i128 = math.minInt(i128);
const max: i128 = math.maxInt(i128);
if (((a > 0) and (b > max - a)) or
((a < 0) and (b < min - a)))
overflow.* = 1;
return a +% b;
}
test "addoti4" {
const min: i128 = math.minInt(i128);
const max: i128 = math.maxInt(i128);
var i: i128 = 1;
while (i < max) : (i *|= 2) {
try test__addoti4(i, i);
try test__addoti4(-i, -i);
try test__addoti4(i, -i);
try test__addoti4(-i, i);
}
// edge cases
// 0 + 0 = 0
// MIN + MIN overflow
// MAX + MAX overflow
// 0 + MIN MIN
// 0 + MAX MAX
// MIN + 0 MIN
// MAX + 0 MAX
// MIN + MAX -1
// MAX + MIN -1
try test__addoti4(0, 0);
try test__addoti4(min, min);
try test__addoti4(max, max);
try test__addoti4(0, min);
try test__addoti4(0, max);
try test__addoti4(min, 0);
try test__addoti4(max, 0);
try test__addoti4(min, max);
try test__addoti4(max, min);
// derived edge cases
// MIN+1 + MIN overflow
// MAX-1 + MAX overflow
// 1 + MIN = MIN+1
// -1 + MIN overflow
// -1 + MAX = MAX-1
// +1 + MAX overflow
// MIN + 1 = MIN+1
// MIN + -1 overflow
// MAX + 1 overflow
// MAX + -1 = MAX-1
try test__addoti4(min + 1, min);
try test__addoti4(max - 1, max);
try test__addoti4(1, min);
try test__addoti4(-1, min);
try test__addoti4(-1, max);
try test__addoti4(1, max);
try test__addoti4(min, 1);
try test__addoti4(min, -1);
try test__addoti4(max, -1);
try test__addoti4(max, 1);
}

View File

@ -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);
}

View File

@ -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.*);
}

View File

@ -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);
}

188
lib/compiler_rt/arm.zig Normal file
View File

@ -0,0 +1,188 @@
// 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;
const __divmoddi4 = @import("int.zig").__divmoddi4;
const __udivmoddi4 = @import("int.zig").__udivmoddi4;
extern fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8;
extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8;
extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8;
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);
// This is dentical to the standard `memset` definition but with the last
// 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(.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 {
@setRuntimeSafety(false);
asm volatile (
\\ mrc p15, 0, r0, c13, c0, 3
\\ bx lr
);
unreachable;
}
// The following functions are wrapped in an asm block to ensure the required
// calling convention is always respected
pub fn __aeabi_uidivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
\\ sub sp, #4
\\ mov r2, sp
\\ bl __udivmodsi4
\\ ldr r1, [sp]
\\ add sp, #4
\\ pop {pc}
::: "memory");
unreachable;
}
pub fn __aeabi_uldivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}
\\ sub sp, #16
\\ add r4, sp, #8
\\ str r4, [sp]
\\ bl __udivmoddi4
\\ ldr r2, [sp, #8]
\\ ldr r3, [sp, #12]
\\ add sp, #16
\\ pop {r4, pc}
::: "memory");
unreachable;
}
pub fn __aeabi_idivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
\\ sub sp, #4
\\ mov r2, sp
\\ bl __divmodsi4
\\ ldr r1, [sp]
\\ add sp, #4
\\ pop {pc}
::: "memory");
unreachable;
}
pub fn __aeabi_ldivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}
\\ sub sp, #16
\\ add r4, sp, #8
\\ str r4, [sp]
\\ bl __divmoddi4
\\ ldr r2, [sp, #8]
\\ ldr r3, [sp, #12]
\\ add sp, #16
\\ pop {r4, pc}
::: "memory");
unreachable;
}

View File

@ -1,8 +1,9 @@
const std = @import("std");
const builtin = @import("builtin");
const arch = builtin.cpu.arch;
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.
@ -24,6 +25,11 @@ const supports_atomic_ops = switch (arch) {
// load/store atomically.
// Objects bigger than this threshold require the use of a lock.
const largest_atomic_size = switch (arch) {
// On SPARC systems that lacks CAS and/or swap instructions, the only
// available atomic operation is a test-and-set (`ldstub`), so we force
// every atomic memory access to go through the lock.
.sparc, .sparcel => if (cpu.features.featureSetHas(.hasleoncasa)) @sizeOf(usize) else 0,
// XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b
// and set this parameter accordingly.
else => @sizeOf(usize),
@ -36,21 +42,45 @@ const SpinlockTable = struct {
const max_spinlocks = 64;
const Spinlock = struct {
// SPARC ldstub instruction will write a 255 into the memory location.
// We'll use that as a sign that the lock is currently held.
// See also: Section B.7 in SPARCv8 spec & A.29 in SPARCv9 spec.
const sparc_lock: type = enum(u8) { Unlocked = 0, Locked = 255 };
const other_lock: type = enum(usize) { Unlocked = 0, Locked };
// Prevent false sharing by providing enough padding between two
// consecutive spinlock elements
v: enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked,
v: if (arch.isSPARC()) sparc_lock else other_lock align(cache_line_size) = .Unlocked,
fn acquire(self: *@This()) void {
while (true) {
switch (@atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire)) {
const flag = if (comptime arch.isSPARC()) flag: {
break :flag asm volatile ("ldstub [%[addr]], %[flag]"
: [flag] "=r" (-> @TypeOf(self.v)),
: [addr] "r" (&self.v),
: "memory"
);
} else flag: {
break :flag @atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire);
};
switch (flag) {
.Unlocked => break,
.Locked => {},
}
}
}
fn release(self: *@This()) void {
if (comptime arch.isSPARC()) {
_ = asm volatile ("clrb [%[addr]]"
:
: [addr] "r" (&self.v),
: "memory"
);
} else {
@atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release);
}
}
};
list: [max_spinlocks]Spinlock = [_]Spinlock{.{}} ** max_spinlocks,

View File

@ -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);

View File

@ -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);

View File

@ -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

180
lib/compiler_rt/ceil.zig Normal file
View File

@ -0,0 +1,180 @@
//! 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
return @floatCast(f16, ceilf(x));
}
pub fn ceilf(x: f32) callconv(.C) f32 {
var u = @bitCast(u32, x);
var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
var m: u32 = undefined;
// TODO: Shouldn't need this explicit check.
if (x == 0.0) {
return x;
}
if (e >= 23) {
return x;
} else if (e >= 0) {
m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
if (u & m == 0) {
return x;
}
math.doNotOptimizeAway(x + 0x1.0p120);
if (u >> 31 == 0) {
u += m;
}
u &= ~m;
return @bitCast(f32, u);
} else {
math.doNotOptimizeAway(x + 0x1.0p120);
if (u >> 31 != 0) {
return -0.0;
} else {
return 1.0;
}
}
}
pub fn ceil(x: f64) callconv(.C) f64 {
const f64_toint = 1.0 / math.floatEps(f64);
const u = @bitCast(u64, x);
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
if (e >= 0x3FF + 52 or x == 0) {
return x;
}
if (u >> 63 != 0) {
y = x - f64_toint + f64_toint - x;
} else {
y = x + f64_toint - f64_toint - x;
}
if (e <= 0x3FF - 1) {
math.doNotOptimizeAway(y);
if (u >> 63 != 0) {
return -0.0;
} else {
return 1.0;
}
} else if (y < 0) {
return x + y + 1;
} else {
return x + y;
}
}
pub fn __ceilx(x: f80) callconv(.C) f80 {
// TODO: more efficient implementation
return @floatCast(f80, ceilq(x));
}
pub fn ceilq(x: f128) callconv(.C) f128 {
const f128_toint = 1.0 / math.floatEps(f128);
const u = @bitCast(u128, x);
const e = (u >> 112) & 0x7FFF;
var y: f128 = undefined;
if (e >= 0x3FFF + 112 or x == 0) return x;
if (u >> 127 != 0) {
y = x - f128_toint + f128_toint - x;
} else {
y = x + f128_toint - f128_toint - x;
}
if (e <= 0x3FFF - 1) {
math.doNotOptimizeAway(y);
if (u >> 127 != 0) {
return -0.0;
} else {
return 1.0;
}
} else if (y < 0) {
return x + y + 1;
} else {
return x + y;
}
}
pub fn ceill(x: c_longdouble) callconv(.C) c_longdouble {
switch (@typeInfo(c_longdouble).Float.bits) {
16 => return __ceilh(x),
32 => return ceilf(x),
64 => return ceil(x),
80 => return __ceilx(x),
128 => return ceilq(x),
else => @compileError("unreachable"),
}
}
test "ceil32" {
try expect(ceilf(1.3) == 2.0);
try expect(ceilf(-1.3) == -1.0);
try expect(ceilf(0.2) == 1.0);
}
test "ceil64" {
try expect(ceil(1.3) == 2.0);
try expect(ceil(-1.3) == -1.0);
try expect(ceil(0.2) == 1.0);
}
test "ceil128" {
try expect(ceilq(1.3) == 2.0);
try expect(ceilq(-1.3) == -1.0);
try expect(ceilq(0.2) == 1.0);
}
test "ceil32.special" {
try expect(ceilf(0.0) == 0.0);
try expect(ceilf(-0.0) == -0.0);
try expect(math.isPositiveInf(ceilf(math.inf(f32))));
try expect(math.isNegativeInf(ceilf(-math.inf(f32))));
try expect(math.isNan(ceilf(math.nan(f32))));
}
test "ceil64.special" {
try expect(ceil(0.0) == 0.0);
try expect(ceil(-0.0) == -0.0);
try expect(math.isPositiveInf(ceil(math.inf(f64))));
try expect(math.isNegativeInf(ceil(-math.inf(f64))));
try expect(math.isNan(ceil(math.nan(f64))));
}
test "ceil128.special" {
try expect(ceilq(0.0) == 0.0);
try expect(ceilq(-0.0) == -0.0);
try expect(math.isPositiveInf(ceilq(math.inf(f128))));
try expect(math.isNegativeInf(ceilq(-math.inf(f128))));
try expect(math.isNan(ceilq(math.nan(f128))));
}

View File

@ -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,
@ -36,7 +43,7 @@ pub fn clear_cache(start: usize, end: usize) callconv(.C) void {
else => false,
};
const sparc = switch (arch) {
.sparc, .sparcv9, .sparcel => true,
.sparc, .sparc64, .sparcel => true,
else => false,
};
const apple = switch (os) {

View File

@ -1,14 +1,26 @@
const builtin = @import("builtin");
const clz = @import("count0bits.zig");
const testing = @import("std").testing;
fn test__clzsi2(a: u32, expected: i32) !void {
// XXX At high optimization levels this test may be horribly miscompiled if
// one of the naked implementations is selected.
// stage1 and stage2 diverge on function pointer semantics
switch (builtin.zig_backend) {
.stage1 => {
// Use of `var` here is working around a stage1 bug.
var nakedClzsi2 = clz.__clzsi2;
var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);
var x = @bitCast(i32, a);
var result = actualClzsi2(x);
try testing.expectEqual(expected, result);
},
else => {
const nakedClzsi2 = clz.__clzsi2;
const actualClzsi2 = @ptrCast(*const fn (a: i32) callconv(.C) i32, &nakedClzsi2);
const x = @bitCast(i32, a);
const result = actualClzsi2(x);
try testing.expectEqual(expected, result);
},
}
}
test "clzsi2" {

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

122
lib/compiler_rt/cmptf2.zig Normal file
View File

@ -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,
};
}

View File

@ -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);
}

202
lib/compiler_rt/common.zig Normal file
View File

@ -0,0 +1,202 @@
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;
}
pub inline fn fneg(a: anytype) @TypeOf(a) {
const F = @TypeOf(a);
const bits = @typeInfo(F).Float.bits;
const U = @Type(.{ .Int = .{
.signedness = .unsigned,
.bits = bits,
} });
const sign_bit_mask = @as(U, 1) << (bits - 1);
const negated = @bitCast(U, a) ^ sign_bit_mask;
return @bitCast(F, negated);
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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;

170
lib/compiler_rt/cos.zig Normal file
View File

@ -0,0 +1,170 @@
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));
}
pub fn cosf(x: f32) callconv(.C) f32 {
// Small multiples of pi/2 rounded to double precision.
const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
const c3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
const c4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
var ix = @bitCast(u32, x);
const sign = ix >> 31 != 0;
ix &= 0x7fffffff;
if (ix <= 0x3f490fda) { // |x| ~<= pi/4
if (ix < 0x39800000) { // |x| < 2**-12
// raise inexact if x != 0
math.doNotOptimizeAway(x + 0x1p120);
return 1.0;
}
return trig.__cosdf(x);
}
if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4
return -trig.__cosdf(if (sign) x + c2pio2 else x - c2pio2);
} else {
if (sign) {
return trig.__sindf(x + c1pio2);
} else {
return trig.__sindf(c1pio2 - x);
}
}
}
if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
if (ix > 0x40afeddf) { // |x| ~> 7*pi/4
return trig.__cosdf(if (sign) x + c4pio2 else x - c4pio2);
} else {
if (sign) {
return trig.__sindf(-x - c3pio2);
} else {
return trig.__sindf(x - c3pio2);
}
}
}
// cos(Inf or NaN) is NaN
if (ix >= 0x7f800000) {
return x - x;
}
var y: f64 = undefined;
const n = rem_pio2f(x, &y);
return switch (n & 3) {
0 => trig.__cosdf(y),
1 => trig.__sindf(-y),
2 => -trig.__cosdf(y),
else => trig.__sindf(y),
};
}
pub fn cos(x: f64) callconv(.C) f64 {
var ix = @bitCast(u64, x) >> 32;
ix &= 0x7fffffff;
// |x| ~< pi/4
if (ix <= 0x3fe921fb) {
if (ix < 0x3e46a09e) { // |x| < 2**-27 * sqrt(2)
// raise inexact if x!=0
math.doNotOptimizeAway(x + 0x1p120);
return 1.0;
}
return trig.__cos(x, 0);
}
// cos(Inf or NaN) is NaN
if (ix >= 0x7ff00000) {
return x - x;
}
var y: [2]f64 = undefined;
const n = rem_pio2(x, &y);
return switch (n & 3) {
0 => trig.__cos(y[0], y[1]),
1 => -trig.__sin(y[0], y[1], 1),
2 => -trig.__cos(y[0], y[1]),
else => trig.__sin(y[0], y[1], 1),
};
}
pub fn __cosx(a: f80) callconv(.C) f80 {
// TODO: more efficient implementation
return @floatCast(f80, cosq(a));
}
pub fn cosq(a: f128) callconv(.C) f128 {
// TODO: more correct implementation
return cos(@floatCast(f64, a));
}
pub fn cosl(x: c_longdouble) callconv(.C) c_longdouble {
switch (@typeInfo(c_longdouble).Float.bits) {
16 => return __cosh(x),
32 => return cosf(x),
64 => return cos(x),
80 => return __cosx(x),
128 => return cosq(x),
else => @compileError("unreachable"),
}
}
test "cos32" {
const epsilon = 0.00001;
try expect(math.approxEqAbs(f32, cosf(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f32, cosf(0.2), 0.980067, epsilon));
try expect(math.approxEqAbs(f32, cosf(0.8923), 0.627623, epsilon));
try expect(math.approxEqAbs(f32, cosf(1.5), 0.070737, epsilon));
try expect(math.approxEqAbs(f32, cosf(-1.5), 0.070737, epsilon));
try expect(math.approxEqAbs(f32, cosf(37.45), 0.969132, epsilon));
try expect(math.approxEqAbs(f32, cosf(89.123), 0.400798, epsilon));
}
test "cos64" {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f64, cos(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f64, cos(0.2), 0.980067, epsilon));
try expect(math.approxEqAbs(f64, cos(0.8923), 0.627623, epsilon));
try expect(math.approxEqAbs(f64, cos(1.5), 0.070737, epsilon));
try expect(math.approxEqAbs(f64, cos(-1.5), 0.070737, epsilon));
try expect(math.approxEqAbs(f64, cos(37.45), 0.969132, epsilon));
try expect(math.approxEqAbs(f64, cos(89.123), 0.40080, epsilon));
}
test "cos32.special" {
try expect(math.isNan(cosf(math.inf(f32))));
try expect(math.isNan(cosf(-math.inf(f32))));
try expect(math.isNan(cosf(math.nan(f32))));
}
test "cos64.special" {
try expect(math.isNan(cos(math.inf(f64))));
try expect(math.isNan(cos(-math.inf(f64))));
try expect(math.isNan(cos(math.nan(f64))));
}

View File

@ -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),

View File

@ -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,131 +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 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_ddiv(a: f64, b: f64) callconv(.AAPCS) f64 {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __divdf3, .{ a, b });
}
test {
_ = @import("divdf3_test.zig");
}

View File

@ -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");
}

View File

@ -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);

View File

@ -34,8 +34,12 @@ test "divtf3" {
try test__divtf3(math.qnan_f128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0);
// NaN / any = NaN
try test__divtf3(math.nan_f128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0);
// inf / any = inf
try test__divtf3(math.inf_f128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0);
// inf / any(except inf and nan) = inf
try test__divtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0);
// inf / inf = nan
try test__divtf3(math.inf(f128), math.inf(f128), 0x7fff800000000000, 0);
// inf / nan = nan
try test__divtf3(math.inf(f128), math.nan(f128), 0x7fff800000000000, 0);
try test__divtf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1, 0x4004b0b72924d407, 0x0717e84356c6eba2);
try test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9, 0x3fd5b2af3f828c9b, 0x40e51f64cde8b1f2);

View File

@ -0,0 +1,54 @@
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 {
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);
const an = (a ^ s_a) -% s_a;
const bn = (b ^ s_b) -% s_b;
const r = udivmod(u128, @bitCast(u128, an), @bitCast(u128, bn), null);
const s = s_a ^ s_b;
return (@bitCast(i128, r) ^ s) -% s;
}
test {
_ = @import("divti3_test.zig");
}

210
lib/compiler_rt/divxf3.zig Normal file
View File

@ -0,0 +1,210 @@
const std = @import("std");
const builtin = @import("builtin");
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 {
const T = f80;
const Z = std.meta.Int(.unsigned, @bitSizeOf(T));
const significandBits = std.math.floatMantissaBits(T);
const fractionalBits = std.math.floatFractionalBits(T);
const exponentBits = std.math.floatExponentBits(T);
const signBit = (@as(Z, 1) << (significandBits + exponentBits));
const maxExponent = ((1 << exponentBits) - 1);
const exponentBias = (maxExponent >> 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, std.math.nan(T)) | quietBit;
const infRep = @bitCast(Z, std.math.inf(T));
const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent);
const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent);
const quotientSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit;
var aSignificand: Z = @bitCast(Z, a) & significandMask;
var bSignificand: Z = @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 / infinity = NaN
if (bAbs == infRep) {
return @bitCast(T, qnanRep);
}
// infinity / anything else = +/- infinity
else {
return @bitCast(T, aAbs | quotientSign);
}
}
// anything else / infinity = +/- 0
if (bAbs == infRep) return @bitCast(T, quotientSign);
if (aAbs == 0) {
// zero / zero = NaN
if (bAbs == 0) {
return @bitCast(T, qnanRep);
}
// zero / anything else = +/- zero
else {
return @bitCast(T, quotientSign);
}
}
// anything else / zero = +/- infinity
if (bAbs == 0) return @bitCast(T, infRep | quotientSign);
// 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 < integerBit) scale +%= normalize(T, &aSignificand);
if (bAbs < integerBit) scale -%= normalize(T, &bSignificand);
}
var quotientExponent: i32 = @bitCast(i32, aExponent -% bExponent) +% scale;
// Align the significand of b as a Q63 fixed-point number in the range
// [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
// polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
// is accurate to about 3.5 binary digits.
const q63b = @intCast(u64, bSignificand);
var recip64 = @as(u64, 0x7504f333F9DE6484) -% q63b;
// 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
// Now refine the reciprocal estimate using a Newton-Raphson iteration:
//
// x1 = x0 * (2 - x0 * b)
//
// This doubles the number of correct binary digits in the approximation
// with each iteration.
var correction64: u64 = undefined;
correction64 = @truncate(u64, ~(@as(u128, recip64) *% q63b >> 64) +% 1);
recip64 = @truncate(u64, @as(u128, recip64) *% correction64 >> 63);
correction64 = @truncate(u64, ~(@as(u128, recip64) *% q63b >> 64) +% 1);
recip64 = @truncate(u64, @as(u128, recip64) *% correction64 >> 63);
correction64 = @truncate(u64, ~(@as(u128, recip64) *% q63b >> 64) +% 1);
recip64 = @truncate(u64, @as(u128, recip64) *% correction64 >> 63);
correction64 = @truncate(u64, ~(@as(u128, recip64) *% q63b >> 64) +% 1);
recip64 = @truncate(u64, @as(u128, recip64) *% correction64 >> 63);
correction64 = @truncate(u64, ~(@as(u128, recip64) *% q63b >> 64) +% 1);
recip64 = @truncate(u64, @as(u128, recip64) *% correction64 >> 63);
// The reciprocal may have overflowed to zero if the upper half of b is
// exactly 1.0. This would sabatoge the full-width final stage of the
// computation that follows, so we adjust the reciprocal down by one bit.
recip64 -%= 1;
// We need to perform one more iteration to get us to 112 binary digits;
// The last iteration needs to happen with extra precision.
// NOTE: This operation is equivalent to __multi3, which is not implemented
// in some architechures
var reciprocal: u128 = undefined;
var correction: u128 = undefined;
var dummy: u128 = undefined;
wideMultiply(u128, recip64, q63b, &dummy, &correction);
correction = -%correction;
const cHi = @truncate(u64, correction >> 64);
const cLo = @truncate(u64, correction);
var r64cH: u128 = undefined;
var r64cL: u128 = undefined;
wideMultiply(u128, recip64, cHi, &dummy, &r64cH);
wideMultiply(u128, recip64, cLo, &dummy, &r64cL);
reciprocal = r64cH + (r64cL >> 64);
// Adjust the final 128-bit reciprocal estimate downward to ensure that it
// is strictly smaller than the infinitely precise exact reciprocal. Because
// the computation of the Newton-Raphson step is truncating at every step,
// this adjustment is small; most of the work is already done.
reciprocal -%= 2;
// The numerical reciprocal is accurate to within 2^-112, lies in the
// interval [0.5, 1.0), and is strictly smaller than the true reciprocal
// of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
// in Q127 with the following properties:
//
// 1. q < a/b
// 2. q is in the interval [0.5, 2.0)
// 3. The error in q is bounded away from 2^-63 (actually, we have
// many bits to spare, but this is all we need).
// We need a 128 x 128 multiply high to compute q.
var quotient128: u128 = undefined;
var quotientLo: u128 = undefined;
wideMultiply(u128, aSignificand << 2, reciprocal, &quotient128, &quotientLo);
// Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
// Right shift the quotient if it falls in the [1,2) range and adjust the
// exponent accordingly.
var quotient: u64 = if (quotient128 < (integerBit << 1)) b: {
quotientExponent -= 1;
break :b @intCast(u64, quotient128);
} else @intCast(u64, quotient128 >> 1);
// We are going to compute a residual of the form
//
// r = a - q*b
//
// We know from the construction of q that r satisfies:
//
// 0 <= r < ulp(q)*b
//
// If r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
// already have the correct result. The exact halfway case cannot occur.
var residual: u64 = -%(quotient *% q63b);
const writtenExponent = quotientExponent + exponentBias;
if (writtenExponent >= maxExponent) {
// If we have overflowed the exponent, return infinity.
return @bitCast(T, infRep | quotientSign);
} else if (writtenExponent < 1) {
if (writtenExponent == 0) {
// Check whether the rounded result is normal.
if (residual > (bSignificand >> 1)) { // round
if (quotient == (integerBit - 1)) // If the rounded result is normal, return it
return @bitCast(T, @bitCast(Z, std.math.floatMin(T)) | quotientSign);
}
}
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return @bitCast(T, quotientSign);
} else {
const round = @boolToInt(residual > (bSignificand >> 1));
// Insert the exponent
var absResult = quotient | (@intCast(Z, writtenExponent) << significandBits);
// Round
absResult +%= round;
// Insert the sign and return
return @bitCast(T, absResult | quotientSign | integerBit);
}
}
test {
_ = @import("divxf3_test.zig");
}

View File

@ -0,0 +1,65 @@
const std = @import("std");
const math = std.math;
const testing = std.testing;
const __divxf3 = @import("divxf3.zig").__divxf3;
fn compareResult(result: f80, expected: u80) bool {
const rep = @bitCast(u80, result);
if (rep == expected) return true;
// test other possible NaN representations (signal NaN)
if (math.isNan(result) and math.isNan(@bitCast(f80, expected))) return true;
return false;
}
fn expect__divxf3_result(a: f80, b: f80, expected: u80) !void {
const x = __divxf3(a, b);
const ret = compareResult(x, expected);
try testing.expect(ret == true);
}
fn test__divxf3(a: f80, b: f80) !void {
const integerBit = 1 << math.floatFractionalBits(f80);
const x = __divxf3(a, b);
// Next float (assuming normal, non-zero result)
const x_plus_eps = @bitCast(f80, (@bitCast(u80, x) + 1) | integerBit);
// Prev float (assuming normal, non-zero result)
const x_minus_eps = @bitCast(f80, (@bitCast(u80, x) - 1) | integerBit);
// Make sure result is more accurate than the adjacent floats
const err_x = @fabs(@mulAdd(f80, x, b, -a));
const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a));
const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a));
try testing.expect(err_x_minus_eps > err_x);
try testing.expect(err_x_plus_eps > err_x);
}
test "divxf3" {
// qNaN / any = qNaN
try expect__divxf3_result(math.qnan_f80, 0x1.23456789abcdefp+5, 0x7fffC000000000000000);
// NaN / any = NaN
try expect__divxf3_result(math.nan_f80, 0x1.23456789abcdefp+5, 0x7fffC000000000000000);
// inf / any(except inf and nan) = inf
try expect__divxf3_result(math.inf(f80), 0x1.23456789abcdefp+5, 0x7fff8000000000000000);
// inf / inf = nan
try expect__divxf3_result(math.inf(f80), math.inf(f80), 0x7fffC000000000000000);
// inf / nan = nan
try expect__divxf3_result(math.inf(f80), math.nan(f80), 0x7fffC000000000000000);
try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1);
try test__divxf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9);
try test__divxf3(0x1.2345f6aaaa786555f42432abcdefp+456, 0x1.edacbba9874f765463544dd3621fp+6400);
try test__divxf3(0x1.2d3456f789ba6322bc665544edefp-234, 0x1.eddcdba39f3c8b7a36564354321fp-4455);
try test__divxf3(0x1.2345f6b77b7a8953365433abcdefp+234, 0x1.edcba987d6bb3aa467754354321fp-4055);
try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.a2b34c56d745382f9abf2c3dfeffp-50);
try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.1234567890abcdef987654321123p0);
try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.12394205810257120adae8929f23p+16);
try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.febdcefa1231245f9abf2c3dfeffp-50);
// Result rounds down to zero
try expect__divxf3_result(6.72420628622418701252535563464350521E-4932, 2.0, 0x0);
}

View File

@ -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;

View File

@ -4,25 +4,31 @@
// https://git.musl-libc.org/cgit/musl/tree/src/math/expf.c
// https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c
const std = @import("../std.zig");
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");
/// Returns e raised to the power of x (e^x).
///
/// Special Cases:
/// - exp(+inf) = +inf
/// - exp(nan) = nan
pub fn exp(x: anytype) @TypeOf(x) {
const T = @TypeOf(x);
return switch (T) {
f32 => exp32(x),
f64 => exp64(x),
else => @compileError("exp not implemented for " ++ @typeName(T)),
};
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 });
}
fn exp32(x_: f32) f32 {
pub fn __exph(a: f16) callconv(.C) f16 {
// TODO: more efficient implementation
return @floatCast(f16, expf(a));
}
pub fn expf(x_: f32) callconv(.C) f32 {
const half = [_]f32{ 0.5, -0.5 };
const ln2hi = 6.9314575195e-1;
const ln2lo = 1.4286067653e-6;
@ -97,7 +103,7 @@ fn exp32(x_: f32) f32 {
}
}
fn exp64(x_: f64) f64 {
pub fn exp(x_: f64) callconv(.C) f64 {
const half = [_]f64{ 0.5, -0.5 };
const ln2hi: f64 = 6.93147180369123816490e-01;
const ln2lo: f64 = 1.90821492927058770002e-10;
@ -181,37 +187,53 @@ fn exp64(x_: f64) f64 {
}
}
test "math.exp" {
try expect(exp(@as(f32, 0.0)) == exp32(0.0));
try expect(exp(@as(f64, 0.0)) == exp64(0.0));
pub fn __expx(a: f80) callconv(.C) f80 {
// TODO: more efficient implementation
return @floatCast(f80, expq(a));
}
test "math.exp32" {
pub fn expq(a: f128) callconv(.C) f128 {
// TODO: more correct implementation
return exp(@floatCast(f64, a));
}
pub fn expl(x: c_longdouble) callconv(.C) c_longdouble {
switch (@typeInfo(c_longdouble).Float.bits) {
16 => return __exph(x),
32 => return expf(x),
64 => return exp(x),
80 => return __expx(x),
128 => return expq(x),
else => @compileError("unreachable"),
}
}
test "exp32" {
const epsilon = 0.000001;
try expect(exp32(0.0) == 1.0);
try expect(math.approxEqAbs(f32, exp32(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f32, exp32(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f32, exp32(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f32, exp32(1.5), 4.481689, epsilon));
try expect(expf(0.0) == 1.0);
try expect(math.approxEqAbs(f32, expf(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f32, expf(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f32, expf(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f32, expf(1.5), 4.481689, epsilon));
}
test "math.exp64" {
test "exp64" {
const epsilon = 0.000001;
try expect(exp64(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp64(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f64, exp64(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f64, exp64(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f64, exp64(1.5), 4.481689, epsilon));
try expect(exp(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f64, exp(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f64, exp(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f64, exp(1.5), 4.481689, epsilon));
}
test "math.exp32.special" {
try expect(math.isPositiveInf(exp32(math.inf(f32))));
try expect(math.isNan(exp32(math.nan(f32))));
test "exp32.special" {
try expect(math.isPositiveInf(expf(math.inf(f32))));
try expect(math.isNan(expf(math.nan(f32))));
}
test "math.exp64.special" {
try expect(math.isPositiveInf(exp64(math.inf(f64))));
try expect(math.isNan(exp64(math.nan(f64))));
test "exp64.special" {
try expect(math.isPositiveInf(exp(math.inf(f64))));
try expect(math.isNan(exp(math.nan(f64))));
}

View File

@ -4,44 +4,31 @@
// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2f.c
// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c
const std = @import("../std.zig");
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");
/// Returns 2 raised to the power of x (2^x).
///
/// Special Cases:
/// - exp2(+inf) = +inf
/// - exp2(nan) = nan
pub fn exp2(x: anytype) @TypeOf(x) {
const T = @TypeOf(x);
return switch (T) {
f32 => exp2_32(x),
f64 => exp2_64(x),
else => @compileError("exp2 not implemented for " ++ @typeName(T)),
};
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 });
}
const exp2ft = [_]f64{
0x1.6a09e667f3bcdp-1,
0x1.7a11473eb0187p-1,
0x1.8ace5422aa0dbp-1,
0x1.9c49182a3f090p-1,
0x1.ae89f995ad3adp-1,
0x1.c199bdd85529cp-1,
0x1.d5818dcfba487p-1,
0x1.ea4afa2a490dap-1,
0x1.0000000000000p+0,
0x1.0b5586cf9890fp+0,
0x1.172b83c7d517bp+0,
0x1.2387a6e756238p+0,
0x1.306fe0a31b715p+0,
0x1.3dea64c123422p+0,
0x1.4bfdad5362a27p+0,
0x1.5ab07dd485429p+0,
};
pub fn __exp2h(x: f16) callconv(.C) f16 {
// TODO: more efficient implementation
return @floatCast(f16, exp2f(x));
}
fn exp2_32(x: f32) f32 {
pub fn exp2f(x: f32) callconv(.C) f32 {
const tblsiz = @intCast(u32, exp2ft.len);
const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz);
const P1: f32 = 0x1.62e430p-1;
@ -98,6 +85,115 @@ fn exp2_32(x: f32) f32 {
return @floatCast(f32, r * uk);
}
pub fn exp2(x: f64) callconv(.C) f64 {
const tblsiz: u32 = @intCast(u32, exp2dt.len / 2);
const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz);
const P1: f64 = 0x1.62e42fefa39efp-1;
const P2: f64 = 0x1.ebfbdff82c575p-3;
const P3: f64 = 0x1.c6b08d704a0a6p-5;
const P4: f64 = 0x1.3b2ab88f70400p-7;
const P5: f64 = 0x1.5d88003875c74p-10;
const ux = @bitCast(u64, x);
const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
// TODO: This should be handled beneath.
if (math.isNan(x)) {
return math.nan(f64);
}
// |x| >= 1022 or nan
if (ix >= 0x408FF000) {
// x >= 1024 or nan
if (ix >= 0x40900000 and ux >> 63 == 0) {
math.raiseOverflow();
return math.inf(f64);
}
// -inf or -nan
if (ix >= 0x7FF00000) {
return -1 / x;
}
// x <= -1022
if (ux >> 63 != 0) {
// underflow
if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) {
math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x));
}
if (x <= -1075) {
return 0;
}
}
}
// |x| < 0x1p-54
else if (ix < 0x3C900000) {
return 1.0 + x;
}
// NOTE: musl relies on unsafe behaviours which are replicated below
// (addition overflow, division truncation, casting). Appears that this
// produces the intended result but should confirm how GCC/Clang handle this
// to ensure.
// reduce x
var uf: f64 = x + redux;
// NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here
var i_0: u32 = @truncate(u32, @bitCast(u64, uf));
i_0 +%= tblsiz / 2;
const k: u32 = i_0 / tblsiz * tblsiz;
const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz);
i_0 %= tblsiz;
uf -= redux;
// r = exp2(y) = exp2t[i_0] * p(z - eps[i])
var z: f64 = x - uf;
const t: f64 = exp2dt[@intCast(usize, 2 * i_0)];
z -= exp2dt[@intCast(usize, 2 * i_0 + 1)];
const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
return math.scalbn(r, ik);
}
pub fn __exp2x(x: f80) callconv(.C) f80 {
// TODO: more efficient implementation
return @floatCast(f80, exp2q(x));
}
pub fn exp2q(x: f128) callconv(.C) f128 {
// TODO: more correct implementation
return exp2(@floatCast(f64, x));
}
pub fn exp2l(x: c_longdouble) callconv(.C) c_longdouble {
switch (@typeInfo(c_longdouble).Float.bits) {
16 => return __exp2h(x),
32 => return exp2f(x),
64 => return exp2(x),
80 => return __exp2x(x),
128 => return exp2q(x),
else => @compileError("unreachable"),
}
}
const exp2ft = [_]f64{
0x1.6a09e667f3bcdp-1,
0x1.7a11473eb0187p-1,
0x1.8ace5422aa0dbp-1,
0x1.9c49182a3f090p-1,
0x1.ae89f995ad3adp-1,
0x1.c199bdd85529cp-1,
0x1.d5818dcfba487p-1,
0x1.ea4afa2a490dap-1,
0x1.0000000000000p+0,
0x1.0b5586cf9890fp+0,
0x1.172b83c7d517bp+0,
0x1.2387a6e756238p+0,
0x1.306fe0a31b715p+0,
0x1.3dea64c123422p+0,
0x1.4bfdad5362a27p+0,
0x1.5ab07dd485429p+0,
};
const exp2dt = [_]f64{
// exp2(z + eps) eps
0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
@ -358,108 +454,34 @@ const exp2dt = [_]f64{
0x1.690f4b19e9471p+0, -0x1.9780p-45,
};
fn exp2_64(x: f64) f64 {
const tblsiz: u32 = @intCast(u32, exp2dt.len / 2);
const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz);
const P1: f64 = 0x1.62e42fefa39efp-1;
const P2: f64 = 0x1.ebfbdff82c575p-3;
const P3: f64 = 0x1.c6b08d704a0a6p-5;
const P4: f64 = 0x1.3b2ab88f70400p-7;
const P5: f64 = 0x1.5d88003875c74p-10;
const ux = @bitCast(u64, x);
const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
// TODO: This should be handled beneath.
if (math.isNan(x)) {
return math.nan(f64);
}
// |x| >= 1022 or nan
if (ix >= 0x408FF000) {
// x >= 1024 or nan
if (ix >= 0x40900000 and ux >> 63 == 0) {
math.raiseOverflow();
return math.inf(f64);
}
// -inf or -nan
if (ix >= 0x7FF00000) {
return -1 / x;
}
// x <= -1022
if (ux >> 63 != 0) {
// underflow
if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) {
math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x));
}
if (x <= -1075) {
return 0;
}
}
}
// |x| < 0x1p-54
else if (ix < 0x3C900000) {
return 1.0 + x;
}
// NOTE: musl relies on unsafe behaviours which are replicated below
// (addition overflow, division truncation, casting). Appears that this
// produces the intended result but should confirm how GCC/Clang handle this
// to ensure.
// reduce x
var uf: f64 = x + redux;
// NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here
var i_0: u32 = @truncate(u32, @bitCast(u64, uf));
i_0 +%= tblsiz / 2;
const k: u32 = i_0 / tblsiz * tblsiz;
const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz);
i_0 %= tblsiz;
uf -= redux;
// r = exp2(y) = exp2t[i_0] * p(z - eps[i])
var z: f64 = x - uf;
const t: f64 = exp2dt[@intCast(usize, 2 * i_0)];
z -= exp2dt[@intCast(usize, 2 * i_0 + 1)];
const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
return math.scalbn(r, ik);
}
test "math.exp2" {
try expect(exp2(@as(f32, 0.8923)) == exp2_32(0.8923));
try expect(exp2(@as(f64, 0.8923)) == exp2_64(0.8923));
}
test "math.exp2_32" {
test "exp2_32" {
const epsilon = 0.000001;
try expect(exp2_32(0.0) == 1.0);
try expect(math.approxEqAbs(f32, exp2_32(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f32, exp2_32(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f32, exp2_32(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f32, exp2_32(37.45), 187747237888, epsilon));
try expect(math.approxEqAbs(f32, exp2_32(-1), 0.5, epsilon));
try expect(exp2f(0.0) == 1.0);
try expect(math.approxEqAbs(f32, exp2f(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f32, exp2f(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f32, exp2f(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f32, exp2f(37.45), 187747237888, epsilon));
try expect(math.approxEqAbs(f32, exp2f(-1), 0.5, epsilon));
}
test "math.exp2_64" {
test "exp2_64" {
const epsilon = 0.000001;
try expect(exp2_64(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp2_64(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f64, exp2_64(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f64, exp2_64(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f64, exp2_64(-1), 0.5, epsilon));
try expect(math.approxEqAbs(f64, exp2_64(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
try expect(exp2(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp2(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f64, exp2(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f64, exp2(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f64, exp2(-1), 0.5, epsilon));
try expect(math.approxEqAbs(f64, exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
}
test "math.exp2_32.special" {
try expect(math.isPositiveInf(exp2_32(math.inf(f32))));
try expect(math.isNan(exp2_32(math.nan(f32))));
test "exp2_32.special" {
try expect(math.isPositiveInf(exp2f(math.inf(f32))));
try expect(math.isNan(exp2f(math.nan(f32))));
}
test "math.exp2_64.special" {
try expect(math.isPositiveInf(exp2_64(math.inf(f64))));
try expect(math.isNan(exp2_64(math.nan(f64))));
test "exp2_64.special" {
try expect(math.isPositiveInf(exp2(math.inf(f64))));
try expect(math.isNan(exp2(math.nan(f64))));
}

View File

@ -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));
}

Some files were not shown because too many files have changed in this diff Show More