aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt39
-rw-r--r--deps/SoftFloat-3e-prebuilt/platform.h14
-rw-r--r--doc/langref.html.in46
-rw-r--r--lib/std/Thread/Condition.zig175
-rw-r--r--lib/std/Thread/Futex.zig4
-rw-r--r--lib/std/bounded_array.zig24
-rw-r--r--lib/std/build.zig168
-rw-r--r--lib/std/builtin.zig6
-rw-r--r--lib/std/compress/deflate/compressor.zig2
-rw-r--r--lib/std/crypto/25519/curve25519.zig11
-rw-r--r--lib/std/crypto/argon2.zig28
-rw-r--r--lib/std/crypto/scrypt.zig4
-rw-r--r--lib/std/debug.zig2
-rw-r--r--lib/std/dynamic_library.zig2
-rw-r--r--lib/std/elf.zig4
-rw-r--r--lib/std/event/wait_group.zig14
-rw-r--r--lib/std/fmt.zig42
-rw-r--r--lib/std/fmt/errol.zig7
-rw-r--r--lib/std/fmt/parse_hex_float.zig65
-rw-r--r--lib/std/fs.zig2
-rw-r--r--lib/std/fs/file.zig11
-rw-r--r--lib/std/fs/test.zig53
-rw-r--r--lib/std/io.zig1
-rw-r--r--lib/std/math.zig150
-rw-r--r--lib/std/math/__rem_pio2.zig2
-rw-r--r--lib/std/math/__rem_pio2f.zig2
-rw-r--r--lib/std/math/big/int.zig4
-rw-r--r--lib/std/math/ceil.zig12
-rw-r--r--lib/std/math/complex/exp.zig4
-rw-r--r--lib/std/math/complex/sinh.zig4
-rw-r--r--lib/std/math/epsilon.zig15
-rw-r--r--lib/std/math/fabs.zig112
-rw-r--r--lib/std/math/float.zig110
-rw-r--r--lib/std/math/floor.zig12
-rw-r--r--lib/std/math/fma.zig4
-rw-r--r--lib/std/math/inf.zig14
-rw-r--r--lib/std/math/isfinite.zig71
-rw-r--r--lib/std/math/isinf.zig145
-rw-r--r--lib/std/math/isnormal.zig89
-rw-r--r--lib/std/math/ldexp.zig46
-rw-r--r--lib/std/math/round.zig18
-rw-r--r--lib/std/mem/Allocator.zig4
-rw-r--r--lib/std/os.zig6
-rw-r--r--lib/std/os/test.zig2
-rw-r--r--lib/std/os/uefi/pool_allocator.zig2
-rw-r--r--lib/std/os/uefi/tables/boot_services.zig2
-rw-r--r--lib/std/packed_int_array.zig2
-rw-r--r--lib/std/priority_queue.zig23
-rw-r--r--lib/std/rand.zig4
-rw-r--r--lib/std/rand/ziggurat.zig2
-rw-r--r--lib/std/simd.zig6
-rw-r--r--lib/std/special/compiler_rt.zig225
-rw-r--r--lib/std/special/compiler_rt/divtf3_test.zig8
-rw-r--r--lib/std/special/compiler_rt/fixXfYi.zig224
-rw-r--r--lib/std/special/compiler_rt/fixXfYi_test.zig948
-rw-r--r--lib/std/special/compiler_rt/fixdfdi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixdfdi_test.zig62
-rw-r--r--lib/std/special/compiler_rt/fixdfsi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixdfsi_test.zig70
-rw-r--r--lib/std/special/compiler_rt/fixdfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixdfti_test.zig62
-rw-r--r--lib/std/special/compiler_rt/fixint.zig75
-rw-r--r--lib/std/special/compiler_rt/fixint_test.zig72
-rw-r--r--lib/std/special/compiler_rt/fixsfdi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixsfdi_test.zig64
-rw-r--r--lib/std/special/compiler_rt/fixsfsi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixsfsi_test.zig72
-rw-r--r--lib/std/special/compiler_rt/fixsfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixsfti_test.zig80
-rw-r--r--lib/std/special/compiler_rt/fixtfdi.zig11
-rw-r--r--lib/std/special/compiler_rt/fixtfdi_test.zig72
-rw-r--r--lib/std/special/compiler_rt/fixtfsi.zig11
-rw-r--r--lib/std/special/compiler_rt/fixtfsi_test.zig72
-rw-r--r--lib/std/special/compiler_rt/fixtfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixtfti_test.zig62
-rw-r--r--lib/std/special/compiler_rt/fixuint.zig50
-rw-r--r--lib/std/special/compiler_rt/fixunsdfdi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixunsdfdi_test.zig39
-rw-r--r--lib/std/special/compiler_rt/fixunsdfsi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixunsdfsi_test.zig39
-rw-r--r--lib/std/special/compiler_rt/fixunsdfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixunsdfti_test.zig46
-rw-r--r--lib/std/special/compiler_rt/fixunssfdi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixunssfdi_test.zig35
-rw-r--r--lib/std/special/compiler_rt/fixunssfsi.zig16
-rw-r--r--lib/std/special/compiler_rt/fixunssfsi_test.zig36
-rw-r--r--lib/std/special/compiler_rt/fixunssfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixunssfti_test.zig41
-rw-r--r--lib/std/special/compiler_rt/fixunstfdi.zig11
-rw-r--r--lib/std/special/compiler_rt/fixunstfdi_test.zig49
-rw-r--r--lib/std/special/compiler_rt/fixunstfsi.zig11
-rw-r--r--lib/std/special/compiler_rt/fixunstfsi_test.zig22
-rw-r--r--lib/std/special/compiler_rt/fixunstfti.zig11
-rw-r--r--lib/std/special/compiler_rt/fixunstfti_test.zig32
-rw-r--r--lib/std/special/compiler_rt/floatXiYf.zig222
-rw-r--r--lib/std/special/compiler_rt/floatXiYf_test.zig835
-rw-r--r--lib/std/special/compiler_rt/floatXisf.zig90
-rw-r--r--lib/std/special/compiler_rt/floatdidf.zig27
-rw-r--r--lib/std/special/compiler_rt/floatdidf_test.zig53
-rw-r--r--lib/std/special/compiler_rt/floatdisf_test.zig32
-rw-r--r--lib/std/special/compiler_rt/floatditf.zig38
-rw-r--r--lib/std/special/compiler_rt/floatditf_test.zig26
-rw-r--r--lib/std/special/compiler_rt/floatfmodl_test.zig46
-rw-r--r--lib/std/special/compiler_rt/floatfmodq.zig (renamed from lib/std/special/compiler_rt/floatfmodl.zig)12
-rw-r--r--lib/std/special/compiler_rt/floatfmodq_test.zig46
-rw-r--r--lib/std/special/compiler_rt/floatsiXf.zig120
-rw-r--r--lib/std/special/compiler_rt/floattidf.zig71
-rw-r--r--lib/std/special/compiler_rt/floattidf_test.zig84
-rw-r--r--lib/std/special/compiler_rt/floattisf_test.zig60
-rw-r--r--lib/std/special/compiler_rt/floattitf.zig71
-rw-r--r--lib/std/special/compiler_rt/floattitf_test.zig96
-rw-r--r--lib/std/special/compiler_rt/floatundidf.zig29
-rw-r--r--lib/std/special/compiler_rt/floatundidf_test.zig50
-rw-r--r--lib/std/special/compiler_rt/floatundisf.zig94
-rw-r--r--lib/std/special/compiler_rt/floatunditf.zig28
-rw-r--r--lib/std/special/compiler_rt/floatunditf_test.zig32
-rw-r--r--lib/std/special/compiler_rt/floatunsidf.zig41
-rw-r--r--lib/std/special/compiler_rt/floatunsisf.zig61
-rw-r--r--lib/std/special/compiler_rt/floatunsitf.zig29
-rw-r--r--lib/std/special/compiler_rt/floatunsitf_test.zig28
-rw-r--r--lib/std/special/compiler_rt/floatuntidf.zig62
-rw-r--r--lib/std/special/compiler_rt/floatuntidf_test.zig81
-rw-r--r--lib/std/special/compiler_rt/floatuntisf.zig61
-rw-r--r--lib/std/special/compiler_rt/floatuntisf_test.zig72
-rw-r--r--lib/std/special/compiler_rt/floatuntitf.zig62
-rw-r--r--lib/std/special/compiler_rt/floatuntitf_test.zig99
-rw-r--r--lib/std/special/compiler_rt/sparc.zig16
-rw-r--r--lib/std/special/compiler_rt/trunc_f80.zig34
-rw-r--r--lib/std/start.zig9
-rw-r--r--lib/std/testing.zig144
-rw-r--r--lib/std/time.zig6
-rw-r--r--lib/std/unicode.zig19
-rw-r--r--lib/std/x/net/tcp.zig2
-rw-r--r--lib/std/x/os/socket_posix.zig6
-rw-r--r--lib/std/zig/parser_test.zig84
-rw-r--r--lib/std/zig/render.zig12
-rw-r--r--lib/std/zig/string_literal.zig2
-rw-r--r--lib/std/zig/system/NativeTargetInfo.zig2
-rw-r--r--src/AstGen.zig4
-rw-r--r--src/Compilation.zig1
-rw-r--r--src/InternPool.zig (renamed from src/InternArena.zig)70
-rw-r--r--src/Liveness.zig83
-rw-r--r--src/Module.zig46
-rw-r--r--src/Sema.zig288
-rw-r--r--src/ThreadPool.zig7
-rw-r--r--src/arch/aarch64/CodeGen.zig39
-rw-r--r--src/arch/arm/CodeGen.zig39
-rw-r--r--src/arch/arm/Emit.zig29
-rw-r--r--src/arch/riscv64/CodeGen.zig36
-rw-r--r--src/arch/sparcv9/CodeGen.zig1658
-rw-r--r--src/arch/sparcv9/Emit.zig292
-rw-r--r--src/arch/sparcv9/Mir.zig258
-rw-r--r--src/arch/sparcv9/abi.zig23
-rw-r--r--src/arch/sparcv9/bits.zig223
-rw-r--r--src/arch/wasm/CodeGen.zig37
-rw-r--r--src/arch/wasm/Emit.zig2
-rw-r--r--src/arch/wasm/Mir.zig8
-rw-r--r--src/arch/x86_64/CodeGen.zig244
-rw-r--r--src/arch/x86_64/Emit.zig88
-rw-r--r--src/arch/x86_64/Mir.zig24
-rw-r--r--src/arch/x86_64/PrintMir.zig2
-rw-r--r--src/codegen.zig2
-rw-r--r--src/codegen/c.zig19
-rw-r--r--src/codegen/llvm.zig10
-rw-r--r--src/link.zig48
-rw-r--r--src/link/C.zig5
-rw-r--r--src/link/Dwarf.zig218
-rw-r--r--src/link/Elf.zig346
-rw-r--r--src/link/MachO.zig10
-rw-r--r--src/link/MachO/DebugSymbols.zig52
-rw-r--r--src/link/MachO/Object.zig1
-rw-r--r--src/link/MachO/fat.zig1
-rw-r--r--src/link/Plan9.zig2
-rw-r--r--src/link/Wasm.zig70
-rw-r--r--src/link/Wasm/Atom.zig2
-rw-r--r--src/link/Wasm/Object.zig23
-rw-r--r--src/link/Wasm/types.zig12
-rw-r--r--src/print_air.zig26
-rw-r--r--src/stage1/ir.cpp6
-rw-r--r--src/target.zig1
-rw-r--r--src/test.zig135
-rw-r--r--src/type.zig9
-rw-r--r--src/value.zig34
-rw-r--r--test/behavior/call.zig141
-rw-r--r--test/behavior/cast.zig9
-rw-r--r--test/behavior/generics.zig18
-rw-r--r--test/behavior/math.zig14
-rw-r--r--test/behavior/ptrcast.zig16
-rw-r--r--test/behavior/switch.zig22
-rw-r--r--test/behavior/union.zig15
-rw-r--r--test/behavior/vector.zig2
-rw-r--r--test/cases.zig1
-rw-r--r--test/stage2/aarch64.zig2
-rw-r--r--test/stage2/sparcv9.zig39
-rw-r--r--test/stage2/x86_64.zig4
195 files changed, 7585 insertions, 4711 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39d12843be..81b96d67ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -444,9 +444,9 @@ 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/float.zig"
"${CMAKE_SOURCE_DIR}/lib/std/math/floor.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"
@@ -493,41 +493,8 @@ set(ZIG_STAGE2_SOURCES
"${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/fixXfYi.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatXiYf.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"
diff --git a/deps/SoftFloat-3e-prebuilt/platform.h b/deps/SoftFloat-3e-prebuilt/platform.h
index ef99e21b97..588c548c60 100644
--- a/deps/SoftFloat-3e-prebuilt/platform.h
+++ b/deps/SoftFloat-3e-prebuilt/platform.h
@@ -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
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 578f0297ae..0f90a88822 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -7833,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>
@@ -11957,17 +11957,6 @@ fn readU32Be() u32 {}
</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>
</th>
<td>
@@ -12043,17 +12032,6 @@ fn readU32Be() u32 {}
</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>
</th>
<td>
@@ -12192,17 +12170,6 @@ fn readU32Be() u32 {}
</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>
</th>
<td>
@@ -12216,17 +12183,6 @@ fn readU32Be() u32 {}
</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>
</th>
<td>
diff --git a/lib/std/Thread/Condition.zig b/lib/std/Thread/Condition.zig
index 7a479e5540..fb48db8e53 100644
--- a/lib/std/Thread/Condition.zig
+++ b/lib/std/Thread/Condition.zig
@@ -17,6 +17,10 @@ pub fn wait(cond: *Condition, mutex: *Mutex) void {
cond.impl.wait(mutex);
}
+pub fn timedWait(cond: *Condition, mutex: *Mutex, timeout_ns: u64) error{TimedOut}!void {
+ try cond.impl.timedWait(mutex, timeout_ns);
+}
+
pub fn signal(cond: *Condition) void {
cond.impl.signal();
}
@@ -41,6 +45,14 @@ pub const SingleThreadedCondition = struct {
unreachable; // deadlock detected
}
+ pub fn timedWait(cond: *SingleThreadedCondition, mutex: *Mutex, timeout_ns: u64) error{TimedOut}!void {
+ _ = cond;
+ _ = mutex;
+ _ = timeout_ns;
+ std.time.sleep(timeout_ns);
+ return error.TimedOut;
+ }
+
pub fn signal(cond: *SingleThreadedCondition) void {
_ = cond;
}
@@ -63,6 +75,25 @@ pub const WindowsCondition = struct {
assert(rc != windows.FALSE);
}
+ pub fn timedWait(cond: *WindowsCondition, mutex: *Mutex, timeout_ns: u64) error{TimedOut}!void {
+ var timeout_checked = std.math.cast(windows.DWORD, timeout_ns / std.time.ns_per_ms) catch overflow: {
+ break :overflow std.math.maxInt(windows.DWORD);
+ };
+
+ // Handle the case where timeout is INFINITE, otherwise SleepConditionVariableSRW's time-out never elapses
+ const timeout_overflowed = timeout_checked == windows.INFINITE;
+ timeout_checked -= @boolToInt(timeout_overflowed);
+
+ const rc = windows.kernel32.SleepConditionVariableSRW(
+ &cond.cond,
+ &mutex.impl.srwlock,
+ timeout_checked,
+ @as(windows.ULONG, 0),
+ );
+ if (rc == windows.FALSE and windows.kernel32.GetLastError() == windows.Win32Error.TIMEOUT) return error.TimedOut;
+ assert(rc != windows.FALSE);
+ }
+
pub fn signal(cond: *WindowsCondition) void {
windows.kernel32.WakeConditionVariable(&cond.cond);
}
@@ -80,6 +111,24 @@ pub const PthreadCondition = struct {
assert(rc == .SUCCESS);
}
+ pub fn timedWait(cond: *PthreadCondition, mutex: *Mutex, timeout_ns: u64) error{TimedOut}!void {
+ var ts: std.os.timespec = undefined;
+ std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts) catch unreachable;
+ ts.tv_sec += @intCast(@TypeOf(ts.tv_sec), timeout_ns / std.time.ns_per_s);
+ ts.tv_nsec += @intCast(@TypeOf(ts.tv_nsec), timeout_ns % std.time.ns_per_s);
+ if (ts.tv_nsec >= std.time.ns_per_s) {
+ ts.tv_sec += 1;
+ ts.tv_nsec -= std.time.ns_per_s;
+ }
+
+ const rc = std.c.pthread_cond_timedwait(&cond.cond, &mutex.impl.pthread_mutex, &ts);
+ return switch (rc) {
+ .SUCCESS => {},
+ .TIMEDOUT => error.TimedOut,
+ else => unreachable,
+ };
+ }
+
pub fn signal(cond: *PthreadCondition) void {
const rc = std.c.pthread_cond_signal(&cond.cond);
assert(rc == .SUCCESS);
@@ -100,6 +149,7 @@ pub const AtomicCondition = struct {
pub const QueueItem = struct {
futex: i32 = 0,
+ dequeued: bool = false,
fn wait(cond: *@This()) void {
while (@atomicLoad(i32, &cond.futex, .Acquire) == 0) {
@@ -122,6 +172,39 @@ pub const AtomicCondition = struct {
}
}
+ pub fn timedWait(cond: *@This(), timeout_ns: u64) error{TimedOut}!void {
+ const start_time = std.time.nanoTimestamp();
+ while (@atomicLoad(i32, &cond.futex, .Acquire) == 0) {
+ switch (builtin.os.tag) {
+ .linux => {
+ var ts: std.os.timespec = undefined;
+ ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), timeout_ns / std.time.ns_per_s);
+ ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), timeout_ns % std.time.ns_per_s);
+ switch (linux.getErrno(linux.futex_wait(
+ &cond.futex,
+ linux.FUTEX.PRIVATE_FLAG | linux.FUTEX.WAIT,
+ 0,
+ &ts,
+ ))) {
+ .SUCCESS => {},
+ .INTR => {},
+ .AGAIN => {},
+ .TIMEDOUT => return error.TimedOut,
+ .INVAL => {}, // possibly timeout overflow
+ .FAULT => unreachable,
+ else => unreachable,
+ }
+ },
+ else => {
+ if (std.time.nanoTimestamp() - start_time >= timeout_ns) {
+ return error.TimedOut;
+ }
+ std.atomic.spinLoopHint();
+ },
+ }
+ }
+ }
+
fn notify(cond: *@This()) void {
@atomicStore(i32, &cond.futex, 1, .Release);
@@ -158,6 +241,41 @@ pub const AtomicCondition = struct {
mutex.lock();
}
+ pub fn timedWait(cond: *AtomicCondition, mutex: *Mutex, timeout_ns: u64) error{TimedOut}!void {
+ var waiter = QueueList.Node{ .data = .{} };
+
+ {
+ cond.queue_mutex.lock();
+ defer cond.queue_mutex.unlock();
+
+ cond.queue_list.prepend(&waiter);
+ @atomicStore(bool, &cond.pending, true, .SeqCst);
+ }
+
+ var timed_out = false;
+ mutex.unlock();
+ defer mutex.lock();
+ waiter.data.timedWait(timeout_ns) catch |err| switch (err) {
+ error.TimedOut => {
+ defer if (!timed_out) {
+ waiter.data.wait();
+ };
+ cond.queue_mutex.lock();
+ defer cond.queue_mutex.unlock();
+
+ if (!waiter.data.dequeued) {
+ timed_out = true;
+ cond.queue_list.remove(&waiter);
+ }
+ },
+ else => unreachable,
+ };
+
+ if (timed_out) {
+ return error.TimedOut;
+ }
+ }
+
pub fn signal(cond: *AtomicCondition) void {
if (@atomicLoad(bool, &cond.pending, .SeqCst) == false)
return;
@@ -167,12 +285,16 @@ pub const AtomicCondition = struct {
defer cond.queue_mutex.unlock();
const maybe_waiter = cond.queue_list.popFirst();
+ if (maybe_waiter) |waiter| {
+ waiter.data.dequeued = true;
+ }
@atomicStore(bool, &cond.pending, cond.queue_list.first != null, .SeqCst);
break :blk maybe_waiter;
};
- if (maybe_waiter) |waiter|
+ if (maybe_waiter) |waiter| {
waiter.data.notify();
+ }
}
pub fn broadcast(cond: *AtomicCondition) void {
@@ -186,12 +308,19 @@ pub const AtomicCondition = struct {
defer cond.queue_mutex.unlock();
const waiters = cond.queue_list;
+
+ var it = waiters.first;
+ while (it) |node| : (it = node.next) {
+ node.data.dequeued = true;
+ }
+
cond.queue_list = .{};
break :blk waiters;
};
- while (waiters.popFirst()) |waiter|
+ while (waiters.popFirst()) |waiter| {
waiter.data.notify();
+ }
}
};
@@ -238,3 +367,45 @@ test "Thread.Condition" {
for (threads) |t| t.join();
}
+
+test "Thread.Condition.timedWait" {
+ if (builtin.single_threaded) {
+ return error.SkipZigTest;
+ }
+
+ var cond = Condition{};
+ var mut = Mutex{};
+
+ // Expect a timeout, as the condition variable is never signaled
+ {
+ mut.lock();
+ defer mut.unlock();
+ try testing.expectError(error.TimedOut, cond.timedWait(&mut, 10 * std.time.ns_per_ms));
+ }
+
+ // Expect a signal before timeout
+ {
+ const TestContext = struct {
+ cond: *Condition,
+ mutex: *Mutex,
+ n: *u32,
+ fn worker(ctx: *@This()) void {
+ ctx.mutex.lock();
+ defer ctx.mutex.unlock();
+ ctx.n.* = 1;
+ ctx.cond.signal();
+ }
+ };
+
+ var n: u32 = 0;
+
+ var ctx = TestContext{ .cond = &cond, .mutex = &mut, .n = &n };
+ mut.lock();
+ var thread = try std.Thread.spawn(.{}, TestContext.worker, .{&ctx});
+ // Looped check to handle spurious wakeups
+ while (n != 1) try cond.timedWait(&mut, 500 * std.time.ns_per_ms);
+ mut.unlock();
+ try testing.expect(n == 1);
+ thread.join();
+ }
+}
diff --git a/lib/std/Thread/Futex.zig b/lib/std/Thread/Futex.zig
index c9a19b4cd9..d256fb5a43 100644
--- a/lib/std/Thread/Futex.zig
+++ b/lib/std/Thread/Futex.zig
@@ -1,7 +1,7 @@
//! Futex is a mechanism used to block (`wait`) and unblock (`wake`) threads using a 32bit memory address as hints.
//! Blocking a thread is acknowledged only if the 32bit memory address is equal to a given value.
//! This check helps avoid block/unblock deadlocks which occur if a `wake()` happens before a `wait()`.
-//! Using Futex, other Thread synchronization primitives can be built which efficiently wait for cross-thread events or signals.
+//! Using Futex, other Thread synchronization primitives can be built which efficiently wait for cross-thread events or signals.
const std = @import("../std.zig");
const builtin = @import("builtin");
@@ -20,7 +20,7 @@ const spinLoopHint = std.atomic.spinLoopHint;
/// - The value at `ptr` is no longer equal to `expect`.
/// - The caller is unblocked by a matching `wake()`.
/// - The caller is unblocked spuriously by an arbitrary internal signal.
-///
+///
/// If `timeout` is provided, and the caller is blocked for longer than `timeout` nanoseconds`, `error.TimedOut` is returned.
///
/// The checking of `ptr` and `expect`, along with blocking the caller, is done atomically
diff --git a/lib/std/bounded_array.zig b/lib/std/bounded_array.zig
index 7c562b7c84..0b0efc55e4 100644
--- a/lib/std/bounded_array.zig
+++ b/lib/std/bounded_array.zig
@@ -239,6 +239,24 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
assert(self.len <= capacity);
mem.set(T, self.slice()[old_len..self.len], value);
}
+
+ pub const Writer = if (T != u8)
+ @compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
+ "but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)")
+ else
+ std.io.Writer(*Self, error{Overflow}, appendWrite);
+
+ /// Initializes a writer which will write into the array.
+ pub fn writer(self: *Self) Writer {
+ return .{ .context = self };
+ }
+
+ /// Same as `appendSlice` except it returns the number of bytes written, which is always the same
+ /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
+ fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize {
+ try self.appendSlice(m);
+ return m.len;
+ }
};
}
@@ -336,4 +354,10 @@ test "BoundedArray" {
const swapped = a.swapRemove(0);
try testing.expectEqual(swapped, 0xdd);
try testing.expectEqual(a.get(0), 0xee);
+
+ while (a.popOrNull()) |_| {}
+ const w = a.writer();
+ const s = "hello, this is a test string";
+ try w.writeAll(s);
+ try testing.expectEqualStrings(s, a.constSlice());
}
diff --git a/lib/std/build.zig b/lib/std/build.zig
index f1287c7be5..ff0f36b4a8 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1600,12 +1600,26 @@ pub const LibExeObjStep = struct {
pub const LinkObject = union(enum) {
static_path: FileSource,
other_step: *LibExeObjStep,
- system_lib: []const u8,
+ system_lib: SystemLib,
assembly_file: FileSource,
c_source_file: *CSourceFile,
c_source_files: *CSourceFiles,
};
+ pub const SystemLib = struct {
+ name: []const u8,
+ use_pkg_config: enum {
+ /// Don't use pkg-config, just pass -lfoo where foo is name.
+ no,
+ /// Try to get information on how to link the library from pkg-config.
+ /// If that fails, fall back to passing -lfoo where foo is name.
+ yes,
+ /// Try to get information on how to link the library from pkg-config.
+ /// If that fails, error out.
+ force,
+ },
+ };
+
pub const IncludeDir = union(enum) {
raw_path: []const u8,
raw_path_system: []const u8,
@@ -1854,7 +1868,7 @@ pub const LibExeObjStep = struct {
}
for (self.link_objects.items) |link_object| {
switch (link_object) {
- .system_lib => |n| if (mem.eql(u8, n, name)) return true,
+ .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
else => continue,
}
}
@@ -1879,14 +1893,24 @@ pub const LibExeObjStep = struct {
pub fn linkLibC(self: *LibExeObjStep) void {
if (!self.is_linking_libc) {
self.is_linking_libc = true;
- self.link_objects.append(.{ .system_lib = "c" }) catch unreachable;
+ self.link_objects.append(.{
+ .system_lib = .{
+ .name = "c",
+ .use_pkg_config = .no,
+ },
+ }) catch unreachable;
}
}
pub fn linkLibCpp(self: *LibExeObjStep) void {
if (!self.is_linking_libcpp) {
self.is_linking_libcpp = true;
- self.link_objects.append(.{ .system_lib = "c++" }) catch unreachable;
+ self.link_objects.append(.{
+ .system_lib = .{
+ .name = "c++",
+ .use_pkg_config = .no,
+ },
+ }) catch unreachable;
}
}
@@ -1905,12 +1929,28 @@ pub const LibExeObjStep = struct {
/// This one has no integration with anything, it just puts -lname on the command line.
/// Prefer to use `linkSystemLibrary` instead.
pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void {
- self.link_objects.append(.{ .system_lib = self.builder.dupe(name) }) catch unreachable;
+ self.link_objects.append(.{
+ .system_lib = .{
+ .name = self.builder.dupe(name),
+ .use_pkg_config = .no,
+ },
+ }) catch unreachable;
}
/// This links against a system library, exclusively using pkg-config to find the library.
/// Prefer to use `linkSystemLibrary` instead.
- pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) !void {
+ pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void {
+ self.link_objects.append(.{
+ .system_lib = .{
+ .name = self.builder.dupe(lib_name),
+ .use_pkg_config = .force,
+ },
+ }) catch unreachable;
+ }
+
+ /// Run pkg-config for the given library name and parse the output, returning the arguments
+ /// that should be passed to zig to link the given library.
+ fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const u8 {
const pkg_name = match: {
// First we have to map the library name to pkg config name. Unfortunately,
// there are several examples where this is not straightforward:
@@ -1970,34 +2010,38 @@ pub const LibExeObjStep = struct {
error.ChildExecFailed => return error.PkgConfigFailed,
else => return err,
};
+
+ var zig_args = std.ArrayList([]const u8).init(self.builder.allocator);
+ defer zig_args.deinit();
+
var it = mem.tokenize(u8, stdout, " \r\n\t");
while (it.next()) |tok| {
if (mem.eql(u8, tok, "-I")) {
const dir = it.next() orelse return error.PkgConfigInvalidOutput;
- self.addIncludePath(dir);
+ try zig_args.appendSlice(&[_][]const u8{ "-I", dir });
} else if (mem.startsWith(u8, tok, "-I")) {
- self.addIncludePath(tok["-I".len..]);
+ try zig_args.append(tok);
} else if (mem.eql(u8, tok, "-L")) {
const dir = it.next() orelse return error.PkgConfigInvalidOutput;
- self.addLibraryPath(dir);
+ try zig_args.appendSlice(&[_][]const u8{ "-L", dir });
} else if (mem.startsWith(u8, tok, "-L")) {
- self.addLibraryPath(tok["-L".len..]);
+ try zig_args.append(tok);
} else if (mem.eql(u8, tok, "-l")) {
const lib = it.next() orelse return error.PkgConfigInvalidOutput;
- self.linkSystemLibraryName(lib);
+ try zig_args.appendSlice(&[_][]const u8{ "-l", lib });
} else if (mem.startsWith(u8, tok, "-l")) {
- self.linkSystemLibraryName(tok["-l".len..]);
+ try zig_args.append(tok);
} else if (mem.eql(u8, tok, "-D")) {
const macro = it.next() orelse return error.PkgConfigInvalidOutput;
- self.defineCMacroRaw(macro);
+ try zig_args.appendSlice(&[_][]const u8{ "-D", macro });
} else if (mem.startsWith(u8, tok, "-D")) {
- self.defineCMacroRaw(tok["-D".len..]);
- } else if (mem.eql(u8, tok, "-pthread")) {
- self.linkLibC();
+ try zig_args.append(tok);
} else if (self.builder.verbose) {
warn("Ignoring pkg-config flag '{s}'\n", .{tok});
}
}
+
+ return zig_args.toOwnedSlice();
}
pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
@@ -2009,21 +2053,13 @@ pub const LibExeObjStep = struct {
self.linkLibCpp();
return;
}
- if (self.linkSystemLibraryPkgConfigOnly(name)) |_| {
- // pkg-config worked, so nothing further needed to do.
- return;
- } else |err| switch (err) {
- error.PkgConfigInvalidOutput,
- error.PkgConfigCrashed,
- error.PkgConfigFailed,
- error.PkgConfigNotInstalled,
- error.PackageNotFound,
- => {},
-
- else => unreachable,
- }
- self.linkSystemLibraryName(name);
+ self.link_objects.append(.{
+ .system_lib = .{
+ .name = self.builder.dupe(name),
+ .use_pkg_config = .yes,
+ },
+ }) catch unreachable;
}
pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
@@ -2317,27 +2353,34 @@ pub const LibExeObjStep = struct {
var prev_has_extra_flags = false;
// Resolve transitive dependencies
- for (self.link_objects.items) |link_object| {
- switch (link_object) {
- .other_step => |other| {
- // Inherit dependency on system libraries
- for (other.link_objects.items) |other_link_object| {
- switch (other_link_object) {
- .system_lib => |name| self.linkSystemLibrary(name),
- else => continue,
+ {
+ var transitive_dependencies = std.ArrayList(LinkObject).init(builder.allocator);
+ defer transitive_dependencies.deinit();
+
+ for (self.link_objects.items) |link_object| {
+ switch (link_object) {
+ .other_step => |other| {
+ // Inherit dependency on system libraries
+ for (other.link_objects.items) |other_link_object| {
+ switch (other_link_object) {
+ .system_lib => try transitive_dependencies.append(other_link_object),
+ else => continue,
+ }
}
- }
- // Inherit dependencies on darwin frameworks
- if (!other.isDynamicLibrary()) {
- var it = other.frameworks.iterator();
- while (it.next()) |framework| {
- self.frameworks.insert(framework.*) catch unreachable;
+ // Inherit dependencies on darwin frameworks
+ if (!other.isDynamicLibrary()) {
+ var it = other.frameworks.iterator();
+ while (it.next()) |framework| {
+ self.frameworks.insert(framework.*) catch unreachable;
+ }
}
- }
- },
- else => continue,
+ },
+ else => continue,
+ }
}
+
+ try self.link_objects.appendSlice(transitive_dependencies.items);
}
for (self.link_objects.items) |link_object| {
@@ -2363,8 +2406,35 @@ pub const LibExeObjStep = struct {
}
},
},
- .system_lib => |name| {
- try zig_args.append(builder.fmt("-l{s}", .{name}));
+
+ .system_lib => |system_lib| {
+ switch (system_lib.use_pkg_config) {
+ .no => try zig_args.append(builder.fmt("-l{s}", .{system_lib.name})),
+ .yes, .force => {
+ if (self.runPkgConfig(system_lib.name)) |args| {
+ try zig_args.appendSlice(args);
+ } else |err| switch (err) {
+ error.PkgConfigInvalidOutput,
+ error.PkgConfigCrashed,
+ error.PkgConfigFailed,
+ error.PkgConfigNotInstalled,
+ error.PackageNotFound,
+ => switch (system_lib.use_pkg_config) {
+ .yes => {
+ // pkg-config failed, so fall back to linking the library
+ // by name directly.
+ try zig_args.append(builder.fmt("-l{s}", .{system_lib.name}));
+ },
+ .force => {
+ panic("pkg-config failed for library {s}", .{system_lib.name});
+ },
+ .no => unreachable,
+ },
+
+ else => |e| return e,
+ }
+ },
+ }
},
.assembly_file => |asm_file| {
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 7b66998dc1..f38fc4e155 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -716,6 +716,9 @@ pub const CompilerBackend = enum(u64) {
/// The reference implementation self-hosted compiler of Zig, using the
/// riscv64 backend.
stage2_riscv64 = 9,
+ /// The reference implementation self-hosted compiler of Zig, using the
+ /// sparcv9 backend.
+ stage2_sparcv9 = 10,
_,
};
@@ -761,7 +764,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
builtin.zig_backend == .stage2_aarch64 or
builtin.zig_backend == .stage2_x86_64 or
builtin.zig_backend == .stage2_x86 or
- builtin.zig_backend == .stage2_riscv64)
+ builtin.zig_backend == .stage2_riscv64 or
+ builtin.zig_backend == .stage2_sparcv9)
{
while (true) {
@breakpoint();
diff --git a/lib/std/compress/deflate/compressor.zig b/lib/std/compress/deflate/compressor.zig
index 8ced8b5faf..58b1955838 100644
--- a/lib/std/compress/deflate/compressor.zig
+++ b/lib/std/compress/deflate/compressor.zig
@@ -219,7 +219,7 @@ const CompressorOptions = struct {
///
/// `dictionary` is optional and initializes the new `Compressor` with a preset dictionary.
/// The returned Compressor behaves as if the dictionary had been written to it without producing
-/// any compressed output. The compressed data written to hm_bw can only be decompressed by a
+/// any compressed output. The compressed data written to hm_bw can only be decompressed by a
/// Decompressor initialized with the same dictionary.
///
/// The compressed data will be passed to the provided `writer`, see `writer()` and `write()`.
diff --git a/lib/std/crypto/25519/curve25519.zig b/lib/std/crypto/25519/curve25519.zig
index 20b0dccaa0..f5938dd218 100644
--- a/lib/std/crypto/25519/curve25519.zig
+++ b/lib/std/crypto/25519/curve25519.zig
@@ -39,8 +39,11 @@ pub const Curve25519 = struct {
}
}
- /// Multiply a point by the cofactor
- pub const clearCofactor = @compileError("TODO what was this function supposed to do? it didn't compile successfully");
+ /// Multiply a point by the cofactor, returning WeakPublicKey if the element is in a small-order group.
+ pub fn clearCofactor(p: Curve25519) WeakPublicKeyError!Curve25519 {
+ const cofactor = [_]u8{8} ++ [_]u8{0} ** 31;
+ return ladder(p, cofactor, 4) catch return error.WeakPublicKey;
+ }
fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) IdentityElementError!Curve25519 {
var x1 = p.x;
@@ -94,8 +97,7 @@ pub const Curve25519 = struct {
/// the identity element or error.WeakPublicKey if the public
/// key is a low-order point.
pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 {
- const cofactor = [_]u8{8} ++ [_]u8{0} ** 31;
- _ = ladder(p, cofactor, 4) catch return error.WeakPublicKey;
+ _ = try p.clearCofactor();
return try ladder(p, s, 256);
}
@@ -148,6 +150,7 @@ test "curve25519 small order check" {
},
};
for (small_order_ss) |small_order_s| {
+ try std.testing.expectError(error.WeakPublicKey, Curve25519.fromBytes(small_order_s).clearCofactor());
try std.testing.expectError(error.WeakPublicKey, Curve25519.fromBytes(small_order_s).mul(s));
var extra = small_order_s;
extra[31] ^= 0x80;
diff --git a/lib/std/crypto/argon2.zig b/lib/std/crypto/argon2.zig
index 493f36ca94..7269470d5f 100644
--- a/lib/std/crypto/argon2.zig
+++ b/lib/std/crypto/argon2.zig
@@ -34,18 +34,18 @@ const max_hash_len = 64;
/// Argon2 type
pub const Mode = enum {
- /// Argon2d is faster and uses data-depending memory access, which makes it highly resistant
- /// against GPU cracking attacks and suitable for applications with no threats from side-channel
+ /// Argon2d is faster and uses data-depending memory access, which makes it highly resistant
+ /// against GPU cracking attacks and suitable for applications with no threats from side-channel
/// timing attacks (eg. cryptocurrencies).
argon2d,
- /// Argon2i instead uses data-independent memory access, which is preferred for password
- /// hashing and password-based key derivation, but it is slower as it makes more passes over
+ /// Argon2i instead uses data-independent memory access, which is preferred for password
+ /// hashing and password-based key derivation, but it is slower as it makes more passes over
/// the memory to protect from tradeoff attacks.
argon2i,
- /// Argon2id is a hybrid of Argon2i and Argon2d, using a combination of data-depending and
- /// data-independent memory accesses, which gives some of Argon2i's resistance to side-channel
+ /// Argon2id is a hybrid of Argon2i and Argon2d, using a combination of data-depending and
+ /// data-independent memory accesses, which gives some of Argon2i's resistance to side-channel
/// cache timing attacks and much of Argon2d's resistance to GPU cracking attacks.
argon2id,
};
@@ -54,7 +54,7 @@ pub const Mode = enum {
pub const Params = struct {
const Self = @This();
- /// A [t]ime cost, which defines the amount of computation realized and therefore the execution
+ /// A [t]ime cost, which defines the amount of computation realized and therefore the execution
/// time, given in number of iterations.
t: u32,
@@ -64,16 +64,16 @@ pub const Params = struct {
/// A [p]arallelism degree, which defines the number of parallel threads.
p: u24,
- /// The [secret] parameter, which is used for keyed hashing. This allows a secret key to be input
- /// at hashing time (from some external location) and be folded into the value of the hash. This
- /// means that even if your salts and hashes are compromised, an attacker cannot brute-force to
+ /// The [secret] parameter, which is used for keyed hashing. This allows a secret key to be input
+ /// at hashing time (from some external location) and be folded into the value of the hash. This
+ /// means that even if your salts and hashes are compromised, an attacker cannot brute-force to
/// find the password without the key.
secret: ?[]const u8 = null,
- /// The [ad] parameter, which is used to fold any additional data into the hash value. Functionally,
- /// this behaves almost exactly like the secret or salt parameters; the ad parameter is folding
- /// into the value of the hash. However, this parameter is used for different data. The salt
- /// should be a random string stored alongside your password. The secret should be a random key
+ /// The [ad] parameter, which is used to fold any additional data into the hash value. Functionally,
+ /// this behaves almost exactly like the secret or salt parameters; the ad parameter is folding
+ /// into the value of the hash. However, this parameter is used for different data. The salt
+ /// should be a random string stored alongside your password. The secret should be a random key
/// only usable at hashing time. The ad is for any other data.
ad: ?[]const u8 = null,
diff --git a/lib/std/crypto/scrypt.zig b/lib/std/crypto/scrypt.zig
index e464cca28e..a9506d3d23 100644
--- a/lib/std/crypto/scrypt.zig
+++ b/lib/std/crypto/scrypt.zig
@@ -131,7 +131,7 @@ pub const Params = struct {
r: u30,
/// The [p]arallelization parameter.
- /// A large value of [p] can be used to increase the computational cost of scrypt without
+ /// A large value of [p] can be used to increase the computational cost of scrypt without
/// increasing the memory usage.
p: u30,
@@ -326,7 +326,7 @@ const crypt_format = struct {
try out.writeAll(hash_str);
}
- /// Custom codec that maps 6 bits into 8 like regular Base64, but uses its own alphabet,
+ /// Custom codec that maps 6 bits into 8 like regular Base64, but uses its own alphabet,
/// encodes bits in little-endian, and can also encode integers.
fn CustomB64Codec(comptime map: [64]u8) type {
return struct {
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index d2173e114a..e00c0a21a2 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -842,7 +842,7 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
nosuspend {
const mapped_mem = try mapWholeFile(elf_file);
const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]);
- if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
+ if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
const endian: std.builtin.Endian = switch (hdr.e_ident[elf.EI_DATA]) {
diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig
index d9ebb0d1d5..40a84fc76f 100644
--- a/lib/std/dynamic_library.zig
+++ b/lib/std/dynamic_library.zig
@@ -133,7 +133,7 @@ pub const ElfDynLib = struct {
defer os.munmap(file_bytes);
const eh = @ptrCast(*elf.Ehdr, file_bytes.ptr);
- if (!mem.eql(u8, eh.e_ident[0..4], "\x7fELF")) return error.NotElfFile;
+ if (!mem.eql(u8, eh.e_ident[0..4], elf.MAGIC)) return error.NotElfFile;
if (eh.e_type != elf.ET.DYN) return error.NotDynamicLibrary;
const elf_addr = @ptrToInt(file_bytes.ptr);
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 84001ec1c9..846bb8d11a 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -305,6 +305,8 @@ pub const STT_ARM_16BIT = STT_HIPROC;
pub const VER_FLG_BASE = 0x1;
pub const VER_FLG_WEAK = 0x2;
+pub const MAGIC = "\x7fELF";
+
/// File types
pub const ET = enum(u16) {
/// No file type
@@ -367,7 +369,7 @@ pub const Header = struct {
pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
- if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
+ if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
diff --git a/lib/std/event/wait_group.zig b/lib/std/event/wait_group.zig
index d26986f384..4cc82cf98e 100644
--- a/lib/std/event/wait_group.zig
+++ b/lib/std/event/wait_group.zig
@@ -35,8 +35,8 @@ pub fn WaitGroupGeneric(comptime counter_size: u16) type {
const Self = @This();
pub fn begin(self: *Self, count: CounterType) error{Overflow}!void {
- const held = self.mutex.acquire();
- defer held.release();
+ self.mutex.lock();
+ defer self.mutex.unlock();
const new_counter = try std.math.add(CounterType, self.counter, count);
if (new_counter > self.max_counter) return error.Overflow;
@@ -45,8 +45,8 @@ pub fn WaitGroupGeneric(comptime counter_size: u16) type {
pub fn finish(self: *Self, count: CounterType) void {
var waiters = blk: {
- const held = self.mutex.acquire();
- defer held.release();
+ self.mutex.lock();
+ defer self.mutex.unlock();
self.counter = std.math.sub(CounterType, self.counter, count) catch unreachable;
if (self.counter == 0) {
const temp = self.waiters;
@@ -65,10 +65,10 @@ pub fn WaitGroupGeneric(comptime counter_size: u16) type {
}
pub fn wait(self: *Self) void {
- const held = self.mutex.acquire();
+ self.mutex.lock();
if (self.counter == 0) {
- held.release();
+ self.mutex.unlock();
return;
}
@@ -83,7 +83,7 @@ pub fn WaitGroupGeneric(comptime counter_size: u16) type {
self_waiter.next = null;
}
suspend {
- held.release();
+ self.mutex.unlock();
}
}
};
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 395c502d61..80a2e87c5c 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -766,12 +766,10 @@ fn formatFloatValue(
} else if (comptime std.mem.eql(u8, fmt, "d")) {
formatFloatDecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
} else if (comptime std.mem.eql(u8, fmt, "x")) {
formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
} else {
@compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
@@ -968,10 +966,10 @@ pub fn formatUnicodeCodepoint(
writer: anytype,
) !void {
var buf: [4]u8 = undefined;
- const len = std.unicode.utf8Encode(c, &buf) catch |err| switch (err) {
+ const len = unicode.utf8Encode(c, &buf) catch |err| switch (err) {
error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => {
- // In case of error output the replacement char U+FFFD
- return formatBuf(&[_]u8{ 0xef, 0xbf, 0xbd }, options, writer);
+ const len = unicode.utf8Encode(unicode.replacement_character, &buf) catch unreachable;
+ return formatBuf(buf[0..len], options, writer);
},
};
return formatBuf(buf[0..len], options, writer);
@@ -2228,8 +2226,8 @@ test "float.special" {
if (builtin.target.cpu.arch != .arm) {
try expectFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
}
- try expectFmt("f64: inf", "f64: {}", .{math.inf_f64});
- try expectFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
+ try expectFmt("f64: inf", "f64: {}", .{math.inf(f64)});
+ try expectFmt("f64: -inf", "f64: {}", .{-math.inf(f64)});
}
test "float.hexadecimal.special" {
@@ -2239,8 +2237,8 @@ test "float.hexadecimal.special" {
if (builtin.target.cpu.arch != .arm) {
try expectFmt("f64: -nan", "f64: {x}", .{-math.nan_f64});
}
- try expectFmt("f64: inf", "f64: {x}", .{math.inf_f64});
- try expectFmt("f64: -inf", "f64: {x}", .{-math.inf_f64});
+ try expectFmt("f64: inf", "f64: {x}", .{math.inf(f64)});
+ try expectFmt("f64: -inf", "f64: {x}", .{-math.inf(f64)});
try expectFmt("f64: 0x0.0p0", "f64: {x}", .{@as(f64, 0)});
try expectFmt("f64: -0x0.0p0", "f64: {x}", .{-@as(f64, 0)});
@@ -2252,20 +2250,20 @@ test "float.hexadecimal" {
try expectFmt("f64: 0x1.5555555555555p-2", "f64: {x}", .{@as(f64, 1.0 / 3.0)});
try expectFmt("f128: 0x1.5555555555555555555555555555p-2", "f128: {x}", .{@as(f128, 1.0 / 3.0)});
- try expectFmt("f16: 0x1p-14", "f16: {x}", .{@as(f16, math.f16_min)});
- try expectFmt("f32: 0x1p-126", "f32: {x}", .{@as(f32, math.f32_min)});
- try expectFmt("f64: 0x1p-1022", "f64: {x}", .{@as(f64, math.f64_min)});
- try expectFmt("f128: 0x1p-16382", "f128: {x}", .{@as(f128, math.f128_min)});
+ try expectFmt("f16: 0x1p-14", "f16: {x}", .{math.floatMin(f16)});
+ try expectFmt("f32: 0x1p-126", "f32: {x}", .{math.floatMin(f32)});
+ try expectFmt("f64: 0x1p-1022", "f64: {x}", .{math.floatMin(f64)});
+ try expectFmt("f128: 0x1p-16382", "f128: {x}", .{math.floatMin(f128)});
- try expectFmt("f16: 0x0.004p-14", "f16: {x}", .{@as(f16, math.f16_true_min)});
- try expectFmt("f32: 0x0.000002p-126", "f32: {x}", .{@as(f32, math.f32_true_min)});
- try expectFmt("f64: 0x0.0000000000001p-1022", "f64: {x}", .{@as(f64, math.f64_true_min)});
- try expectFmt("f128: 0x0.0000000000000000000000000001p-16382", "f128: {x}", .{@as(f128, math.f128_true_min)});
+ try expectFmt("f16: 0x0.004p-14", "f16: {x}", .{math.floatTrueMin(f16)});
+ try expectFmt("f32: 0x0.000002p-126", "f32: {x}", .{math.floatTrueMin(f32)});
+ try expectFmt("f64: 0x0.0000000000001p-1022", "f64: {x}", .{math.floatTrueMin(f64)});
+ try expectFmt("f128: 0x0.0000000000000000000000000001p-16382", "f128: {x}", .{math.floatTrueMin(f128)});
- try expectFmt("f16: 0x1.ffcp15", "f16: {x}", .{@as(f16, math.f16_max)});
- try expectFmt("f32: 0x1.fffffep127", "f32: {x}", .{@as(f32, math.f32_max)});
- try expectFmt("f64: 0x1.fffffffffffffp1023", "f64: {x}", .{@as(f64, math.f64_max)});
- try expectFmt("f128: 0x1.ffffffffffffffffffffffffffffp16383", "f128: {x}", .{@as(f128, math.f128_max)});
+ try expectFmt("f16: 0x1.ffcp15", "f16: {x}", .{math.floatMax(f16)});
+ try expectFmt("f32: 0x1.fffffep127", "f32: {x}", .{math.floatMax(f32)});
+ try expectFmt("f64: 0x1.fffffffffffffp1023", "f64: {x}", .{math.floatMax(f64)});
+ try expectFmt("f128: 0x1.ffffffffffffffffffffffffffffp16383", "f128: {x}", .{math.floatMax(f128)});
}
test "float.hexadecimal.precision" {
@@ -2299,6 +2297,8 @@ test "float.decimal" {
try expectFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
try expectFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
try expectFmt("f64: 10000000000000.00", "f64: {d:.2}", .{@as(f64, 9999999999999.999)});
+ try expectFmt("f64: 10000000000000000000000000000000000000", "f64: {d}", .{@as(f64, 1e37)});
+ try expectFmt("f64: 100000000000000000000000000000000000000", "f64: {d}", .{@as(f64, 1e38)});
}
test "float.libc.sanity" {
diff --git a/lib/std/fmt/errol.zig b/lib/std/fmt/errol.zig
index e98c23f6ec..29dd2b7a63 100644
--- a/lib/std/fmt/errol.zig
+++ b/lib/std/fmt/errol.zig
@@ -106,7 +106,10 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
} else if (val >= 16.0 and val < 9.007199254740992e15) {
return errolFixed(val, buffer);
}
+ return errolSlow(val, buffer);
+}
+fn errolSlow(val: f64, buffer: []u8) FloatDecimal {
// normalize the midpoint
const e = math.frexp(val).exponent;
@@ -336,7 +339,9 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
var buf_index = u64toa(m64, buffer) - 1;
if (mi != 0) {
- buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
+ const round_up = buffer[buf_index] >= '5';
+ if (buf_index == 0 or (round_up and buffer[buf_index - 1] == '9')) return errolSlow(val, buffer);
+ buffer[buf_index - 1] += @boolToInt(round_up);
} else {
buf_index += 1;
}
diff --git a/lib/std/fmt/parse_hex_float.zig b/lib/std/fmt/parse_hex_float.zig
index 83c798ab96..3e8bc5c5d9 100644
--- a/lib/std/fmt/parse_hex_float.zig
+++ b/lib/std/fmt/parse_hex_float.zig
@@ -12,17 +12,16 @@ const assert = std.debug.assert;
pub fn parseHexFloat(comptime T: type, s: []const u8) !T {
assert(@typeInfo(T) == .Float);
- const IntT = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
+ const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
const mantissa_bits = math.floatMantissaBits(T);
const exponent_bits = math.floatExponentBits(T);
+ const exponent_min = math.floatExponentMin(T);
+ const exponent_max = math.floatExponentMax(T);
+ const exponent_bias = exponent_max;
const sign_shift = mantissa_bits + exponent_bits;
- const exponent_bias = (1 << (exponent_bits - 1)) - 1;
- const exponent_min = 1 - exponent_bias;
- const exponent_max = exponent_bias;
-
if (s.len == 0)
return error.InvalidCharacter;
@@ -233,10 +232,10 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T {
// Remove the implicit bit.
mantissa &= @as(u128, (1 << mantissa_bits) - 1);
- const raw: IntT =
- (if (negative) @as(IntT, 1) << sign_shift else 0) |
- @as(IntT, @bitCast(u16, exponent + exponent_bias)) << mantissa_bits |
- @truncate(IntT, mantissa);
+ const raw: TBits =
+ (if (negative) @as(TBits, 1) << sign_shift else 0) |
+ @as(TBits, @bitCast(u16, exponent + exponent_bias)) << mantissa_bits |
+ @truncate(TBits, mantissa);
return @bitCast(T, raw);
}
@@ -263,14 +262,14 @@ test "f16" {
.{ .s = "0x10p+10", .v = 16384.0 },
.{ .s = "0x10p-10", .v = 0.015625 },
// Max normalized value.
- .{ .s = "0x1.ffcp+15", .v = math.f16_max },
- .{ .s = "-0x1.ffcp+15", .v = -math.f16_max },
+ .{ .s = "0x1.ffcp+15", .v = math.floatMax(f16) },
+ .{ .s = "-0x1.ffcp+15", .v = -math.floatMax(f16) },
// Min normalized value.
- .{ .s = "0x1p-14", .v = math.f16_min },
- .{ .s = "-0x1p-14", .v = -math.f16_min },
+ .{ .s = "0x1p-14", .v = math.floatMin(f16) },
+ .{ .s = "-0x1p-14", .v = -math.floatMin(f16) },
// Min denormal value.
- .{ .s = "0x1p-24", .v = math.f16_true_min },
- .{ .s = "-0x1p-24", .v = -math.f16_true_min },
+ .{ .s = "0x1p-24", .v = math.floatTrueMin(f16) },
+ .{ .s = "-0x1p-24", .v = -math.floatTrueMin(f16) },
};
for (cases) |case| {
@@ -287,14 +286,14 @@ test "f32" {
.{ .s = "0x0.ffffffp128", .v = 0x0.ffffffp128 },
.{ .s = "0x0.1234570p-125", .v = 0x0.1234570p-125 },
// Max normalized value.
- .{ .s = "0x1.fffffeP+127", .v = math.f32_max },
- .{ .s = "-0x1.fffffeP+127", .v = -math.f32_max },
+ .{ .s = "0x1.fffffeP+127", .v = math.floatMax(f32) },
+ .{ .s = "-0x1.fffffeP+127", .v = -math.floatMax(f32) },
// Min normalized value.
- .{ .s = "0x1p-126", .v = math.f32_min },
- .{ .s = "-0x1p-126", .v = -math.f32_min },
+ .{ .s = "0x1p-126", .v = math.floatMin(f32) },
+ .{ .s = "-0x1p-126", .v = -math.floatMin(f32) },
// Min denormal value.
- .{ .s = "0x1P-149", .v = math.f32_true_min },
- .{ .s = "-0x1P-149", .v = -math.f32_true_min },
+ .{ .s = "0x1P-149", .v = math.floatTrueMin(f32) },
+ .{ .s = "-0x1P-149", .v = -math.floatTrueMin(f32) },
};
for (cases) |case| {
@@ -309,14 +308,14 @@ test "f64" {
.{ .s = "0x10p+10", .v = 16384.0 },
.{ .s = "0x10p-10", .v = 0.015625 },
// Max normalized value.
- .{ .s = "0x1.fffffffffffffp+1023", .v = math.f64_max },
- .{ .s = "-0x1.fffffffffffffp1023", .v = -math.f64_max },
+ .{ .s = "0x1.fffffffffffffp+1023", .v = math.floatMax(f64) },
+ .{ .s = "-0x1.fffffffffffffp1023", .v = -math.floatMax(f64) },
// Min normalized value.
- .{ .s = "0x1p-1022", .v = math.f64_min },
- .{ .s = "-0x1p-1022", .v = -math.f64_min },
+ .{ .s = "0x1p-1022", .v = math.floatMin(f64) },
+ .{ .s = "-0x1p-1022", .v = -math.floatMin(f64) },
// Min denormalized value.
- .{ .s = "0x1p-1074", .v = math.f64_true_min },
- .{ .s = "-0x1p-1074", .v = -math.f64_true_min },
+ .{ .s = "0x1p-1074", .v = math.floatTrueMin(f64) },
+ .{ .s = "-0x1p-1074", .v = -math.floatTrueMin(f64) },
};
for (cases) |case| {
@@ -331,14 +330,14 @@ test "f128" {
.{ .s = "0x10p+10", .v = 16384.0 },
.{ .s = "0x10p-10", .v = 0.015625 },
// Max normalized value.
- .{ .s = "0xf.fffffffffffffffffffffffffff8p+16380", .v = math.f128_max },
- .{ .s = "-0xf.fffffffffffffffffffffffffff8p+16380", .v = -math.f128_max },
+ .{ .s = "0xf.fffffffffffffffffffffffffff8p+16380", .v = math.floatMax(f128) },
+ .{ .s = "-0xf.fffffffffffffffffffffffffff8p+16380", .v = -math.floatMax(f128) },
// Min normalized value.
- .{ .s = "0x1p-16382", .v = math.f128_min },
- .{ .s = "-0x1p-16382", .v = -math.f128_min },
+ .{ .s = "0x1p-16382", .v = math.floatMin(f128) },
+ .{ .s = "-0x1p-16382", .v = -math.floatMin(f128) },
// // Min denormalized value.
- .{ .s = "0x1p-16494", .v = math.f128_true_min },
- .{ .s = "-0x1p-16494", .v = -math.f128_true_min },
+ .{ .s = "0x1p-16494", .v = math.floatTrueMin(f128) },
+ .{ .s = "-0x1p-16494", .v = -math.floatTrueMin(f128) },
.{ .s = "0x1.edcb34a235253948765432134674fp-1", .v = 0x1.edcb34a235253948765432134674fp-1 },
};
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 73efccbbfc..052343599e 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1308,9 +1308,9 @@ pub const Dir = struct {
if (end_index == sub_path.len) return;
},
error.FileNotFound => {
- if (end_index == 0) return err;
// march end_index backward until next path component
while (true) {
+ if (end_index == 0) return err;
end_index -= 1;
if (path.isSep(sub_path[end_index])) break;
}
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 568c34e0ac..3ea8dd0285 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -200,6 +200,17 @@ pub const File = struct {
}
}
+ pub const SyncError = os.SyncError;
+
+ /// Blocks until all pending file contents and metadata modifications
+ /// for the file have been synchronized with the underlying filesystem.
+ ///
+ /// Note that this does not ensure that metadata for the
+ /// directory containing the file has also reached disk.
+ pub fn sync(self: File) SyncError!void {
+ return os.fsync(self.handle);
+ }
+
/// Test whether the file refers to a terminal.
/// See also `supportsAnsiEscapeCodes`.
pub fn isTty(self: File) bool {
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 69fbe5449f..82005152e5 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -434,9 +434,6 @@ test "Dir.rename files" {
}
test "Dir.rename directories" {
- // TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
- if (builtin.os.tag == .windows) return error.SkipZigTest;
-
var tmp_dir = tmpDir(.{});
defer tmp_dir.cleanup();
@@ -461,18 +458,44 @@ test "Dir.rename directories" {
file = try dir.openFile("test_file", .{});
file.close();
dir.close();
+}
+
+test "Dir.rename directory onto empty dir" {
+ // TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
+ if (builtin.os.tag == .windows) return error.SkipZigTest;
+
+ var tmp_dir = testing.tmpDir(.{});
+ defer tmp_dir.cleanup();
+
+ try tmp_dir.dir.makeDir("test_dir");
+ try tmp_dir.dir.makeDir("target_dir");
+ try tmp_dir.dir.rename("test_dir", "target_dir");
+
+ // Ensure the directory was renamed
+ try testing.expectError(error.FileNotFound, tmp_dir.dir.openDir("test_dir", .{}));
+ var dir = try tmp_dir.dir.openDir("target_dir", .{});
+ dir.close();
+}
- // Try to rename to a non-empty directory now
- var target_dir = try tmp_dir.dir.makeOpenPath("non_empty_target_dir", .{});
- file = try target_dir.createFile("filler", .{ .read = true });
+test "Dir.rename directory onto non-empty dir" {
+ // TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
+ if (builtin.os.tag == .windows) return error.SkipZigTest;
+
+ var tmp_dir = testing.tmpDir(.{});
+ defer tmp_dir.cleanup();
+
+ try tmp_dir.dir.makeDir("test_dir");
+
+ var target_dir = try tmp_dir.dir.makeOpenPath("target_dir", .{});
+ var file = try target_dir.createFile("test_file", .{ .read = true });
file.close();
+ target_dir.close();
- try testing.expectError(error.PathAlreadyExists, tmp_dir.dir.rename("test_dir_renamed_again", "non_empty_target_dir"));
+ // Rename should fail with PathAlreadyExists if target_dir is non-empty
+ try testing.expectError(error.PathAlreadyExists, tmp_dir.dir.rename("test_dir", "target_dir"));
// Ensure the directory was not renamed
- dir = try tmp_dir.dir.openDir("test_dir_renamed_again", .{});
- file = try dir.openFile("test_file", .{});
- file.close();
+ var dir = try tmp_dir.dir.openDir("test_dir", .{});
dir.close();
}
@@ -587,6 +610,16 @@ test "makePath, put some files in it, deleteTree" {
}
}
+test "makePath in a directory that no longer exists" {
+ if (builtin.os.tag == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+ try tmp.parent_dir.deleteTree(&tmp.sub_path);
+
+ try testing.expectError(error.FileNotFound, tmp.dir.makePath("sub-path"));
+}
+
test "writev, readv" {
var tmp = tmpDir(.{});
defer tmp.cleanup();
diff --git a/lib/std/io.zig b/lib/std/io.zig
index fba1c289f7..50d134b856 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -9,7 +9,6 @@ const os = std.os;
const fs = std.fs;
const mem = std.mem;
const meta = std.meta;
-const trait = meta.trait;
const File = std.fs.File;
pub const Mode = enum {
diff --git a/lib/std/math.zig b/lib/std/math.zig
index 318d70c726..be49ba8030 100644
--- a/lib/std/math.zig
+++ b/lib/std/math.zig
@@ -36,38 +36,54 @@ pub const sqrt2 = 1.414213562373095048801688724209698079;
/// 1/sqrt(2)
pub const sqrt1_2 = 0.707106781186547524400844362104849039;
-pub const f128_true_min = @bitCast(f128, @as(u128, 0x00000000000000000000000000000001));
-pub const f128_min = @bitCast(f128, @as(u128, 0x00010000000000000000000000000000));
-pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
-pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000));
-pub const f128_toint = 1.0 / f128_epsilon;
-
-// float.h details
-pub const f80_true_min = make_f80(.{ .fraction = 1, .exp = 0 });
-pub const f80_min = make_f80(.{ .fraction = 0x8000000000000000, .exp = 1 });
-pub const f80_max = make_f80(.{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE });
-pub const f80_epsilon = make_f80(.{ .fraction = 0x8000000000000000, .exp = 0x3FC0 });
-pub const f80_toint = 1.0 / f80_epsilon;
-
-pub const f64_true_min = 4.94065645841246544177e-324;
-pub const f64_min = 2.2250738585072014e-308;
-pub const f64_max = 1.79769313486231570815e+308;
-pub const f64_epsilon = 2.22044604925031308085e-16;
-pub const f64_toint = 1.0 / f64_epsilon;
-
-pub const f32_true_min = 1.40129846432481707092e-45;
-pub const f32_min = 1.17549435082228750797e-38;
-pub const f32_max = 3.40282346638528859812e+38;
-pub const f32_epsilon = 1.1920928955078125e-07;
-pub const f32_toint = 1.0 / f32_epsilon;
-
-pub const f16_true_min = 0.000000059604644775390625; // 2**-24
-pub const f16_min = 0.00006103515625; // 2**-14
-pub const f16_max = 65504;
-pub const f16_epsilon = 0.0009765625; // 2**-10
-pub const f16_toint = 1.0 / f16_epsilon;
-
-pub const epsilon = @import("math/epsilon.zig").epsilon;
+pub const floatExponentBits = @import("math/float.zig").floatExponentBits;
+pub const floatMantissaBits = @import("math/float.zig").floatMantissaBits;
+pub const floatFractionalBits = @import("math/float.zig").floatFractionalBits;
+pub const floatExponentMin = @import("math/float.zig").floatExponentMin;
+pub const floatExponentMax = @import("math/float.zig").floatExponentMax;
+pub const floatTrueMin = @import("math/float.zig").floatTrueMin;
+pub const floatMin = @import("math/float.zig").floatMin;
+pub const floatMax = @import("math/float.zig").floatMax;
+pub const floatEps = @import("math/float.zig").floatEps;
+pub const inf = @import("math/float.zig").inf;
+
+// TODO Replace with @compileError("deprecated for foobar") after 0.10.0 is released.
+pub const f16_true_min: comptime_float = floatTrueMin(f16); // prev: 0.000000059604644775390625
+pub const f32_true_min: comptime_float = floatTrueMin(f32); // prev: 1.40129846432481707092e-45
+pub const f64_true_min: comptime_float = floatTrueMin(f64); // prev: 4.94065645841246544177e-324
+pub const f80_true_min = floatTrueMin(f80); // prev: make_f80(.{ .fraction = 1, .exp = 0 })
+pub const f128_true_min = floatTrueMin(f128); // prev: @bitCast(f128, @as(u128, 0x00000000000000000000000000000001))
+pub const f16_min: comptime_float = floatMin(f16); // prev: 0.00006103515625
+pub const f32_min: comptime_float = floatMin(f32); // prev: 1.17549435082228750797e-38
+pub const f64_min: comptime_float = floatMin(f64); // prev: 2.2250738585072014e-308
+pub const f80_min = floatMin(f80); // prev: make_f80(.{ .fraction = 0x8000000000000000, .exp = 1 })
+pub const f128_min = floatMin(f128); // prev: @bitCast(f128, @as(u128, 0x00010000000000000000000000000000))
+pub const f16_max: comptime_float = floatMax(f16); // prev: 65504
+pub const f32_max: comptime_float = floatMax(f32); // prev: 3.40282346638528859812e+38
+pub const f64_max: comptime_float = floatMax(f64); // prev: 1.79769313486231570815e+308
+pub const f80_max = floatMax(f80); // prev: make_f80(.{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE })
+pub const f128_max = floatMax(f128); // prev: @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
+pub const f16_epsilon: comptime_float = floatEps(f16); // prev: 0.0009765625
+pub const f32_epsilon: comptime_float = floatEps(f32); // prev: 1.1920928955078125e-07
+pub const f64_epsilon: comptime_float = floatEps(f64); // prev: 2.22044604925031308085e-16
+pub const f80_epsilon = floatEps(f80); // prev: make_f80(.{ .fraction = 0x8000000000000000, .exp = 0x3FC0 })
+pub const f128_epsilon = floatEps(f128); // prev: @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000))
+pub const f16_toint: comptime_float = 1.0 / f16_epsilon; // same as before
+pub const f32_toint: comptime_float = 1.0 / f32_epsilon; // same as before
+pub const f64_toint: comptime_float = 1.0 / f64_epsilon; // same as before
+pub const f80_toint = 1.0 / f80_epsilon; // same as before
+pub const f128_toint = 1.0 / f128_epsilon; // same as before
+pub const inf_u16 = @bitCast(u16, inf_f16); // prev: @as(u16, 0x7C00)
+pub const inf_f16 = inf(f16); // prev: @bitCast(f16, inf_u16)
+pub const inf_u32 = @bitCast(u32, inf_f32); // prev: @as(u32, 0x7F800000)
+pub const inf_f32 = inf(f32); // prev: @bitCast(f32, inf_u32)
+pub const inf_u64 = @bitCast(u64, inf_f64); // prev: @as(u64, 0x7FF << 52)
+pub const inf_f64 = inf(f64); // prev: @bitCast(f64, inf_u64)
+pub const inf_f80 = inf(f80); // prev: make_f80(F80{ .fraction = 0x8000000000000000, .exp = 0x7fff })
+pub const inf_u128 = @bitCast(u128, inf_f128); // prev: @as(u128, 0x7fff0000000000000000000000000000)
+pub const inf_f128 = inf(f128); // prev: @bitCast(f128, inf_u128)
+pub const epsilon = floatEps;
+// End of "soft deprecated" section
pub const nan_u16 = @as(u16, 0x7C01);
pub const nan_f16 = @bitCast(f16, nan_u16);
@@ -75,28 +91,18 @@ pub const nan_f16 = @bitCast(f16, nan_u16);
pub const qnan_u16 = @as(u16, 0x7E00);
pub const qnan_f16 = @bitCast(f16, qnan_u16);
-pub const inf_u16 = @as(u16, 0x7C00);
-pub const inf_f16 = @bitCast(f16, inf_u16);
-
pub const nan_u32 = @as(u32, 0x7F800001);
pub const nan_f32 = @bitCast(f32, nan_u32);
pub const qnan_u32 = @as(u32, 0x7FC00000);
pub const qnan_f32 = @bitCast(f32, qnan_u32);
-pub const inf_u32 = @as(u32, 0x7F800000);
-pub const inf_f32 = @bitCast(f32, inf_u32);
-
pub const nan_u64 = @as(u64, 0x7FF << 52) | 1;
pub const nan_f64 = @bitCast(f64, nan_u64);
pub const qnan_u64 = @as(u64, 0x7ff8000000000000);
pub const qnan_f64 = @bitCast(f64, qnan_u64);
-pub const inf_u64 = @as(u64, 0x7FF << 52);
-pub const inf_f64 = @bitCast(f64, inf_u64);
-
-pub const inf_f80 = make_f80(F80{ .fraction = 0x8000000000000000, .exp = 0x7fff });
pub const nan_f80 = make_f80(F80{ .fraction = 0xA000000000000000, .exp = 0x7fff });
pub const qnan_f80 = make_f80(F80{ .fraction = 0xC000000000000000, .exp = 0x7fff });
@@ -106,12 +112,8 @@ pub const nan_f128 = @bitCast(f128, nan_u128);
pub const qnan_u128 = @as(u128, 0x7fff8000000000000000000000000000);
pub const qnan_f128 = @bitCast(f128, qnan_u128);
-pub const inf_u128 = @as(u128, 0x7fff0000000000000000000000000000);
-pub const inf_f128 = @bitCast(f128, inf_u128);
-
pub const nan = @import("math/nan.zig").nan;
pub const snan = @import("math/nan.zig").snan;
-pub const inf = @import("math/inf.zig").inf;
/// Performs an approximate comparison of two floating point values `x` and `y`.
/// Returns true if the absolute difference between them is less or equal than
@@ -119,7 +121,7 @@ pub const inf = @import("math/inf.zig").inf;
///
/// The `tolerance` parameter is the absolute tolerance used when determining if
/// the two numbers are close enough; a good value for this parameter is a small
-/// multiple of `epsilon(T)`.
+/// multiple of `floatEps(T)`.
///
/// Note that this function is recommended for comparing small numbers
/// around zero; using `approxEqRel` is suggested otherwise.
@@ -146,7 +148,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool {
///
/// The `tolerance` parameter is the relative tolerance used when determining if
/// the two numbers are close enough; a good value for this parameter is usually
-/// `sqrt(epsilon(T))`, meaning that the two numbers are considered equal if at
+/// `sqrt(floatEps(T))`, meaning that the two numbers are considered equal if at
/// least half of the digits are equal.
///
/// Note that for comparisons of small numbers around zero this function won't
@@ -177,25 +179,19 @@ pub fn approxEq(comptime T: type, x: T, y: T, tolerance: T) bool {
test "approxEqAbs and approxEqRel" {
inline for ([_]type{ f16, f32, f64, f128 }) |T| {
- const eps_value = comptime epsilon(T);
+ const eps_value = comptime floatEps(T);
const sqrt_eps_value = comptime sqrt(eps_value);
const nan_value = comptime nan(T);
const inf_value = comptime inf(T);
- const min_value: T = switch (T) {
- f16 => f16_min,
- f32 => f32_min,
- f64 => f64_min,
- f128 => f128_min,
- else => unreachable,
- };
+ const min_value = comptime floatMin(T);
try testing.expect(approxEqAbs(T, 0.0, 0.0, eps_value));
try testing.expect(approxEqAbs(T, -0.0, -0.0, eps_value));
try testing.expect(approxEqAbs(T, 0.0, -0.0, eps_value));
try testing.expect(approxEqRel(T, 1.0, 1.0, sqrt_eps_value));
try testing.expect(!approxEqRel(T, 1.0, 0.0, sqrt_eps_value));
- try testing.expect(!approxEqAbs(T, 1.0 + 2 * epsilon(T), 1.0, eps_value));
- try testing.expect(approxEqAbs(T, 1.0 + 1 * epsilon(T), 1.0, eps_value));
+ try testing.expect(!approxEqAbs(T, 1.0 + 2 * eps_value, 1.0, eps_value));
+ try testing.expect(approxEqAbs(T, 1.0 + 1 * eps_value, 1.0, eps_value));
try testing.expect(!approxEqRel(T, 1.0, nan_value, sqrt_eps_value));
try testing.expect(!approxEqRel(T, nan_value, nan_value, sqrt_eps_value));
try testing.expect(approxEqRel(T, inf_value, inf_value, sqrt_eps_value));
@@ -294,36 +290,6 @@ test {
std.testing.refAllDecls(@This());
}
-/// Returns the number of bits in the mantissa of floating point type
-/// T.
-pub fn floatMantissaBits(comptime T: type) comptime_int {
- assert(@typeInfo(T) == .Float);
-
- return switch (@typeInfo(T).Float.bits) {
- 16 => 10,
- 32 => 23,
- 64 => 52,
- 80 => 64,
- 128 => 112,
- else => @compileError("unknown floating point type " ++ @typeName(T)),
- };
-}
-
-/// Returns the number of bits in the exponent of floating point type
-/// T.
-pub fn floatExponentBits(comptime T: type) comptime_int {
- assert(@typeInfo(T) == .Float);
-
- return switch (@typeInfo(T).Float.bits) {
- 16 => 5,
- 32 => 8,
- 64 => 11,
- 80 => 15,
- 128 => 15,
- else => @compileError("unknown floating point type " ++ @typeName(T)),
- };
-}
-
/// Given two types, returns the smallest one which is capable of holding the
/// full range of the minimum value.
pub fn Min(comptime A: type, comptime B: type) type {
@@ -437,7 +403,7 @@ test "max3" {
try testing.expect(max3(@as(i32, 2), @as(i32, 1), @as(i32, 0)) == 2);
}
-/// Limit val to the inclusive range [lower, upper].
+/// Limit val to the inclusive range [lower, upper].
pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val, lower, upper) {
assert(lower <= upper);
return max(lower, min(val, upper));
@@ -1221,12 +1187,6 @@ test "lossyCast" {
try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));
}
-test "f64_min" {
- const f64_min_u64 = 0x0010000000000000;
- const fmin: f64 = f64_min;
- try testing.expect(@bitCast(u64, fmin) == f64_min_u64);
-}
-
/// Returns the maximum value of integer type T.
pub fn maxInt(comptime T: type) comptime_int {
const info = @typeInfo(T);
diff --git a/lib/std/math/__rem_pio2.zig b/lib/std/math/__rem_pio2.zig
index c8cb8fb644..f01d8fe94a 100644
--- a/lib/std/math/__rem_pio2.zig
+++ b/lib/std/math/__rem_pio2.zig
@@ -7,7 +7,7 @@ const std = @import("../std.zig");
const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large;
const math = std.math;
-const toint = 1.5 / math.epsilon(f64);
+const toint = 1.5 / math.floatEps(f64);
// pi/4
const pio4 = 0x1.921fb54442d18p-1;
// invpio2: 53 bits of 2/pi
diff --git a/lib/std/math/__rem_pio2f.zig b/lib/std/math/__rem_pio2f.zig
index 9f78e18d36..5867fb30d9 100644
--- a/lib/std/math/__rem_pio2f.zig
+++ b/lib/std/math/__rem_pio2f.zig
@@ -7,7 +7,7 @@ const std = @import("../std.zig");
const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large;
const math = std.math;
-const toint = 1.5 / math.epsilon(f64);
+const toint = 1.5 / math.floatEps(f64);
// pi/4
const pio4 = 0x1.921fb6p-1;
// invpio2: 53 bits of 2/pi
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index 0303aa12f7..7ca9b9ccb7 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -1750,8 +1750,8 @@ pub const Mutable = struct {
/// Read the value of `x` from `buffer`
/// Asserts that `buffer`, `abi_size`, and `bit_count` are large enough to store the value.
///
- /// The contents of `buffer` are interpreted as if they were the contents of
- /// @ptrCast(*[abi_size]const u8, &x). Byte ordering is determined by `endian`
+ /// The contents of `buffer` are interpreted as if they were the contents of
+ /// @ptrCast(*[abi_size]const u8, &x). Byte ordering is determined by `endian`
/// and any required padding bits are expected on the MSB end.
pub fn readTwosComplement(
x: *Mutable,
diff --git a/lib/std/math/ceil.zig b/lib/std/math/ceil.zig
index cf3adcf5b5..686be8e58d 100644
--- a/lib/std/math/ceil.zig
+++ b/lib/std/math/ceil.zig
@@ -62,6 +62,8 @@ fn ceil32(x: f32) f32 {
}
fn ceil64(x: f64) f64 {
+ const f64_toint = 1.0 / math.floatEps(f64);
+
const u = @bitCast(u64, x);
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
@@ -71,9 +73,9 @@ fn ceil64(x: f64) f64 {
}
if (u >> 63 != 0) {
- y = x - math.f64_toint + math.f64_toint - x;
+ y = x - f64_toint + f64_toint - x;
} else {
- y = x + math.f64_toint - math.f64_toint - x;
+ y = x + f64_toint - f64_toint - x;
}
if (e <= 0x3FF - 1) {
@@ -91,6 +93,8 @@ fn ceil64(x: f64) f64 {
}
fn ceil128(x: f128) f128 {
+ const f128_toint = 1.0 / math.floatEps(f128);
+
const u = @bitCast(u128, x);
const e = (u >> 112) & 0x7FFF;
var y: f128 = undefined;
@@ -98,9 +102,9 @@ fn ceil128(x: f128) f128 {
if (e >= 0x3FFF + 112 or x == 0) return x;
if (u >> 127 != 0) {
- y = x - math.f128_toint + math.f128_toint - x;
+ y = x - f128_toint + f128_toint - x;
} else {
- y = x + math.f128_toint - math.f128_toint - x;
+ y = x + f128_toint - f128_toint - x;
}
if (e <= 0x3FFF - 1) {
diff --git a/lib/std/math/complex/exp.zig b/lib/std/math/complex/exp.zig
index f2ae28d3fd..ce25025ded 100644
--- a/lib/std/math/complex/exp.zig
+++ b/lib/std/math/complex/exp.zig
@@ -120,7 +120,7 @@ fn exp64(z: Complex(f64)) Complex(f64) {
}
test "complex.cexp32" {
- const tolerance_f32 = math.sqrt(math.epsilon(f32));
+ const tolerance_f32 = math.sqrt(math.floatEps(f32));
{
const a = Complex(f32).init(5, 3);
@@ -140,7 +140,7 @@ test "complex.cexp32" {
}
test "complex.cexp64" {
- const tolerance_f64 = math.sqrt(math.epsilon(f64));
+ const tolerance_f64 = math.sqrt(math.floatEps(f64));
{
const a = Complex(f64).init(5, 3);
diff --git a/lib/std/math/complex/sinh.zig b/lib/std/math/complex/sinh.zig
index ed344999ee..851af3e62e 100644
--- a/lib/std/math/complex/sinh.zig
+++ b/lib/std/math/complex/sinh.zig
@@ -79,7 +79,7 @@ fn sinh32(z: Complex(f32)) Complex(f32) {
if (iy >= 0x7f800000) {
return Complex(f32).init(x * x, x * (y - y));
}
- return Complex(f32).init(x * math.cos(y), math.inf_f32 * math.sin(y));
+ return Complex(f32).init(x * math.cos(y), math.inf(f32) * math.sin(y));
}
return Complex(f32).init((x * x) * (y - y), (x + x) * (y - y));
@@ -146,7 +146,7 @@ fn sinh64(z: Complex(f64)) Complex(f64) {
if (iy >= 0x7ff00000) {
return Complex(f64).init(x * x, x * (y - y));
}
- return Complex(f64).init(x * math.cos(y), math.inf_f64 * math.sin(y));
+ return Complex(f64).init(x * math.cos(y), math.inf(f64) * math.sin(y));
}
return Complex(f64).init((x * x) * (y - y), (x + x) * (y - y));
diff --git a/lib/std/math/epsilon.zig b/lib/std/math/epsilon.zig
deleted file mode 100644
index 7f78be1aab..0000000000
--- a/lib/std/math/epsilon.zig
+++ /dev/null
@@ -1,15 +0,0 @@
-const math = @import("../math.zig");
-
-/// Returns the machine epsilon for type T.
-/// This is the smallest value of type T that satisfies the inequality 1.0 +
-/// epsilon != 1.0.
-pub fn epsilon(comptime T: type) T {
- return switch (T) {
- f16 => math.f16_epsilon,
- f32 => math.f32_epsilon,
- f64 => math.f64_epsilon,
- f80 => math.f80_epsilon,
- f128 => math.f128_epsilon,
- else => @compileError("epsilon not implemented for " ++ @typeName(T)),
- };
-}
diff --git a/lib/std/math/fabs.zig b/lib/std/math/fabs.zig
index f098d531cf..f1bb4be7e7 100644
--- a/lib/std/math/fabs.zig
+++ b/lib/std/math/fabs.zig
@@ -1,13 +1,6 @@
-// Ported from musl, which is licensed under the MIT license:
-// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
-//
-// https://git.musl-libc.org/cgit/musl/tree/src/math/fabsf.c
-// https://git.musl-libc.org/cgit/musl/tree/src/math/fabs.c
-
const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
-const maxInt = std.math.maxInt;
/// Returns the absolute value of x.
///
@@ -16,86 +9,37 @@ const maxInt = std.math.maxInt;
/// - fabs(nan) = nan
pub fn fabs(x: anytype) @TypeOf(x) {
const T = @TypeOf(x);
- return switch (T) {
- f16 => fabs16(x),
- f32 => fabs32(x),
- f64 => fabs64(x),
- f128 => fabs128(x),
- else => @compileError("fabs not implemented for " ++ @typeName(T)),
- };
-}
-
-fn fabs16(x: f16) f16 {
- var u = @bitCast(u16, x);
- u &= maxInt(u16) >> 1;
- return @bitCast(f16, u);
-}
-
-fn fabs32(x: f32) f32 {
- var u = @bitCast(u32, x);
- u &= maxInt(u32) >> 1;
- return @bitCast(f32, u);
-}
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+ if (@typeInfo(T) != .Float) {
+ @compileError("fabs not implemented for " ++ @typeName(T));
+ }
-fn fabs64(x: f64) f64 {
- var u = @bitCast(u64, x);
- u &= maxInt(u64) >> 1;
- return @bitCast(f64, u);
-}
+ const float_bits = @bitCast(TBits, x);
+ const remove_sign = ~@as(TBits, 0) >> 1;
-fn fabs128(x: f128) f128 {
- var u = @bitCast(u128, x);
- u &= maxInt(u128) >> 1;
- return @bitCast(f128, u);
+ return @bitCast(T, float_bits & remove_sign);
}
test "math.fabs" {
- try expect(fabs(@as(f16, 1.0)) == fabs16(1.0));
- try expect(fabs(@as(f32, 1.0)) == fabs32(1.0));
- try expect(fabs(@as(f64, 1.0)) == fabs64(1.0));
- try expect(fabs(@as(f128, 1.0)) == fabs128(1.0));
-}
-
-test "math.fabs16" {
- try expect(fabs16(1.0) == 1.0);
- try expect(fabs16(-1.0) == 1.0);
-}
-
-test "math.fabs32" {
- try expect(fabs32(1.0) == 1.0);
- try expect(fabs32(-1.0) == 1.0);
-}
-
-test "math.fabs64" {
- try expect(fabs64(1.0) == 1.0);
- try expect(fabs64(-1.0) == 1.0);
-}
-
-test "math.fabs128" {
- try expect(fabs128(1.0) == 1.0);
- try expect(fabs128(-1.0) == 1.0);
-}
-
-test "math.fabs16.special" {
- try expect(math.isPositiveInf(fabs(math.inf(f16))));
- try expect(math.isPositiveInf(fabs(-math.inf(f16))));
- try expect(math.isNan(fabs(math.nan(f16))));
-}
-
-test "math.fabs32.special" {
- try expect(math.isPositiveInf(fabs(math.inf(f32))));
- try expect(math.isPositiveInf(fabs(-math.inf(f32))));
- try expect(math.isNan(fabs(math.nan(f32))));
-}
-
-test "math.fabs64.special" {
- try expect(math.isPositiveInf(fabs(math.inf(f64))));
- try expect(math.isPositiveInf(fabs(-math.inf(f64))));
- try expect(math.isNan(fabs(math.nan(f64))));
-}
-
-test "math.fabs128.special" {
- try expect(math.isPositiveInf(fabs(math.inf(f128))));
- try expect(math.isPositiveInf(fabs(-math.inf(f128))));
- try expect(math.isNan(fabs(math.nan(f128))));
+ // TODO add support for f80 & c_longdouble here
+ inline for ([_]type{ f16, f32, f64, f128 }) |T| {
+ // normals
+ try expect(fabs(@as(T, 1.0)) == 1.0);
+ try expect(fabs(@as(T, -1.0)) == 1.0);
+ try expect(fabs(math.floatMin(T)) == math.floatMin(T));
+ try expect(fabs(-math.floatMin(T)) == math.floatMin(T));
+ try expect(fabs(math.floatMax(T)) == math.floatMax(T));
+ try expect(fabs(-math.floatMax(T)) == math.floatMax(T));
+
+ // subnormals
+ try expect(fabs(@as(T, 0.0)) == 0.0);
+ try expect(fabs(@as(T, -0.0)) == 0.0);
+ try expect(fabs(math.floatTrueMin(T)) == math.floatTrueMin(T));
+ try expect(fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
+
+ // non-finite numbers
+ try expect(math.isPositiveInf(fabs(math.inf(T))));
+ try expect(math.isPositiveInf(fabs(-math.inf(T))));
+ try expect(math.isNan(fabs(math.nan(T))));
+ }
}
diff --git a/lib/std/math/float.zig b/lib/std/math/float.zig
new file mode 100644
index 0000000000..72c7f086ac
--- /dev/null
+++ b/lib/std/math/float.zig
@@ -0,0 +1,110 @@
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const expect = std.testing.expect;
+
+/// Creates a raw "1.0" mantissa for floating point type T. Used to dedupe f80 logic.
+fn mantissaOne(comptime T: type) comptime_int {
+ return if (@typeInfo(T).Float.bits == 80) 1 << floatFractionalBits(T) else 0;
+}
+
+/// Creates floating point type T from an unbiased exponent and raw mantissa.
+fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T {
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+ const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
+ return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));
+}
+
+/// Returns the number of bits in the exponent of floating point type T.
+pub fn floatExponentBits(comptime T: type) comptime_int {
+ assert(@typeInfo(T) == .Float);
+
+ return switch (@typeInfo(T).Float.bits) {
+ 16 => 5,
+ 32 => 8,
+ 64 => 11,
+ 80 => 15,
+ 128 => 15,
+ else => @compileError("unknown floating point type " ++ @typeName(T)),
+ };
+}
+
+/// Returns the number of bits in the mantissa of floating point type T.
+pub fn floatMantissaBits(comptime T: type) comptime_int {
+ assert(@typeInfo(T) == .Float);
+
+ return switch (@typeInfo(T).Float.bits) {
+ 16 => 10,
+ 32 => 23,
+ 64 => 52,
+ 80 => 64,
+ 128 => 112,
+ else => @compileError("unknown floating point type " ++ @typeName(T)),
+ };
+}
+
+/// Returns the number of fractional bits in the mantissa of floating point type T.
+pub fn floatFractionalBits(comptime T: type) comptime_int {
+ assert(@typeInfo(T) == .Float);
+
+ // standard IEEE floats have an implicit 0.m or 1.m integer part
+ // f80 is special and has an explicitly stored bit in the MSB
+ // this function corresponds to `MANT_DIG - 1' from C
+ return switch (@typeInfo(T).Float.bits) {
+ 16 => 10,
+ 32 => 23,
+ 64 => 52,
+ 80 => 63,
+ 128 => 112,
+ else => @compileError("unknown floating point type " ++ @typeName(T)),
+ };
+}
+
+/// Returns the minimum exponent that can represent
+/// a normalised value in floating point type T.
+pub fn floatExponentMin(comptime T: type) comptime_int {
+ return -floatExponentMax(T) + 1;
+}
+
+/// Returns the maximum exponent that can represent
+/// a normalised value in floating point type T.
+pub fn floatExponentMax(comptime T: type) comptime_int {
+ return (1 << (floatExponentBits(T) - 1)) - 1;
+}
+
+/// Returns the smallest subnormal number representable in floating point type T.
+pub fn floatTrueMin(comptime T: type) T {
+ return reconstructFloat(T, floatExponentMin(T) - 1, 1);
+}
+
+/// Returns the smallest normal number representable in floating point type T.
+pub fn floatMin(comptime T: type) T {
+ return reconstructFloat(T, floatExponentMin(T), mantissaOne(T));
+}
+
+/// Returns the largest normal number representable in floating point type T.
+pub fn floatMax(comptime T: type) T {
+ const all1s_mantissa = (1 << floatMantissaBits(T)) - 1;
+ return reconstructFloat(T, floatExponentMax(T), all1s_mantissa);
+}
+
+/// Returns the machine epsilon of floating point type T.
+pub fn floatEps(comptime T: type) T {
+ return reconstructFloat(T, -floatFractionalBits(T), mantissaOne(T));
+}
+
+/// Returns the value inf for floating point type T.
+pub fn inf(comptime T: type) T {
+ return reconstructFloat(T, floatExponentMax(T) + 1, mantissaOne(T));
+}
+
+test "std.math.float" {
+ inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
+ // (1 +) for the sign bit, since it is separate from the other bits
+ const size = 1 + floatExponentBits(T) + floatMantissaBits(T);
+ try expect(@bitSizeOf(T) == size);
+
+ // for machine epsilon, assert expmin <= -prec <= expmax
+ try expect(floatExponentMin(T) <= -floatFractionalBits(T));
+ try expect(-floatFractionalBits(T) <= floatExponentMax(T));
+ }
+}
diff --git a/lib/std/math/floor.zig b/lib/std/math/floor.zig
index d6761ba77e..ab5ca3583b 100644
--- a/lib/std/math/floor.zig
+++ b/lib/std/math/floor.zig
@@ -98,6 +98,8 @@ fn floor32(x: f32) f32 {
}
fn floor64(x: f64) f64 {
+ const f64_toint = 1.0 / math.floatEps(f64);
+
const u = @bitCast(u64, x);
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
@@ -107,9 +109,9 @@ fn floor64(x: f64) f64 {
}
if (u >> 63 != 0) {
- y = x - math.f64_toint + math.f64_toint - x;
+ y = x - f64_toint + f64_toint - x;
} else {
- y = x + math.f64_toint - math.f64_toint - x;
+ y = x + f64_toint - f64_toint - x;
}
if (e <= 0x3FF - 1) {
@@ -127,6 +129,8 @@ fn floor64(x: f64) f64 {
}
fn floor128(x: f128) f128 {
+ const f128_toint = 1.0 / math.floatEps(f128);
+
const u = @bitCast(u128, x);
const e = (u >> 112) & 0x7FFF;
var y: f128 = undefined;
@@ -134,9 +138,9 @@ fn floor128(x: f128) f128 {
if (e >= 0x3FFF + 112 or x == 0) return x;
if (u >> 127 != 0) {
- y = x - math.f128_toint + math.f128_toint - x;
+ y = x - f128_toint + f128_toint - x;
} else {
- y = x + math.f128_toint - math.f128_toint - x;
+ y = x + f128_toint - f128_toint - x;
}
if (e <= 0x3FFF - 1) {
diff --git a/lib/std/math/fma.zig b/lib/std/math/fma.zig
index 7ef734cf4e..7afc6e557e 100644
--- a/lib/std/math/fma.zig
+++ b/lib/std/math/fma.zig
@@ -68,7 +68,7 @@ fn fma64(x: f64, y: f64, z: f64) f64 {
if (spread <= 53 * 2) {
zs = math.scalbn(zs, -spread);
} else {
- zs = math.copysign(f64, math.f64_min, zs);
+ zs = math.copysign(f64, math.floatMin(f64), zs);
}
const xy = dd_mul(xs, ys);
@@ -277,7 +277,7 @@ fn fma128(x: f128, y: f128, z: f128) f128 {
if (spread <= 113 * 2) {
zs = math.scalbn(zs, -spread);
} else {
- zs = math.copysign(f128, math.f128_min, zs);
+ zs = math.copysign(f128, math.floatMin(f128), zs);
}
const xy = dd_mul128(xs, ys);
diff --git a/lib/std/math/inf.zig b/lib/std/math/inf.zig
deleted file mode 100644
index fd7d7c4380..0000000000
--- a/lib/std/math/inf.zig
+++ /dev/null
@@ -1,14 +0,0 @@
-const std = @import("../std.zig");
-const math = std.math;
-
-/// Returns value inf for the type T.
-pub fn inf(comptime T: type) T {
- return switch (T) {
- f16 => math.inf_f16,
- f32 => math.inf_f32,
- f64 => math.inf_f64,
- f80 => math.inf_f80,
- f128 => math.inf_f128,
- else => @compileError("inf not implemented for " ++ @typeName(T)),
- };
-}
diff --git a/lib/std/math/isfinite.zig b/lib/std/math/isfinite.zig
index 762fb39991..e9314213ce 100644
--- a/lib/std/math/isfinite.zig
+++ b/lib/std/math/isfinite.zig
@@ -1,59 +1,40 @@
const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
-const maxInt = std.math.maxInt;
/// Returns whether x is a finite value.
pub fn isFinite(x: anytype) bool {
const T = @TypeOf(x);
- switch (T) {
- f16 => {
- const bits = @bitCast(u16, x);
- return bits & 0x7FFF < 0x7C00;
- },
- f32 => {
- const bits = @bitCast(u32, x);
- return bits & 0x7FFFFFFF < 0x7F800000;
- },
- f64 => {
- const bits = @bitCast(u64, x);
- return bits & (maxInt(u64) >> 1) < (0x7FF << 52);
- },
- f128 => {
- const bits = @bitCast(u128, x);
- return bits & (maxInt(u128) >> 1) < (0x7FFF << 112);
- },
- else => {
- @compileError("isFinite not implemented for " ++ @typeName(T));
- },
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+ if (@typeInfo(T) != .Float) {
+ @compileError("isFinite not implemented for " ++ @typeName(T));
}
+ const remove_sign = ~@as(TBits, 0) >> 1;
+ return @bitCast(TBits, x) & remove_sign < @bitCast(TBits, math.inf(T));
}
test "math.isFinite" {
- try expect(isFinite(@as(f16, 0.0)));
- try expect(isFinite(@as(f16, -0.0)));
- try expect(isFinite(@as(f32, 0.0)));
- try expect(isFinite(@as(f32, -0.0)));
- try expect(isFinite(@as(f64, 0.0)));
- try expect(isFinite(@as(f64, -0.0)));
- try expect(isFinite(@as(f128, 0.0)));
- try expect(isFinite(@as(f128, -0.0)));
+ // TODO remove when #11391 is resolved
+ if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest;
- try expect(!isFinite(math.inf(f16)));
- try expect(!isFinite(-math.inf(f16)));
- try expect(!isFinite(math.inf(f32)));
- try expect(!isFinite(-math.inf(f32)));
- try expect(!isFinite(math.inf(f64)));
- try expect(!isFinite(-math.inf(f64)));
- try expect(!isFinite(math.inf(f128)));
- try expect(!isFinite(-math.inf(f128)));
+ inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
+ // normals
+ try expect(isFinite(@as(T, 1.0)));
+ try expect(isFinite(-@as(T, 1.0)));
- try expect(!isFinite(math.nan(f16)));
- try expect(!isFinite(-math.nan(f16)));
- try expect(!isFinite(math.nan(f32)));
- try expect(!isFinite(-math.nan(f32)));
- try expect(!isFinite(math.nan(f64)));
- try expect(!isFinite(-math.nan(f64)));
- try expect(!isFinite(math.nan(f128)));
- try expect(!isFinite(-math.nan(f128)));
+ // zero & subnormals
+ try expect(isFinite(@as(T, 0.0)));
+ try expect(isFinite(@as(T, -0.0)));
+ try expect(isFinite(math.floatTrueMin(T)));
+
+ // other float limits
+ try expect(isFinite(math.floatMin(T)));
+ try expect(isFinite(math.floatMax(T)));
+
+ // inf & nan
+ try expect(!isFinite(math.inf(T)));
+ try expect(!isFinite(-math.inf(T)));
+ try expect(!isFinite(math.nan(T)));
+ try expect(!isFinite(-math.nan(T)));
+ }
}
diff --git a/lib/std/math/isinf.zig b/lib/std/math/isinf.zig
index cadaa8d937..e88b9810b6 100644
--- a/lib/std/math/isinf.zig
+++ b/lib/std/math/isinf.zig
@@ -1,131 +1,66 @@
const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
-const maxInt = std.math.maxInt;
/// Returns whether x is an infinity, ignoring sign.
pub fn isInf(x: anytype) bool {
const T = @TypeOf(x);
- switch (T) {
- f16 => {
- const bits = @bitCast(u16, x);
- return bits & 0x7FFF == 0x7C00;
- },
- f32 => {
- const bits = @bitCast(u32, x);
- return bits & 0x7FFFFFFF == 0x7F800000;
- },
- f64 => {
- const bits = @bitCast(u64, x);
- return bits & (maxInt(u64) >> 1) == (0x7FF << 52);
- },
- f128 => {
- const bits = @bitCast(u128, x);
- return bits & (maxInt(u128) >> 1) == (0x7FFF << 112);
- },
- else => {
- @compileError("isInf not implemented for " ++ @typeName(T));
- },
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+ if (@typeInfo(T) != .Float) {
+ @compileError("isInf not implemented for " ++ @typeName(T));
}
+ const remove_sign = ~@as(TBits, 0) >> 1;
+ return @bitCast(TBits, x) & remove_sign == @bitCast(TBits, math.inf(T));
}
/// Returns whether x is an infinity with a positive sign.
pub fn isPositiveInf(x: anytype) bool {
- const T = @TypeOf(x);
- switch (T) {
- f16 => {
- return @bitCast(u16, x) == 0x7C00;
- },
- f32 => {
- return @bitCast(u32, x) == 0x7F800000;
- },
- f64 => {
- return @bitCast(u64, x) == 0x7FF << 52;
- },
- f128 => {
- return @bitCast(u128, x) == 0x7FFF << 112;
- },
- else => {
- @compileError("isPositiveInf not implemented for " ++ @typeName(T));
- },
- }
+ return x == math.inf(@TypeOf(x));
}
/// Returns whether x is an infinity with a negative sign.
pub fn isNegativeInf(x: anytype) bool {
- const T = @TypeOf(x);
- switch (T) {
- f16 => {
- return @bitCast(u16, x) == 0xFC00;
- },
- f32 => {
- return @bitCast(u32, x) == 0xFF800000;
- },
- f64 => {
- return @bitCast(u64, x) == 0xFFF << 52;
- },
- f128 => {
- return @bitCast(u128, x) == 0xFFFF << 112;
- },
- else => {
- @compileError("isNegativeInf not implemented for " ++ @typeName(T));
- },
- }
+ return x == -math.inf(@TypeOf(x));
}
test "math.isInf" {
- try expect(!isInf(@as(f16, 0.0)));
- try expect(!isInf(@as(f16, -0.0)));
- try expect(!isInf(@as(f32, 0.0)));
- try expect(!isInf(@as(f32, -0.0)));
- try expect(!isInf(@as(f64, 0.0)));
- try expect(!isInf(@as(f64, -0.0)));
- try expect(!isInf(@as(f128, 0.0)));
- try expect(!isInf(@as(f128, -0.0)));
- try expect(isInf(math.inf(f16)));
- try expect(isInf(-math.inf(f16)));
- try expect(isInf(math.inf(f32)));
- try expect(isInf(-math.inf(f32)));
- try expect(isInf(math.inf(f64)));
- try expect(isInf(-math.inf(f64)));
- try expect(isInf(math.inf(f128)));
- try expect(isInf(-math.inf(f128)));
+ // TODO remove when #11391 is resolved
+ if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest;
+
+ inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
+ try expect(!isInf(@as(T, 0.0)));
+ try expect(!isInf(@as(T, -0.0)));
+ try expect(isInf(math.inf(T)));
+ try expect(isInf(-math.inf(T)));
+ try expect(!isInf(math.nan(T)));
+ try expect(!isInf(-math.nan(T)));
+ }
}
test "math.isPositiveInf" {
- try expect(!isPositiveInf(@as(f16, 0.0)));
- try expect(!isPositiveInf(@as(f16, -0.0)));
- try expect(!isPositiveInf(@as(f32, 0.0)));
- try expect(!isPositiveInf(@as(f32, -0.0)));
- try expect(!isPositiveInf(@as(f64, 0.0)));
- try expect(!isPositiveInf(@as(f64, -0.0)));
- try expect(!isPositiveInf(@as(f128, 0.0)));
- try expect(!isPositiveInf(@as(f128, -0.0)));
- try expect(isPositiveInf(math.inf(f16)));
- try expect(!isPositiveInf(-math.inf(f16)));
- try expect(isPositiveInf(math.inf(f32)));
- try expect(!isPositiveInf(-math.inf(f32)));
- try expect(isPositiveInf(math.inf(f64)));
- try expect(!isPositiveInf(-math.inf(f64)));
- try expect(isPositiveInf(math.inf(f128)));
- try expect(!isPositiveInf(-math.inf(f128)));
+ // TODO remove when #11391 is resolved
+ if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest;
+
+ inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
+ try expect(!isPositiveInf(@as(T, 0.0)));
+ try expect(!isPositiveInf(@as(T, -0.0)));
+ try expect(isPositiveInf(math.inf(T)));
+ try expect(!isPositiveInf(-math.inf(T)));
+ try expect(!isInf(math.nan(T)));
+ try expect(!isInf(-math.nan(T)));
+ }
}
test "math.isNegativeInf" {
- try expect(!isNegativeInf(@as(f16, 0.0)));
- try expect(!isNegativeInf(@as(f16, -0.0)));
- try expect(!isNegativeInf(@as(f32, 0.0)));
- try expect(!isNegativeInf(@as(f32, -0.0)));
- try expect(!isNegativeInf(@as(f64, 0.0)));
- try expect(!isNegativeInf(@as(f64, -0.0)));
- try expect(!isNegativeInf(@as(f128, 0.0)));
- try expect(!isNegativeInf(@as(f128, -0.0)));
- try expect(!isNegativeInf(math.inf(f16)));
- try expect(isNegativeInf(-math.inf(f16)));
- try expect(!isNegativeInf(math.inf(f32)));
- try expect(isNegativeInf(-math.inf(f32)));
- try expect(!isNegativeInf(math.inf(f64)));
- try expect(isNegativeInf(-math.inf(f64)));
- try expect(!isNegativeInf(math.inf(f128)));
- try expect(isNegativeInf(-math.inf(f128)));
+ // TODO remove when #11391 is resolved
+ if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest;
+
+ inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
+ try expect(!isNegativeInf(@as(T, 0.0)));
+ try expect(!isNegativeInf(@as(T, -0.0)));
+ try expect(!isNegativeInf(math.inf(T)));
+ try expect(isNegativeInf(-math.inf(T)));
+ try expect(!isInf(math.nan(T)));
+ try expect(!isInf(-math.nan(T)));
+ }
}
diff --git a/lib/std/math/isnormal.zig b/lib/std/math/isnormal.zig
index 88e186a3c9..42b2e1c188 100644
--- a/lib/std/math/isnormal.zig
+++ b/lib/std/math/isnormal.zig
@@ -1,57 +1,54 @@
const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
-const maxInt = std.math.maxInt;
-// Returns whether x has a normalized representation (i.e. integer part of mantissa is 1).
+/// Returns whether x is neither zero, subnormal, infinity, or NaN.
pub fn isNormal(x: anytype) bool {
const T = @TypeOf(x);
- switch (T) {
- f16 => {
- const bits = @bitCast(u16, x);
- return (bits +% (1 << 10)) & (maxInt(u16) >> 1) >= (1 << 11);
- },
- f32 => {
- const bits = @bitCast(u32, x);
- return (bits +% (1 << 23)) & (maxInt(u32) >> 1) >= (1 << 24);
- },
- f64 => {
- const bits = @bitCast(u64, x);
- return (bits +% (1 << 52)) & (maxInt(u64) >> 1) >= (1 << 53);
- },
- f128 => {
- const bits = @bitCast(u128, x);
- return (bits +% (1 << 112)) & (maxInt(u128) >> 1) >= (1 << 113);
- },
- else => {
- @compileError("isNormal not implemented for " ++ @typeName(T));
- },
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+ if (@typeInfo(T) != .Float) {
+ @compileError("isNormal not implemented for " ++ @typeName(T));
}
+
+ const increment_exp = 1 << math.floatMantissaBits(T);
+ const remove_sign = ~@as(TBits, 0) >> 1;
+
+ // We add 1 to the exponent, and if it overflows to 0 or becomes 1,
+ // then it was all zeroes (subnormal) or all ones (special, inf/nan).
+ // The sign bit is removed because all ones would overflow into it.
+ // For f80, even though it has an explicit integer part stored,
+ // the exponent effectively takes priority if mismatching.
+ const value = @bitCast(TBits, x) +% increment_exp;
+ return value & remove_sign >= (increment_exp << 1);
}
test "math.isNormal" {
- try expect(!isNormal(math.nan(f16)));
- try expect(!isNormal(math.nan(f32)));
- try expect(!isNormal(math.nan(f64)));
- try expect(!isNormal(math.nan(f128)));
- try expect(!isNormal(-math.nan(f16)));
- try expect(!isNormal(-math.nan(f32)));
- try expect(!isNormal(-math.nan(f64)));
- try expect(!isNormal(-math.nan(f128)));
- try expect(!isNormal(math.inf(f16)));
- try expect(!isNormal(math.inf(f32)));
- try expect(!isNormal(math.inf(f64)));
- try expect(!isNormal(math.inf(f128)));
- try expect(!isNormal(-math.inf(f16)));
- try expect(!isNormal(-math.inf(f32)));
- try expect(!isNormal(-math.inf(f64)));
- try expect(!isNormal(-math.inf(f128)));
- try expect(!isNormal(@as(f16, 0)));
- try expect(!isNormal(@as(f32, 0)));
- try expect(!isNormal(@as(f64, 0)));
- try expect(!isNormal(@as(f128, 0)));
- try expect(isNormal(@as(f16, 1.0)));
- try expect(isNormal(@as(f32, 1.0)));
- try expect(isNormal(@as(f64, 1.0)));
- try expect(isNormal(@as(f128, 1.0)));
+ // TODO remove when #11391 is resolved
+ if (@import("builtin").os.tag == .freebsd) return error.SkipZigTest;
+
+ // TODO add `c_longdouble' when math.inf(T) supports it
+ inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
+
+ // normals
+ try expect(isNormal(@as(T, 1.0)));
+ try expect(isNormal(math.floatMin(T)));
+ try expect(isNormal(math.floatMax(T)));
+
+ // subnormals
+ try expect(!isNormal(@as(T, -0.0)));
+ try expect(!isNormal(@as(T, 0.0)));
+ try expect(!isNormal(@as(T, math.floatTrueMin(T))));
+
+ // largest subnormal
+ try expect(!isNormal(@bitCast(T, ~(~@as(TBits, 0) << math.floatFractionalBits(T)))));
+
+ // non-finite numbers
+ try expect(!isNormal(-math.inf(T)));
+ try expect(!isNormal(math.inf(T)));
+ try expect(!isNormal(math.nan(T)));
+
+ // overflow edge-case (described in implementation, also see #10133)
+ try expect(!isNormal(@bitCast(T, ~@as(TBits, 0))));
+ }
}
diff --git a/lib/std/math/ldexp.zig b/lib/std/math/ldexp.zig
index 228bd7dd39..0934244c65 100644
--- a/lib/std/math/ldexp.zig
+++ b/lib/std/math/ldexp.zig
@@ -15,22 +15,22 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
var shift = n;
const T = @TypeOf(base);
- const IntT = std.meta.Int(.unsigned, @bitSizeOf(T));
+ const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
if (@typeInfo(T) != .Float) {
@compileError("ldexp not implemented for " ++ @typeName(T));
}
const mantissa_bits = math.floatMantissaBits(T);
- const exponent_bits = math.floatExponentBits(T);
- const exponent_bias = (1 << (exponent_bits - 1)) - 1;
- const exponent_min = 1 - exponent_bias;
- const exponent_max = exponent_bias;
+ const exponent_min = math.floatExponentMin(T);
+ const exponent_max = math.floatExponentMax(T);
+
+ const exponent_bias = exponent_max;
// fix double rounding errors in subnormal ranges
// https://git.musl-libc.org/cgit/musl/commit/src/math/ldexp.c?id=8c44a060243f04283ca68dad199aab90336141db
const scale_min_expo = exponent_min + mantissa_bits + 1;
- const scale_min = @bitCast(T, @as(IntT, scale_min_expo + exponent_bias) << mantissa_bits);
- const scale_max = @bitCast(T, @intCast(IntT, exponent_max + exponent_bias) << mantissa_bits);
+ const scale_min = @bitCast(T, @as(TBits, scale_min_expo + exponent_bias) << mantissa_bits);
+ const scale_max = @bitCast(T, @intCast(TBits, exponent_max + exponent_bias) << mantissa_bits);
// scale `shift` within floating point limits, if possible
// second pass is possible due to subnormal range
@@ -53,10 +53,12 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
}
}
- return base * @bitCast(T, @intCast(IntT, shift + exponent_bias) << mantissa_bits);
+ return base * @bitCast(T, @intCast(TBits, shift + exponent_bias) << mantissa_bits);
}
test "math.ldexp" {
+ // TODO derive the various constants here with new maths API
+
// basic usage
try expect(ldexp(@as(f16, 1.5), 4) == 24.0);
try expect(ldexp(@as(f32, 1.5), 4) == 24.0);
@@ -73,20 +75,20 @@ test "math.ldexp" {
try expect(math.isNormal(ldexp(@as(f128, 1.0), -16382)));
try expect(!math.isNormal(ldexp(@as(f128, 1.0), -16383)));
// unreliable due to lack of native f16 support, see talk on PR #8733
- // try expect(ldexp(@as(f16, 0x1.1FFp-1), -14 - 9) == math.f16_true_min);
- try expect(ldexp(@as(f32, 0x1.3FFFFFp-1), -126 - 22) == math.f32_true_min);
- try expect(ldexp(@as(f64, 0x1.7FFFFFFFFFFFFp-1), -1022 - 51) == math.f64_true_min);
- try expect(ldexp(@as(f128, 0x1.7FFFFFFFFFFFFFFFFFFFFFFFFFFFp-1), -16382 - 111) == math.f128_true_min);
+ // try expect(ldexp(@as(f16, 0x1.1FFp-1), -14 - 9) == math.floatTrueMin(f16));
+ try expect(ldexp(@as(f32, 0x1.3FFFFFp-1), -126 - 22) == math.floatTrueMin(f32));
+ try expect(ldexp(@as(f64, 0x1.7FFFFFFFFFFFFp-1), -1022 - 51) == math.floatTrueMin(f64));
+ try expect(ldexp(@as(f128, 0x1.7FFFFFFFFFFFFFFFFFFFFFFFFFFFp-1), -16382 - 111) == math.floatTrueMin(f128));
// float limits
- try expect(ldexp(@as(f32, math.f32_max), -128 - 149) > 0.0);
- try expect(ldexp(@as(f32, math.f32_max), -128 - 149 - 1) == 0.0);
- try expect(!math.isPositiveInf(ldexp(@as(f16, math.f16_true_min), 15 + 24)));
- try expect(math.isPositiveInf(ldexp(@as(f16, math.f16_true_min), 15 + 24 + 1)));
- try expect(!math.isPositiveInf(ldexp(@as(f32, math.f32_true_min), 127 + 149)));
- try expect(math.isPositiveInf(ldexp(@as(f32, math.f32_true_min), 127 + 149 + 1)));
- try expect(!math.isPositiveInf(ldexp(@as(f64, math.f64_true_min), 1023 + 1074)));
- try expect(math.isPositiveInf(ldexp(@as(f64, math.f64_true_min), 1023 + 1074 + 1)));
- try expect(!math.isPositiveInf(ldexp(@as(f128, math.f128_true_min), 16383 + 16494)));
- try expect(math.isPositiveInf(ldexp(@as(f128, math.f128_true_min), 16383 + 16494 + 1)));
+ try expect(ldexp(math.floatMax(f32), -128 - 149) > 0.0);
+ try expect(ldexp(math.floatMax(f32), -128 - 149 - 1) == 0.0);
+ try expect(!math.isPositiveInf(ldexp(math.floatTrueMin(f16), 15 + 24)));
+ try expect(math.isPositiveInf(ldexp(math.floatTrueMin(f16), 15 + 24 + 1)));
+ try expect(!math.isPositiveInf(ldexp(math.floatTrueMin(f32), 127 + 149)));
+ try expect(math.isPositiveInf(ldexp(math.floatTrueMin(f32), 127 + 149 + 1)));
+ try expect(!math.isPositiveInf(ldexp(math.floatTrueMin(f64), 1023 + 1074)));
+ try expect(math.isPositiveInf(ldexp(math.floatTrueMin(f64), 1023 + 1074 + 1)));
+ try expect(!math.isPositiveInf(ldexp(math.floatTrueMin(f128), 16383 + 16494)));
+ try expect(math.isPositiveInf(ldexp(math.floatTrueMin(f128), 16383 + 16494 + 1)));
}
diff --git a/lib/std/math/round.zig b/lib/std/math/round.zig
index c948431a35..be33a9cfbd 100644
--- a/lib/std/math/round.zig
+++ b/lib/std/math/round.zig
@@ -29,6 +29,8 @@ pub fn round(x: anytype) @TypeOf(x) {
}
fn round32(x_: f32) f32 {
+ const f32_toint = 1.0 / math.floatEps(f32);
+
var x = x_;
const u = @bitCast(u32, x);
const e = (u >> 23) & 0xFF;
@@ -41,11 +43,11 @@ fn round32(x_: f32) f32 {
x = -x;
}
if (e < 0x7F - 1) {
- math.doNotOptimizeAway(x + math.f32_toint);
+ math.doNotOptimizeAway(x + f32_toint);
return 0 * @bitCast(f32, u);
}
- y = x + math.f32_toint - math.f32_toint - x;
+ y = x + f32_toint - f32_toint - x;
if (y > 0.5) {
y = y + x - 1;
} else if (y <= -0.5) {
@@ -62,6 +64,8 @@ fn round32(x_: f32) f32 {
}
fn round64(x_: f64) f64 {
+ const f64_toint = 1.0 / math.floatEps(f64);
+
var x = x_;
const u = @bitCast(u64, x);
const e = (u >> 52) & 0x7FF;
@@ -74,11 +78,11 @@ fn round64(x_: f64) f64 {
x = -x;
}
if (e < 0x3ff - 1) {
- math.doNotOptimizeAway(x + math.f64_toint);
+ math.doNotOptimizeAway(x + f64_toint);
return 0 * @bitCast(f64, u);
}
- y = x + math.f64_toint - math.f64_toint - x;
+ y = x + f64_toint - f64_toint - x;
if (y > 0.5) {
y = y + x - 1;
} else if (y <= -0.5) {
@@ -95,6 +99,8 @@ fn round64(x_: f64) f64 {
}
fn round128(x_: f128) f128 {
+ const f128_toint = 1.0 / math.floatEps(f128);
+
var x = x_;
const u = @bitCast(u128, x);
const e = (u >> 112) & 0x7FFF;
@@ -107,11 +113,11 @@ fn round128(x_: f128) f128 {
x = -x;
}
if (e < 0x3FFF - 1) {
- math.doNotOptimizeAway(x + math.f64_toint);
+ math.doNotOptimizeAway(x + f128_toint);
return 0 * @bitCast(f128, u);
}
- y = x + math.f128_toint - math.f128_toint - x;
+ y = x + f128_toint - f128_toint - x;
if (y > 0.5) {
y = y + x - 1;
} else if (y <= -0.5) {
diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig
index 59e93480ba..2c6d53849d 100644
--- a/lib/std/mem/Allocator.zig
+++ b/lib/std/mem/Allocator.zig
@@ -50,7 +50,7 @@ pub const VTable = struct {
else => *const resizeProto,
},
- /// Free and invalidate a buffer. `buf.len` must equal the most recent length returned by `alloc` or `resize`.
+ /// Free and invalidate a buffer. `buf.len` must equal the most recent length returned by `alloc` or `resize`.
/// `buf_align` must equal the same value that was passed as the `ptr_align` parameter to the original `alloc` call.
///
/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
@@ -603,7 +603,7 @@ test "allocBytes non-zero len_align" {
/// allocation could not be granted this function returns `error.OutOfMemory`.
/// When the size/alignment is less than or equal to the previous allocation,
/// this function returns `error.OutOfMemory` when the allocator decides the client
-/// would be better off keeping the extra alignment/size.
+/// would be better off keeping the extra alignment/size.
/// Clients will call `resizeFn` when they require the allocator to track a new alignment/size,
/// and so this function should only return success when the allocator considers
/// the reallocation desirable from the allocator's perspective.
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 87fe6c7f7b..df42d14c3d 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -1441,7 +1441,7 @@ var wasi_cwd = if (builtin.os.tag == .wasi and !builtin.link_libc) struct {
/// Note that `cwd_init` corresponds to a Preopen directory, not necessarily
/// a POSIX path. For example, "." matches a Preopen provided with `--dir=.`
///
-/// This must be called before using any relative or absolute paths with `std.os`
+/// This must be called before using any relative or absolute paths with `std.os`
/// functions, if you are on WASI without linking libc.
///
/// `alloc` must not be a temporary or leak-detecting allocator, since `std.os`
@@ -1475,7 +1475,7 @@ pub fn initPreopensWasi(alloc: Allocator, cwd_init: ?[]const u8) !void {
/// Resolve a relative or absolute path to an handle (`fd_t`) and a relative subpath.
///
-/// For absolute paths, this automatically searches among available Preopens to find
+/// For absolute paths, this automatically searches among available Preopens to find
/// a match. For relative paths, it uses the "emulated" CWD.
pub fn resolvePathWasi(path: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) !RelativePathWasi {
// Note: Due to WASI's "sandboxed" file handles, operations with this RelativePathWasi
@@ -5325,7 +5325,7 @@ pub fn dl_iterate_phdr(
const elf_base = std.process.getBaseAddress();
const ehdr = @intToPtr(*elf.Ehdr, elf_base);
// Make sure the base address points to an ELF image.
- assert(mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF"));
+ assert(mem.eql(u8, ehdr.e_ident[0..4], elf.MAGIC));
const n_phdr = ehdr.e_phnum;
const phdrs = (@intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff))[0..n_phdr];
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 1ca83dada6..8598c7b3be 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -447,7 +447,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
// Find the ELF header
const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset);
// Validate the magic
- if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return error.BadElfMagic;
+ if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
// Consistency check
if (elf_header.e_phnum != info.dlpi_phnum) return error.FailedConsistencyCheck;
diff --git a/lib/std/os/uefi/pool_allocator.zig b/lib/std/os/uefi/pool_allocator.zig
index 3294621a18..544179aad3 100644
--- a/lib/std/os/uefi/pool_allocator.zig
+++ b/lib/std/os/uefi/pool_allocator.zig
@@ -90,7 +90,7 @@ const pool_allocator_vtable = Allocator.VTable{
.free = UefiPoolAllocator.free,
};
-/// Asserts allocations are 8 byte aligned and calls `boot_services.allocatePool`.
+/// Asserts allocations are 8 byte aligned and calls `boot_services.allocatePool`.
pub const raw_pool_allocator = Allocator{
.ptr = undefined,
.vtable = &raw_pool_allocator_table,
diff --git a/lib/std/os/uefi/tables/boot_services.zig b/lib/std/os/uefi/tables/boot_services.zig
index ee1e72f094..4774375b3c 100644
--- a/lib/std/os/uefi/tables/boot_services.zig
+++ b/lib/std/os/uefi/tables/boot_services.zig
@@ -67,7 +67,7 @@ pub const BootServices = extern struct {
/// Reinstalls a protocol interface on a device handle
reinstallProtocolInterface: fn (handle: Handle, protocol: *align(8) const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(.C) Status,
- /// Removes a protocol interface from a device handle. Usage of
+ /// Removes a protocol interface from a device handle. Usage of
/// uninstallMultipleProtocolInterfaces is recommended over this.
uninstallProtocolInterface: fn (handle: Handle, protocol: *align(8) const Guid, interface: *anyopaque) callconv(.C) Status,
diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig
index 599f02ca89..a07fc13af1 100644
--- a/lib/std/packed_int_array.zig
+++ b/lib/std/packed_int_array.zig
@@ -182,7 +182,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
/// Creates a bit-packed array of `Int`. Non-byte-multiple integers
/// will take up less memory in PackedIntArray than in a normal array.
-/// Elements are packed using native endianess and without storing any
+/// Elements are packed using native endianess and without storing any
/// meta data. PackedArray(i3, 8) will occupy exactly 3 bytes
/// of memory.
pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {
diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig
index 9f82a15d28..52d9f59951 100644
--- a/lib/std/priority_queue.zig
+++ b/lib/std/priority_queue.zig
@@ -100,7 +100,7 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
const item = self.items[index];
self.items[index] = last;
self.len -= 1;
- siftDown(self, 0);
+ siftDown(self, index);
return item;
}
@@ -460,22 +460,25 @@ test "std.PriorityQueue: remove at index" {
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
- try queue.add(3);
- try queue.add(2);
- try queue.add(1);
+ const items = [_]u32{ 2, 1, 8, 9, 3, 4, 5 };
+ for (items) |e| {
+ _ = try queue.add(e);
+ }
var it = queue.iterator();
- var elem = it.next();
var idx: usize = 0;
- const two_idx = while (elem != null) : (elem = it.next()) {
- if (elem.? == 2)
+ const two_idx = while (it.next()) |elem| {
+ if (elem == 2)
break idx;
idx += 1;
} else unreachable;
-
+ var sorted_items = [_]u32{ 1, 3, 4, 5, 8, 9 };
try expectEqual(queue.removeIndex(two_idx), 2);
- try expectEqual(queue.remove(), 1);
- try expectEqual(queue.remove(), 3);
+
+ var i: usize = 0;
+ while (queue.removeOrNull()) |n| : (i += 1) {
+ try expectEqual(n, sorted_items[i]);
+ }
try expectEqual(queue.removeOrNull(), null);
}
diff --git a/lib/std/rand.zig b/lib/std/rand.zig
index cfac15a1fb..0c3a0fd2ba 100644
--- a/lib/std/rand.zig
+++ b/lib/std/rand.zig
@@ -66,9 +66,7 @@ pub const Random = struct {
/// Returns a random value from an enum, evenly distributed.
pub fn enumValue(r: Random, comptime EnumType: type) EnumType {
- if (comptime !std.meta.trait.is(.Enum)(EnumType)) {
- @compileError("Random.enumValue requires an enum type, not a " ++ @typeName(EnumType));
- }
+ comptime assert(@typeInfo(EnumType) == .Enum);
// We won't use int -> enum casting because enum elements can have
// arbitrary values. Instead we'll randomly pick one of the type's values.
diff --git a/lib/std/rand/ziggurat.zig b/lib/std/rand/ziggurat.zig
index 59b7e53395..5c18d0023b 100644
--- a/lib/std/rand/ziggurat.zig
+++ b/lib/std/rand/ziggurat.zig
@@ -28,7 +28,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
} else {
// Generate a value in the range [1, 2) and scale into (0, 1)
const repr = (0x3ff << 52) | (bits >> 12);
- break :blk @bitCast(f64, repr) - (1.0 - math.f64_epsilon / 2.0);
+ break :blk @bitCast(f64, repr) - (1.0 - math.floatEps(f64) / 2.0);
}
};
diff --git a/lib/std/simd.zig b/lib/std/simd.zig
index 02e08b0dad..a30622aef6 100644
--- a/lib/std/simd.zig
+++ b/lib/std/simd.zig
@@ -23,7 +23,9 @@ pub fn suggestVectorSizeForCpu(comptime T: type, cpu: std.Target.Cpu) ?usize {
const element_bit_size = std.math.max(8, std.math.ceilPowerOfTwo(T, @bitSizeOf(T)));
return @divExact(vector_bit_size, element_bit_size);
},
- else => @compileError("No vector sizes for this CPU architecture have yet been recommended"),
+ else => {
+ return null;
+ },
}
}
@@ -296,7 +298,7 @@ test "vector searching" {
pub fn prefixScanWithFunc(
comptime hop: isize,
vec: anytype,
- /// The error type that `func` might return. Set this to `void` if `func` doesn't return an error union.
+ /// The error type that `func` might return. Set this to `void` if `func` doesn't return an error union.
comptime ErrorType: type,
comptime func: fn (@TypeOf(vec), @TypeOf(vec)) if (ErrorType == void) @TypeOf(vec) else ErrorType!@TypeOf(vec),
/// When one operand of the operation performed by `func` is this value, the result must equal the other operand.
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index a017266304..b54a1e980e 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -291,100 +291,149 @@ comptime {
const __bswapti2 = @import("compiler_rt/bswap.zig").__bswapti2;
@export(__bswapti2, .{ .name = "__bswapti2", .linkage = linkage });
- // Integral / floating point conversion (part 1/2)
- const __floatsidf = @import("compiler_rt/floatsiXf.zig").__floatsidf;
- @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage });
- const __floatsisf = @import("compiler_rt/floatsiXf.zig").__floatsisf;
- @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage });
- const __floatdidf = @import("compiler_rt/floatdidf.zig").__floatdidf;
- @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage });
- const __floatsitf = @import("compiler_rt/floatsiXf.zig").__floatsitf;
- @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage });
+ // Integral -> Float Conversion
- const __floatunsisf = @import("compiler_rt/floatunsisf.zig").__floatunsisf;
+ // Conversion to f32
+ const __floatsisf = @import("compiler_rt/floatXiYf.zig").__floatsisf;
+ @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage });
+ const __floatunsisf = @import("compiler_rt/floatXiYf.zig").__floatunsisf;
@export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage });
- const __floatundisf = @import("compiler_rt/floatundisf.zig").__floatundisf;
+
+ const __floatundisf = @import("compiler_rt/floatXiYf.zig").__floatundisf;
@export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage });
- const __floatunsidf = @import("compiler_rt/floatunsidf.zig").__floatunsidf;
+ const __floatdisf = @import("compiler_rt/floatXiYf.zig").__floatdisf;
+ @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage });
+
+ const __floattisf = @import("compiler_rt/floatXiYf.zig").__floattisf;
+ @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage });
+ const __floatuntisf = @import("compiler_rt/floatXiYf.zig").__floatuntisf;
+ @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage });
+
+ // Conversion to f64
+ const __floatsidf = @import("compiler_rt/floatXiYf.zig").__floatsidf;
+ @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage });
+ const __floatunsidf = @import("compiler_rt/floatXiYf.zig").__floatunsidf;
@export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage });
- const __floatundidf = @import("compiler_rt/floatundidf.zig").__floatundidf;
+
+ const __floatdidf = @import("compiler_rt/floatXiYf.zig").__floatdidf;
+ @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage });
+ const __floatundidf = @import("compiler_rt/floatXiYf.zig").__floatundidf;
@export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage });
- const __floatditf = @import("compiler_rt/floatditf.zig").__floatditf;
- @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage });
- const __floattitf = @import("compiler_rt/floattitf.zig").__floattitf;
- @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage });
- const __floattidf = @import("compiler_rt/floattidf.zig").__floattidf;
+ const __floattidf = @import("compiler_rt/floatXiYf.zig").__floattidf;
@export(__floattidf, .{ .name = "__floattidf", .linkage = linkage });
- const __floattisf = @import("compiler_rt/floatXisf.zig").__floattisf;
- @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage });
- const __floatdisf = @import("compiler_rt/floatXisf.zig").__floatdisf;
- @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage });
+ const __floatuntidf = @import("compiler_rt/floatXiYf.zig").__floatuntidf;
+ @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage });
- const __floatunditf = @import("compiler_rt/floatunditf.zig").__floatunditf;
- @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage });
- const __floatunsitf = @import("compiler_rt/floatunsitf.zig").__floatunsitf;
+ // Conversion to f80
+ const __floatsixf = @import("compiler_rt/floatXiYf.zig").__floatsixf;
+ @export(__floatsixf, .{ .name = "__floatsixf", .linkage = linkage });
+ const __floatunsixf = @import("compiler_rt/floatXiYf.zig").__floatunsixf;
+ @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = linkage });
+
+ const __floatdixf = @import("compiler_rt/floatXiYf.zig").__floatdixf;
+ @export(__floatdixf, .{ .name = "__floatdixf", .linkage = linkage });
+ const __floatundixf = @import("compiler_rt/floatXiYf.zig").__floatundixf;
+ @export(__floatundixf, .{ .name = "__floatundixf", .linkage = linkage });
+
+ const __floattixf = @import("compiler_rt/floatXiYf.zig").__floattixf;
+ @export(__floattixf, .{ .name = "__floattixf", .linkage = linkage });
+ const __floatuntixf = @import("compiler_rt/floatXiYf.zig").__floatuntixf;
+ @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = linkage });
+
+ // Conversion to f128
+ const __floatsitf = @import("compiler_rt/floatXiYf.zig").__floatsitf;
+ @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage });
+ const __floatunsitf = @import("compiler_rt/floatXiYf.zig").__floatunsitf;
@export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage });
- const __floatuntitf = @import("compiler_rt/floatuntitf.zig").__floatuntitf;
+ const __floatditf = @import("compiler_rt/floatXiYf.zig").__floatditf;
+ @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage });
+ const __floatunditf = @import("compiler_rt/floatXiYf.zig").__floatunditf;
+ @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage });
+
+ const __floattitf = @import("compiler_rt/floatXiYf.zig").__floattitf;
+ @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage });
+ const __floatuntitf = @import("compiler_rt/floatXiYf.zig").__floatuntitf;
@export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage });
- const __floatuntidf = @import("compiler_rt/floatuntidf.zig").__floatuntidf;
- @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage });
- const __floatuntisf = @import("compiler_rt/floatuntisf.zig").__floatuntisf;
- @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage });
- const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2;
- @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage });
- if (!is_test) {
- @export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
- }
- const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2;
- @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage });
+ // Float -> Integral Conversion
- // Integral / floating point conversion (part 2/2)
- const __fixunssfsi = @import("compiler_rt/fixunssfsi.zig").__fixunssfsi;
+ // Conversion from f32
+ const __fixsfsi = @import("compiler_rt/fixXfYi.zig").__fixsfsi;
+ @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage });
+ const __fixunssfsi = @import("compiler_rt/fixXfYi.zig").__fixunssfsi;
@export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage });
- const __fixunssfdi = @import("compiler_rt/fixunssfdi.zig").__fixunssfdi;
+
+ const __fixsfdi = @import("compiler_rt/fixXfYi.zig").__fixsfdi;
+ @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage });
+ const __fixunssfdi = @import("compiler_rt/fixXfYi.zig").__fixunssfdi;
@export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage });
- const __fixunssfti = @import("compiler_rt/fixunssfti.zig").__fixunssfti;
+
+ const __fixsfti = @import("compiler_rt/fixXfYi.zig").__fixsfti;
+ @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage });
+ const __fixunssfti = @import("compiler_rt/fixXfYi.zig").__fixunssfti;
@export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage });
- const __fixunsdfsi = @import("compiler_rt/fixunsdfsi.zig").__fixunsdfsi;
+ // Conversion from f64
+ const __fixdfsi = @import("compiler_rt/fixXfYi.zig").__fixdfsi;
+ @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage });
+ const __fixunsdfsi = @import("compiler_rt/fixXfYi.zig").__fixunsdfsi;
@export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage });
- const __fixunsdfdi = @import("compiler_rt/fixunsdfdi.zig").__fixunsdfdi;
+
+ const __fixdfdi = @import("compiler_rt/fixXfYi.zig").__fixdfdi;
+ @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage });
+ const __fixunsdfdi = @import("compiler_rt/fixXfYi.zig").__fixunsdfdi;
@export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage });
- const __fixunsdfti = @import("compiler_rt/fixunsdfti.zig").__fixunsdfti;
+
+ const __fixdfti = @import("compiler_rt/fixXfYi.zig").__fixdfti;
+ @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage });
+ const __fixunsdfti = @import("compiler_rt/fixXfYi.zig").__fixunsdfti;
@export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage });
- const __fixunstfsi = @import("compiler_rt/fixunstfsi.zig").__fixunstfsi;
+ // Conversion from f80
+ const __fixxfsi = @import("compiler_rt/fixXfYi.zig").__fixxfsi;
+ @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = linkage });
+ const __fixunsxfsi = @import("compiler_rt/fixXfYi.zig").__fixunsxfsi;
+ @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = linkage });
+
+ const __fixxfdi = @import("compiler_rt/fixXfYi.zig").__fixxfdi;
+ @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = linkage });
+ const __fixunsxfdi = @import("compiler_rt/fixXfYi.zig").__fixunsxfdi;
+ @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = linkage });
+
+ const __fixxfti = @import("compiler_rt/fixXfYi.zig").__fixxfti;
+ @export(__fixxfti, .{ .name = "__fixxfti", .linkage = linkage });
+ const __fixunsxfti = @import("compiler_rt/fixXfYi.zig").__fixunsxfti;
+ @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = linkage });
+
+ // Conversion from f128
+ const __fixtfsi = @import("compiler_rt/fixXfYi.zig").__fixtfsi;
+ @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage });
+ const __fixunstfsi = @import("compiler_rt/fixXfYi.zig").__fixunstfsi;
@export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage });
- const __fixunstfdi = @import("compiler_rt/fixunstfdi.zig").__fixunstfdi;
- @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage });
- const __fixunstfti = @import("compiler_rt/fixunstfti.zig").__fixunstfti;
- @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage });
- const __fixdfdi = @import("compiler_rt/fixdfdi.zig").__fixdfdi;
- @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage });
- const __fixdfsi = @import("compiler_rt/fixdfsi.zig").__fixdfsi;
- @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage });
- const __fixdfti = @import("compiler_rt/fixdfti.zig").__fixdfti;
- @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage });
- const __fixsfdi = @import("compiler_rt/fixsfdi.zig").__fixsfdi;
- @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage });
- const __fixsfsi = @import("compiler_rt/fixsfsi.zig").__fixsfsi;
- @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage });
- const __fixsfti = @import("compiler_rt/fixsfti.zig").__fixsfti;
- @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage });
- const __fixtfdi = @import("compiler_rt/fixtfdi.zig").__fixtfdi;
+ const __fixtfdi = @import("compiler_rt/fixXfYi.zig").__fixtfdi;
@export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage });
- const __fixtfsi = @import("compiler_rt/fixtfsi.zig").__fixtfsi;
- @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage });
- const __fixtfti = @import("compiler_rt/fixtfti.zig").__fixtfti;
+ const __fixunstfdi = @import("compiler_rt/fixXfYi.zig").__fixunstfdi;
+ @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage });
+
+ const __fixtfti = @import("compiler_rt/fixXfYi.zig").__fixtfti;
@export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage });
+ const __fixunstfti = @import("compiler_rt/fixXfYi.zig").__fixunstfti;
+ @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage });
const __udivmoddi4 = @import("compiler_rt/int.zig").__udivmoddi4;
@export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = linkage });
+ const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2;
+ @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage });
+ if (!is_test) {
+ @export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
+ }
+ const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2;
+ @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage });
+
if (is_darwin) {
const __isPlatformVersionAtLeast = @import("compiler_rt/os_version_check.zig").__isPlatformVersionAtLeast;
@export(__isPlatformVersionAtLeast, .{ .name = "__isPlatformVersionAtLeast", .linkage = linkage });
@@ -553,19 +602,19 @@ comptime {
const __aeabi_f2d = @import("compiler_rt/extendXfYf2.zig").__aeabi_f2d;
@export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage });
- const __aeabi_i2d = @import("compiler_rt/floatsiXf.zig").__aeabi_i2d;
+ const __aeabi_i2d = @import("compiler_rt/floatXiYf.zig").__aeabi_i2d;
@export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage });
- const __aeabi_l2d = @import("compiler_rt/floatdidf.zig").__aeabi_l2d;
+ const __aeabi_l2d = @import("compiler_rt/floatXiYf.zig").__aeabi_l2d;
@export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage });
- const __aeabi_l2f = @import("compiler_rt/floatXisf.zig").__aeabi_l2f;
+ const __aeabi_l2f = @import("compiler_rt/floatXiYf.zig").__aeabi_l2f;
@export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage });
- const __aeabi_ui2d = @import("compiler_rt/floatunsidf.zig").__aeabi_ui2d;
+ const __aeabi_ui2d = @import("compiler_rt/floatXiYf.zig").__aeabi_ui2d;
@export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage });
- const __aeabi_ul2d = @import("compiler_rt/floatundidf.zig").__aeabi_ul2d;
+ const __aeabi_ul2d = @import("compiler_rt/floatXiYf.zig").__aeabi_ul2d;
@export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage });
- const __aeabi_ui2f = @import("compiler_rt/floatunsisf.zig").__aeabi_ui2f;
+ const __aeabi_ui2f = @import("compiler_rt/floatXiYf.zig").__aeabi_ui2f;
@export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage });
- const __aeabi_ul2f = @import("compiler_rt/floatundisf.zig").__aeabi_ul2f;
+ const __aeabi_ul2f = @import("compiler_rt/floatXiYf.zig").__aeabi_ul2f;
@export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage });
const __aeabi_fneg = @import("compiler_rt/negXf2.zig").__aeabi_fneg;
@@ -581,17 +630,17 @@ comptime {
const __aeabi_d2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2h;
@export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage });
- const __aeabi_f2ulz = @import("compiler_rt/fixunssfdi.zig").__aeabi_f2ulz;
+ const __aeabi_f2ulz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2ulz;
@export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage });
- const __aeabi_d2ulz = @import("compiler_rt/fixunsdfdi.zig").__aeabi_d2ulz;
+ const __aeabi_d2ulz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2ulz;
@export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage });
- const __aeabi_f2lz = @import("compiler_rt/fixsfdi.zig").__aeabi_f2lz;
+ const __aeabi_f2lz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2lz;
@export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage });
- const __aeabi_d2lz = @import("compiler_rt/fixdfdi.zig").__aeabi_d2lz;
+ const __aeabi_d2lz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2lz;
@export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage });
- const __aeabi_d2uiz = @import("compiler_rt/fixunsdfsi.zig").__aeabi_d2uiz;
+ const __aeabi_d2uiz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2uiz;
@export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage });
const __aeabi_h2f = @import("compiler_rt/extendXfYf2.zig").__aeabi_h2f;
@@ -599,7 +648,7 @@ comptime {
const __aeabi_f2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_f2h;
@export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage });
- const __aeabi_i2f = @import("compiler_rt/floatsiXf.zig").__aeabi_i2f;
+ const __aeabi_i2f = @import("compiler_rt/floatXiYf.zig").__aeabi_i2f;
@export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage });
const __aeabi_d2f = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2f;
@export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage });
@@ -613,12 +662,12 @@ comptime {
const __aeabi_dsub = @import("compiler_rt/addXf3.zig").__aeabi_dsub;
@export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage });
- const __aeabi_f2uiz = @import("compiler_rt/fixunssfsi.zig").__aeabi_f2uiz;
+ const __aeabi_f2uiz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2uiz;
@export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage });
- const __aeabi_f2iz = @import("compiler_rt/fixsfsi.zig").__aeabi_f2iz;
+ const __aeabi_f2iz = @import("compiler_rt/fixXfYi.zig").__aeabi_f2iz;
@export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage });
- const __aeabi_d2iz = @import("compiler_rt/fixdfsi.zig").__aeabi_d2iz;
+ const __aeabi_d2iz = @import("compiler_rt/fixXfYi.zig").__aeabi_d2iz;
@export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage });
const __aeabi_fdiv = @import("compiler_rt/divsf3.zig").__aeabi_fdiv;
@@ -672,9 +721,13 @@ comptime {
@export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
}
- const fmodl = @import("compiler_rt/floatfmodl.zig").fmodl;
if (!is_test) {
@export(fmodl, .{ .name = "fmodl", .linkage = linkage });
+ if (long_double_is_f128) {
+ @export(fmodl, .{ .name = "fmodq", .linkage = linkage });
+ } else {
+ @export(fmodq, .{ .name = "fmodq", .linkage = linkage });
+ }
@export(floorf, .{ .name = "floorf", .linkage = linkage });
@export(floor, .{ .name = "floor", .linkage = linkage });
@@ -828,6 +881,14 @@ fn ceill(x: c_longdouble) callconv(.C) c_longdouble {
return math.ceil(x);
}
+const fmodq = @import("compiler_rt/floatfmodq.zig").fmodq;
+fn fmodl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble {
+ if (!long_double_is_f128) {
+ @panic("TODO implement this");
+ }
+ return @floatCast(c_longdouble, fmodq(x, y));
+}
+
// 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 {
diff --git a/lib/std/special/compiler_rt/divtf3_test.zig b/lib/std/special/compiler_rt/divtf3_test.zig
index f426f827e8..62204057d4 100644
--- a/lib/std/special/compiler_rt/divtf3_test.zig
+++ b/lib/std/special/compiler_rt/divtf3_test.zig
@@ -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);
diff --git a/lib/std/special/compiler_rt/fixXfYi.zig b/lib/std/special/compiler_rt/fixXfYi.zig
new file mode 100644
index 0000000000..01832ec56f
--- /dev/null
+++ b/lib/std/special/compiler_rt/fixXfYi.zig
@@ -0,0 +1,224 @@
+const std = @import("std");
+const math = std.math;
+const Log2Int = math.Log2Int;
+const is_test = @import("builtin").is_test;
+
+pub inline fn fixXfYi(comptime I: type, a: anytype) I {
+ @setRuntimeSafety(is_test);
+
+ const F = @TypeOf(a);
+ const float_bits = @typeInfo(F).Float.bits;
+ const int_bits = @typeInfo(I).Int.bits;
+ const rep_t = std.meta.Int(.unsigned, float_bits);
+ const sig_bits = math.floatMantissaBits(F);
+ const exp_bits = math.floatExponentBits(F);
+ const fractional_bits = math.floatFractionalBits(F);
+
+ const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0;
+ const max_exp = (1 << (exp_bits - 1));
+ const exp_bias = max_exp - 1;
+ const sig_mask = (@as(rep_t, 1) << sig_bits) - 1;
+
+ // Break a into sign, exponent, significand
+ const a_rep: rep_t = @bitCast(rep_t, a);
+ const negative = (a_rep >> (float_bits - 1)) != 0;
+ const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias;
+ const significand: rep_t = (a_rep & sig_mask) | implicit_bit;
+
+ // If the exponent is negative, the result rounds to zero.
+ if (exponent < 0) return 0;
+
+ // If the value is too large for the integer type, saturate.
+ switch (@typeInfo(I).Int.signedness) {
+ .unsigned => {
+ if (negative) return 0;
+ if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I);
+ },
+ .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) {
+ return if (negative) math.minInt(I) else math.maxInt(I);
+ },
+ }
+
+ // If 0 <= exponent < sig_bits, right shift to get the result.
+ // Otherwise, shift left.
+ var result: I = undefined;
+ if (exponent < fractional_bits) {
+ result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent));
+ } else {
+ result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits);
+ }
+
+ if ((@typeInfo(I).Int.signedness == .signed) and negative)
+ return ~result +% 1;
+ return result;
+}
+
+// Conversion from f16
+
+pub fn __fixhfsi(a: f16) callconv(.C) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __fixunshfsi(a: f16) callconv(.C) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __fixhfdi(a: f16) callconv(.C) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __fixunshfdi(a: f16) callconv(.C) u64 {
+ return fixXfYi(u64, a);
+}
+
+pub fn __fixhfti(a: f16) callconv(.C) i128 {
+ return fixXfYi(i128, a);
+}
+
+pub fn __fixunshfti(a: f16) callconv(.C) u128 {
+ return fixXfYi(u128, a);
+}
+
+// Conversion from f32
+
+pub fn __fixsfsi(a: f32) callconv(.C) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __fixunssfsi(a: f32) callconv(.C) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __fixsfdi(a: f32) callconv(.C) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __fixunssfdi(a: f32) callconv(.C) u64 {
+ return fixXfYi(u64, a);
+}
+
+pub fn __fixsfti(a: f32) callconv(.C) i128 {
+ return fixXfYi(i128, a);
+}
+
+pub fn __fixunssfti(a: f32) callconv(.C) u128 {
+ return fixXfYi(u128, a);
+}
+
+// Conversion from f64
+
+pub fn __fixdfsi(a: f64) callconv(.C) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __fixunsdfsi(a: f64) callconv(.C) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __fixdfdi(a: f64) callconv(.C) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __fixunsdfdi(a: f64) callconv(.C) u64 {
+ return fixXfYi(u64, a);
+}
+
+pub fn __fixdfti(a: f64) callconv(.C) i128 {
+ return fixXfYi(i128, a);
+}
+
+pub fn __fixunsdfti(a: f64) callconv(.C) u128 {
+ return fixXfYi(u128, a);
+}
+
+// Conversion from f80
+
+pub fn __fixxfsi(a: f80) callconv(.C) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __fixunsxfsi(a: f80) callconv(.C) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __fixxfdi(a: f80) callconv(.C) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __fixunsxfdi(a: f80) callconv(.C) u64 {
+ return fixXfYi(u64, a);
+}
+
+pub fn __fixxfti(a: f80) callconv(.C) i128 {
+ return fixXfYi(i128, a);
+}
+
+pub fn __fixunsxfti(a: f80) callconv(.C) u128 {
+ return fixXfYi(u128, a);
+}
+
+// Conversion from f128
+
+pub fn __fixtfsi(a: f128) callconv(.C) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __fixunstfsi(a: f128) callconv(.C) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __fixtfdi(a: f128) callconv(.C) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __fixunstfdi(a: f128) callconv(.C) u64 {
+ return fixXfYi(u64, a);
+}
+
+pub fn __fixtfti(a: f128) callconv(.C) i128 {
+ return fixXfYi(i128, a);
+}
+
+pub fn __fixunstfti(a: f128) callconv(.C) u128 {
+ return fixXfYi(u128, a);
+}
+
+// Conversion from f32
+
+pub fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 {
+ return fixXfYi(u64, a);
+}
+
+// Conversion from f64
+
+pub fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 {
+ return fixXfYi(i32, a);
+}
+
+pub fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 {
+ return fixXfYi(u32, a);
+}
+
+pub fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 {
+ return fixXfYi(i64, a);
+}
+
+pub fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 {
+ return fixXfYi(u64, a);
+}
+
+test {
+ _ = @import("fixXfYi_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/fixXfYi_test.zig b/lib/std/special/compiler_rt/fixXfYi_test.zig
new file mode 100644
index 0000000000..00ed455609
--- /dev/null
+++ b/lib/std/special/compiler_rt/fixXfYi_test.zig
@@ -0,0 +1,948 @@
+const std = @import("std");
+const testing = std.testing;
+const math = std.math;
+const fixXfYi = @import("fixXfYi.zig").fixXfYi;
+
+// Conversion from f32
+const __fixsfsi = @import("fixXfYi.zig").__fixsfsi;
+const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi;
+const __fixsfdi = @import("fixXfYi.zig").__fixsfdi;
+const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi;
+const __fixsfti = @import("fixXfYi.zig").__fixsfti;
+const __fixunssfti = @import("fixXfYi.zig").__fixunssfti;
+
+// Conversion from f64
+const __fixdfsi = @import("fixXfYi.zig").__fixdfsi;
+const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi;
+const __fixdfdi = @import("fixXfYi.zig").__fixdfdi;
+const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi;
+const __fixdfti = @import("fixXfYi.zig").__fixdfti;
+const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti;
+
+// Conversion from f128
+const __fixtfsi = @import("fixXfYi.zig").__fixtfsi;
+const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi;
+const __fixtfdi = @import("fixXfYi.zig").__fixtfdi;
+const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi;
+const __fixtfti = @import("fixXfYi.zig").__fixtfti;
+const __fixunstfti = @import("fixXfYi.zig").__fixunstfti;
+
+fn test__fixsfsi(a: f32, expected: i32) !void {
+ const x = __fixsfsi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunssfsi(a: f32, expected: u32) !void {
+ const x = __fixunssfsi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixsfsi" {
+ try test__fixsfsi(-math.floatMax(f32), math.minInt(i32));
+
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
+
+ try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
+
+ try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000);
+ try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
+
+ try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000);
+
+ try test__fixsfsi(-0x1.000000p+31, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000);
+ try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
+ try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00);
+
+ try test__fixsfsi(-2.01, -2);
+ try test__fixsfsi(-2.0, -2);
+ try test__fixsfsi(-1.99, -1);
+ try test__fixsfsi(-1.0, -1);
+ try test__fixsfsi(-0.99, 0);
+ try test__fixsfsi(-0.5, 0);
+ try test__fixsfsi(-math.floatMin(f32), 0);
+ try test__fixsfsi(0.0, 0);
+ try test__fixsfsi(math.floatMin(f32), 0);
+ try test__fixsfsi(0.5, 0);
+ try test__fixsfsi(0.99, 0);
+ try test__fixsfsi(1.0, 1);
+ try test__fixsfsi(1.5, 1);
+ try test__fixsfsi(1.99, 1);
+ try test__fixsfsi(2.0, 2);
+ try test__fixsfsi(2.01, 2);
+
+ try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
+ try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF);
+
+ try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
+
+ try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
+
+ try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
+
+ try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
+ try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
+
+ try test__fixsfsi(math.floatMax(f32), math.maxInt(i32));
+}
+
+test "fixunssfsi" {
+ try test__fixunssfsi(0.0, 0);
+
+ try test__fixunssfsi(0.5, 0);
+ try test__fixunssfsi(0.99, 0);
+ try test__fixunssfsi(1.0, 1);
+ try test__fixunssfsi(1.5, 1);
+ try test__fixunssfsi(1.99, 1);
+ try test__fixunssfsi(2.0, 2);
+ try test__fixunssfsi(2.01, 2);
+ try test__fixunssfsi(-0.5, 0);
+ try test__fixunssfsi(-0.99, 0);
+
+ try test__fixunssfsi(-1.0, 0);
+ try test__fixunssfsi(-1.5, 0);
+ try test__fixunssfsi(-1.99, 0);
+ try test__fixunssfsi(-2.0, 0);
+ try test__fixunssfsi(-2.01, 0);
+
+ try test__fixunssfsi(0x1.000000p+31, 0x80000000);
+ try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF);
+ try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00);
+ try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
+
+ try test__fixunssfsi(-0x1.FFFFFEp+30, 0);
+ try test__fixunssfsi(-0x1.FFFFFCp+30, 0);
+}
+
+fn test__fixsfdi(a: f32, expected: i64) !void {
+ const x = __fixsfdi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunssfdi(a: f32, expected: u64) !void {
+ const x = __fixunssfdi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixsfdi" {
+ try test__fixsfdi(-math.floatMax(f32), math.minInt(i64));
+
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
+
+ try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000);
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
+
+ try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000);
+ try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000);
+ try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000);
+
+ try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000);
+ try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000);
+ try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000);
+
+ try test__fixsfdi(-2.01, -2);
+ try test__fixsfdi(-2.0, -2);
+ try test__fixsfdi(-1.99, -1);
+ try test__fixsfdi(-1.0, -1);
+ try test__fixsfdi(-0.99, 0);
+ try test__fixsfdi(-0.5, 0);
+ try test__fixsfdi(-math.floatMin(f32), 0);
+ try test__fixsfdi(0.0, 0);
+ try test__fixsfdi(math.floatMin(f32), 0);
+ try test__fixsfdi(0.5, 0);
+ try test__fixsfdi(0.99, 0);
+ try test__fixsfdi(1.0, 1);
+ try test__fixsfdi(1.5, 1);
+ try test__fixsfdi(1.99, 1);
+ try test__fixsfdi(2.0, 2);
+ try test__fixsfdi(2.01, 2);
+
+ try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
+ try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
+
+ try test__fixsfdi(math.floatMax(f32), math.maxInt(i64));
+}
+
+test "fixunssfdi" {
+ try test__fixunssfdi(0.0, 0);
+
+ try test__fixunssfdi(0.5, 0);
+ try test__fixunssfdi(0.99, 0);
+ try test__fixunssfdi(1.0, 1);
+ try test__fixunssfdi(1.5, 1);
+ try test__fixunssfdi(1.99, 1);
+ try test__fixunssfdi(2.0, 2);
+ try test__fixunssfdi(2.01, 2);
+ try test__fixunssfdi(-0.5, 0);
+ try test__fixunssfdi(-0.99, 0);
+
+ try test__fixunssfdi(-1.0, 0);
+ try test__fixunssfdi(-1.5, 0);
+ try test__fixunssfdi(-1.99, 0);
+ try test__fixunssfdi(-2.0, 0);
+ try test__fixunssfdi(-2.01, 0);
+
+ try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000);
+ try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000);
+ try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+
+ try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000);
+ try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000);
+}
+
+fn test__fixsfti(a: f32, expected: i128) !void {
+ const x = __fixsfti(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunssfti(a: f32, expected: u128) !void {
+ const x = __fixunssfti(a);
+ try testing.expect(x == expected);
+}
+
+test "fixsfti" {
+ try test__fixsfti(-math.floatMax(f32), math.minInt(i128));
+
+ try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
+ try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
+
+ try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
+ try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000);
+ try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000);
+ try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000);
+ try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000);
+ try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000);
+
+ try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000);
+ try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000);
+ try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000);
+
+ try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000);
+ try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
+ try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
+
+ try test__fixsfti(-0x1.000000p+31, -0x80000000);
+ try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000);
+ try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80);
+ try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00);
+
+ try test__fixsfti(-2.01, -2);
+ try test__fixsfti(-2.0, -2);
+ try test__fixsfti(-1.99, -1);
+ try test__fixsfti(-1.0, -1);
+ try test__fixsfti(-0.99, 0);
+ try test__fixsfti(-0.5, 0);
+ try test__fixsfti(-math.floatMin(f32), 0);
+ try test__fixsfti(0.0, 0);
+ try test__fixsfti(math.floatMin(f32), 0);
+ try test__fixsfti(0.5, 0);
+ try test__fixsfti(0.99, 0);
+ try test__fixsfti(1.0, 1);
+ try test__fixsfti(1.5, 1);
+ try test__fixsfti(1.99, 1);
+ try test__fixsfti(2.0, 2);
+ try test__fixsfti(2.01, 2);
+
+ try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00);
+ try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixsfti(0x1.FFFFFFp+30, 0x80000000);
+ try test__fixsfti(0x1.000000p+31, 0x80000000);
+
+ try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000);
+
+ try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000);
+ try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000);
+ try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000);
+ try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000);
+
+ try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000);
+ try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000);
+ try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+
+ try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
+
+ try test__fixsfti(math.floatMax(f32), math.maxInt(i128));
+}
+
+test "fixunssfti" {
+ try test__fixunssfti(0.0, 0);
+
+ try test__fixunssfti(0.5, 0);
+ try test__fixunssfti(0.99, 0);
+ try test__fixunssfti(1.0, 1);
+ try test__fixunssfti(1.5, 1);
+ try test__fixunssfti(1.99, 1);
+ try test__fixunssfti(2.0, 2);
+ try test__fixunssfti(2.01, 2);
+ try test__fixunssfti(-0.5, 0);
+ try test__fixunssfti(-0.99, 0);
+
+ try test__fixunssfti(-1.0, 0);
+ try test__fixunssfti(-1.5, 0);
+ try test__fixunssfti(-1.99, 0);
+ try test__fixunssfti(-2.0, 0);
+ try test__fixunssfti(-2.01, 0);
+
+ try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000);
+ try test__fixunssfti(0x1.000000p+63, 0x8000000000000000);
+ try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000);
+ try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000);
+ try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000);
+ try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000);
+
+ try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000);
+ try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000);
+ try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000);
+ try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000);
+ try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000);
+ try test__fixunssfti(math.inf(f32), math.maxInt(u128));
+}
+
+fn test__fixdfsi(a: f64, expected: i32) !void {
+ const x = __fixdfsi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunsdfsi(a: f64, expected: u32) !void {
+ const x = __fixunsdfsi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixdfsi" {
+ try test__fixdfsi(-math.floatMax(f64), math.minInt(i32));
+
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
+
+ try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
+
+ try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000);
+ try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
+
+ try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000);
+
+ try test__fixdfsi(-0x1.000000p+31, -0x80000000);
+ try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
+ try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
+
+ try test__fixdfsi(-2.01, -2);
+ try test__fixdfsi(-2.0, -2);
+ try test__fixdfsi(-1.99, -1);
+ try test__fixdfsi(-1.0, -1);
+ try test__fixdfsi(-0.99, 0);
+ try test__fixdfsi(-0.5, 0);
+ try test__fixdfsi(-math.floatMin(f64), 0);
+ try test__fixdfsi(0.0, 0);
+ try test__fixdfsi(math.floatMin(f64), 0);
+ try test__fixdfsi(0.5, 0);
+ try test__fixdfsi(0.99, 0);
+ try test__fixdfsi(1.0, 1);
+ try test__fixdfsi(1.5, 1);
+ try test__fixdfsi(1.99, 1);
+ try test__fixdfsi(2.0, 2);
+ try test__fixdfsi(2.01, 2);
+
+ try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0);
+ try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF);
+
+ try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
+
+ try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
+
+ try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
+
+ try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
+ try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
+
+ try test__fixdfsi(math.floatMax(f64), math.maxInt(i32));
+}
+
+test "fixunsdfsi" {
+ try test__fixunsdfsi(0.0, 0);
+
+ try test__fixunsdfsi(0.5, 0);
+ try test__fixunsdfsi(0.99, 0);
+ try test__fixunsdfsi(1.0, 1);
+ try test__fixunsdfsi(1.5, 1);
+ try test__fixunsdfsi(1.99, 1);
+ try test__fixunsdfsi(2.0, 2);
+ try test__fixunsdfsi(2.01, 2);
+ try test__fixunsdfsi(-0.5, 0);
+ try test__fixunsdfsi(-0.99, 0);
+ try test__fixunsdfsi(-1.0, 0);
+ try test__fixunsdfsi(-1.5, 0);
+ try test__fixunsdfsi(-1.99, 0);
+ try test__fixunsdfsi(-2.0, 0);
+ try test__fixunsdfsi(-2.01, 0);
+
+ try test__fixunsdfsi(0x1.000000p+31, 0x80000000);
+ try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF);
+ try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00);
+ try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
+
+ try test__fixunsdfsi(-0x1.FFFFFEp+30, 0);
+ try test__fixunsdfsi(-0x1.FFFFFCp+30, 0);
+
+ try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF);
+ try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF);
+ try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE);
+}
+
+fn test__fixdfdi(a: f64, expected: i64) !void {
+ const x = __fixdfdi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunsdfdi(a: f64, expected: u64) !void {
+ const x = __fixunsdfdi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixdfdi" {
+ try test__fixdfdi(-math.floatMax(f64), math.minInt(i64));
+
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
+
+ try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000);
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
+
+ try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000);
+ try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
+ try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
+
+ try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000);
+ try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000);
+
+ try test__fixdfdi(-2.01, -2);
+ try test__fixdfdi(-2.0, -2);
+ try test__fixdfdi(-1.99, -1);
+ try test__fixdfdi(-1.0, -1);
+ try test__fixdfdi(-0.99, 0);
+ try test__fixdfdi(-0.5, 0);
+ try test__fixdfdi(-math.floatMin(f64), 0);
+ try test__fixdfdi(0.0, 0);
+ try test__fixdfdi(math.floatMin(f64), 0);
+ try test__fixdfdi(0.5, 0);
+ try test__fixdfdi(0.99, 0);
+ try test__fixdfdi(1.0, 1);
+ try test__fixdfdi(1.5, 1);
+ try test__fixdfdi(1.99, 1);
+ try test__fixdfdi(2.0, 2);
+ try test__fixdfdi(2.01, 2);
+
+ try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+
+ try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+ try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
+ try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
+ try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
+
+ try test__fixdfdi(math.floatMax(f64), math.maxInt(i64));
+}
+
+test "fixunsdfdi" {
+ try test__fixunsdfdi(0.0, 0);
+ try test__fixunsdfdi(0.5, 0);
+ try test__fixunsdfdi(0.99, 0);
+ try test__fixunsdfdi(1.0, 1);
+ try test__fixunsdfdi(1.5, 1);
+ try test__fixunsdfdi(1.99, 1);
+ try test__fixunsdfdi(2.0, 2);
+ try test__fixunsdfdi(2.01, 2);
+ try test__fixunsdfdi(-0.5, 0);
+ try test__fixunsdfdi(-0.99, 0);
+ try test__fixunsdfdi(-1.0, 0);
+ try test__fixunsdfdi(-1.5, 0);
+ try test__fixunsdfdi(-1.99, 0);
+ try test__fixunsdfdi(-2.0, 0);
+ try test__fixunsdfdi(-2.01, 0);
+
+ try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+
+ try test__fixunsdfdi(-0x1.FFFFFEp+62, 0);
+ try test__fixunsdfdi(-0x1.FFFFFCp+62, 0);
+
+ try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800);
+ try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000);
+ try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+
+ try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
+ try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
+}
+
+fn test__fixdfti(a: f64, expected: i128) !void {
+ const x = __fixdfti(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunsdfti(a: f64, expected: u128) !void {
+ const x = __fixunsdfti(a);
+ try testing.expect(x == expected);
+}
+
+test "fixdfti" {
+ try test__fixdfti(-math.floatMax(f64), math.minInt(i128));
+
+ try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
+ try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
+
+ try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
+ try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000);
+ try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000);
+
+ try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800);
+ try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
+ try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
+
+ try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
+ try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
+
+ try test__fixdfti(-2.01, -2);
+ try test__fixdfti(-2.0, -2);
+ try test__fixdfti(-1.99, -1);
+ try test__fixdfti(-1.0, -1);
+ try test__fixdfti(-0.99, 0);
+ try test__fixdfti(-0.5, 0);
+ try test__fixdfti(-math.floatMin(f64), 0);
+ try test__fixdfti(0.0, 0);
+ try test__fixdfti(math.floatMin(f64), 0);
+ try test__fixdfti(0.5, 0);
+ try test__fixdfti(0.99, 0);
+ try test__fixdfti(1.0, 1);
+ try test__fixdfti(1.5, 1);
+ try test__fixdfti(1.99, 1);
+ try test__fixdfti(2.0, 2);
+ try test__fixdfti(2.01, 2);
+
+ try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+
+ try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+ try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000);
+ try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800);
+
+ try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
+ try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
+ try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+
+ try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
+
+ try test__fixdfti(math.floatMax(f64), math.maxInt(i128));
+}
+
+test "fixunsdfti" {
+ try test__fixunsdfti(0.0, 0);
+
+ try test__fixunsdfti(0.5, 0);
+ try test__fixunsdfti(0.99, 0);
+ try test__fixunsdfti(1.0, 1);
+ try test__fixunsdfti(1.5, 1);
+ try test__fixunsdfti(1.99, 1);
+ try test__fixunsdfti(2.0, 2);
+ try test__fixunsdfti(2.01, 2);
+ try test__fixunsdfti(-0.5, 0);
+ try test__fixunsdfti(-0.99, 0);
+ try test__fixunsdfti(-1.0, 0);
+ try test__fixunsdfti(-1.5, 0);
+ try test__fixunsdfti(-1.99, 0);
+ try test__fixunsdfti(-2.0, 0);
+ try test__fixunsdfti(-2.01, 0);
+
+ try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+
+ try test__fixunsdfti(-0x1.FFFFFEp+62, 0);
+ try test__fixunsdfti(-0x1.FFFFFCp+62, 0);
+
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800);
+ try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000);
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000);
+ try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000);
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
+ try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
+ try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+
+ try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0);
+ try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0);
+}
+
+fn test__fixtfsi(a: f128, expected: i32) !void {
+ const x = __fixtfsi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunstfsi(a: f128, expected: u32) !void {
+ const x = __fixunstfsi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixtfsi" {
+ try test__fixtfsi(-math.floatMax(f128), math.minInt(i32));
+
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
+
+ try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
+
+ try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000);
+ try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
+
+ try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000);
+
+ try test__fixtfsi(-0x1.000000p+31, -0x80000000);
+ try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
+ try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
+ try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00);
+
+ try test__fixtfsi(-2.01, -2);
+ try test__fixtfsi(-2.0, -2);
+ try test__fixtfsi(-1.99, -1);
+ try test__fixtfsi(-1.0, -1);
+ try test__fixtfsi(-0.99, 0);
+ try test__fixtfsi(-0.5, 0);
+ try test__fixtfsi(-math.floatMin(f32), 0);
+ try test__fixtfsi(0.0, 0);
+ try test__fixtfsi(math.floatMin(f32), 0);
+ try test__fixtfsi(0.5, 0);
+ try test__fixtfsi(0.99, 0);
+ try test__fixtfsi(1.0, 1);
+ try test__fixtfsi(1.5, 1);
+ try test__fixtfsi(1.99, 1);
+ try test__fixtfsi(2.0, 2);
+ try test__fixtfsi(2.01, 2);
+
+ try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
+ try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0);
+ try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF);
+
+ try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
+
+ try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
+
+ try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
+
+ try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
+ try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
+
+ try test__fixtfsi(math.floatMax(f128), math.maxInt(i32));
+}
+
+test "fixunstfsi" {
+ try test__fixunstfsi(math.inf(f128), 0xffffffff);
+ try test__fixunstfsi(0, 0x0);
+ try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
+ try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0);
+ try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456);
+ try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff);
+ try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff);
+ try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0);
+
+ try test__fixunstfsi(0x1p+32, 0xFFFFFFFF);
+}
+
+fn test__fixtfdi(a: f128, expected: i64) !void {
+ const x = __fixtfdi(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunstfdi(a: f128, expected: u64) !void {
+ const x = __fixunstfdi(a);
+ try testing.expect(x == expected);
+}
+
+test "fixtfdi" {
+ try test__fixtfdi(-math.floatMax(f128), math.minInt(i64));
+
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
+
+ try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000);
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
+
+ try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000);
+ try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
+ try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
+
+ try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000);
+ try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000);
+
+ try test__fixtfdi(-0x1.000000p+31, -0x80000000);
+ try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
+ try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80);
+ try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00);
+
+ try test__fixtfdi(-2.01, -2);
+ try test__fixtfdi(-2.0, -2);
+ try test__fixtfdi(-1.99, -1);
+ try test__fixtfdi(-1.0, -1);
+ try test__fixtfdi(-0.99, 0);
+ try test__fixtfdi(-0.5, 0);
+ try test__fixtfdi(-math.floatMin(f64), 0);
+ try test__fixtfdi(0.0, 0);
+ try test__fixtfdi(math.floatMin(f64), 0);
+ try test__fixtfdi(0.5, 0);
+ try test__fixtfdi(0.99, 0);
+ try test__fixtfdi(1.0, 1);
+ try test__fixtfdi(1.5, 1);
+ try test__fixtfdi(1.99, 1);
+ try test__fixtfdi(2.0, 2);
+ try test__fixtfdi(2.01, 2);
+
+ try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00);
+ try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80);
+ try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0);
+ try test__fixtfdi(0x1.000000p+31, 0x80000000);
+
+ try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+
+ try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+ try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
+ try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
+ try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
+
+ try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
+ try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
+
+ try test__fixtfdi(math.floatMax(f128), math.maxInt(i64));
+}
+
+test "fixunstfdi" {
+ try test__fixunstfdi(0.0, 0);
+
+ try test__fixunstfdi(0.5, 0);
+ try test__fixunstfdi(0.99, 0);
+ try test__fixunstfdi(1.0, 1);
+ try test__fixunstfdi(1.5, 1);
+ try test__fixunstfdi(1.99, 1);
+ try test__fixunstfdi(2.0, 2);
+ try test__fixunstfdi(2.01, 2);
+ try test__fixunstfdi(-0.5, 0);
+ try test__fixunstfdi(-0.99, 0);
+ try test__fixunstfdi(-1.0, 0);
+ try test__fixunstfdi(-1.5, 0);
+ try test__fixunstfdi(-1.99, 0);
+ try test__fixunstfdi(-2.0, 0);
+ try test__fixunstfdi(-2.01, 0);
+
+ try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+ try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+
+ try test__fixunstfdi(-0x1.FFFFFEp+62, 0);
+ try test__fixunstfdi(-0x1.FFFFFCp+62, 0);
+
+ try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+
+ try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
+ try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
+
+ try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF);
+ try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001);
+ try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000);
+ try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF);
+ try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE);
+ try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF);
+
+ try test__fixunstfdi(-0x1.0000000000000000p+63, 0);
+ try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0);
+ try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0);
+}
+
+fn test__fixtfti(a: f128, expected: i128) !void {
+ const x = __fixtfti(a);
+ try testing.expect(x == expected);
+}
+
+fn test__fixunstfti(a: f128, expected: u128) !void {
+ const x = __fixunstfti(a);
+ try testing.expect(x == expected);
+}
+
+test "fixtfti" {
+ try test__fixtfti(-math.floatMax(f128), math.minInt(i128));
+
+ try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
+ try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
+
+ try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
+ try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000);
+ try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000);
+
+ try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800);
+ try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000);
+ try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
+ try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
+
+ try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
+ try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
+
+ try test__fixtfti(-2.01, -2);
+ try test__fixtfti(-2.0, -2);
+ try test__fixtfti(-1.99, -1);
+ try test__fixtfti(-1.0, -1);
+ try test__fixtfti(-0.99, 0);
+ try test__fixtfti(-0.5, 0);
+ try test__fixtfti(-math.floatMin(f128), 0);
+ try test__fixtfti(0.0, 0);
+ try test__fixtfti(math.floatMin(f128), 0);
+ try test__fixtfti(0.5, 0);
+ try test__fixtfti(0.99, 0);
+ try test__fixtfti(1.0, 1);
+ try test__fixtfti(1.5, 1);
+ try test__fixtfti(1.99, 1);
+ try test__fixtfti(2.0, 2);
+ try test__fixtfti(2.01, 2);
+
+ try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
+ try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
+
+ try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
+ try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
+ try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000);
+ try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800);
+
+ try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
+ try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
+ try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+
+ try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
+
+ try test__fixtfti(math.floatMax(f128), math.maxInt(i128));
+}
+
+test "fixunstfti" {
+ try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff);
+
+ try test__fixunstfti(0.0, 0);
+
+ try test__fixunstfti(0.5, 0);
+ try test__fixunstfti(0.99, 0);
+ try test__fixunstfti(1.0, 1);
+ try test__fixunstfti(1.5, 1);
+ try test__fixunstfti(1.99, 1);
+ try test__fixunstfti(2.0, 2);
+ try test__fixunstfti(2.01, 2);
+ try test__fixunstfti(-0.01, 0);
+ try test__fixunstfti(-0.99, 0);
+
+ try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff);
+
+ try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000);
+ try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000);
+ try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff);
+ try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff);
+}
+
+fn test__fixunshfti(a: f16, expected: u128) !void {
+ const x = fixXfYi(u128, a);
+ try testing.expect(x == expected);
+}
+
+test "fixXfYi for f16" {
+ try test__fixunshfti(math.inf(f16), math.maxInt(u128));
+ try test__fixunshfti(math.floatMax(f16), 65504);
+}
+
+fn test__fixunsxfti(a: f80, expected: u128) !void {
+ const x = fixXfYi(u128, a);
+ try testing.expect(x == expected);
+}
+
+test "fixXfYi for f80" {
+ try test__fixunsxfti(math.inf(f80), math.maxInt(u128));
+ try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128));
+ try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64));
+}
diff --git a/lib/std/special/compiler_rt/fixdfdi.zig b/lib/std/special/compiler_rt/fixdfdi.zig
deleted file mode 100644
index 6c69f10e09..0000000000
--- a/lib/std/special/compiler_rt/fixdfdi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixdfdi(a: f64) callconv(.C) i64 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f64, i64, a);
-}
-
-pub fn __aeabi_d2lz(arg: f64) callconv(.AAPCS) i64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixdfdi, .{arg});
-}
-
-test {
- _ = @import("fixdfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixdfdi_test.zig b/lib/std/special/compiler_rt/fixdfdi_test.zig
deleted file mode 100644
index ac2fdbe7ef..0000000000
--- a/lib/std/special/compiler_rt/fixdfdi_test.zig
+++ /dev/null
@@ -1,62 +0,0 @@
-const __fixdfdi = @import("fixdfdi.zig").__fixdfdi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixdfdi(a: f64, expected: i64) !void {
- const x = __fixdfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixdfdi" {
- try test__fixdfdi(-math.f64_max, math.minInt(i64));
-
- try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
- try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
-
- try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000);
- try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
- try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
-
- try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000);
- try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
- try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
-
- try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000);
- try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000);
-
- try test__fixdfdi(-2.01, -2);
- try test__fixdfdi(-2.0, -2);
- try test__fixdfdi(-1.99, -1);
- try test__fixdfdi(-1.0, -1);
- try test__fixdfdi(-0.99, 0);
- try test__fixdfdi(-0.5, 0);
- try test__fixdfdi(-math.f64_min, 0);
- try test__fixdfdi(0.0, 0);
- try test__fixdfdi(math.f64_min, 0);
- try test__fixdfdi(0.5, 0);
- try test__fixdfdi(0.99, 0);
- try test__fixdfdi(1.0, 1);
- try test__fixdfdi(1.5, 1);
- try test__fixdfdi(1.99, 1);
- try test__fixdfdi(2.0, 2);
- try test__fixdfdi(2.01, 2);
-
- try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
-
- try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
- try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
- try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
- try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
-
- try test__fixdfdi(math.f64_max, math.maxInt(i64));
-}
diff --git a/lib/std/special/compiler_rt/fixdfsi.zig b/lib/std/special/compiler_rt/fixdfsi.zig
deleted file mode 100644
index 5842d99cd3..0000000000
--- a/lib/std/special/compiler_rt/fixdfsi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixdfsi(a: f64) callconv(.C) i32 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f64, i32, a);
-}
-
-pub fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixdfsi, .{a});
-}
-
-test {
- _ = @import("fixdfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixdfsi_test.zig b/lib/std/special/compiler_rt/fixdfsi_test.zig
deleted file mode 100644
index 39d4f64369..0000000000
--- a/lib/std/special/compiler_rt/fixdfsi_test.zig
+++ /dev/null
@@ -1,70 +0,0 @@
-const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixdfsi(a: f64, expected: i32) !void {
- const x = __fixdfsi(a);
- try testing.expect(x == expected);
-}
-
-test "fixdfsi" {
- try test__fixdfsi(-math.f64_max, math.minInt(i32));
-
- try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
- try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
-
- try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
-
- try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000);
- try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
-
- try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000);
-
- try test__fixdfsi(-0x1.000000p+31, -0x80000000);
- try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
- try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
-
- try test__fixdfsi(-2.01, -2);
- try test__fixdfsi(-2.0, -2);
- try test__fixdfsi(-1.99, -1);
- try test__fixdfsi(-1.0, -1);
- try test__fixdfsi(-0.99, 0);
- try test__fixdfsi(-0.5, 0);
- try test__fixdfsi(-math.f64_min, 0);
- try test__fixdfsi(0.0, 0);
- try test__fixdfsi(math.f64_min, 0);
- try test__fixdfsi(0.5, 0);
- try test__fixdfsi(0.99, 0);
- try test__fixdfsi(1.0, 1);
- try test__fixdfsi(1.5, 1);
- try test__fixdfsi(1.99, 1);
- try test__fixdfsi(2.0, 2);
- try test__fixdfsi(2.01, 2);
-
- try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0);
- try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF);
-
- try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
- try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
-
- try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
- try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
- try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
- try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
-
- try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
- try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
- try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
-
- try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
- try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
-
- try test__fixdfsi(math.f64_max, math.maxInt(i32));
-}
diff --git a/lib/std/special/compiler_rt/fixdfti.zig b/lib/std/special/compiler_rt/fixdfti.zig
deleted file mode 100644
index e8af6a2daf..0000000000
--- a/lib/std/special/compiler_rt/fixdfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixdfti(a: f64) callconv(.C) i128 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f64, i128, a);
-}
-
-test {
- _ = @import("fixdfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixdfti_test.zig b/lib/std/special/compiler_rt/fixdfti_test.zig
deleted file mode 100644
index eb8269b0ea..0000000000
--- a/lib/std/special/compiler_rt/fixdfti_test.zig
+++ /dev/null
@@ -1,62 +0,0 @@
-const __fixdfti = @import("fixdfti.zig").__fixdfti;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixdfti(a: f64, expected: i128) !void {
- const x = __fixdfti(a);
- try testing.expect(x == expected);
-}
-
-test "fixdfti" {
- try test__fixdfti(-math.f64_max, math.minInt(i128));
-
- try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
- try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
-
- try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
- try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000);
- try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000);
-
- try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800);
- try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
- try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
-
- try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
- try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
-
- try test__fixdfti(-2.01, -2);
- try test__fixdfti(-2.0, -2);
- try test__fixdfti(-1.99, -1);
- try test__fixdfti(-1.0, -1);
- try test__fixdfti(-0.99, 0);
- try test__fixdfti(-0.5, 0);
- try test__fixdfti(-math.f64_min, 0);
- try test__fixdfti(0.0, 0);
- try test__fixdfti(math.f64_min, 0);
- try test__fixdfti(0.5, 0);
- try test__fixdfti(0.99, 0);
- try test__fixdfti(1.0, 1);
- try test__fixdfti(1.5, 1);
- try test__fixdfti(1.99, 1);
- try test__fixdfti(2.0, 2);
- try test__fixdfti(2.01, 2);
-
- try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
-
- try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
- try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000);
- try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800);
-
- try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
- try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
- try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-
- try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
-
- try test__fixdfti(math.f64_max, math.maxInt(i128));
-}
diff --git a/lib/std/special/compiler_rt/fixint.zig b/lib/std/special/compiler_rt/fixint.zig
deleted file mode 100644
index ff0577c115..0000000000
--- a/lib/std/special/compiler_rt/fixint.zig
+++ /dev/null
@@ -1,75 +0,0 @@
-const is_test = @import("builtin").is_test;
-const std = @import("std");
-const math = std.math;
-const Log2Int = std.math.Log2Int;
-const maxInt = std.math.maxInt;
-const minInt = std.math.minInt;
-
-const DBG = false;
-
-pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t {
- @setRuntimeSafety(is_test);
-
- const rep_t = switch (fp_t) {
- f32 => u32,
- f64 => u64,
- f128 => u128,
- else => unreachable,
- };
- const significandBits = switch (fp_t) {
- f32 => 23,
- f64 => 52,
- f128 => 112,
- else => unreachable,
- };
-
- const typeWidth = @typeInfo(rep_t).Int.bits;
- const exponentBits = (typeWidth - significandBits - 1);
- const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
- const maxExponent = ((1 << exponentBits) - 1);
- const exponentBias = (maxExponent >> 1);
-
- const implicitBit = (@as(rep_t, 1) << significandBits);
- const significandMask = (implicitBit - 1);
-
- // Break a into sign, exponent, significand
- const aRep: rep_t = @bitCast(rep_t, a);
- const absMask = signBit - 1;
- const aAbs: rep_t = aRep & absMask;
-
- const negative = (aRep & signBit) != 0;
- const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
- const significand: rep_t = (aAbs & significandMask) | implicitBit;
-
- // If exponent is negative, the uint_result is zero.
- if (exponent < 0) return 0;
-
- // The unsigned result needs to be large enough to handle an fixint_t or rep_t
- const fixint_bits = @typeInfo(fixint_t).Int.bits;
- const fixuint_t = std.meta.Int(.unsigned, fixint_bits);
- const UintResultType = if (fixint_bits > typeWidth) fixuint_t else rep_t;
- var uint_result: UintResultType = undefined;
-
- // If the value is too large for the integer type, saturate.
- if (@intCast(usize, exponent) >= fixint_bits) {
- return if (negative) @as(fixint_t, minInt(fixint_t)) else @as(fixint_t, maxInt(fixint_t));
- }
-
- // If 0 <= exponent < significandBits, right shift else left shift
- if (exponent < significandBits) {
- uint_result = @intCast(UintResultType, significand) >> @intCast(Log2Int(UintResultType), significandBits - exponent);
- } else {
- uint_result = @intCast(UintResultType, significand) << @intCast(Log2Int(UintResultType), exponent - significandBits);
- }
-
- // Cast to final signed result
- if (negative) {
- return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result);
- } else {
- return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result);
- }
-}
-
-test {
- _ = @import("fixint_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixint_test.zig b/lib/std/special/compiler_rt/fixint_test.zig
index 9c31444ac5..57b4093809 100644
--- a/lib/std/special/compiler_rt/fixint_test.zig
+++ b/lib/std/special/compiler_rt/fixint_test.zig
@@ -11,49 +11,49 @@ fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected:
}
test "fixint.i1" {
- try test__fixint(f32, i1, -math.inf_f32, -1);
- try test__fixint(f32, i1, -math.f32_max, -1);
+ try test__fixint(f32, i1, -math.inf(f32), -1);
+ try test__fixint(f32, i1, -math.floatMax(f32), -1);
try test__fixint(f32, i1, -2.0, -1);
try test__fixint(f32, i1, -1.1, -1);
try test__fixint(f32, i1, -1.0, -1);
try test__fixint(f32, i1, -0.9, 0);
try test__fixint(f32, i1, -0.1, 0);
- try test__fixint(f32, i1, -math.f32_min, 0);
+ try test__fixint(f32, i1, -math.floatMin(f32), 0);
try test__fixint(f32, i1, -0.0, 0);
try test__fixint(f32, i1, 0.0, 0);
- try test__fixint(f32, i1, math.f32_min, 0);
+ try test__fixint(f32, i1, math.floatMin(f32), 0);
try test__fixint(f32, i1, 0.1, 0);
try test__fixint(f32, i1, 0.9, 0);
try test__fixint(f32, i1, 1.0, 0);
try test__fixint(f32, i1, 2.0, 0);
- try test__fixint(f32, i1, math.f32_max, 0);
- try test__fixint(f32, i1, math.inf_f32, 0);
+ try test__fixint(f32, i1, math.floatMax(f32), 0);
+ try test__fixint(f32, i1, math.inf(f32), 0);
}
test "fixint.i2" {
- try test__fixint(f32, i2, -math.inf_f32, -2);
- try test__fixint(f32, i2, -math.f32_max, -2);
+ try test__fixint(f32, i2, -math.inf(f32), -2);
+ try test__fixint(f32, i2, -math.floatMax(f32), -2);
try test__fixint(f32, i2, -2.0, -2);
try test__fixint(f32, i2, -1.9, -1);
try test__fixint(f32, i2, -1.1, -1);
try test__fixint(f32, i2, -1.0, -1);
try test__fixint(f32, i2, -0.9, 0);
try test__fixint(f32, i2, -0.1, 0);
- try test__fixint(f32, i2, -math.f32_min, 0);
+ try test__fixint(f32, i2, -math.floatMin(f32), 0);
try test__fixint(f32, i2, -0.0, 0);
try test__fixint(f32, i2, 0.0, 0);
- try test__fixint(f32, i2, math.f32_min, 0);
+ try test__fixint(f32, i2, math.floatMin(f32), 0);
try test__fixint(f32, i2, 0.1, 0);
try test__fixint(f32, i2, 0.9, 0);
try test__fixint(f32, i2, 1.0, 1);
try test__fixint(f32, i2, 2.0, 1);
- try test__fixint(f32, i2, math.f32_max, 1);
- try test__fixint(f32, i2, math.inf_f32, 1);
+ try test__fixint(f32, i2, math.floatMax(f32), 1);
+ try test__fixint(f32, i2, math.inf(f32), 1);
}
test "fixint.i3" {
- try test__fixint(f32, i3, -math.inf_f32, -4);
- try test__fixint(f32, i3, -math.f32_max, -4);
+ try test__fixint(f32, i3, -math.inf(f32), -4);
+ try test__fixint(f32, i3, -math.floatMax(f32), -4);
try test__fixint(f32, i3, -4.0, -4);
try test__fixint(f32, i3, -3.0, -3);
try test__fixint(f32, i3, -2.0, -2);
@@ -62,23 +62,23 @@ test "fixint.i3" {
try test__fixint(f32, i3, -1.0, -1);
try test__fixint(f32, i3, -0.9, 0);
try test__fixint(f32, i3, -0.1, 0);
- try test__fixint(f32, i3, -math.f32_min, 0);
+ try test__fixint(f32, i3, -math.floatMin(f32), 0);
try test__fixint(f32, i3, -0.0, 0);
try test__fixint(f32, i3, 0.0, 0);
- try test__fixint(f32, i3, math.f32_min, 0);
+ try test__fixint(f32, i3, math.floatMin(f32), 0);
try test__fixint(f32, i3, 0.1, 0);
try test__fixint(f32, i3, 0.9, 0);
try test__fixint(f32, i3, 1.0, 1);
try test__fixint(f32, i3, 2.0, 2);
try test__fixint(f32, i3, 3.0, 3);
try test__fixint(f32, i3, 4.0, 3);
- try test__fixint(f32, i3, math.f32_max, 3);
- try test__fixint(f32, i3, math.inf_f32, 3);
+ try test__fixint(f32, i3, math.floatMax(f32), 3);
+ try test__fixint(f32, i3, math.inf(f32), 3);
}
test "fixint.i32" {
- try test__fixint(f64, i32, -math.inf_f64, math.minInt(i32));
- try test__fixint(f64, i32, -math.f64_max, math.minInt(i32));
+ try test__fixint(f64, i32, -math.inf(f64), math.minInt(i32));
+ try test__fixint(f64, i32, -math.floatMax(f64), math.minInt(i32));
try test__fixint(f64, i32, @as(f64, math.minInt(i32)), math.minInt(i32));
try test__fixint(f64, i32, @as(f64, math.minInt(i32)) + 1, math.minInt(i32) + 1);
try test__fixint(f64, i32, -2.0, -2);
@@ -87,22 +87,22 @@ test "fixint.i32" {
try test__fixint(f64, i32, -1.0, -1);
try test__fixint(f64, i32, -0.9, 0);
try test__fixint(f64, i32, -0.1, 0);
- try test__fixint(f64, i32, -math.f32_min, 0);
+ try test__fixint(f64, i32, -@as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i32, -0.0, 0);
try test__fixint(f64, i32, 0.0, 0);
- try test__fixint(f64, i32, math.f32_min, 0);
+ try test__fixint(f64, i32, @as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i32, 0.1, 0);
try test__fixint(f64, i32, 0.9, 0);
try test__fixint(f64, i32, 1.0, 1);
try test__fixint(f64, i32, @as(f64, math.maxInt(i32)) - 1, math.maxInt(i32) - 1);
try test__fixint(f64, i32, @as(f64, math.maxInt(i32)), math.maxInt(i32));
- try test__fixint(f64, i32, math.f64_max, math.maxInt(i32));
- try test__fixint(f64, i32, math.inf_f64, math.maxInt(i32));
+ try test__fixint(f64, i32, math.floatMax(f64), math.maxInt(i32));
+ try test__fixint(f64, i32, math.inf(f64), math.maxInt(i32));
}
test "fixint.i64" {
- try test__fixint(f64, i64, -math.inf_f64, math.minInt(i64));
- try test__fixint(f64, i64, -math.f64_max, math.minInt(i64));
+ try test__fixint(f64, i64, -math.inf(f64), math.minInt(i64));
+ try test__fixint(f64, i64, -math.floatMax(f64), math.minInt(i64));
try test__fixint(f64, i64, @as(f64, math.minInt(i64)), math.minInt(i64));
try test__fixint(f64, i64, @as(f64, math.minInt(i64)) + 1, math.minInt(i64));
try test__fixint(f64, i64, @as(f64, math.minInt(i64) / 2), math.minInt(i64) / 2);
@@ -112,22 +112,22 @@ test "fixint.i64" {
try test__fixint(f64, i64, -1.0, -1);
try test__fixint(f64, i64, -0.9, 0);
try test__fixint(f64, i64, -0.1, 0);
- try test__fixint(f64, i64, -math.f32_min, 0);
+ try test__fixint(f64, i64, -@as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i64, -0.0, 0);
try test__fixint(f64, i64, 0.0, 0);
- try test__fixint(f64, i64, math.f32_min, 0);
+ try test__fixint(f64, i64, @as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i64, 0.1, 0);
try test__fixint(f64, i64, 0.9, 0);
try test__fixint(f64, i64, 1.0, 1);
try test__fixint(f64, i64, @as(f64, math.maxInt(i64)) - 1, math.maxInt(i64));
try test__fixint(f64, i64, @as(f64, math.maxInt(i64)), math.maxInt(i64));
- try test__fixint(f64, i64, math.f64_max, math.maxInt(i64));
- try test__fixint(f64, i64, math.inf_f64, math.maxInt(i64));
+ try test__fixint(f64, i64, math.floatMax(f64), math.maxInt(i64));
+ try test__fixint(f64, i64, math.inf(f64), math.maxInt(i64));
}
test "fixint.i128" {
- try test__fixint(f64, i128, -math.inf_f64, math.minInt(i128));
- try test__fixint(f64, i128, -math.f64_max, math.minInt(i128));
+ try test__fixint(f64, i128, -math.inf(f64), math.minInt(i128));
+ try test__fixint(f64, i128, -math.floatMax(f64), math.minInt(i128));
try test__fixint(f64, i128, @as(f64, math.minInt(i128)), math.minInt(i128));
try test__fixint(f64, i128, @as(f64, math.minInt(i128)) + 1, math.minInt(i128));
try test__fixint(f64, i128, -2.0, -2);
@@ -136,15 +136,15 @@ test "fixint.i128" {
try test__fixint(f64, i128, -1.0, -1);
try test__fixint(f64, i128, -0.9, 0);
try test__fixint(f64, i128, -0.1, 0);
- try test__fixint(f64, i128, -math.f32_min, 0);
+ try test__fixint(f64, i128, -@as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i128, -0.0, 0);
try test__fixint(f64, i128, 0.0, 0);
- try test__fixint(f64, i128, math.f32_min, 0);
+ try test__fixint(f64, i128, @as(f64, math.floatMin(f32)), 0);
try test__fixint(f64, i128, 0.1, 0);
try test__fixint(f64, i128, 0.9, 0);
try test__fixint(f64, i128, 1.0, 1);
try test__fixint(f64, i128, @as(f64, math.maxInt(i128)) - 1, math.maxInt(i128));
try test__fixint(f64, i128, @as(f64, math.maxInt(i128)), math.maxInt(i128));
- try test__fixint(f64, i128, math.f64_max, math.maxInt(i128));
- try test__fixint(f64, i128, math.inf_f64, math.maxInt(i128));
+ try test__fixint(f64, i128, math.floatMax(f64), math.maxInt(i128));
+ try test__fixint(f64, i128, math.inf(f64), math.maxInt(i128));
}
diff --git a/lib/std/special/compiler_rt/fixsfdi.zig b/lib/std/special/compiler_rt/fixsfdi.zig
deleted file mode 100644
index 64961075d0..0000000000
--- a/lib/std/special/compiler_rt/fixsfdi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixsfdi(a: f32) callconv(.C) i64 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f32, i64, a);
-}
-
-pub fn __aeabi_f2lz(arg: f32) callconv(.AAPCS) i64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixsfdi, .{arg});
-}
-
-test {
- _ = @import("fixsfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixsfdi_test.zig b/lib/std/special/compiler_rt/fixsfdi_test.zig
deleted file mode 100644
index 95f56bd29e..0000000000
--- a/lib/std/special/compiler_rt/fixsfdi_test.zig
+++ /dev/null
@@ -1,64 +0,0 @@
-const __fixsfdi = @import("fixsfdi.zig").__fixsfdi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixsfdi(a: f32, expected: i64) !void {
- const x = __fixsfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixsfdi" {
- try test__fixsfdi(-math.f32_max, math.minInt(i64));
-
- try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
- try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
-
- try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000);
- try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
- try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
-
- try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000);
- try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000);
- try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000);
-
- try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000);
- try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000);
- try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000);
-
- try test__fixsfdi(-2.01, -2);
- try test__fixsfdi(-2.0, -2);
- try test__fixsfdi(-1.99, -1);
- try test__fixsfdi(-1.0, -1);
- try test__fixsfdi(-0.99, 0);
- try test__fixsfdi(-0.5, 0);
- try test__fixsfdi(-math.f32_min, 0);
- try test__fixsfdi(0.0, 0);
- try test__fixsfdi(math.f32_min, 0);
- try test__fixsfdi(0.5, 0);
- try test__fixsfdi(0.99, 0);
- try test__fixsfdi(1.0, 1);
- try test__fixsfdi(1.5, 1);
- try test__fixsfdi(1.99, 1);
- try test__fixsfdi(2.0, 2);
- try test__fixsfdi(2.01, 2);
-
- try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
- try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
-
- try test__fixsfdi(math.f64_max, math.maxInt(i64));
-}
diff --git a/lib/std/special/compiler_rt/fixsfsi.zig b/lib/std/special/compiler_rt/fixsfsi.zig
deleted file mode 100644
index 932a6e1a4f..0000000000
--- a/lib/std/special/compiler_rt/fixsfsi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixsfsi(a: f32) callconv(.C) i32 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f32, i32, a);
-}
-
-pub fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixsfsi, .{a});
-}
-
-test {
- _ = @import("fixsfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixsfsi_test.zig b/lib/std/special/compiler_rt/fixsfsi_test.zig
deleted file mode 100644
index 9ea1aafb3e..0000000000
--- a/lib/std/special/compiler_rt/fixsfsi_test.zig
+++ /dev/null
@@ -1,72 +0,0 @@
-const __fixsfsi = @import("fixsfsi.zig").__fixsfsi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixsfsi(a: f32, expected: i32) !void {
- const x = __fixsfsi(a);
- try testing.expect(x == expected);
-}
-
-test "fixsfsi" {
- try test__fixsfsi(-math.f32_max, math.minInt(i32));
-
- try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
- try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
-
- try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
-
- try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000);
- try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
-
- try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000);
-
- try test__fixsfsi(-0x1.000000p+31, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000);
- try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
- try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00);
-
- try test__fixsfsi(-2.01, -2);
- try test__fixsfsi(-2.0, -2);
- try test__fixsfsi(-1.99, -1);
- try test__fixsfsi(-1.0, -1);
- try test__fixsfsi(-0.99, 0);
- try test__fixsfsi(-0.5, 0);
- try test__fixsfsi(-math.f32_min, 0);
- try test__fixsfsi(0.0, 0);
- try test__fixsfsi(math.f32_min, 0);
- try test__fixsfsi(0.5, 0);
- try test__fixsfsi(0.99, 0);
- try test__fixsfsi(1.0, 1);
- try test__fixsfsi(1.5, 1);
- try test__fixsfsi(1.99, 1);
- try test__fixsfsi(2.0, 2);
- try test__fixsfsi(2.01, 2);
-
- try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
- try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF);
- try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF);
-
- try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
- try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
-
- try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
- try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
- try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
- try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
-
- try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
- try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
- try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
-
- try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
- try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
-
- try test__fixsfsi(math.f32_max, math.maxInt(i32));
-}
diff --git a/lib/std/special/compiler_rt/fixsfti.zig b/lib/std/special/compiler_rt/fixsfti.zig
deleted file mode 100644
index e67bbabbd7..0000000000
--- a/lib/std/special/compiler_rt/fixsfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixsfti(a: f32) callconv(.C) i128 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f32, i128, a);
-}
-
-test {
- _ = @import("fixsfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixsfti_test.zig b/lib/std/special/compiler_rt/fixsfti_test.zig
deleted file mode 100644
index 8f29d9ea06..0000000000
--- a/lib/std/special/compiler_rt/fixsfti_test.zig
+++ /dev/null
@@ -1,80 +0,0 @@
-const __fixsfti = @import("fixsfti.zig").__fixsfti;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixsfti(a: f32, expected: i128) !void {
- const x = __fixsfti(a);
- try testing.expect(x == expected);
-}
-
-test "fixsfti" {
- try test__fixsfti(-math.f32_max, math.minInt(i128));
-
- try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
- try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
-
- try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
- try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000);
- try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000);
- try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000);
- try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000);
- try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000);
-
- try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000);
- try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000);
- try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000);
-
- try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000);
- try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
- try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
-
- try test__fixsfti(-0x1.000000p+31, -0x80000000);
- try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000);
- try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80);
- try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00);
-
- try test__fixsfti(-2.01, -2);
- try test__fixsfti(-2.0, -2);
- try test__fixsfti(-1.99, -1);
- try test__fixsfti(-1.0, -1);
- try test__fixsfti(-0.99, 0);
- try test__fixsfti(-0.5, 0);
- try test__fixsfti(-math.f32_min, 0);
- try test__fixsfti(0.0, 0);
- try test__fixsfti(math.f32_min, 0);
- try test__fixsfti(0.5, 0);
- try test__fixsfti(0.99, 0);
- try test__fixsfti(1.0, 1);
- try test__fixsfti(1.5, 1);
- try test__fixsfti(1.99, 1);
- try test__fixsfti(2.0, 2);
- try test__fixsfti(2.01, 2);
-
- try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00);
- try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixsfti(0x1.FFFFFFp+30, 0x80000000);
- try test__fixsfti(0x1.000000p+31, 0x80000000);
-
- try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000);
-
- try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000);
- try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000);
- try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000);
- try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000);
-
- try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000);
- try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000);
- try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-
- try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
-
- try test__fixsfti(math.f32_max, math.maxInt(i128));
-}
diff --git a/lib/std/special/compiler_rt/fixtfdi.zig b/lib/std/special/compiler_rt/fixtfdi.zig
deleted file mode 100644
index 6087d7e720..0000000000
--- a/lib/std/special/compiler_rt/fixtfdi.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixtfdi(a: f128) callconv(.C) i64 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f128, i64, a);
-}
-
-test {
- _ = @import("fixtfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixtfdi_test.zig b/lib/std/special/compiler_rt/fixtfdi_test.zig
deleted file mode 100644
index 5e43a85408..0000000000
--- a/lib/std/special/compiler_rt/fixtfdi_test.zig
+++ /dev/null
@@ -1,72 +0,0 @@
-const __fixtfdi = @import("fixtfdi.zig").__fixtfdi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixtfdi(a: f128, expected: i64) !void {
- const x = __fixtfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixtfdi" {
- try test__fixtfdi(-math.f128_max, math.minInt(i64));
-
- try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
- try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
-
- try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000);
- try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
- try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
-
- try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000);
- try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
- try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
-
- try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000);
- try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000);
-
- try test__fixtfdi(-0x1.000000p+31, -0x80000000);
- try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
- try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80);
- try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00);
-
- try test__fixtfdi(-2.01, -2);
- try test__fixtfdi(-2.0, -2);
- try test__fixtfdi(-1.99, -1);
- try test__fixtfdi(-1.0, -1);
- try test__fixtfdi(-0.99, 0);
- try test__fixtfdi(-0.5, 0);
- try test__fixtfdi(-math.f64_min, 0);
- try test__fixtfdi(0.0, 0);
- try test__fixtfdi(math.f64_min, 0);
- try test__fixtfdi(0.5, 0);
- try test__fixtfdi(0.99, 0);
- try test__fixtfdi(1.0, 1);
- try test__fixtfdi(1.5, 1);
- try test__fixtfdi(1.99, 1);
- try test__fixtfdi(2.0, 2);
- try test__fixtfdi(2.01, 2);
-
- try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00);
- try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0);
- try test__fixtfdi(0x1.000000p+31, 0x80000000);
-
- try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
-
- try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
- try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
- try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
- try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
-
- try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
- try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
-
- try test__fixtfdi(math.f128_max, math.maxInt(i64));
-}
diff --git a/lib/std/special/compiler_rt/fixtfsi.zig b/lib/std/special/compiler_rt/fixtfsi.zig
deleted file mode 100644
index b5fea97c5c..0000000000
--- a/lib/std/special/compiler_rt/fixtfsi.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixtfsi(a: f128) callconv(.C) i32 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f128, i32, a);
-}
-
-test {
- _ = @import("fixtfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixtfsi_test.zig b/lib/std/special/compiler_rt/fixtfsi_test.zig
deleted file mode 100644
index f00c4735d6..0000000000
--- a/lib/std/special/compiler_rt/fixtfsi_test.zig
+++ /dev/null
@@ -1,72 +0,0 @@
-const __fixtfsi = @import("fixtfsi.zig").__fixtfsi;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixtfsi(a: f128, expected: i32) !void {
- const x = __fixtfsi(a);
- try testing.expect(x == expected);
-}
-
-test "fixtfsi" {
- try test__fixtfsi(-math.f128_max, math.minInt(i32));
-
- try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
- try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
-
- try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
-
- try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000);
- try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
-
- try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000);
-
- try test__fixtfsi(-0x1.000000p+31, -0x80000000);
- try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
- try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
- try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00);
-
- try test__fixtfsi(-2.01, -2);
- try test__fixtfsi(-2.0, -2);
- try test__fixtfsi(-1.99, -1);
- try test__fixtfsi(-1.0, -1);
- try test__fixtfsi(-0.99, 0);
- try test__fixtfsi(-0.5, 0);
- try test__fixtfsi(-math.f32_min, 0);
- try test__fixtfsi(0.0, 0);
- try test__fixtfsi(math.f32_min, 0);
- try test__fixtfsi(0.5, 0);
- try test__fixtfsi(0.99, 0);
- try test__fixtfsi(1.0, 1);
- try test__fixtfsi(1.5, 1);
- try test__fixtfsi(1.99, 1);
- try test__fixtfsi(2.0, 2);
- try test__fixtfsi(2.01, 2);
-
- try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
- try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0);
- try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF);
-
- try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
- try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
-
- try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
- try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
- try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
- try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
-
- try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
- try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
- try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
-
- try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
- try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
-
- try test__fixtfsi(math.f128_max, math.maxInt(i32));
-}
diff --git a/lib/std/special/compiler_rt/fixtfti.zig b/lib/std/special/compiler_rt/fixtfti.zig
deleted file mode 100644
index 5a001d0b69..0000000000
--- a/lib/std/special/compiler_rt/fixtfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixint = @import("fixint.zig").fixint;
-const builtin = @import("builtin");
-
-pub fn __fixtfti(a: f128) callconv(.C) i128 {
- @setRuntimeSafety(builtin.is_test);
- return fixint(f128, i128, a);
-}
-
-test {
- _ = @import("fixtfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixtfti_test.zig b/lib/std/special/compiler_rt/fixtfti_test.zig
deleted file mode 100644
index 3bb113e46b..0000000000
--- a/lib/std/special/compiler_rt/fixtfti_test.zig
+++ /dev/null
@@ -1,62 +0,0 @@
-const __fixtfti = @import("fixtfti.zig").__fixtfti;
-const std = @import("std");
-const math = std.math;
-const testing = std.testing;
-
-fn test__fixtfti(a: f128, expected: i128) !void {
- const x = __fixtfti(a);
- try testing.expect(x == expected);
-}
-
-test "fixtfti" {
- try test__fixtfti(-math.f128_max, math.minInt(i128));
-
- try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
- try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
-
- try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
- try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000);
- try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000);
-
- try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800);
- try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000);
- try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
- try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
-
- try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
- try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
-
- try test__fixtfti(-2.01, -2);
- try test__fixtfti(-2.0, -2);
- try test__fixtfti(-1.99, -1);
- try test__fixtfti(-1.0, -1);
- try test__fixtfti(-0.99, 0);
- try test__fixtfti(-0.5, 0);
- try test__fixtfti(-math.f128_min, 0);
- try test__fixtfti(0.0, 0);
- try test__fixtfti(math.f128_min, 0);
- try test__fixtfti(0.5, 0);
- try test__fixtfti(0.99, 0);
- try test__fixtfti(1.0, 1);
- try test__fixtfti(1.5, 1);
- try test__fixtfti(1.99, 1);
- try test__fixtfti(2.0, 2);
- try test__fixtfti(2.01, 2);
-
- try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
-
- try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
- try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000);
- try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800);
-
- try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
- try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
- try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-
- try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
-
- try test__fixtfti(math.f128_max, math.maxInt(i128));
-}
diff --git a/lib/std/special/compiler_rt/fixuint.zig b/lib/std/special/compiler_rt/fixuint.zig
deleted file mode 100644
index 6bfbcf6d65..0000000000
--- a/lib/std/special/compiler_rt/fixuint.zig
+++ /dev/null
@@ -1,50 +0,0 @@
-const is_test = @import("builtin").is_test;
-const Log2Int = @import("std").math.Log2Int;
-
-pub inline fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {
- @setRuntimeSafety(is_test);
-
- const rep_t = switch (fp_t) {
- f32 => u32,
- f64 => u64,
- f128 => u128,
- else => unreachable,
- };
- const typeWidth = @typeInfo(rep_t).Int.bits;
- const significandBits = switch (fp_t) {
- f32 => 23,
- f64 => 52,
- f128 => 112,
- else => unreachable,
- };
- const exponentBits = (typeWidth - significandBits - 1);
- const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
- const maxExponent = ((1 << exponentBits) - 1);
- const exponentBias = (maxExponent >> 1);
-
- const implicitBit = (@as(rep_t, 1) << significandBits);
- const significandMask = (implicitBit - 1);
-
- // Break a into sign, exponent, significand
- const aRep: rep_t = @bitCast(rep_t, a);
- const absMask = signBit - 1;
- const aAbs: rep_t = aRep & absMask;
-
- const sign = if ((aRep & signBit) != 0) @as(i32, -1) else @as(i32, 1);
- const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
- const significand: rep_t = (aAbs & significandMask) | implicitBit;
-
- // If either the value or the exponent is negative, the result is zero.
- if (sign == -1 or exponent < 0) return 0;
-
- // If the value is too large for the integer type, saturate.
- if (@intCast(c_uint, exponent) >= @typeInfo(fixuint_t).Int.bits) return ~@as(fixuint_t, 0);
-
- // If 0 <= exponent < significandBits, right shift to get the result.
- // Otherwise, shift left.
- if (exponent < significandBits) {
- return @intCast(fixuint_t, significand >> @intCast(Log2Int(rep_t), significandBits - exponent));
- } else {
- return @intCast(fixuint_t, significand) << @intCast(Log2Int(fixuint_t), exponent - significandBits);
- }
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfdi.zig b/lib/std/special/compiler_rt/fixunsdfdi.zig
deleted file mode 100644
index c864f0f6c2..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfdi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunsdfdi(a: f64) callconv(.C) u64 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f64, u64, a);
-}
-
-pub fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixunsdfdi, .{a});
-}
-
-test {
- _ = @import("fixunsdfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfdi_test.zig b/lib/std/special/compiler_rt/fixunsdfdi_test.zig
deleted file mode 100644
index 59591cf181..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfdi_test.zig
+++ /dev/null
@@ -1,39 +0,0 @@
-const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
-const testing = @import("std").testing;
-
-fn test__fixunsdfdi(a: f64, expected: u64) !void {
- const x = __fixunsdfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixunsdfdi" {
- //test__fixunsdfdi(0.0, 0);
- //test__fixunsdfdi(0.5, 0);
- //test__fixunsdfdi(0.99, 0);
- try test__fixunsdfdi(1.0, 1);
- try test__fixunsdfdi(1.5, 1);
- try test__fixunsdfdi(1.99, 1);
- try test__fixunsdfdi(2.0, 2);
- try test__fixunsdfdi(2.01, 2);
- try test__fixunsdfdi(-0.5, 0);
- try test__fixunsdfdi(-0.99, 0);
- try test__fixunsdfdi(-1.0, 0);
- try test__fixunsdfdi(-1.5, 0);
- try test__fixunsdfdi(-1.99, 0);
- try test__fixunsdfdi(-2.0, 0);
- try test__fixunsdfdi(-2.01, 0);
-
- try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
-
- try test__fixunsdfdi(-0x1.FFFFFEp+62, 0);
- try test__fixunsdfdi(-0x1.FFFFFCp+62, 0);
-
- try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800);
- try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000);
- try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
-
- try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
- try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfsi.zig b/lib/std/special/compiler_rt/fixunsdfsi.zig
deleted file mode 100644
index c1f5173661..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfsi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunsdfsi(a: f64) callconv(.C) u32 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f64, u32, a);
-}
-
-pub fn __aeabi_d2uiz(arg: f64) callconv(.AAPCS) u32 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixunsdfsi, .{arg});
-}
-
-test {
- _ = @import("fixunsdfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfsi_test.zig b/lib/std/special/compiler_rt/fixunsdfsi_test.zig
deleted file mode 100644
index b4b7ec8840..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfsi_test.zig
+++ /dev/null
@@ -1,39 +0,0 @@
-const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
-const testing = @import("std").testing;
-
-fn test__fixunsdfsi(a: f64, expected: u32) !void {
- const x = __fixunsdfsi(a);
- try testing.expect(x == expected);
-}
-
-test "fixunsdfsi" {
- try test__fixunsdfsi(0.0, 0);
-
- try test__fixunsdfsi(0.5, 0);
- try test__fixunsdfsi(0.99, 0);
- try test__fixunsdfsi(1.0, 1);
- try test__fixunsdfsi(1.5, 1);
- try test__fixunsdfsi(1.99, 1);
- try test__fixunsdfsi(2.0, 2);
- try test__fixunsdfsi(2.01, 2);
- try test__fixunsdfsi(-0.5, 0);
- try test__fixunsdfsi(-0.99, 0);
- try test__fixunsdfsi(-1.0, 0);
- try test__fixunsdfsi(-1.5, 0);
- try test__fixunsdfsi(-1.99, 0);
- try test__fixunsdfsi(-2.0, 0);
- try test__fixunsdfsi(-2.01, 0);
-
- try test__fixunsdfsi(0x1.000000p+31, 0x80000000);
- try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF);
- try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00);
- try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
-
- try test__fixunsdfsi(-0x1.FFFFFEp+30, 0);
- try test__fixunsdfsi(-0x1.FFFFFCp+30, 0);
-
- try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF);
- try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF);
- try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE);
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfti.zig b/lib/std/special/compiler_rt/fixunsdfti.zig
deleted file mode 100644
index 3c9871a4df..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunsdfti(a: f64) callconv(.C) u128 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f64, u128, a);
-}
-
-test {
- _ = @import("fixunsdfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunsdfti_test.zig b/lib/std/special/compiler_rt/fixunsdfti_test.zig
deleted file mode 100644
index d9e1424836..0000000000
--- a/lib/std/special/compiler_rt/fixunsdfti_test.zig
+++ /dev/null
@@ -1,46 +0,0 @@
-const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
-const testing = @import("std").testing;
-
-fn test__fixunsdfti(a: f64, expected: u128) !void {
- const x = __fixunsdfti(a);
- try testing.expect(x == expected);
-}
-
-test "fixunsdfti" {
- try test__fixunsdfti(0.0, 0);
-
- try test__fixunsdfti(0.5, 0);
- try test__fixunsdfti(0.99, 0);
- try test__fixunsdfti(1.0, 1);
- try test__fixunsdfti(1.5, 1);
- try test__fixunsdfti(1.99, 1);
- try test__fixunsdfti(2.0, 2);
- try test__fixunsdfti(2.01, 2);
- try test__fixunsdfti(-0.5, 0);
- try test__fixunsdfti(-0.99, 0);
- try test__fixunsdfti(-1.0, 0);
- try test__fixunsdfti(-1.5, 0);
- try test__fixunsdfti(-1.99, 0);
- try test__fixunsdfti(-2.0, 0);
- try test__fixunsdfti(-2.01, 0);
-
- try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
-
- try test__fixunsdfti(-0x1.FFFFFEp+62, 0);
- try test__fixunsdfti(-0x1.FFFFFCp+62, 0);
-
- try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800);
- try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000);
- try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
-
- try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000);
- try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000);
- try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
- try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
- try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-
- try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0);
- try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0);
-}
diff --git a/lib/std/special/compiler_rt/fixunssfdi.zig b/lib/std/special/compiler_rt/fixunssfdi.zig
deleted file mode 100644
index edad20e8bf..0000000000
--- a/lib/std/special/compiler_rt/fixunssfdi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunssfdi(a: f32) callconv(.C) u64 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f32, u64, a);
-}
-
-pub fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixunssfdi, .{a});
-}
-
-test {
- _ = @import("fixunssfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunssfdi_test.zig b/lib/std/special/compiler_rt/fixunssfdi_test.zig
deleted file mode 100644
index 3c46511b6d..0000000000
--- a/lib/std/special/compiler_rt/fixunssfdi_test.zig
+++ /dev/null
@@ -1,35 +0,0 @@
-const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
-const testing = @import("std").testing;
-
-fn test__fixunssfdi(a: f32, expected: u64) !void {
- const x = __fixunssfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixunssfdi" {
- try test__fixunssfdi(0.0, 0);
-
- try test__fixunssfdi(0.5, 0);
- try test__fixunssfdi(0.99, 0);
- try test__fixunssfdi(1.0, 1);
- try test__fixunssfdi(1.5, 1);
- try test__fixunssfdi(1.99, 1);
- try test__fixunssfdi(2.0, 2);
- try test__fixunssfdi(2.01, 2);
- try test__fixunssfdi(-0.5, 0);
- try test__fixunssfdi(-0.99, 0);
-
- try test__fixunssfdi(-1.0, 0);
- try test__fixunssfdi(-1.5, 0);
- try test__fixunssfdi(-1.99, 0);
- try test__fixunssfdi(-2.0, 0);
- try test__fixunssfdi(-2.01, 0);
-
- try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000);
- try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000);
- try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
-
- try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000);
- try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000);
-}
diff --git a/lib/std/special/compiler_rt/fixunssfsi.zig b/lib/std/special/compiler_rt/fixunssfsi.zig
deleted file mode 100644
index 96722a2a36..0000000000
--- a/lib/std/special/compiler_rt/fixunssfsi.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunssfsi(a: f32) callconv(.C) u32 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f32, u32, a);
-}
-
-pub fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __fixunssfsi, .{a});
-}
-
-test {
- _ = @import("fixunssfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunssfsi_test.zig b/lib/std/special/compiler_rt/fixunssfsi_test.zig
deleted file mode 100644
index 4bf90e4bff..0000000000
--- a/lib/std/special/compiler_rt/fixunssfsi_test.zig
+++ /dev/null
@@ -1,36 +0,0 @@
-const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
-const testing = @import("std").testing;
-
-fn test__fixunssfsi(a: f32, expected: u32) !void {
- const x = __fixunssfsi(a);
- try testing.expect(x == expected);
-}
-
-test "fixunssfsi" {
- try test__fixunssfsi(0.0, 0);
-
- try test__fixunssfsi(0.5, 0);
- try test__fixunssfsi(0.99, 0);
- try test__fixunssfsi(1.0, 1);
- try test__fixunssfsi(1.5, 1);
- try test__fixunssfsi(1.99, 1);
- try test__fixunssfsi(2.0, 2);
- try test__fixunssfsi(2.01, 2);
- try test__fixunssfsi(-0.5, 0);
- try test__fixunssfsi(-0.99, 0);
-
- try test__fixunssfsi(-1.0, 0);
- try test__fixunssfsi(-1.5, 0);
- try test__fixunssfsi(-1.99, 0);
- try test__fixunssfsi(-2.0, 0);
- try test__fixunssfsi(-2.01, 0);
-
- try test__fixunssfsi(0x1.000000p+31, 0x80000000);
- try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF);
- try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00);
- try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
- try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00);
-
- try test__fixunssfsi(-0x1.FFFFFEp+30, 0);
- try test__fixunssfsi(-0x1.FFFFFCp+30, 0);
-}
diff --git a/lib/std/special/compiler_rt/fixunssfti.zig b/lib/std/special/compiler_rt/fixunssfti.zig
deleted file mode 100644
index 4967202e69..0000000000
--- a/lib/std/special/compiler_rt/fixunssfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunssfti(a: f32) callconv(.C) u128 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f32, u128, a);
-}
-
-test {
- _ = @import("fixunssfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunssfti_test.zig b/lib/std/special/compiler_rt/fixunssfti_test.zig
deleted file mode 100644
index 3c1a314e91..0000000000
--- a/lib/std/special/compiler_rt/fixunssfti_test.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
-const testing = @import("std").testing;
-
-fn test__fixunssfti(a: f32, expected: u128) !void {
- const x = __fixunssfti(a);
- try testing.expect(x == expected);
-}
-
-test "fixunssfti" {
- try test__fixunssfti(0.0, 0);
-
- try test__fixunssfti(0.5, 0);
- try test__fixunssfti(0.99, 0);
- try test__fixunssfti(1.0, 1);
- try test__fixunssfti(1.5, 1);
- try test__fixunssfti(1.99, 1);
- try test__fixunssfti(2.0, 2);
- try test__fixunssfti(2.01, 2);
- try test__fixunssfti(-0.5, 0);
- try test__fixunssfti(-0.99, 0);
-
- try test__fixunssfti(-1.0, 0);
- try test__fixunssfti(-1.5, 0);
- try test__fixunssfti(-1.99, 0);
- try test__fixunssfti(-2.0, 0);
- try test__fixunssfti(-2.01, 0);
-
- try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000);
- try test__fixunssfti(0x1.000000p+63, 0x8000000000000000);
- try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
- try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000);
- try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000);
- try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000);
- try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000);
-
- try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000);
- try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000);
- try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000);
- try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000);
-}
diff --git a/lib/std/special/compiler_rt/fixunstfdi.zig b/lib/std/special/compiler_rt/fixunstfdi.zig
deleted file mode 100644
index 0db4987a08..0000000000
--- a/lib/std/special/compiler_rt/fixunstfdi.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunstfdi(a: f128) callconv(.C) u64 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f128, u64, a);
-}
-
-test {
- _ = @import("fixunstfdi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunstfdi_test.zig b/lib/std/special/compiler_rt/fixunstfdi_test.zig
deleted file mode 100644
index aa746799b7..0000000000
--- a/lib/std/special/compiler_rt/fixunstfdi_test.zig
+++ /dev/null
@@ -1,49 +0,0 @@
-const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
-const testing = @import("std").testing;
-
-fn test__fixunstfdi(a: f128, expected: u64) !void {
- const x = __fixunstfdi(a);
- try testing.expect(x == expected);
-}
-
-test "fixunstfdi" {
- try test__fixunstfdi(0.0, 0);
-
- try test__fixunstfdi(0.5, 0);
- try test__fixunstfdi(0.99, 0);
- try test__fixunstfdi(1.0, 1);
- try test__fixunstfdi(1.5, 1);
- try test__fixunstfdi(1.99, 1);
- try test__fixunstfdi(2.0, 2);
- try test__fixunstfdi(2.01, 2);
- try test__fixunstfdi(-0.5, 0);
- try test__fixunstfdi(-0.99, 0);
- try test__fixunstfdi(-1.0, 0);
- try test__fixunstfdi(-1.5, 0);
- try test__fixunstfdi(-1.99, 0);
- try test__fixunstfdi(-2.0, 0);
- try test__fixunstfdi(-2.01, 0);
-
- try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
- try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
-
- try test__fixunstfdi(-0x1.FFFFFEp+62, 0);
- try test__fixunstfdi(-0x1.FFFFFCp+62, 0);
-
- try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
- try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
-
- try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
- try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
-
- try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF);
- try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001);
- try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000);
- try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF);
- try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE);
- try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF);
-
- try test__fixunstfdi(-0x1.0000000000000000p+63, 0);
- try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0);
- try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0);
-}
diff --git a/lib/std/special/compiler_rt/fixunstfsi.zig b/lib/std/special/compiler_rt/fixunstfsi.zig
deleted file mode 100644
index 8cedc07a35..0000000000
--- a/lib/std/special/compiler_rt/fixunstfsi.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunstfsi(a: f128) callconv(.C) u32 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f128, u32, a);
-}
-
-test {
- _ = @import("fixunstfsi_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunstfsi_test.zig b/lib/std/special/compiler_rt/fixunstfsi_test.zig
deleted file mode 100644
index 206161bef5..0000000000
--- a/lib/std/special/compiler_rt/fixunstfsi_test.zig
+++ /dev/null
@@ -1,22 +0,0 @@
-const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
-const testing = @import("std").testing;
-
-fn test__fixunstfsi(a: f128, expected: u32) !void {
- const x = __fixunstfsi(a);
- try testing.expect(x == expected);
-}
-
-const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
-
-test "fixunstfsi" {
- try test__fixunstfsi(inf128, 0xffffffff);
- try test__fixunstfsi(0, 0x0);
- try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
- try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0);
- try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456);
- try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff);
- try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff);
- try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0);
-
- try test__fixunstfsi(0x1p+32, 0xFFFFFFFF);
-}
diff --git a/lib/std/special/compiler_rt/fixunstfti.zig b/lib/std/special/compiler_rt/fixunstfti.zig
deleted file mode 100644
index 0359327027..0000000000
--- a/lib/std/special/compiler_rt/fixunstfti.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const fixuint = @import("fixuint.zig").fixuint;
-const builtin = @import("builtin");
-
-pub fn __fixunstfti(a: f128) callconv(.C) u128 {
- @setRuntimeSafety(builtin.is_test);
- return fixuint(f128, u128, a);
-}
-
-test {
- _ = @import("fixunstfti_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/fixunstfti_test.zig b/lib/std/special/compiler_rt/fixunstfti_test.zig
deleted file mode 100644
index e35e2a65be..0000000000
--- a/lib/std/special/compiler_rt/fixunstfti_test.zig
+++ /dev/null
@@ -1,32 +0,0 @@
-const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
-const testing = @import("std").testing;
-
-fn test__fixunstfti(a: f128, expected: u128) !void {
- const x = __fixunstfti(a);
- try testing.expect(x == expected);
-}
-
-const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
-
-test "fixunstfti" {
- try test__fixunstfti(inf128, 0xffffffffffffffffffffffffffffffff);
-
- try test__fixunstfti(0.0, 0);
-
- try test__fixunstfti(0.5, 0);
- try test__fixunstfti(0.99, 0);
- try test__fixunstfti(1.0, 1);
- try test__fixunstfti(1.5, 1);
- try test__fixunstfti(1.99, 1);
- try test__fixunstfti(2.0, 2);
- try test__fixunstfti(2.01, 2);
- try test__fixunstfti(-0.01, 0);
- try test__fixunstfti(-0.99, 0);
-
- try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff);
-
- try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000);
- try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000);
- try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff);
- try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff);
-}
diff --git a/lib/std/special/compiler_rt/floatXiYf.zig b/lib/std/special/compiler_rt/floatXiYf.zig
new file mode 100644
index 0000000000..068413f715
--- /dev/null
+++ b/lib/std/special/compiler_rt/floatXiYf.zig
@@ -0,0 +1,222 @@
+const builtin = @import("builtin");
+const is_test = builtin.is_test;
+const std = @import("std");
+const math = std.math;
+const expect = std.testing.expect;
+
+pub fn floatXiYf(comptime T: type, x: anytype) T {
+ @setRuntimeSafety(is_test);
+
+ if (x == 0) return 0;
+
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const Z = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(x)));
+ const uT = std.meta.Int(.unsigned, @bitSizeOf(T));
+ const inf = math.inf(T);
+ const float_bits = @bitSizeOf(T);
+ const int_bits = @bitSizeOf(@TypeOf(x));
+ const exp_bits = math.floatExponentBits(T);
+ const fractional_bits = math.floatFractionalBits(T);
+ const exp_bias = math.maxInt(std.meta.Int(.unsigned, exp_bits - 1));
+ const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0;
+ const max_exp = exp_bias;
+
+ // Sign
+ var abs_val = math.absCast(x);
+ const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
+ var result: uT = sign_bit;
+
+ // Compute significand
+ var exp = int_bits - @clz(Z, abs_val) - 1;
+ if (int_bits <= fractional_bits or exp <= fractional_bits) {
+ const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp);
+
+ // Shift up result to line up with the significand - no rounding required
+ result = (@intCast(uT, abs_val) << shift_amt);
+ result ^= implicit_bit; // Remove implicit integer bit
+ } else {
+ var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits);
+ const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1;
+
+ // Shift down result and remove implicit integer bit
+ result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1);
+
+ // Round result, including round-to-even for exact ties
+ result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie));
+ }
+
+ // Compute exponent
+ if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity
+ return @bitCast(T, sign_bit | @bitCast(uT, inf));
+
+ result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T);
+
+ // If the result included a carry, we need to restore the explicit integer bit
+ if (T == f80) result |= 1 << fractional_bits;
+
+ return @bitCast(T, sign_bit | result);
+}
+
+// Conversion to f16
+pub fn __floatsihf(a: i32) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+pub fn __floatunsihf(a: u32) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+pub fn __floatdihf(a: i64) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+pub fn __floatundihf(a: u64) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+pub fn __floattihf(a: i128) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+pub fn __floatuntihf(a: u128) callconv(.C) f16 {
+ return floatXiYf(f16, a);
+}
+
+// Conversion to f32
+pub fn __floatsisf(a: i32) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+pub fn __floatunsisf(a: u32) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+pub fn __floatdisf(a: i64) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+pub fn __floatundisf(a: u64) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+pub fn __floattisf(a: i128) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+pub fn __floatuntisf(a: u128) callconv(.C) f32 {
+ return floatXiYf(f32, a);
+}
+
+// Conversion to f64
+pub fn __floatsidf(a: i32) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+pub fn __floatunsidf(a: u32) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+pub fn __floatdidf(a: i64) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+pub fn __floatundidf(a: u64) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+pub fn __floattidf(a: i128) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+pub fn __floatuntidf(a: u128) callconv(.C) f64 {
+ return floatXiYf(f64, a);
+}
+
+// Conversion to f80
+pub fn __floatsixf(a: i32) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+pub fn __floatunsixf(a: u32) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+pub fn __floatdixf(a: i64) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+pub fn __floatundixf(a: u64) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+pub fn __floattixf(a: i128) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+pub fn __floatuntixf(a: u128) callconv(.C) f80 {
+ return floatXiYf(f80, a);
+}
+
+// Conversion to f128
+pub fn __floatsitf(a: i32) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+pub fn __floatunsitf(a: u32) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+pub fn __floatditf(a: i64) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+pub fn __floatunditf(a: u64) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+pub fn __floattitf(a: i128) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+pub fn __floatuntitf(a: u128) callconv(.C) f128 {
+ return floatXiYf(f128, a);
+}
+
+// Conversion to f32
+pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 {
+ return floatXiYf(f32, arg);
+}
+
+pub fn __aeabi_i2f(arg: i32) callconv(.AAPCS) f32 {
+ return floatXiYf(f32, arg);
+}
+
+pub fn __aeabi_ul2f(arg: u64) callconv(.AAPCS) f32 {
+ return floatXiYf(f32, arg);
+}
+
+pub fn __aeabi_l2f(arg: i64) callconv(.AAPCS) f32 {
+ return floatXiYf(f32, arg);
+}
+
+// Conversion to f64
+pub fn __aeabi_ui2d(arg: u32) callconv(.AAPCS) f64 {
+ return floatXiYf(f64, arg);
+}
+
+pub fn __aeabi_i2d(arg: i32) callconv(.AAPCS) f64 {
+ return floatXiYf(f64, arg);
+}
+
+pub fn __aeabi_ul2d(arg: u64) callconv(.AAPCS) f64 {
+ return floatXiYf(f64, arg);
+}
+
+pub fn __aeabi_l2d(arg: i64) callconv(.AAPCS) f64 {
+ return floatXiYf(f64, arg);
+}
+
+test {
+ _ = @import("floatXiYf_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/floatXiYf_test.zig b/lib/std/special/compiler_rt/floatXiYf_test.zig
new file mode 100644
index 0000000000..cffa2a5b42
--- /dev/null
+++ b/lib/std/special/compiler_rt/floatXiYf_test.zig
@@ -0,0 +1,835 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const testing = std.testing;
+const math = std.math;
+const floatXiYf = @import("floatXiYf.zig").floatXiYf;
+
+// Conversion to f32
+const __floatsisf = @import("floatXiYf.zig").__floatsisf;
+const __floatunsisf = @import("floatXiYf.zig").__floatunsisf;
+const __floatdisf = @import("floatXiYf.zig").__floatdisf;
+const __floatundisf = @import("floatXiYf.zig").__floatundisf;
+const __floattisf = @import("floatXiYf.zig").__floattisf;
+const __floatuntisf = @import("floatXiYf.zig").__floatuntisf;
+
+// Conversion to f64
+const __floatsidf = @import("floatXiYf.zig").__floatsidf;
+const __floatunsidf = @import("floatXiYf.zig").__floatunsidf;
+const __floatdidf = @import("floatXiYf.zig").__floatdidf;
+const __floatundidf = @import("floatXiYf.zig").__floatundidf;
+const __floattidf = @import("floatXiYf.zig").__floattidf;
+const __floatuntidf = @import("floatXiYf.zig").__floatuntidf;
+
+// Conversion to f128
+const __floatsitf = @import("floatXiYf.zig").__floatsitf;
+const __floatunsitf = @import("floatXiYf.zig").__floatunsitf;
+const __floatditf = @import("floatXiYf.zig").__floatditf;
+const __floatunditf = @import("floatXiYf.zig").__floatunditf;
+const __floattitf = @import("floatXiYf.zig").__floattitf;
+const __floatuntitf = @import("floatXiYf.zig").__floatuntitf;
+
+fn test__floatsisf(a: i32, expected: u32) !void {
+ const r = __floatsisf(a);
+ try std.testing.expect(@bitCast(u32, r) == expected);
+}
+
+fn test_one_floatunsisf(a: u32, expected: u32) !void {
+ const r = __floatunsisf(a);
+ try std.testing.expect(@bitCast(u32, r) == expected);
+}
+
+test "floatsisf" {
+ try test__floatsisf(0, 0x00000000);
+ try test__floatsisf(1, 0x3f800000);
+ try test__floatsisf(-1, 0xbf800000);
+ try test__floatsisf(0x7FFFFFFF, 0x4f000000);
+ try test__floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000);
+}
+
+test "floatunsisf" {
+ // Test the produced bit pattern
+ try test_one_floatunsisf(0, 0);
+ try test_one_floatunsisf(1, 0x3f800000);
+ try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000);
+ try test_one_floatunsisf(0x80000000, 0x4f000000);
+ try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000);
+}
+
+fn test__floatdisf(a: i64, expected: f32) !void {
+ const x = __floatdisf(a);
+ try testing.expect(x == expected);
+}
+
+fn test__floatundisf(a: u64, expected: f32) !void {
+ try std.testing.expectEqual(expected, __floatundisf(a));
+}
+
+test "floatdisf" {
+ try test__floatdisf(0, 0.0);
+ try test__floatdisf(1, 1.0);
+ try test__floatdisf(2, 2.0);
+ try test__floatdisf(-1, -1.0);
+ try test__floatdisf(-2, -2.0);
+ try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatdisf(@bitCast(i64, @as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62);
+ try test__floatdisf(@bitCast(i64, @as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62);
+ try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000000)), -0x1.000000p+63);
+ try test__floatdisf(@bitCast(i64, @as(u64, 0x8000000000000001)), -0x1.000000p+63);
+ try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
+ try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
+ try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
+}
+
+test "floatundisf" {
+ try test__floatundisf(0, 0.0);
+ try test__floatundisf(1, 1.0);
+ try test__floatundisf(2, 2.0);
+ try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatundisf(0x8000008000000000, 0x1p+63);
+ try test__floatundisf(0x8000010000000000, 0x1.000002p+63);
+ try test__floatundisf(0x8000000000000000, 0x1p+63);
+ try test__floatundisf(0x8000000000000001, 0x1p+63);
+ try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
+ try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
+ try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
+ try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
+ try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
+}
+
+fn test__floattisf(a: i128, expected: f32) !void {
+ const x = __floattisf(a);
+ try testing.expect(x == expected);
+}
+
+fn test__floatuntisf(a: u128, expected: f32) !void {
+ const x = __floatuntisf(a);
+ try testing.expect(x == expected);
+}
+
+test "floattisf" {
+ try test__floattisf(0, 0.0);
+
+ try test__floattisf(1, 1.0);
+ try test__floattisf(2, 2.0);
+ try test__floattisf(-1, -1.0);
+ try test__floattisf(-2, -2.0);
+
+ try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+
+ try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62);
+ try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62);
+
+ try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63);
+ try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63);
+
+ try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
+ try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
+
+ try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
+ try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
+
+ try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114);
+
+ try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114);
+ try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114);
+
+ try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114);
+ try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114);
+}
+
+test "floatuntisf" {
+ try test__floatuntisf(0, 0.0);
+
+ try test__floatuntisf(1, 1.0);
+ try test__floatuntisf(2, 2.0);
+ try test__floatuntisf(20, 20.0);
+
+ try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+
+ try test__floatuntisf(make_uti(0x8000008000000000, 0), 0x1.000001p+127);
+ try test__floatuntisf(make_uti(0x8000000000000800, 0), 0x1.0p+127);
+ try test__floatuntisf(make_uti(0x8000010000000000, 0), 0x1.000002p+127);
+
+ try test__floatuntisf(make_uti(0x8000000000000000, 0), 0x1.000000p+127);
+
+ try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+
+ try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+
+ try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+
+ try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
+ try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
+
+ try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
+ try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
+
+ try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
+ try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
+
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76);
+ try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76);
+
+ // Test overflow to infinity
+ try test__floatuntisf(@as(u128, math.maxInt(u128)), @bitCast(f32, math.inf(f32)));
+}
+
+fn test_one_floatsidf(a: i32, expected: u64) !void {
+ const r = __floatsidf(a);
+ try std.testing.expect(@bitCast(u64, r) == expected);
+}
+
+fn test_one_floatunsidf(a: u32, expected: u64) !void {
+ const r = __floatunsidf(a);
+ try std.testing.expect(@bitCast(u64, r) == expected);
+}
+
+test "floatsidf" {
+ try test_one_floatsidf(0, 0x0000000000000000);
+ try test_one_floatsidf(1, 0x3ff0000000000000);
+ try test_one_floatsidf(-1, 0xbff0000000000000);
+ try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000);
+ try test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000);
+}
+
+test "floatunsidf" {
+ try test_one_floatunsidf(0, 0x0000000000000000);
+ try test_one_floatunsidf(1, 0x3ff0000000000000);
+ try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000);
+ try test_one_floatunsidf(@intCast(u32, 0x80000000), 0x41e0000000000000);
+ try test_one_floatunsidf(@intCast(u32, 0xFFFFFFFF), 0x41efffffffe00000);
+}
+
+fn test__floatdidf(a: i64, expected: f64) !void {
+ const r = __floatdidf(a);
+ try testing.expect(r == expected);
+}
+
+fn test__floatundidf(a: u64, expected: f64) !void {
+ const r = __floatundidf(a);
+ try testing.expect(r == expected);
+}
+
+test "floatdidf" {
+ try test__floatdidf(0, 0.0);
+ try test__floatdidf(1, 1.0);
+ try test__floatdidf(2, 2.0);
+ try test__floatdidf(20, 20.0);
+ try test__floatdidf(-1, -1.0);
+ try test__floatdidf(-2, -2.0);
+ try test__floatdidf(-20, -20.0);
+ try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000008000000000)), -0x1.FFFFFEp+62);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000800)), -0x1.FFFFFFFFFFFFEp+62);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000010000000000)), -0x1.FFFFFCp+62);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000001000)), -0x1.FFFFFFFFFFFFCp+62);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000000)), -0x1.000000p+63);
+ try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000001)), -0x1.000000p+63); // 0x8000000000000001
+ try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+ try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+ try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+ try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
+ try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
+ try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
+ try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
+ try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
+ try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+}
+
+test "floatundidf" {
+ try test__floatundidf(0, 0.0);
+ try test__floatundidf(1, 1.0);
+ try test__floatundidf(2, 2.0);
+ try test__floatundidf(20, 20.0);
+ try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+ try test__floatundidf(0x8000008000000000, 0x1.000001p+63);
+ try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63);
+ try test__floatundidf(0x8000010000000000, 0x1.000002p+63);
+ try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63);
+ try test__floatundidf(0x8000000000000000, 0x1p+63);
+ try test__floatundidf(0x8000000000000001, 0x1p+63);
+ try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+ try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+ try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+ try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
+ try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
+ try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
+ try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
+ try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
+ try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+}
+
+fn test__floattidf(a: i128, expected: f64) !void {
+ const x = __floattidf(a);
+ try testing.expect(x == expected);
+}
+
+fn test__floatuntidf(a: u128, expected: f64) !void {
+ const x = __floatuntidf(a);
+ try testing.expect(x == expected);
+}
+
+test "floattidf" {
+ try test__floattidf(0, 0.0);
+
+ try test__floattidf(1, 1.0);
+ try test__floattidf(2, 2.0);
+ try test__floattidf(20, 20.0);
+ try test__floattidf(-1, -1.0);
+ try test__floattidf(-2, -2.0);
+ try test__floattidf(-20, -20.0);
+
+ try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+
+ try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
+ try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
+ try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
+ try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
+
+ try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
+ try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127);
+
+ try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+
+ try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+
+ try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
+ try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
+ try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
+ try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
+ try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
+ try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+
+ try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
+ try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
+ try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
+ try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
+ try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
+}
+
+test "floatuntidf" {
+ try test__floatuntidf(0, 0.0);
+
+ try test__floatuntidf(1, 1.0);
+ try test__floatuntidf(2, 2.0);
+ try test__floatuntidf(20, 20.0);
+
+ try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+
+ try test__floatuntidf(make_uti(0x8000008000000000, 0), 0x1.000001p+127);
+ try test__floatuntidf(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127);
+ try test__floatuntidf(make_uti(0x8000010000000000, 0), 0x1.000002p+127);
+ try test__floatuntidf(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127);
+
+ try test__floatuntidf(make_uti(0x8000000000000000, 0), 0x1.000000p+127);
+ try test__floatuntidf(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127);
+
+ try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+
+ try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+
+ try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
+ try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
+ try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
+ try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
+ try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+
+ try test__floatuntidf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
+ try test__floatuntidf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
+}
+
+fn test__floatsitf(a: i32, expected: u128) !void {
+ const r = __floatsitf(a);
+ try std.testing.expect(@bitCast(u128, r) == expected);
+}
+
+test "floatsitf" {
+ try test__floatsitf(0, 0);
+ try test__floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000);
+ try test__floatsitf(0x12345678, 0x401b2345678000000000000000000000);
+ try test__floatsitf(-0x12345678, 0xc01b2345678000000000000000000000);
+ try test__floatsitf(@bitCast(i32, @intCast(u32, 0xffffffff)), 0xbfff0000000000000000000000000000);
+ try test__floatsitf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc01e0000000000000000000000000000);
+}
+
+fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void {
+ const x = __floatunsitf(a);
+
+ const x_repr = @bitCast(u128, x);
+ const x_hi = @intCast(u64, x_repr >> 64);
+ const x_lo = @truncate(u64, x_repr);
+
+ if (x_hi == expected_hi and x_lo == expected_lo) {
+ return;
+ }
+ // nan repr
+ else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
+ if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
+ return;
+ }
+ }
+
+ @panic("__floatunsitf test failure");
+}
+
+test "floatunsitf" {
+ try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0);
+ try test__floatunsitf(0, 0x0, 0x0);
+ try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0);
+ try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0);
+}
+
+fn test__floatditf(a: i64, expected: f128) !void {
+ const x = __floatditf(a);
+ try testing.expect(x == expected);
+}
+
+fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void {
+ const x = __floatunditf(a);
+
+ const x_repr = @bitCast(u128, x);
+ const x_hi = @intCast(u64, x_repr >> 64);
+ const x_lo = @truncate(u64, x_repr);
+
+ if (x_hi == expected_hi and x_lo == expected_lo) {
+ return;
+ }
+ // nan repr
+ else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
+ if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
+ return;
+ }
+ }
+
+ @panic("__floatunditf test failure");
+}
+
+test "floatditf" {
+ try test__floatditf(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000));
+ try test__floatditf(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000));
+ try test__floatditf(0x2, make_tf(0x4000000000000000, 0x0));
+ try test__floatditf(0x1, make_tf(0x3fff000000000000, 0x0));
+ try test__floatditf(0x0, make_tf(0x0, 0x0));
+ try test__floatditf(@bitCast(i64, @as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0));
+ try test__floatditf(@bitCast(i64, @as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0));
+ try test__floatditf(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000));
+ try test__floatditf(@bitCast(i64, @as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0));
+}
+
+test "floatunditf" {
+ try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000);
+ try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000);
+ try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0);
+ try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000);
+ try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000);
+ try test__floatunditf(0x2, 0x4000000000000000, 0x0);
+ try test__floatunditf(0x1, 0x3fff000000000000, 0x0);
+ try test__floatunditf(0x0, 0x0, 0x0);
+}
+
+fn test__floattitf(a: i128, expected: f128) !void {
+ const x = __floattitf(a);
+ try testing.expect(x == expected);
+}
+
+fn test__floatuntitf(a: u128, expected: f128) !void {
+ const x = __floatuntitf(a);
+ try testing.expect(x == expected);
+}
+
+test "floattitf" {
+ try test__floattitf(0, 0.0);
+
+ try test__floattitf(1, 1.0);
+ try test__floattitf(2, 2.0);
+ try test__floattitf(20, 20.0);
+ try test__floattitf(-1, -1.0);
+ try test__floattitf(-2, -2.0);
+ try test__floattitf(-20, -20.0);
+
+ try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+
+ try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
+ try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
+ try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
+ try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
+
+ try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
+ try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126);
+
+ try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+
+ try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+
+ try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
+ try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
+ try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
+ try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
+ try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
+ try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
+ try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
+ try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
+ try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
+ try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
+ try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
+ try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
+ try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
+ try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+
+ try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
+ try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
+ try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
+ try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
+ try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
+
+ try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
+
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
+ try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
+}
+
+test "floatuntitf" {
+ try test__floatuntitf(0, 0.0);
+
+ try test__floatuntitf(1, 1.0);
+ try test__floatuntitf(2, 2.0);
+ try test__floatuntitf(20, 20.0);
+
+ try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
+ try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
+ try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
+ try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
+ try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59);
+ try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60);
+ try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60);
+
+ try test__floatuntitf(0x8000008000000000, 0x8.000008p+60);
+ try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60);
+ try test__floatuntitf(0x8000010000000000, 0x8.00001p+60);
+ try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60);
+
+ try test__floatuntitf(0x8000000000000000, 0x8p+60);
+ try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60);
+
+ try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
+
+ try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
+ try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
+ try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
+ try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
+ try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
+
+ try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
+ try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
+ try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
+ try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
+ try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
+
+ try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
+ try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
+ try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
+ try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
+ try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
+ try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
+ try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
+ try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
+ try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
+ try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
+ try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
+ try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
+ try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
+ try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
+ try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
+
+ try test__floatuntitf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
+ try test__floatuntitf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
+
+ try test__floatuntitf(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
+
+ try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127);
+ try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128);
+
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
+ try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
+}
+
+fn make_ti(high: u64, low: u64) i128 {
+ var result: u128 = high;
+ result <<= 64;
+ result |= low;
+ return @bitCast(i128, result);
+}
+
+fn make_uti(high: u64, low: u64) u128 {
+ var result: u128 = high;
+ result <<= 64;
+ result |= low;
+ return result;
+}
+
+fn make_tf(high: u64, low: u64) f128 {
+ var result: u128 = high;
+ result <<= 64;
+ result |= low;
+ return @bitCast(f128, result);
+}
+
+test "conversion to f16" {
+ try testing.expect(floatXiYf(f16, @as(u32, 0)) == 0.0);
+ try testing.expect(floatXiYf(f16, @as(u32, 1)) == 1.0);
+ try testing.expect(floatXiYf(f16, @as(u32, 65504)) == 65504);
+ try testing.expect(floatXiYf(f16, @as(u32, 65504 + (1 << 4))) == math.inf(f16));
+}
+
+test "conversion to f32" {
+ try testing.expect(floatXiYf(f32, @as(u32, 0)) == 0.0);
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u32))) != 1.0);
+ try testing.expect(floatXiYf(f32, @as(i32, math.minInt(i32))) != 1.0);
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24))) == math.maxInt(u24));
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even
+ try testing.expect(floatXiYf(f32, @as(u32, math.maxInt(u24)) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact
+}
+
+test "conversion to f80" {
+ if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64)
+ return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408
+
+ try testing.expect(floatXiYf(f80, @as(i80, -12)) == -12);
+ try testing.expect(@floatToInt(u80, floatXiYf(f80, @as(u64, math.maxInt(u64)) + 0)) == math.maxInt(u64) + 0);
+ try testing.expect(@floatToInt(u80, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1);
+
+ try testing.expect(floatXiYf(f80, @as(u32, 0)) == 0.0);
+ try testing.expect(floatXiYf(f80, @as(u32, 1)) == 1.0);
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u32, math.maxInt(u24)) + 0)) == math.maxInt(u24));
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 0)) == math.maxInt(u64));
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 1)) == math.maxInt(u64) + 1); // Exact
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 2)) == math.maxInt(u64) + 1); // Rounds down
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 3)) == math.maxInt(u64) + 3); // Tie - Exact
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u64)) + 4)) == math.maxInt(u64) + 5); // Rounds up
+
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 0)) == math.maxInt(u65) + 1); // Rounds up
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 1)) == math.maxInt(u65) + 1); // Exact
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 2)) == math.maxInt(u65) + 1); // Rounds down
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 3)) == math.maxInt(u65) + 1); // Tie - Rounds down
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 4)) == math.maxInt(u65) + 5); // Rounds up
+ try testing.expect(@floatToInt(u128, floatXiYf(f80, @as(u80, math.maxInt(u65)) + 5)) == math.maxInt(u65) + 5); // Exact
+}
diff --git a/lib/std/special/compiler_rt/floatXisf.zig b/lib/std/special/compiler_rt/floatXisf.zig
deleted file mode 100644
index de3f4495cb..0000000000
--- a/lib/std/special/compiler_rt/floatXisf.zig
+++ /dev/null
@@ -1,90 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const FLT_MANT_DIG = 24;
-
-inline fn floatXisf(comptime T: type, arg: T) f32 {
- @setRuntimeSafety(builtin.is_test);
-
- const bits = @typeInfo(T).Int.bits;
- const Z = std.meta.Int(.unsigned, bits);
- const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1));
-
- if (arg == 0) {
- return @as(f32, 0.0);
- }
-
- var ai = arg;
- const N: u32 = bits;
- const si = ai >> @intCast(S, (N - 1));
- ai = ((ai ^ si) -% si);
- var a = @bitCast(Z, ai);
-
- const sd = @bitCast(i32, N - @clz(Z, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
-
- if (sd > FLT_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit FLT_MANT_DIG-1 bits to the right of 1
- // Q = bit FLT_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- FLT_MANT_DIG + 1 => {
- a <<= 1;
- },
- FLT_MANT_DIG + 2 => {},
- else => {
- const shift1_amt = @intCast(i32, sd - (FLT_MANT_DIG + 2));
- const shift1_amt_u7 = @intCast(S, shift1_amt);
-
- const shift2_amt = @intCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
- const shift2_amt_u7 = @intCast(S, shift2_amt);
-
- a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(Z, maxInt(Z)) >> shift2_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
- if ((a & (@as(Z, 1) << FLT_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to FLT_MANT_DIG bits
- } else {
- a <<= @intCast(S, FLT_MANT_DIG - sd);
- // a is now rounded to FLT_MANT_DIG bits
- }
-
- const s = @bitCast(Z, arg) >> (@typeInfo(T).Int.bits - 32);
- const r = (@intCast(u32, s) & 0x80000000) | // sign
- (@intCast(u32, (e + 127)) << 23) | // exponent
- (@truncate(u32, a) & 0x007fffff); // mantissa-high
-
- return @bitCast(f32, r);
-}
-
-pub fn __floatdisf(arg: i64) callconv(.C) f32 {
- return floatXisf(i64, arg);
-}
-
-pub fn __floattisf(arg: i128) callconv(.C) f32 {
- return floatXisf(i128, arg);
-}
-
-pub fn __aeabi_l2f(arg: i64) callconv(.AAPCS) f32 {
- return floatXisf(i64, arg);
-}
-
-test {
- _ = @import("floattisf_test.zig");
-}
-test {
- _ = @import("floattisf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatdidf.zig b/lib/std/special/compiler_rt/floatdidf.zig
deleted file mode 100644
index 16a514b615..0000000000
--- a/lib/std/special/compiler_rt/floatdidf.zig
+++ /dev/null
@@ -1,27 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-
-const twop52: f64 = 0x1.0p52;
-const twop32: f64 = 0x1.0p32;
-
-pub fn __floatdidf(a: i64) callconv(.C) f64 {
- @setRuntimeSafety(builtin.is_test);
-
- if (a == 0) return 0;
-
- var low = @bitCast(i64, twop52);
- const high = @intToFloat(f64, @truncate(i32, a >> 32)) * twop32;
-
- low |= @bitCast(i64, a & 0xFFFFFFFF);
-
- return (high - twop52) + @bitCast(f64, low);
-}
-
-pub fn __aeabi_l2d(arg: i64) callconv(.AAPCS) f64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __floatdidf, .{arg});
-}
-
-test {
- _ = @import("floatdidf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatdidf_test.zig b/lib/std/special/compiler_rt/floatdidf_test.zig
deleted file mode 100644
index 6b01ac5f3f..0000000000
--- a/lib/std/special/compiler_rt/floatdidf_test.zig
+++ /dev/null
@@ -1,53 +0,0 @@
-const __floatdidf = @import("floatdidf.zig").__floatdidf;
-const testing = @import("std").testing;
-
-fn test__floatdidf(a: i64, expected: f64) !void {
- const r = __floatdidf(a);
- try testing.expect(r == expected);
-}
-
-test "floatdidf" {
- try test__floatdidf(0, 0.0);
- try test__floatdidf(1, 1.0);
- try test__floatdidf(2, 2.0);
- try test__floatdidf(20, 20.0);
- try test__floatdidf(-1, -1.0);
- try test__floatdidf(-2, -2.0);
- try test__floatdidf(-20, -20.0);
- try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000008000000000)), -0x1.FFFFFEp+62);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000800)), -0x1.FFFFFFFFFFFFEp+62);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000010000000000)), -0x1.FFFFFCp+62);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000001000)), -0x1.FFFFFFFFFFFFCp+62);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000000)), -0x1.000000p+63);
- try test__floatdidf(@bitCast(i64, @intCast(u64, 0x8000000000000001)), -0x1.000000p+63);
- try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
- try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
- try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
- try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
- try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
- try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
- try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
- try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
- try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-}
diff --git a/lib/std/special/compiler_rt/floatdisf_test.zig b/lib/std/special/compiler_rt/floatdisf_test.zig
deleted file mode 100644
index 010c4faddd..0000000000
--- a/lib/std/special/compiler_rt/floatdisf_test.zig
+++ /dev/null
@@ -1,32 +0,0 @@
-const __floatdisf = @import("floatXisf.zig").__floatdisf;
-const testing = @import("std").testing;
-
-fn test__floatdisf(a: i64, expected: f32) !void {
- const x = __floatdisf(a);
- try testing.expect(x == expected);
-}
-
-test "floatdisf" {
- try test__floatdisf(0, 0.0);
- try test__floatdisf(1, 1.0);
- try test__floatdisf(2, 2.0);
- try test__floatdisf(-1, -1.0);
- try test__floatdisf(-2, -2.0);
- try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatdisf(0x8000008000000000, -0x1.FFFFFEp+62);
- try test__floatdisf(0x8000010000000000, -0x1.FFFFFCp+62);
- try test__floatdisf(0x8000000000000000, -0x1.000000p+63);
- try test__floatdisf(0x8000000000000001, -0x1.000000p+63);
- try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
- try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
- try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
-}
diff --git a/lib/std/special/compiler_rt/floatditf.zig b/lib/std/special/compiler_rt/floatditf.zig
deleted file mode 100644
index fef696e6fb..0000000000
--- a/lib/std/special/compiler_rt/floatditf.zig
+++ /dev/null
@@ -1,38 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const significandBits = 112;
-const exponentBias = 16383;
-const implicitBit = (@as(u128, 1) << significandBits);
-
-pub fn __floatditf(arg: i64) callconv(.C) f128 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- // All other cases begin by extracting the sign and absolute value of a
- var sign: u128 = 0;
- var aAbs = @bitCast(u64, arg);
- if (arg < 0) {
- sign = 1 << 127;
- aAbs = ~@bitCast(u64, arg) + 1;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const exponent = 63 - @clz(u64, aAbs);
- var result: u128 = undefined;
-
- // Shift a into the significand field, rounding if it is a right-shift
- const shift = significandBits - exponent;
- result = @as(u128, aAbs) << shift ^ implicitBit;
-
- result += (@as(u128, exponent) + exponentBias) << significandBits;
- return @bitCast(f128, result | sign);
-}
-
-test {
- _ = @import("floatditf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatditf_test.zig b/lib/std/special/compiler_rt/floatditf_test.zig
deleted file mode 100644
index cf8a81c68c..0000000000
--- a/lib/std/special/compiler_rt/floatditf_test.zig
+++ /dev/null
@@ -1,26 +0,0 @@
-const __floatditf = @import("floatditf.zig").__floatditf;
-const testing = @import("std").testing;
-
-fn test__floatditf(a: i64, expected: f128) !void {
- const x = __floatditf(a);
- try testing.expect(x == expected);
-}
-
-test "floatditf" {
- try test__floatditf(0x7fffffffffffffff, make_ti(0x403dffffffffffff, 0xfffc000000000000));
- try test__floatditf(0x123456789abcdef1, make_ti(0x403b23456789abcd, 0xef10000000000000));
- try test__floatditf(0x2, make_ti(0x4000000000000000, 0x0));
- try test__floatditf(0x1, make_ti(0x3fff000000000000, 0x0));
- try test__floatditf(0x0, make_ti(0x0, 0x0));
- try test__floatditf(@bitCast(i64, @as(u64, 0xffffffffffffffff)), make_ti(0xbfff000000000000, 0x0));
- try test__floatditf(@bitCast(i64, @as(u64, 0xfffffffffffffffe)), make_ti(0xc000000000000000, 0x0));
- try test__floatditf(-0x123456789abcdef1, make_ti(0xc03b23456789abcd, 0xef10000000000000));
- try test__floatditf(@bitCast(i64, @as(u64, 0x8000000000000000)), make_ti(0xc03e000000000000, 0x0));
-}
-
-fn make_ti(high: u64, low: u64) f128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return @bitCast(f128, result);
-}
diff --git a/lib/std/special/compiler_rt/floatfmodl_test.zig b/lib/std/special/compiler_rt/floatfmodl_test.zig
deleted file mode 100644
index 58636ef6f7..0000000000
--- a/lib/std/special/compiler_rt/floatfmodl_test.zig
+++ /dev/null
@@ -1,46 +0,0 @@
-const std = @import("std");
-const fmodl = @import("floatfmodl.zig");
-const testing = std.testing;
-
-fn test_fmodl(a: f128, b: f128, exp: f128) !void {
- const res = fmodl.fmodl(a, b);
- try testing.expect(exp == res);
-}
-
-fn test_fmodl_nans() !void {
- try testing.expect(std.math.isNan(fmodl.fmodl(1.0, std.math.nan_f128)));
- try testing.expect(std.math.isNan(fmodl.fmodl(1.0, -std.math.nan_f128)));
- try testing.expect(std.math.isNan(fmodl.fmodl(std.math.nan_f128, 1.0)));
- try testing.expect(std.math.isNan(fmodl.fmodl(-std.math.nan_f128, 1.0)));
-}
-
-fn test_fmodl_infs() !void {
- try testing.expect(fmodl.fmodl(1.0, std.math.inf_f128) == 1.0);
- try testing.expect(fmodl.fmodl(1.0, -std.math.inf_f128) == 1.0);
- try testing.expect(std.math.isNan(fmodl.fmodl(std.math.inf_f128, 1.0)));
- try testing.expect(std.math.isNan(fmodl.fmodl(-std.math.inf_f128, 1.0)));
-}
-
-test "fmodl" {
- try test_fmodl(6.8, 4.0, 2.8);
- try test_fmodl(6.8, -4.0, 2.8);
- try test_fmodl(-6.8, 4.0, -2.8);
- try test_fmodl(-6.8, -4.0, -2.8);
- try test_fmodl(3.0, 2.0, 1.0);
- try test_fmodl(-5.0, 3.0, -2.0);
- try test_fmodl(3.0, 2.0, 1.0);
- try test_fmodl(1.0, 2.0, 1.0);
- try test_fmodl(0.0, 1.0, 0.0);
- try test_fmodl(-0.0, 1.0, -0.0);
- try test_fmodl(7046119.0, 5558362.0, 1487757.0);
- try test_fmodl(9010357.0, 1957236.0, 1181413.0);
-
- // Denormals
- const a: f128 = 0xedcb34a235253948765432134674p-16494;
- const b: f128 = 0x5d2e38791cfbc0737402da5a9518p-16494;
- const exp: f128 = 0x336ec3affb2db8618e4e7d5e1c44p-16494;
- try test_fmodl(a, b, exp);
-
- try test_fmodl_nans();
- try test_fmodl_infs();
-}
diff --git a/lib/std/special/compiler_rt/floatfmodl.zig b/lib/std/special/compiler_rt/floatfmodq.zig
index 942a7c1125..b8da727c90 100644
--- a/lib/std/special/compiler_rt/floatfmodl.zig
+++ b/lib/std/special/compiler_rt/floatfmodq.zig
@@ -1,9 +1,9 @@
const builtin = @import("builtin");
const std = @import("std");
-// fmodl - floating modulo large, returns the remainder of division for f128 types
+// fmodq - floating modulo large, returns the remainder of division for f128 types
// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits
-pub fn fmodl(a: f128, b: f128) callconv(.C) f128 {
+pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {
@setRuntimeSafety(builtin.is_test);
var amod = a;
var bmod = b;
@@ -30,9 +30,9 @@ pub fn fmodl(a: f128, b: f128) callconv(.C) f128 {
var expB = bPtr_u16[exp_and_sign_index] & 0x7fff;
// There are 3 cases where the answer is undefined, check for:
- // - fmodl(val, 0)
- // - fmodl(val, NaN)
- // - fmodl(inf, val)
+ // - fmodq(val, 0)
+ // - fmodq(val, NaN)
+ // - fmodq(inf, val)
// The sign on checked values does not matter.
// Doing (a * b) / (a * b) procudes undefined results
// because the three cases always produce undefined calculations:
@@ -122,5 +122,5 @@ pub fn fmodl(a: f128, b: f128) callconv(.C) f128 {
}
test {
- _ = @import("floatfmodl_test.zig");
+ _ = @import("floatfmodq_test.zig");
}
diff --git a/lib/std/special/compiler_rt/floatfmodq_test.zig b/lib/std/special/compiler_rt/floatfmodq_test.zig
new file mode 100644
index 0000000000..a272b797e3
--- /dev/null
+++ b/lib/std/special/compiler_rt/floatfmodq_test.zig
@@ -0,0 +1,46 @@
+const std = @import("std");
+const fmodq = @import("floatfmodq.zig");
+const testing = std.testing;
+
+fn test_fmodq(a: f128, b: f128, exp: f128) !void {
+ const res = fmodq.fmodq(a, b);
+ try testing.expect(exp == res);
+}
+
+fn test_fmodq_nans() !void {
+ try testing.expect(std.math.isNan(fmodq.fmodq(1.0, std.math.nan(f128))));
+ try testing.expect(std.math.isNan(fmodq.fmodq(1.0, -std.math.nan(f128))));
+ try testing.expect(std.math.isNan(fmodq.fmodq(std.math.nan(f128), 1.0)));
+ try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.nan(f128), 1.0)));
+}
+
+fn test_fmodq_infs() !void {
+ try testing.expect(fmodq.fmodq(1.0, std.math.inf(f128)) == 1.0);
+ try testing.expect(fmodq.fmodq(1.0, -std.math.inf(f128)) == 1.0);
+ try testing.expect(std.math.isNan(fmodq.fmodq(std.math.inf(f128), 1.0)));
+ try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.inf(f128), 1.0)));
+}
+
+test "fmodq" {
+ try test_fmodq(6.8, 4.0, 2.8);
+ try test_fmodq(6.8, -4.0, 2.8);
+ try test_fmodq(-6.8, 4.0, -2.8);
+ try test_fmodq(-6.8, -4.0, -2.8);
+ try test_fmodq(3.0, 2.0, 1.0);
+ try test_fmodq(-5.0, 3.0, -2.0);
+ try test_fmodq(3.0, 2.0, 1.0);
+ try test_fmodq(1.0, 2.0, 1.0);
+ try test_fmodq(0.0, 1.0, 0.0);
+ try test_fmodq(-0.0, 1.0, -0.0);
+ try test_fmodq(7046119.0, 5558362.0, 1487757.0);
+ try test_fmodq(9010357.0, 1957236.0, 1181413.0);
+
+ // Denormals
+ const a: f128 = 0xedcb34a235253948765432134674p-16494;
+ const b: f128 = 0x5d2e38791cfbc0737402da5a9518p-16494;
+ const exp: f128 = 0x336ec3affb2db8618e4e7d5e1c44p-16494;
+ try test_fmodq(a, b, exp);
+
+ try test_fmodq_nans();
+ try test_fmodq_infs();
+}
diff --git a/lib/std/special/compiler_rt/floatsiXf.zig b/lib/std/special/compiler_rt/floatsiXf.zig
deleted file mode 100644
index ef551d1911..0000000000
--- a/lib/std/special/compiler_rt/floatsiXf.zig
+++ /dev/null
@@ -1,120 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-inline fn floatsiXf(comptime T: type, a: i32) T {
- @setRuntimeSafety(builtin.is_test);
-
- 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));
-
- if (a == 0) {
- return @as(T, 0.0);
- }
-
- const significandBits = std.math.floatMantissaBits(T);
- const exponentBits = std.math.floatExponentBits(T);
- const exponentBias = ((1 << exponentBits - 1) - 1);
-
- const implicitBit = @as(Z, 1) << significandBits;
- const signBit = @as(Z, 1 << bits - 1);
-
- const sign = a >> 31;
- // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31).
- const abs_a = (a ^ sign) -% sign;
- // The exponent is the width of abs(a)
- const exp = @as(Z, 31 - @clz(i32, abs_a));
-
- const sign_bit = if (sign < 0) signBit else 0;
-
- var mantissa: Z = undefined;
- // Shift a into the significand field and clear the implicit bit.
- if (exp <= significandBits) {
- // No rounding needed
- const shift = @intCast(S, significandBits - exp);
- mantissa = @intCast(Z, @bitCast(u32, abs_a)) << shift ^ implicitBit;
- } else {
- const shift = @intCast(S, exp - significandBits);
- // Round to the nearest number after truncation
- mantissa = @intCast(Z, @bitCast(u32, abs_a)) >> shift ^ implicitBit;
- // Align to the left and check if the truncated part is halfway over
- const round = @bitCast(u32, abs_a) << @intCast(u5, 31 - shift);
- mantissa += @boolToInt(round > 0x80000000);
- // Tie to even
- mantissa += mantissa & 1;
- }
-
- // Use the addition instead of a or since we may have a carry from the
- // mantissa to the exponent
- var result = mantissa;
- result += (exp + exponentBias) << significandBits;
- result += sign_bit;
-
- return @bitCast(T, result);
-}
-
-pub fn __floatsisf(arg: i32) callconv(.C) f32 {
- @setRuntimeSafety(builtin.is_test);
- return floatsiXf(f32, arg);
-}
-
-pub fn __floatsidf(arg: i32) callconv(.C) f64 {
- @setRuntimeSafety(builtin.is_test);
- return floatsiXf(f64, arg);
-}
-
-pub fn __floatsitf(arg: i32) callconv(.C) f128 {
- @setRuntimeSafety(builtin.is_test);
- return floatsiXf(f128, arg);
-}
-
-pub fn __aeabi_i2d(arg: i32) callconv(.AAPCS) f64 {
- @setRuntimeSafety(false);
- return floatsiXf(f64, arg);
-}
-
-pub fn __aeabi_i2f(arg: i32) callconv(.AAPCS) f32 {
- @setRuntimeSafety(false);
- return floatsiXf(f32, arg);
-}
-
-fn test_one_floatsitf(a: i32, expected: u128) !void {
- const r = __floatsitf(a);
- try std.testing.expect(@bitCast(u128, r) == expected);
-}
-
-fn test_one_floatsidf(a: i32, expected: u64) !void {
- const r = __floatsidf(a);
- try std.testing.expect(@bitCast(u64, r) == expected);
-}
-
-fn test_one_floatsisf(a: i32, expected: u32) !void {
- const r = __floatsisf(a);
- try std.testing.expect(@bitCast(u32, r) == expected);
-}
-
-test "floatsidf" {
- try test_one_floatsidf(0, 0x0000000000000000);
- try test_one_floatsidf(1, 0x3ff0000000000000);
- try test_one_floatsidf(-1, 0xbff0000000000000);
- try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000);
- try test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000);
-}
-
-test "floatsisf" {
- try test_one_floatsisf(0, 0x00000000);
- try test_one_floatsisf(1, 0x3f800000);
- try test_one_floatsisf(-1, 0xbf800000);
- try test_one_floatsisf(0x7FFFFFFF, 0x4f000000);
- try test_one_floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000);
-}
-
-test "floatsitf" {
- try test_one_floatsitf(0, 0);
- try test_one_floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000);
- try test_one_floatsitf(0x12345678, 0x401b2345678000000000000000000000);
- try test_one_floatsitf(-0x12345678, 0xc01b2345678000000000000000000000);
- try test_one_floatsitf(@bitCast(i32, @intCast(u32, 0xffffffff)), 0xbfff0000000000000000000000000000);
- try test_one_floatsitf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc01e0000000000000000000000000000);
-}
diff --git a/lib/std/special/compiler_rt/floattidf.zig b/lib/std/special/compiler_rt/floattidf.zig
deleted file mode 100644
index 85f84a23d6..0000000000
--- a/lib/std/special/compiler_rt/floattidf.zig
+++ /dev/null
@@ -1,71 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const DBL_MANT_DIG = 53;
-
-pub fn __floattidf(arg: i128) callconv(.C) f64 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- var ai = arg;
- const N: u32 = 128;
- const si = ai >> @intCast(u7, (N - 1));
- ai = ((ai ^ si) -% si);
- var a = @bitCast(u128, ai);
-
- const sd = @bitCast(i32, N - @clz(u128, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
- if (sd > DBL_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit DBL_MANT_DIG-1 bits to the right of 1
- // Q = bit DBL_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- DBL_MANT_DIG + 1 => {
- a <<= 1;
- },
- DBL_MANT_DIG + 2 => {},
- else => {
- const shift1_amt = @intCast(i32, sd - (DBL_MANT_DIG + 2));
- const shift1_amt_u7 = @intCast(u7, shift1_amt);
-
- const shift2_amt = @intCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
- const shift2_amt_u7 = @intCast(u7, shift2_amt);
-
- a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, maxInt(u128)) >> shift2_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
- if ((a & (@as(u128, 1) << DBL_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to DBL_MANT_DIG bits
- } else {
- a <<= @intCast(u7, DBL_MANT_DIG - sd);
- // a is now rounded to DBL_MANT_DIG bits
- }
-
- const s = @bitCast(u128, arg) >> (128 - 32);
- const high: u64 = (@intCast(u64, s) & 0x80000000) | // sign
- (@intCast(u32, (e + 1023)) << 20) | // exponent
- (@truncate(u32, a >> 32) & 0x000fffff); // mantissa-high
- const low: u64 = @truncate(u32, a); // mantissa-low
-
- return @bitCast(f64, low | (high << 32));
-}
-
-test {
- _ = @import("floattidf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floattidf_test.zig b/lib/std/special/compiler_rt/floattidf_test.zig
deleted file mode 100644
index 62b131744f..0000000000
--- a/lib/std/special/compiler_rt/floattidf_test.zig
+++ /dev/null
@@ -1,84 +0,0 @@
-const __floattidf = @import("floattidf.zig").__floattidf;
-const testing = @import("std").testing;
-
-fn test__floattidf(a: i128, expected: f64) !void {
- const x = __floattidf(a);
- try testing.expect(x == expected);
-}
-
-test "floattidf" {
- try test__floattidf(0, 0.0);
-
- try test__floattidf(1, 1.0);
- try test__floattidf(2, 2.0);
- try test__floattidf(20, 20.0);
- try test__floattidf(-1, -1.0);
- try test__floattidf(-2, -2.0);
- try test__floattidf(-20, -20.0);
-
- try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
-
- try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
- try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
- try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
- try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
-
- try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
- try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127);
-
- try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
-
- try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
-
- try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
- try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
- try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
- try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
- try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
- try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-
- try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
- try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
- try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
- try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
- try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
-}
-
-fn make_ti(high: u64, low: u64) i128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return @bitCast(i128, result);
-}
diff --git a/lib/std/special/compiler_rt/floattisf_test.zig b/lib/std/special/compiler_rt/floattisf_test.zig
deleted file mode 100644
index 30b36c3f9f..0000000000
--- a/lib/std/special/compiler_rt/floattisf_test.zig
+++ /dev/null
@@ -1,60 +0,0 @@
-const __floattisf = @import("floatXisf.zig").__floattisf;
-const testing = @import("std").testing;
-
-fn test__floattisf(a: i128, expected: f32) !void {
- const x = __floattisf(a);
- try testing.expect(x == expected);
-}
-
-test "floattisf" {
- try test__floattisf(0, 0.0);
-
- try test__floattisf(1, 1.0);
- try test__floattisf(2, 2.0);
- try test__floattisf(-1, -1.0);
- try test__floattisf(-2, -2.0);
-
- try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
-
- try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62);
- try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62);
-
- try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63);
- try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63);
-
- try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
- try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
-
- try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
- try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
-
- try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114);
-
- try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114);
- try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114);
-
- try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114);
- try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114);
-}
-
-fn make_ti(high: u64, low: u64) i128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return @bitCast(i128, result);
-}
diff --git a/lib/std/special/compiler_rt/floattitf.zig b/lib/std/special/compiler_rt/floattitf.zig
deleted file mode 100644
index aa83f6686e..0000000000
--- a/lib/std/special/compiler_rt/floattitf.zig
+++ /dev/null
@@ -1,71 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const LDBL_MANT_DIG = 113;
-
-pub fn __floattitf(arg: i128) callconv(.C) f128 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- var ai = arg;
- const N: u32 = 128;
- const si = ai >> @intCast(u7, (N - 1));
- ai = ((ai ^ si) -% si);
- var a = @bitCast(u128, ai);
-
- const sd = @bitCast(i32, N - @clz(u128, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
- if (sd > LDBL_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit LDBL_MANT_DIG-1 bits to the right of 1
- // Q = bit LDBL_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- LDBL_MANT_DIG + 1 => {
- a <<= 1;
- },
- LDBL_MANT_DIG + 2 => {},
- else => {
- const shift1_amt = @intCast(i32, sd - (LDBL_MANT_DIG + 2));
- const shift1_amt_u7 = @intCast(u7, shift1_amt);
-
- const shift2_amt = @intCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
- const shift2_amt_u7 = @intCast(u7, shift2_amt);
-
- a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, maxInt(u128)) >> shift2_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
- if ((a & (@as(u128, 1) << LDBL_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to LDBL_MANT_DIG bits
- } else {
- a <<= @intCast(u7, LDBL_MANT_DIG - sd);
- // a is now rounded to LDBL_MANT_DIG bits
- }
-
- const s = @bitCast(u128, arg) >> (128 - 64);
- const high: u128 = (@intCast(u64, s) & 0x8000000000000000) | // sign
- (@intCast(u64, (e + 16383)) << 48) | // exponent
- (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
- const low = @truncate(u64, a); // mantissa-low
-
- return @bitCast(f128, low | (high << 64));
-}
-
-test {
- _ = @import("floattitf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floattitf_test.zig b/lib/std/special/compiler_rt/floattitf_test.zig
deleted file mode 100644
index 76dfc8fbfc..0000000000
--- a/lib/std/special/compiler_rt/floattitf_test.zig
+++ /dev/null
@@ -1,96 +0,0 @@
-const __floattitf = @import("floattitf.zig").__floattitf;
-const testing = @import("std").testing;
-
-fn test__floattitf(a: i128, expected: f128) !void {
- const x = __floattitf(a);
- try testing.expect(x == expected);
-}
-
-test "floattitf" {
- try test__floattitf(0, 0.0);
-
- try test__floattitf(1, 1.0);
- try test__floattitf(2, 2.0);
- try test__floattitf(20, 20.0);
- try test__floattitf(-1, -1.0);
- try test__floattitf(-2, -2.0);
- try test__floattitf(-20, -20.0);
-
- try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
-
- try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
- try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
- try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
- try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
-
- try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
- try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126);
-
- try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
-
- try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
-
- try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
- try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
- try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
- try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
- try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
- try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
- try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
- try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
- try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
- try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
- try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
- try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
- try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
- try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-
- try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
- try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
- try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
- try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
- try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
- try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
- try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
- try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
- try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
- try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
- try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
- try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
- try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
- try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
-
- try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
-
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
- try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
-}
-
-fn make_ti(high: u64, low: u64) i128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return @bitCast(i128, result);
-}
diff --git a/lib/std/special/compiler_rt/floatundidf.zig b/lib/std/special/compiler_rt/floatundidf.zig
deleted file mode 100644
index 14e7434490..0000000000
--- a/lib/std/special/compiler_rt/floatundidf.zig
+++ /dev/null
@@ -1,29 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-
-const twop52: f64 = 0x1.0p52;
-const twop84: f64 = 0x1.0p84;
-const twop84_plus_twop52: f64 = 0x1.00000001p84;
-
-pub fn __floatundidf(a: u64) callconv(.C) f64 {
- @setRuntimeSafety(builtin.is_test);
-
- if (a == 0) return 0;
-
- var high = @bitCast(u64, twop84);
- var low = @bitCast(u64, twop52);
-
- high |= a >> 32;
- low |= a & 0xFFFFFFFF;
-
- return (@bitCast(f64, high) - twop84_plus_twop52) + @bitCast(f64, low);
-}
-
-pub fn __aeabi_ul2d(arg: u64) callconv(.AAPCS) f64 {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __floatundidf, .{arg});
-}
-
-test {
- _ = @import("floatundidf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatundidf_test.zig b/lib/std/special/compiler_rt/floatundidf_test.zig
deleted file mode 100644
index 71bfdd3087..0000000000
--- a/lib/std/special/compiler_rt/floatundidf_test.zig
+++ /dev/null
@@ -1,50 +0,0 @@
-const __floatundidf = @import("floatundidf.zig").__floatundidf;
-const testing = @import("std").testing;
-
-fn test__floatundidf(a: u64, expected: f64) !void {
- const r = __floatundidf(a);
- try testing.expect(r == expected);
-}
-
-test "floatundidf" {
- try test__floatundidf(0, 0.0);
- try test__floatundidf(1, 1.0);
- try test__floatundidf(2, 2.0);
- try test__floatundidf(20, 20.0);
- try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
- try test__floatundidf(0x8000008000000000, 0x1.000001p+63);
- try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63);
- try test__floatundidf(0x8000010000000000, 0x1.000002p+63);
- try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63);
- try test__floatundidf(0x8000000000000000, 0x1p+63);
- try test__floatundidf(0x8000000000000001, 0x1p+63);
- try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
- try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
- try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
- try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
- try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
- try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
- try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
- try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
- try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-}
diff --git a/lib/std/special/compiler_rt/floatundisf.zig b/lib/std/special/compiler_rt/floatundisf.zig
deleted file mode 100644
index ffbe3ef252..0000000000
--- a/lib/std/special/compiler_rt/floatundisf.zig
+++ /dev/null
@@ -1,94 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const FLT_MANT_DIG = 24;
-
-inline fn floatundisf(arg: u64) f32 {
- @setRuntimeSafety(builtin.is_test);
-
- if (arg == 0) return 0;
-
- var a = arg;
- const N: usize = @typeInfo(@TypeOf(a)).Int.bits;
- // Number of significant digits
- const sd = N - @clz(u64, a);
- // 8 exponent
- var e = @intCast(u32, sd) - 1;
-
- if (sd > FLT_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit FLT_MANT_DIG-1 bits to the right of 1
- // Q = bit FLT_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- FLT_MANT_DIG + 1 => a <<= 1,
- FLT_MANT_DIG + 2 => {},
- else => {
- const shift_amt = @intCast(u6, ((N + FLT_MANT_DIG + 2) - sd));
- const all_ones: u64 = maxInt(u64);
- a = (a >> @intCast(u6, sd - (FLT_MANT_DIG + 2))) |
- @boolToInt(a & (all_ones >> shift_amt) != 0);
- },
- }
- // Or P into R
- a |= @boolToInt((a & 4) != 0);
- // round - this step may add a significant bit
- a += 1;
- // dump Q and R
- a >>= 2;
- // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
- if ((a & (@as(u64, 1) << FLT_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to FLT_MANT_DIG bits
- } else {
- a <<= @intCast(u6, FLT_MANT_DIG - sd);
- // a is now rounded to FLT_MANT_DIG bits
- }
-
- const result: u32 = ((e + 127) << 23) | // exponent
- @truncate(u32, a & 0x007FFFFF); // mantissa
- return @bitCast(f32, result);
-}
-
-pub fn __floatundisf(arg: u64) callconv(.C) f32 {
- return floatundisf(arg);
-}
-
-pub fn __aeabi_ul2f(arg: u64) callconv(.AAPCS) f32 {
- return floatundisf(arg);
-}
-
-fn test__floatundisf(a: u64, expected: f32) !void {
- try std.testing.expectEqual(expected, __floatundisf(a));
-}
-
-test "floatundisf" {
- try test__floatundisf(0, 0.0);
- try test__floatundisf(1, 1.0);
- try test__floatundisf(2, 2.0);
- try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatundisf(0x8000008000000000, 0x1p+63);
- try test__floatundisf(0x8000010000000000, 0x1.000002p+63);
- try test__floatundisf(0x8000000000000000, 0x1p+63);
- try test__floatundisf(0x8000000000000001, 0x1p+63);
- try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
- try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
- try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
- try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
- try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
-}
diff --git a/lib/std/special/compiler_rt/floatunditf.zig b/lib/std/special/compiler_rt/floatunditf.zig
deleted file mode 100644
index b304c8cdba..0000000000
--- a/lib/std/special/compiler_rt/floatunditf.zig
+++ /dev/null
@@ -1,28 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-
-pub fn __floatunditf(a: u64) callconv(.C) f128 {
- @setRuntimeSafety(is_test);
-
- if (a == 0) {
- return 0;
- }
-
- const mantissa_bits = std.math.floatMantissaBits(f128);
- const exponent_bits = std.math.floatExponentBits(f128);
- const exponent_bias = (1 << (exponent_bits - 1)) - 1;
- const implicit_bit = 1 << mantissa_bits;
-
- const exp: u128 = (64 - 1) - @clz(u64, a);
- const shift: u7 = mantissa_bits - @intCast(u7, exp);
-
- var result: u128 = (@intCast(u128, a) << shift) ^ implicit_bit;
- result += (exp + exponent_bias) << mantissa_bits;
-
- return @bitCast(f128, result);
-}
-
-test {
- _ = @import("floatunditf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatunditf_test.zig b/lib/std/special/compiler_rt/floatunditf_test.zig
deleted file mode 100644
index ae6834c082..0000000000
--- a/lib/std/special/compiler_rt/floatunditf_test.zig
+++ /dev/null
@@ -1,32 +0,0 @@
-const __floatunditf = @import("floatunditf.zig").__floatunditf;
-
-fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void {
- const x = __floatunditf(a);
-
- const x_repr = @bitCast(u128, x);
- const x_hi = @intCast(u64, x_repr >> 64);
- const x_lo = @truncate(u64, x_repr);
-
- if (x_hi == expected_hi and x_lo == expected_lo) {
- return;
- }
- // nan repr
- else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
- if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
- return;
- }
- }
-
- @panic("__floatunditf test failure");
-}
-
-test "floatunditf" {
- try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000);
- try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000);
- try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0);
- try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000);
- try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000);
- try test__floatunditf(0x2, 0x4000000000000000, 0x0);
- try test__floatunditf(0x1, 0x3fff000000000000, 0x0);
- try test__floatunditf(0x0, 0x0, 0x0);
-}
diff --git a/lib/std/special/compiler_rt/floatunsidf.zig b/lib/std/special/compiler_rt/floatunsidf.zig
deleted file mode 100644
index f474c1de8f..0000000000
--- a/lib/std/special/compiler_rt/floatunsidf.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const implicitBit = @as(u64, 1) << 52;
-
-inline fn floatunsidf(arg: u32) f64 {
- @setRuntimeSafety(builtin.is_test);
-
- if (arg == 0) return 0.0;
-
- // The exponent is the width of abs(a)
- const exp = @as(u64, 31) - @clz(u32, arg);
- // Shift a into the significand field and clear the implicit bit
- const shift = @intCast(u6, 52 - exp);
- const mant = @as(u64, arg) << shift ^ implicitBit;
-
- return @bitCast(f64, mant | (exp + 1023) << 52);
-}
-
-pub fn __floatunsidf(arg: u32) callconv(.C) f64 {
- return floatunsidf(arg);
-}
-
-pub fn __aeabi_ui2d(arg: u32) callconv(.AAPCS) f64 {
- return floatunsidf(arg);
-}
-
-fn test_one_floatunsidf(a: u32, expected: u64) !void {
- const r = __floatunsidf(a);
- try std.testing.expect(@bitCast(u64, r) == expected);
-}
-
-test "floatsidf" {
- // Test the produced bit pattern
- try test_one_floatunsidf(0, 0x0000000000000000);
- try test_one_floatunsidf(1, 0x3ff0000000000000);
- try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000);
- try test_one_floatunsidf(@intCast(u32, 0x80000000), 0x41e0000000000000);
- try test_one_floatunsidf(@intCast(u32, 0xFFFFFFFF), 0x41efffffffe00000);
-}
diff --git a/lib/std/special/compiler_rt/floatunsisf.zig b/lib/std/special/compiler_rt/floatunsisf.zig
deleted file mode 100644
index d267baee01..0000000000
--- a/lib/std/special/compiler_rt/floatunsisf.zig
+++ /dev/null
@@ -1,61 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const significandBits = 23;
-const exponentBias = 127;
-const implicitBit = @as(u32, 1) << significandBits;
-
-inline fn floatunsisf(arg: u32) f32 {
- @setRuntimeSafety(builtin.is_test);
-
- if (arg == 0) return 0.0;
-
- // The exponent is the width of abs(a)
- const exp = @as(u32, 31) - @clz(u32, arg);
-
- var mantissa: u32 = undefined;
- if (exp <= significandBits) {
- // Shift a into the significand field and clear the implicit bit
- const shift = @intCast(u5, significandBits - exp);
- mantissa = @as(u32, arg) << shift ^ implicitBit;
- } else {
- const shift = @intCast(u5, exp - significandBits);
- // Round to the nearest number after truncation
- mantissa = @as(u32, arg) >> shift ^ implicitBit;
- // Align to the left and check if the truncated part is halfway over
- const round = arg << @intCast(u5, 31 - shift);
- mantissa += @boolToInt(round > 0x80000000);
- // Tie to even
- mantissa += mantissa & 1;
- }
-
- // Use the addition instead of a or since we may have a carry from the
- // mantissa to the exponent
- var result = mantissa;
- result += (exp + exponentBias) << significandBits;
-
- return @bitCast(f32, result);
-}
-
-pub fn __floatunsisf(arg: u32) callconv(.C) f32 {
- return floatunsisf(arg);
-}
-
-pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 {
- return floatunsisf(arg);
-}
-
-fn test_one_floatunsisf(a: u32, expected: u32) !void {
- const r = __floatunsisf(a);
- try std.testing.expect(@bitCast(u32, r) == expected);
-}
-
-test "floatunsisf" {
- // Test the produced bit pattern
- try test_one_floatunsisf(0, 0);
- try test_one_floatunsisf(1, 0x3f800000);
- try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000);
- try test_one_floatunsisf(0x80000000, 0x4f000000);
- try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000);
-}
diff --git a/lib/std/special/compiler_rt/floatunsitf.zig b/lib/std/special/compiler_rt/floatunsitf.zig
deleted file mode 100644
index 8774d486ea..0000000000
--- a/lib/std/special/compiler_rt/floatunsitf.zig
+++ /dev/null
@@ -1,29 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-
-pub fn __floatunsitf(a: u32) callconv(.C) f128 {
- @setRuntimeSafety(is_test);
-
- if (a == 0) {
- return 0;
- }
-
- const mantissa_bits = std.math.floatMantissaBits(f128);
- const exponent_bits = std.math.floatExponentBits(f128);
- const exponent_bias = (1 << (exponent_bits - 1)) - 1;
- const implicit_bit = 1 << mantissa_bits;
-
- const exp = (32 - 1) - @clz(u32, a);
- const shift = mantissa_bits - @intCast(u7, exp);
-
- // TODO(#1148): @bitCast alignment error
- var result align(16) = (@intCast(u128, a) << shift) ^ implicit_bit;
- result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;
-
- return @bitCast(f128, result);
-}
-
-test {
- _ = @import("floatunsitf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatunsitf_test.zig b/lib/std/special/compiler_rt/floatunsitf_test.zig
deleted file mode 100644
index 7ae7c43281..0000000000
--- a/lib/std/special/compiler_rt/floatunsitf_test.zig
+++ /dev/null
@@ -1,28 +0,0 @@
-const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;
-
-fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void {
- const x = __floatunsitf(a);
-
- const x_repr = @bitCast(u128, x);
- const x_hi = @intCast(u64, x_repr >> 64);
- const x_lo = @truncate(u64, x_repr);
-
- if (x_hi == expected_hi and x_lo == expected_lo) {
- return;
- }
- // nan repr
- else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
- if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
- return;
- }
- }
-
- @panic("__floatunsitf test failure");
-}
-
-test "floatunsitf" {
- try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0);
- try test__floatunsitf(0, 0x0, 0x0);
- try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0);
- try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0);
-}
diff --git a/lib/std/special/compiler_rt/floatuntidf.zig b/lib/std/special/compiler_rt/floatuntidf.zig
deleted file mode 100644
index 2c4729a9d8..0000000000
--- a/lib/std/special/compiler_rt/floatuntidf.zig
+++ /dev/null
@@ -1,62 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const DBL_MANT_DIG = 53;
-
-pub fn __floatuntidf(arg: u128) callconv(.C) f64 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- var a = arg;
- const N: u32 = @sizeOf(u128) * 8;
- const sd = @bitCast(i32, N - @clz(u128, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
- if (sd > DBL_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit DBL_MANT_DIG-1 bits to the right of 1
- // Q = bit DBL_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- DBL_MANT_DIG + 1 => {
- a <<= 1;
- },
- DBL_MANT_DIG + 2 => {},
- else => {
- const shift_amt = @bitCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
- const shift_amt_u7 = @intCast(u7, shift_amt);
- a = (a >> @intCast(u7, sd - (DBL_MANT_DIG + 2))) |
- @boolToInt((a & (@as(u128, maxInt(u128)) >> shift_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
- if ((a & (@as(u128, 1) << DBL_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to DBL_MANT_DIG bits
- } else {
- a <<= @intCast(u7, DBL_MANT_DIG - sd);
- // a is now rounded to DBL_MANT_DIG bits
- }
-
- const high: u64 = @bitCast(u32, (e + 1023) << 20) | // exponent
- (@truncate(u32, a >> 32) & 0x000FFFFF); // mantissa-high
- const low = @truncate(u32, a); // mantissa-low
-
- return @bitCast(f64, low | (high << 32));
-}
-
-test {
- _ = @import("floatuntidf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatuntidf_test.zig b/lib/std/special/compiler_rt/floatuntidf_test.zig
deleted file mode 100644
index 5fc6a47150..0000000000
--- a/lib/std/special/compiler_rt/floatuntidf_test.zig
+++ /dev/null
@@ -1,81 +0,0 @@
-const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;
-const testing = @import("std").testing;
-
-fn test__floatuntidf(a: u128, expected: f64) !void {
- const x = __floatuntidf(a);
- try testing.expect(x == expected);
-}
-
-test "floatuntidf" {
- try test__floatuntidf(0, 0.0);
-
- try test__floatuntidf(1, 1.0);
- try test__floatuntidf(2, 2.0);
- try test__floatuntidf(20, 20.0);
-
- try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
-
- try test__floatuntidf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
- try test__floatuntidf(make_ti(0x8000000000000800, 0), 0x1.0000000000001p+127);
- try test__floatuntidf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
- try test__floatuntidf(make_ti(0x8000000000001000, 0), 0x1.0000000000002p+127);
-
- try test__floatuntidf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
- try test__floatuntidf(make_ti(0x8000000000000001, 0), 0x1.0000000000000002p+127);
-
- try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
-
- try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
-
- try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
- try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
- try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
- try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
- try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
- try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-
- try test__floatuntidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
- try test__floatuntidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
-}
-
-fn make_ti(high: u64, low: u64) u128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return result;
-}
diff --git a/lib/std/special/compiler_rt/floatuntisf.zig b/lib/std/special/compiler_rt/floatuntisf.zig
deleted file mode 100644
index 2a54c2e0f3..0000000000
--- a/lib/std/special/compiler_rt/floatuntisf.zig
+++ /dev/null
@@ -1,61 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const FLT_MANT_DIG = 24;
-
-pub fn __floatuntisf(arg: u128) callconv(.C) f32 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- var a = arg;
- const N: u32 = @sizeOf(u128) * 8;
- const sd = @bitCast(i32, N - @clz(u128, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
- if (sd > FLT_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit FLT_MANT_DIG-1 bits to the right of 1
- // Q = bit FLT_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- FLT_MANT_DIG + 1 => {
- a <<= 1;
- },
- FLT_MANT_DIG + 2 => {},
- else => {
- const shift_amt = @bitCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
- const shift_amt_u7 = @intCast(u7, shift_amt);
- a = (a >> @intCast(u7, sd - (FLT_MANT_DIG + 2))) |
- @boolToInt((a & (@as(u128, maxInt(u128)) >> shift_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
- if ((a & (@as(u128, 1) << FLT_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to FLT_MANT_DIG bits
- } else {
- a <<= @intCast(u7, FLT_MANT_DIG - sd);
- // a is now rounded to FLT_MANT_DIG bits
- }
-
- const high = @bitCast(u32, (e + 127) << 23); // exponent
- const low = @truncate(u32, a) & 0x007fffff; // mantissa
-
- return @bitCast(f32, high | low);
-}
-
-test {
- _ = @import("floatuntisf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatuntisf_test.zig b/lib/std/special/compiler_rt/floatuntisf_test.zig
deleted file mode 100644
index dd06b7e3d7..0000000000
--- a/lib/std/special/compiler_rt/floatuntisf_test.zig
+++ /dev/null
@@ -1,72 +0,0 @@
-const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
-const testing = @import("std").testing;
-
-fn test__floatuntisf(a: u128, expected: f32) !void {
- const x = __floatuntisf(a);
- try testing.expect(x == expected);
-}
-
-test "floatuntisf" {
- try test__floatuntisf(0, 0.0);
-
- try test__floatuntisf(1, 1.0);
- try test__floatuntisf(2, 2.0);
- try test__floatuntisf(20, 20.0);
-
- try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
-
- try test__floatuntisf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
- try test__floatuntisf(make_ti(0x8000000000000800, 0), 0x1.0p+127);
- try test__floatuntisf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
-
- try test__floatuntisf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
-
- try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
-
- try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
-
- try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
-
- try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
- try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
-
- try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
- try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
-
- try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
- try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
-
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76);
- try test__floatuntisf(make_ti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76);
-}
-
-fn make_ti(high: u64, low: u64) u128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return result;
-}
diff --git a/lib/std/special/compiler_rt/floatuntitf.zig b/lib/std/special/compiler_rt/floatuntitf.zig
deleted file mode 100644
index c35b4dcf74..0000000000
--- a/lib/std/special/compiler_rt/floatuntitf.zig
+++ /dev/null
@@ -1,62 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-const std = @import("std");
-const maxInt = std.math.maxInt;
-
-const LDBL_MANT_DIG = 113;
-
-pub fn __floatuntitf(arg: u128) callconv(.C) f128 {
- @setRuntimeSafety(is_test);
-
- if (arg == 0)
- return 0.0;
-
- var a = arg;
- const N: u32 = @sizeOf(u128) * 8;
- const sd = @bitCast(i32, N - @clz(u128, a)); // number of significant digits
- var e: i32 = sd - 1; // exponent
- if (sd > LDBL_MANT_DIG) {
- // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- // 12345678901234567890123456
- // 1 = msb 1 bit
- // P = bit LDBL_MANT_DIG-1 bits to the right of 1
- // Q = bit LDBL_MANT_DIG bits to the right of 1
- // R = "or" of all bits to the right of Q
- switch (sd) {
- LDBL_MANT_DIG + 1 => {
- a <<= 1;
- },
- LDBL_MANT_DIG + 2 => {},
- else => {
- const shift_amt = @bitCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
- const shift_amt_u7 = @intCast(u7, shift_amt);
- a = (a >> @intCast(u7, sd - (LDBL_MANT_DIG + 2))) |
- @boolToInt((a & (@as(u128, maxInt(u128)) >> shift_amt_u7)) != 0);
- },
- }
- // finish
- a |= @boolToInt((a & 4) != 0); // Or P into R
- a += 1; // round - this step may add a significant bit
- a >>= 2; // dump Q and R
- // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
- if ((a & (@as(u128, 1) << LDBL_MANT_DIG)) != 0) {
- a >>= 1;
- e += 1;
- }
- // a is now rounded to LDBL_MANT_DIG bits
- } else {
- a <<= @intCast(u7, LDBL_MANT_DIG - sd);
- // a is now rounded to LDBL_MANT_DIG bits
- }
-
- const high: u128 = (@intCast(u64, (e + 16383)) << 48) | // exponent
- (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
- const low = @truncate(u64, a); // mantissa-low
-
- return @bitCast(f128, low | (high << 64));
-}
-
-test {
- _ = @import("floatuntitf_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/floatuntitf_test.zig b/lib/std/special/compiler_rt/floatuntitf_test.zig
deleted file mode 100644
index 5afbf348c6..0000000000
--- a/lib/std/special/compiler_rt/floatuntitf_test.zig
+++ /dev/null
@@ -1,99 +0,0 @@
-const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;
-const testing = @import("std").testing;
-
-fn test__floatuntitf(a: u128, expected: f128) !void {
- const x = __floatuntitf(a);
- try testing.expect(x == expected);
-}
-
-test "floatuntitf" {
- try test__floatuntitf(0, 0.0);
-
- try test__floatuntitf(1, 1.0);
- try test__floatuntitf(2, 2.0);
- try test__floatuntitf(20, 20.0);
-
- try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
- try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
- try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
- try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
- try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59);
- try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60);
- try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60);
-
- try test__floatuntitf(0x8000008000000000, 0x8.000008p+60);
- try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60);
- try test__floatuntitf(0x8000010000000000, 0x8.00001p+60);
- try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60);
-
- try test__floatuntitf(0x8000000000000000, 0x8p+60);
- try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60);
-
- try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
-
- try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
- try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
- try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
- try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
- try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
-
- try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
- try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
- try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
- try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
- try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
-
- try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
- try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
- try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
- try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
- try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
- try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
- try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
- try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
- try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
- try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
- try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
- try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
- try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
- try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
- try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
-
- try test__floatuntitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
- try test__floatuntitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
-
- try test__floatuntitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
-
- try test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127);
- try test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128);
-
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
- try test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
-}
-
-fn make_ti(high: u64, low: u64) u128 {
- var result: u128 = high;
- result <<= 64;
- result |= low;
- return result;
-}
diff --git a/lib/std/special/compiler_rt/sparc.zig b/lib/std/special/compiler_rt/sparc.zig
index 3f2cbd86b5..3b33afd29a 100644
--- a/lib/std/special/compiler_rt/sparc.zig
+++ b/lib/std/special/compiler_rt/sparc.zig
@@ -66,19 +66,19 @@ pub fn _Qp_fge(a: *f128, b: *f128) callconv(.C) bool {
// Conversion
pub fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void {
- c.* = @import("floatsiXf.zig").__floatsitf(a);
+ c.* = @import("floatXiYf.zig").__floatsitf(a);
}
pub fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void {
- c.* = @import("floatunsitf.zig").__floatunsitf(a);
+ c.* = @import("floatXiYf.zig").__floatunsitf(a);
}
pub fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void {
- c.* = @import("floatditf.zig").__floatditf(a);
+ c.* = @import("floatXiYf.zig").__floatditf(a);
}
pub fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void {
- c.* = @import("floatunditf.zig").__floatunditf(a);
+ c.* = @import("floatXiYf.zig").__floatunditf(a);
}
pub fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void {
@@ -90,19 +90,19 @@ pub fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void {
}
pub fn _Qp_qtoi(a: *f128) callconv(.C) i32 {
- return @import("fixtfsi.zig").__fixtfsi(a.*);
+ return @import("fixXfYi.zig").__fixtfsi(a.*);
}
pub fn _Qp_qtoui(a: *f128) callconv(.C) u32 {
- return @import("fixunstfsi.zig").__fixunstfsi(a.*);
+ return @import("fixXfYi.zig").__fixunstfsi(a.*);
}
pub fn _Qp_qtox(a: *f128) callconv(.C) i64 {
- return @import("fixtfdi.zig").__fixtfdi(a.*);
+ return @import("fixXfYi.zig").__fixtfdi(a.*);
}
pub fn _Qp_qtoux(a: *f128) callconv(.C) u64 {
- return @import("fixunstfdi.zig").__fixunstfdi(a.*);
+ return @import("fixXfYi.zig").__fixunstfdi(a.*);
}
pub fn _Qp_qtos(a: *f128) callconv(.C) f32 {
diff --git a/lib/std/special/compiler_rt/trunc_f80.zig b/lib/std/special/compiler_rt/trunc_f80.zig
index 88381a28ee..107874aeeb 100644
--- a/lib/std/special/compiler_rt/trunc_f80.zig
+++ b/lib/std/special/compiler_rt/trunc_f80.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const builtin = @import("builtin");
const native_arch = builtin.cpu.arch;
+const testing = std.testing;
// AArch64 is the only ABI (at the moment) to support f16 arguments without the
// need for extending them to wider fp types.
@@ -117,13 +118,12 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {
const src_abs_mask = src_sign_mask - 1;
const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1;
const halfway = 1 << (src_sig_bits - dst_sig_bits - 1);
- const src_qnan = 1 << (src_sig_bits - 1);
- const src_nan_mask = src_qnan - 1;
// Break a into a sign and representation of the absolute value
const a_rep = @bitCast(u128, a);
const a_abs = a_rep & src_abs_mask;
const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0;
+ const integer_bit = 1 << 63;
var res: std.math.F80 = undefined;
@@ -133,27 +133,41 @@ pub fn __trunctfxf2(a: f128) callconv(.C) f80 {
// bit and inserting the (truncated) trailing NaN field.
res.exp = 0x7fff;
res.fraction = 0x8000000000000000;
- res.fraction |= @truncate(u64, (a_abs & src_qnan) << (src_sig_bits - dst_sig_bits));
- res.fraction |= @truncate(u64, (a_abs & src_nan_mask) << (src_sig_bits - dst_sig_bits));
+ res.fraction |= @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits));
} else {
// The exponent of a is within the range of normal numbers in the
// destination format. We can convert by simply right-shifting with
- // rounding and adjusting the exponent.
- res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits));
+ // rounding, adding the explicit integer bit, and adjusting the exponent
+ res.fraction = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit;
res.exp = @truncate(u16, a_abs >> src_sig_bits);
const round_bits = a_abs & round_mask;
if (round_bits > halfway) {
// Round to nearest
- const exp = @addWithOverflow(u64, res.fraction, 1, &res.fraction);
- res.exp += @boolToInt(exp);
+ const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction));
+ res.exp += carry;
+ res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
} else if (round_bits == halfway) {
// Ties to even
- const exp = @addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction);
- res.exp += @boolToInt(exp);
+ const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction));
+ res.exp += carry;
+ res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry
}
+ if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals
}
res.exp |= sign;
return std.math.make_f80(res);
}
+
+fn test__trunctfxf2(a: f128, expected: f80) !void {
+ const x = __trunctfxf2(a);
+ try testing.expect(x == expected);
+}
+
+test {
+ try test__trunctfxf2(1.5, 1.5);
+ try test__trunctfxf2(2.5, 2.5);
+ try test__trunctfxf2(-2.5, -2.5);
+ try test__trunctfxf2(0.0, 0.0);
+}
diff --git a/lib/std/start.zig b/lib/std/start.zig
index cd247c915e..f4a5cbb763 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -29,6 +29,7 @@ comptime {
builtin.zig_backend == .stage2_aarch64 or
builtin.zig_backend == .stage2_arm or
builtin.zig_backend == .stage2_riscv64 or
+ builtin.zig_backend == .stage2_sparcv9 or
(builtin.zig_backend == .stage2_llvm and native_os != .linux) or
(builtin.zig_backend == .stage2_llvm and native_arch != .x86_64))
{
@@ -165,6 +166,14 @@ fn exit2(code: usize) noreturn {
: "rcx", "r11", "memory"
);
},
+ .sparcv9 => {
+ asm volatile ("ta 0x6d"
+ :
+ : [number] "{g1}" (1),
+ [arg1] "{o0}" (code),
+ : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory"
+ );
+ },
else => @compileError("TODO"),
},
// exits(0)
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 4146e033b4..56cc86d769 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -574,6 +574,150 @@ test {
try expectEqualStrings("foo", "foo");
}
+/// Exhaustively check that allocation failures within `test_fn` are handled without
+/// introducing memory leaks. If used with the `testing.allocator` as the `backing_allocator`,
+/// it will also be able to detect double frees, etc (when runtime safety is enabled).
+///
+/// The provided `test_fn` must have a `std.mem.Allocator` as its first argument,
+/// and must have a return type of `!void`. Any extra arguments of `test_fn` can
+/// be provided via the `extra_args` tuple.
+///
+/// Any relevant state shared between runs of `test_fn` *must* be reset within `test_fn`.
+///
+/// Expects that the `test_fn` has a deterministic number of memory allocations
+/// (an error will be returned if non-deterministic allocations are detected).
+///
+/// The strategy employed is to:
+/// - Run the test function once to get the total number of allocations.
+/// - Then, iterate and run the function X more times, incrementing
+/// the failing index each iteration (where X is the total number of
+/// allocations determined previously)
+///
+/// ---
+///
+/// Here's an example of using a simple test case that will cause a leak when the
+/// allocation of `bar` fails (but will pass normally):
+///
+/// ```zig
+/// test {
+/// const length: usize = 10;
+/// const allocator = std.testing.allocator;
+/// var foo = try allocator.alloc(u8, length);
+/// var bar = try allocator.alloc(u8, length);
+///
+/// allocator.free(foo);
+/// allocator.free(bar);
+/// }
+/// ```
+///
+/// The test case can be converted to something that this function can use by
+/// doing:
+///
+/// ```zig
+/// fn testImpl(allocator: std.mem.Allocator, length: usize) !void {
+/// var foo = try allocator.alloc(u8, length);
+/// var bar = try allocator.alloc(u8, length);
+///
+/// allocator.free(foo);
+/// allocator.free(bar);
+/// }
+///
+/// test {
+/// const length: usize = 10;
+/// const allocator = std.testing.allocator;
+/// try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length});
+/// }
+/// ```
+///
+/// Running this test will show that `foo` is leaked when the allocation of
+/// `bar` fails. The simplest fix, in this case, would be to use defer like so:
+///
+/// ```zig
+/// fn testImpl(allocator: std.mem.Allocator, length: usize) !void {
+/// var foo = try allocator.alloc(u8, length);
+/// defer allocator.free(foo);
+/// var bar = try allocator.alloc(u8, length);
+/// defer allocator.free(bar);
+/// }
+/// ```
+pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime test_fn: anytype, extra_args: anytype) !void {
+ switch (@typeInfo(@typeInfo(@TypeOf(test_fn)).Fn.return_type.?)) {
+ .ErrorUnion => |info| {
+ if (info.payload != void) {
+ @compileError("Return type must be !void");
+ }
+ },
+ else => @compileError("Return type must be !void"),
+ }
+ if (@typeInfo(@TypeOf(extra_args)) != .Struct) {
+ @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(extra_args)));
+ }
+
+ const ArgsTuple = std.meta.ArgsTuple(@TypeOf(test_fn));
+ const fn_args_fields = @typeInfo(ArgsTuple).Struct.fields;
+ if (fn_args_fields.len == 0 or fn_args_fields[0].field_type != std.mem.Allocator) {
+ @compileError("The provided function must have an " ++ @typeName(std.mem.Allocator) ++ " as its first argument");
+ }
+ const expected_args_tuple_len = fn_args_fields.len - 1;
+ if (extra_args.len != expected_args_tuple_len) {
+ @compileError("The provided function expects " ++ (comptime std.fmt.comptimePrint("{d}", .{expected_args_tuple_len})) ++ " extra arguments, but the provided tuple contains " ++ (comptime std.fmt.comptimePrint("{d}", .{extra_args.len})));
+ }
+
+ // Setup the tuple that will actually be used with @call (we'll need to insert
+ // the failing allocator in field @"0" before each @call)
+ var args: ArgsTuple = undefined;
+ inline for (@typeInfo(@TypeOf(extra_args)).Struct.fields) |field, i| {
+ const expected_type = fn_args_fields[i + 1].field_type;
+ if (expected_type != field.field_type) {
+ @compileError("Unexpected type for extra argument at index " ++ (comptime std.fmt.comptimePrint("{d}", .{i})) ++ ": expected " ++ @typeName(expected_type) ++ ", found " ++ @typeName(field.field_type));
+ }
+ const arg_i_str = comptime str: {
+ var str_buf: [100]u8 = undefined;
+ const args_i = i + 1;
+ const str_len = std.fmt.formatIntBuf(&str_buf, args_i, 10, .lower, .{});
+ break :str str_buf[0..str_len];
+ };
+ @field(args, arg_i_str) = @field(extra_args, field.name);
+ }
+
+ // Try it once with unlimited memory, make sure it works
+ const needed_alloc_count = x: {
+ var failing_allocator_inst = std.testing.FailingAllocator.init(backing_allocator, std.math.maxInt(usize));
+ args.@"0" = failing_allocator_inst.allocator();
+
+ try @call(.{}, test_fn, args);
+ break :x failing_allocator_inst.index;
+ };
+
+ var fail_index: usize = 0;
+ while (fail_index < needed_alloc_count) : (fail_index += 1) {
+ var failing_allocator_inst = std.testing.FailingAllocator.init(backing_allocator, fail_index);
+ args.@"0" = failing_allocator_inst.allocator();
+
+ if (@call(.{}, test_fn, args)) |_| {
+ return error.NondeterministicMemoryUsage;
+ } else |err| switch (err) {
+ error.OutOfMemory => {
+ if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
+ print(
+ "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\n",
+ .{
+ fail_index,
+ needed_alloc_count,
+ failing_allocator_inst.allocated_bytes,
+ failing_allocator_inst.freed_bytes,
+ failing_allocator_inst.allocations,
+ failing_allocator_inst.deallocations,
+ },
+ );
+ return error.MemoryLeakDetected;
+ }
+ },
+ else => return err,
+ }
+ }
+}
+
/// Given a type, reference all the declarations inside, so that the semantic analyzer sees them.
pub fn refAllDecls(comptime T: type) void {
if (!builtin.is_test) return;
diff --git a/lib/std/time.zig b/lib/std/time.zig
index 687a5336de..668a4b2cf8 100644
--- a/lib/std/time.zig
+++ b/lib/std/time.zig
@@ -147,7 +147,7 @@ pub const s_per_day = s_per_hour * 24;
pub const s_per_week = s_per_day * 7;
/// An Instant represents a timestamp with respect to the currently
-/// executing program that ticks during suspend and can be used to
+/// executing program that ticks during suspend and can be used to
/// record elapsed time unlike `nanoTimestamp`.
///
/// It tries to sample the system's fastest and most precise timer available.
@@ -256,7 +256,7 @@ pub const Instant = struct {
///
/// Monotonicity is ensured by saturating on the most previous sample.
/// This means that while timings reported are monotonic,
-/// they're not guaranteed to tick at a steady rate as this is up to the underlying system.
+/// they're not guaranteed to tick at a steady rate as this is up to the underlying system.
pub const Timer = struct {
started: Instant,
previous: Instant,
@@ -290,7 +290,7 @@ pub const Timer = struct {
return current.since(self.started);
}
- /// Returns an Instant sampled at the callsite that is
+ /// Returns an Instant sampled at the callsite that is
/// guaranteed to be monotonic with respect to the timer's starting point.
fn sample(self: *Timer) Instant {
const current = Instant.now() catch unreachable;
diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig
index e0a000dfe5..81a7ed838f 100644
--- a/lib/std/unicode.zig
+++ b/lib/std/unicode.zig
@@ -3,6 +3,11 @@ const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
+/// Use this to replace an unknown, unrecognized, or unrepresentable character.
+///
+/// See also: https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character
+pub const replacement_character: u21 = 0xFFFD;
+
/// Returns how many bytes the UTF-8 representation would require
/// for the given codepoint.
pub fn utf8CodepointSequenceLength(c: u21) !u3 {
@@ -269,14 +274,7 @@ pub const Utf8Iterator = struct {
pub fn nextCodepoint(it: *Utf8Iterator) ?u21 {
const slice = it.nextCodepointSlice() orelse return null;
-
- switch (slice.len) {
- 1 => return @as(u21, slice[0]),
- 2 => return utf8Decode2(slice) catch unreachable,
- 3 => return utf8Decode3(slice) catch unreachable,
- 4 => return utf8Decode4(slice) catch unreachable,
- else => unreachable,
- }
+ return utf8Decode(slice) catch unreachable;
}
/// Look ahead at the next n codepoints without advancing the iterator.
@@ -784,15 +782,14 @@ fn formatUtf16le(
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
- const unknown_codepoint = 0xfffd;
_ = fmt;
_ = options;
var buf: [300]u8 = undefined; // just a random size I chose
var it = Utf16LeIterator.init(utf16le);
var u8len: usize = 0;
- while (it.nextCodepoint() catch unknown_codepoint) |codepoint| {
+ while (it.nextCodepoint() catch replacement_character) |codepoint| {
u8len += utf8Encode(codepoint, buf[u8len..]) catch
- utf8Encode(unknown_codepoint, buf[u8len..]) catch unreachable;
+ utf8Encode(replacement_character, buf[u8len..]) catch unreachable;
if (u8len + 3 >= buf.len) {
try writer.writeAll(buf[0..u8len]);
u8len = 0;
diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig
index cb99940180..a750e27fc9 100644
--- a/lib/std/x/net/tcp.zig
+++ b/lib/std/x/net/tcp.zig
@@ -186,7 +186,7 @@ pub const Client = struct {
/// Have keep-alive messages be sent periodically. The timing in which keep-alive messages are sent are
/// dependant on operating system settings. It returns `error.UnsupportedSocketOption` if the host does
- /// not support periodically sending keep-alive messages on connection-oriented sockets.
+ /// not support periodically sending keep-alive messages on connection-oriented sockets.
pub fn setKeepAlive(self: Client, enabled: bool) !void {
return self.socket.setKeepAlive(enabled);
}
diff --git a/lib/std/x/os/socket_posix.zig b/lib/std/x/os/socket_posix.zig
index 3d8346db17..859075aa20 100644
--- a/lib/std/x/os/socket_posix.zig
+++ b/lib/std/x/os/socket_posix.zig
@@ -205,7 +205,7 @@ pub fn Mixin(comptime Socket: type) type {
/// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
/// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
- /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
+ /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
pub fn setKeepAlive(self: Socket, enabled: bool) !void {
if (@hasDecl(os.SO, "KEEPALIVE")) {
return self.setOption(os.SOL.SOCKET, os.SO.KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
@@ -243,7 +243,7 @@ pub fn Mixin(comptime Socket: type) type {
/// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
/// set on a non-blocking socket.
- ///
+ ///
/// Set a timeout on the socket that is to occur if no messages are successfully written
/// to its bound destination after a specified number of milliseconds. A subsequent write
/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
@@ -258,7 +258,7 @@ pub fn Mixin(comptime Socket: type) type {
/// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
/// set on a non-blocking socket.
- ///
+ ///
/// Set a timeout on the socket that is to occur if no messages are successfully read
/// from its bound destination after a specified number of milliseconds. A subsequent
/// read from the socket will thereafter return `error.WouldBlock` should the timeout be
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index af40d8352c..d9555c1ff8 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -4712,6 +4712,28 @@ test "zig fmt: space after top level doc comment" {
);
}
+test "zig fmt: remove trailing whitespace after container doc comment" {
+ try testTransform(
+ \\//! top level doc comment
+ \\
+ ,
+ \\//! top level doc comment
+ \\
+ );
+}
+
+test "zig fmt: remove trailing whitespace after doc comment" {
+ try testTransform(
+ \\/// doc comment
+ \\a = 0,
+ \\
+ ,
+ \\/// doc comment
+ \\a = 0,
+ \\
+ );
+}
+
test "zig fmt: for loop with ptr payload and index" {
try testCanonical(
\\test {
@@ -5459,52 +5481,24 @@ fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *
anything_changed.* = !mem.eql(u8, formatted, source);
return formatted;
}
-fn testTransform(source: [:0]const u8, expected_source: []const u8) !void {
- const needed_alloc_count = x: {
- // Try it once with unlimited memory, make sure it works
- var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
- var failing_allocator = std.testing.FailingAllocator.init(fixed_allocator.allocator(), maxInt(usize));
- const allocator = failing_allocator.allocator();
- var anything_changed: bool = undefined;
- const result_source = try testParse(source, allocator, &anything_changed);
- try std.testing.expectEqualStrings(expected_source, result_source);
- const changes_expected = source.ptr != expected_source.ptr;
- if (anything_changed != changes_expected) {
- print("std.zig.render returned {} instead of {}\n", .{ anything_changed, changes_expected });
- return error.TestFailed;
- }
- try std.testing.expect(anything_changed == changes_expected);
- allocator.free(result_source);
- break :x failing_allocator.index;
- };
-
- var fail_index: usize = 0;
- while (fail_index < needed_alloc_count) : (fail_index += 1) {
- var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
- var failing_allocator = std.testing.FailingAllocator.init(fixed_allocator.allocator(), fail_index);
- var anything_changed: bool = undefined;
- if (testParse(source, failing_allocator.allocator(), &anything_changed)) |_| {
- return error.NondeterministicMemoryUsage;
- } else |err| switch (err) {
- error.OutOfMemory => {
- if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
- print(
- "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\n",
- .{
- fail_index,
- needed_alloc_count,
- failing_allocator.allocated_bytes,
- failing_allocator.freed_bytes,
- failing_allocator.allocations,
- failing_allocator.deallocations,
- },
- );
- return error.MemoryLeakDetected;
- }
- },
- else => return err,
- }
+fn testTransformImpl(allocator: mem.Allocator, fba: *std.heap.FixedBufferAllocator, source: [:0]const u8, expected_source: []const u8) !void {
+ // reset the fixed buffer allocator each run so that it can be re-used for each
+ // iteration of the failing index
+ fba.reset();
+ var anything_changed: bool = undefined;
+ const result_source = try testParse(source, allocator, &anything_changed);
+ try std.testing.expectEqualStrings(expected_source, result_source);
+ const changes_expected = source.ptr != expected_source.ptr;
+ if (anything_changed != changes_expected) {
+ print("std.zig.render returned {} instead of {}\n", .{ anything_changed, changes_expected });
+ return error.TestFailed;
}
+ try std.testing.expect(anything_changed == changes_expected);
+ allocator.free(result_source);
+}
+fn testTransform(source: [:0]const u8, expected_source: []const u8) !void {
+ var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
+ return std.testing.checkAllAllocationFailures(fixed_allocator.allocator(), testTransformImpl, .{ &fixed_allocator, source, expected_source });
}
fn testCanonical(source: [:0]const u8) !void {
return testTransform(source, source);
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index eaae725e9a..cf7a161b8d 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -2506,9 +2506,15 @@ fn renderContainerDocComments(ais: *Ais, tree: Ast, start_token: Ast.TokenIndex)
fn tokenSliceForRender(tree: Ast, token_index: Ast.TokenIndex) []const u8 {
var ret = tree.tokenSlice(token_index);
- if (tree.tokens.items(.tag)[token_index] == .multiline_string_literal_line) {
- assert(ret[ret.len - 1] == '\n');
- ret.len -= 1;
+ switch (tree.tokens.items(.tag)[token_index]) {
+ .multiline_string_literal_line => {
+ assert(ret[ret.len - 1] == '\n');
+ ret.len -= 1;
+ },
+ .container_doc_comment, .doc_comment => {
+ ret = mem.trimRight(u8, ret, &std.ascii.spaces);
+ },
+ else => {},
}
return ret;
}
diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig
index 07ce08f491..ebee8a3c9f 100644
--- a/lib/std/zig/string_literal.zig
+++ b/lib/std/zig/string_literal.zig
@@ -61,7 +61,7 @@ pub fn parseCharLiteral(slice: []const u8) ParsedCharLiteral {
}
}
-/// Parse an escape sequence from `slice[offset..]`. If parsing is successful,
+/// Parse an escape sequence from `slice[offset..]`. If parsing is successful,
/// offset is updated to reflect the characters consumed.
fn parseEscapeSequence(slice: []const u8, offset: *usize) ParsedCharLiteral {
assert(slice.len > offset.*);
diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig
index 36f6207677..f917ee8e34 100644
--- a/lib/std/zig/system/NativeTargetInfo.zig
+++ b/lib/std/zig/system/NativeTargetInfo.zig
@@ -473,7 +473,7 @@ pub fn abiAndDynamicLinkerFromFile(
_ = try preadMin(file, &hdr_buf, 0, hdr_buf.len);
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
- if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
+ if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
elf.ELFDATA2LSB => .Little,
elf.ELFDATA2MSB => .Big,
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 75882c761b..ccce4b0bc8 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -85,12 +85,12 @@ fn reserveExtra(astgen: *AstGen, size: usize) Allocator.Error!u32 {
}
fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {
- const coerced = @bitCast([]const u32, refs);
+ const coerced = @ptrCast([]const u32, refs);
return astgen.extra.appendSlice(astgen.gpa, coerced);
}
fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {
- const coerced = @bitCast([]const u32, refs);
+ const coerced = @ptrCast([]const u32, refs);
astgen.extra.appendSliceAssumeCapacity(coerced);
}
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 338be582d8..6c486de36a 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -4531,6 +4531,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
.i386 => .stage2_x86,
.aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64,
.riscv64 => .stage2_riscv64,
+ .sparcv9 => .stage2_sparcv9,
else => .other,
};
};
diff --git a/src/InternArena.zig b/src/InternPool.zig
index c2397b8b42..95947df61b 100644
--- a/src/InternArena.zig
+++ b/src/InternPool.zig
@@ -2,17 +2,17 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
items: std.MultiArrayList(Item) = .{},
extra: std.ArrayListUnmanaged(u32) = .{},
-const InternArena = @This();
+const InternPool = @This();
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const KeyAdapter = struct {
- intern_arena: *const InternArena,
+ intern_pool: *const InternPool,
pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
_ = b_void;
- return ctx.intern_arena.indexToKey(@intToEnum(Index, b_map_index)).eql(a);
+ return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a);
}
pub fn hash(ctx: @This(), a: Key) u32 {
@@ -94,10 +94,10 @@ pub const Item = struct {
};
/// Represents an index into `map`. It represents the canonical index
-/// of a `Value` within this `InternArena`. The values are typed.
+/// of a `Value` within this `InternPool`. The values are typed.
/// Two values which have the same type can be equality compared simply
/// by checking if their indexes are equal, provided they are both in
-/// the same `InternArena`.
+/// the same `InternPool`.
pub const Index = enum(u32) {
none = std.math.maxInt(u32),
_,
@@ -180,14 +180,14 @@ pub const Array = struct {
child: Index,
};
-pub fn deinit(ia: *InternArena, gpa: Allocator) void {
- ia.map.deinit(gpa);
- ia.items.deinit(gpa);
- ia.extra.deinit(gpa);
+pub fn deinit(ip: *InternPool, gpa: Allocator) void {
+ ip.map.deinit(gpa);
+ ip.items.deinit(gpa);
+ ip.extra.deinit(gpa);
}
-pub fn indexToKey(ia: InternArena, index: Index) Key {
- const item = ia.items.get(@enumToInt(index));
+pub fn indexToKey(ip: InternPool, index: Index) Key {
+ const item = ip.items.get(@enumToInt(index));
const data = item.data;
return switch (item.tag) {
.type_int_signed => .{
@@ -203,7 +203,7 @@ pub fn indexToKey(ia: InternArena, index: Index) Key {
},
},
.type_array => {
- const array_info = ia.extraData(Array, data);
+ const array_info = ip.extraData(Array, data);
return .{ .array_type = .{
.len = array_info.len,
.child = array_info.child,
@@ -216,9 +216,9 @@ pub fn indexToKey(ia: InternArena, index: Index) Key {
};
}
-pub fn get(ia: *InternArena, gpa: Allocator, key: Key) Allocator.Error!Index {
- const adapter: KeyAdapter = .{ .intern_arena = ia };
- const gop = try ia.map.getOrPutAdapted(gpa, key, adapter);
+pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
+ const adapter: KeyAdapter = .{ .intern_pool = ip };
+ const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);
if (gop.found_existing) {
return @intToEnum(Index, gop.index);
}
@@ -228,7 +228,7 @@ pub fn get(ia: *InternArena, gpa: Allocator, key: Key) Allocator.Error!Index {
.signed => .type_int_signed,
.unsigned => .type_int_unsigned,
};
- try ia.items.append(gpa, .{
+ try ip.items.append(gpa, .{
.tag = tag,
.data = int_type.bits,
});
@@ -236,9 +236,9 @@ pub fn get(ia: *InternArena, gpa: Allocator, key: Key) Allocator.Error!Index {
.array_type => |array_type| {
const len = @intCast(u32, array_type.len); // TODO have a big_array encoding
assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding
- try ia.items.append(gpa, .{
+ try ip.items.append(gpa, .{
.tag = .type_array,
- .data = try ia.addExtra(gpa, Array{
+ .data = try ip.addExtra(gpa, Array{
.len = len,
.child = array_type.child,
}),
@@ -246,20 +246,20 @@ pub fn get(ia: *InternArena, gpa: Allocator, key: Key) Allocator.Error!Index {
},
else => @panic("TODO"),
}
- return @intToEnum(Index, ia.items.len - 1);
+ return @intToEnum(Index, ip.items.len - 1);
}
-fn addExtra(ia: *InternArena, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
+fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
const fields = std.meta.fields(@TypeOf(extra));
- try ia.extra.ensureUnusedCapacity(gpa, fields.len);
- return ia.addExtraAssumeCapacity(extra);
+ try ip.extra.ensureUnusedCapacity(gpa, fields.len);
+ return ip.addExtraAssumeCapacity(extra);
}
-fn addExtraAssumeCapacity(ia: *InternArena, extra: anytype) u32 {
+fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
const fields = std.meta.fields(@TypeOf(extra));
- const result = @intCast(u32, ia.extra.items.len);
+ const result = @intCast(u32, ip.extra.items.len);
inline for (fields) |field| {
- ia.extra.appendAssumeCapacity(switch (field.field_type) {
+ ip.extra.appendAssumeCapacity(switch (field.field_type) {
u32 => @field(extra, field.name),
Index => @enumToInt(@field(extra, field.name)),
i32 => @bitCast(u32, @field(extra, field.name)),
@@ -269,15 +269,15 @@ fn addExtraAssumeCapacity(ia: *InternArena, extra: anytype) u32 {
return result;
}
-fn extraData(ia: InternArena, comptime T: type, index: usize) T {
+fn extraData(ip: InternPool, comptime T: type, index: usize) T {
const fields = std.meta.fields(T);
var i: usize = index;
var result: T = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.field_type) {
- u32 => ia.extra.items[i],
- Index => @intToEnum(Index, ia.extra.items[i]),
- i32 => @bitCast(i32, ia.extra.items[i]),
+ u32 => ip.extra.items[i],
+ Index => @intToEnum(Index, ip.extra.items[i]),
+ i32 => @bitCast(i32, ip.extra.items[i]),
else => @compileError("bad field type"),
};
i += 1;
@@ -288,26 +288,26 @@ fn extraData(ia: InternArena, comptime T: type, index: usize) T {
test "basic usage" {
const gpa = std.testing.allocator;
- var ia: InternArena = .{};
- defer ia.deinit(gpa);
+ var ip: InternPool = .{};
+ defer ip.deinit(gpa);
- const i32_type = try ia.get(gpa, .{ .int_type = .{
+ const i32_type = try ip.get(gpa, .{ .int_type = .{
.signedness = .signed,
.bits = 32,
} });
- const array_i32 = try ia.get(gpa, .{ .array_type = .{
+ const array_i32 = try ip.get(gpa, .{ .array_type = .{
.len = 10,
.child = i32_type,
.sentinel = .none,
} });
- const another_i32_type = try ia.get(gpa, .{ .int_type = .{
+ const another_i32_type = try ip.get(gpa, .{ .int_type = .{
.signedness = .signed,
.bits = 32,
} });
try std.testing.expect(another_i32_type == i32_type);
- const another_array_i32 = try ia.get(gpa, .{ .array_type = .{
+ const another_array_i32 = try ip.get(gpa, .{ .array_type = .{
.len = 10,
.child = i32_type,
.sentinel = .none,
diff --git a/src/Liveness.zig b/src/Liveness.zig
index 59f7f5be91..be4344ab90 100644
--- a/src/Liveness.zig
+++ b/src/Liveness.zig
@@ -178,11 +178,50 @@ pub fn deinit(l: *Liveness, gpa: Allocator) void {
l.* = undefined;
}
+pub fn iterateBigTomb(l: Liveness, inst: Air.Inst.Index) BigTomb {
+ return .{
+ .tomb_bits = l.getTombBits(inst),
+ .extra_start = l.special.get(inst) orelse 0,
+ .extra_offset = 0,
+ .extra = l.extra,
+ .bit_index = 0,
+ };
+}
+
/// How many tomb bits per AIR instruction.
pub const bpi = 4;
pub const Bpi = std.meta.Int(.unsigned, bpi);
pub const OperandInt = std.math.Log2Int(Bpi);
+/// Useful for decoders of Liveness information.
+pub const BigTomb = struct {
+ tomb_bits: Liveness.Bpi,
+ bit_index: u32,
+ extra_start: u32,
+ extra_offset: u32,
+ extra: []const u32,
+
+ /// Returns whether the next operand dies.
+ pub fn feed(bt: *BigTomb) bool {
+ const this_bit_index = bt.bit_index;
+ bt.bit_index += 1;
+
+ const small_tombs = Liveness.bpi - 1;
+ if (this_bit_index < small_tombs) {
+ const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
+ return dies;
+ }
+
+ const big_bit_index = this_bit_index - small_tombs;
+ while (big_bit_index - bt.extra_offset * 31 >= 31) {
+ bt.extra_offset += 1;
+ }
+ const dies = @truncate(u1, bt.extra[bt.extra_start + bt.extra_offset] >>
+ @intCast(u5, big_bit_index - bt.extra_offset * 31)) != 0;
+ return dies;
+ }
+};
+
/// In-progress data; on successful analysis converted into `Liveness`.
const Analysis = struct {
gpa: Allocator,
@@ -415,7 +454,7 @@ fn analyzeInst(
const inst_data = inst_datas[inst].pl_op;
const callee = inst_data.operand;
const extra = a.air.extraData(Air.Call, inst_data.payload);
- const args = @bitCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..extra.data.args_len]);
if (args.len + 1 <= bpi - 1) {
var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
buf[0] = callee;
@@ -428,6 +467,7 @@ fn analyzeInst(
.inst = inst,
.main_tomb = main_tomb,
};
+ defer extra_tombs.deinit();
try extra_tombs.feed(callee);
for (args) |arg| {
try extra_tombs.feed(arg);
@@ -455,7 +495,7 @@ fn analyzeInst(
const ty_pl = inst_datas[inst].ty_pl;
const aggregate_ty = a.air.getRefType(ty_pl.ty);
const len = @intCast(usize, aggregate_ty.arrayLen());
- const elements = @bitCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]);
if (elements.len <= bpi - 1) {
var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
@@ -468,6 +508,7 @@ fn analyzeInst(
.inst = inst,
.main_tomb = main_tomb,
};
+ defer extra_tombs.deinit();
for (elements) |elem| {
try extra_tombs.feed(elem);
}
@@ -530,9 +571,9 @@ fn analyzeInst(
.assembly => {
const extra = a.air.extraData(Air.Asm, inst_datas[inst].ty_pl.payload);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
simple: {
@@ -555,6 +596,7 @@ fn analyzeInst(
.inst = inst,
.main_tomb = main_tomb,
};
+ defer extra_tombs.deinit();
for (outputs) |output| {
if (output != .none) {
try extra_tombs.feed(output);
@@ -790,31 +832,48 @@ const ExtraTombs = struct {
bit_index: usize = 0,
tomb_bits: Bpi = 0,
big_tomb_bits: u32 = 0,
+ big_tomb_bits_extra: std.ArrayListUnmanaged(u32) = .{},
fn feed(et: *ExtraTombs, op_ref: Air.Inst.Ref) !void {
const this_bit_index = et.bit_index;
- assert(this_bit_index < 32); // TODO mechanism for when there are greater than 32 operands
et.bit_index += 1;
const gpa = et.analysis.gpa;
- const op_int = @enumToInt(op_ref);
- if (op_int < Air.Inst.Ref.typed_value_map.len) return;
- const op_index: Air.Inst.Index = op_int - @intCast(u32, Air.Inst.Ref.typed_value_map.len);
+ const op_index = Air.refToIndex(op_ref) orelse return;
const prev = try et.analysis.table.fetchPut(gpa, op_index, {});
if (prev == null) {
// Death.
if (et.new_set) |ns| try ns.putNoClobber(gpa, op_index, {});
- if (this_bit_index < bpi - 1) {
+ const available_tomb_bits = bpi - 1;
+ if (this_bit_index < available_tomb_bits) {
et.tomb_bits |= @as(Bpi, 1) << @intCast(OperandInt, this_bit_index);
} else {
- const big_bit_index = this_bit_index - (bpi - 1);
- et.big_tomb_bits |= @as(u32, 1) << @intCast(u5, big_bit_index);
+ const big_bit_index = this_bit_index - available_tomb_bits;
+ while (big_bit_index >= (et.big_tomb_bits_extra.items.len + 1) * 31) {
+ // We need another element in the extra array.
+ try et.big_tomb_bits_extra.append(gpa, et.big_tomb_bits);
+ et.big_tomb_bits = 0;
+ } else {
+ const final_bit_index = big_bit_index - et.big_tomb_bits_extra.items.len * 31;
+ et.big_tomb_bits |= @as(u32, 1) << @intCast(u5, final_bit_index);
+ }
}
}
}
fn finish(et: *ExtraTombs) !void {
et.tomb_bits |= @as(Bpi, @boolToInt(et.main_tomb)) << (bpi - 1);
+ // Signal the terminal big_tomb_bits element.
+ et.big_tomb_bits |= @as(u32, 1) << 31;
+
et.analysis.storeTombBits(et.inst, et.tomb_bits);
- try et.analysis.special.put(et.analysis.gpa, et.inst, et.big_tomb_bits);
+ const extra_index = @intCast(u32, et.analysis.extra.items.len);
+ try et.analysis.extra.ensureUnusedCapacity(et.analysis.gpa, et.big_tomb_bits_extra.items.len + 1);
+ try et.analysis.special.put(et.analysis.gpa, et.inst, extra_index);
+ et.analysis.extra.appendSliceAssumeCapacity(et.big_tomb_bits_extra.items);
+ et.analysis.extra.appendAssumeCapacity(et.big_tomb_bits);
+ }
+
+ fn deinit(et: *ExtraTombs) void {
+ et.big_tomb_bits_extra.deinit(et.analysis.gpa);
}
};
diff --git a/src/Module.zig b/src/Module.zig
index fdf61c4bf6..53c72ccec2 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -1394,7 +1394,15 @@ pub const Fn = struct {
/// there is a `TypedValue` here for each parameter of the function.
/// Non-comptime parameters are marked with a `generic_poison` for the value.
/// Non-anytype parameters are marked with a `generic_poison` for the type.
- comptime_args: ?[*]TypedValue = null,
+ /// These never have .generic_poison for the Type
+ /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments
+ /// into the inst_map when analyzing the body of a generic function instantiation.
+ /// Instead, the is_anytype knowledge is communicated via `anytype_args`.
+ comptime_args: ?[*]TypedValue,
+ /// When comptime_args is null, this is undefined. Otherwise, this flags each
+ /// parameter and tells whether it is anytype.
+ /// TODO apply the same enhancement for param_names below to this field.
+ anytype_args: [*]bool,
/// The ZIR instruction that is a function instruction. Use this to find
/// the body. We store this rather than the body directly so that when ZIR
/// is regenerated on update(), we can map this to the new corresponding
@@ -4585,7 +4593,7 @@ pub fn clearDecl(
.c => .{ .c = {} },
.wasm => .{ .wasm = link.File.Wasm.FnData.empty },
.spirv => .{ .spirv = .{} },
- .nvptx => .{ .nvptx = .{} },
+ .nvptx => .{ .nvptx = {} },
};
}
if (decl.getInnerNamespace()) |namespace| {
@@ -4782,18 +4790,24 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
else => continue,
};
- if (func.comptime_args) |comptime_args| {
+
+ const param_ty = if (func.comptime_args) |comptime_args| t: {
const arg_tv = comptime_args[total_param_index];
- if (arg_tv.val.tag() != .generic_poison) {
- // We have a comptime value for this parameter.
- const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);
- sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
- total_param_index += 1;
- continue;
- }
- }
- const param_type = fn_ty_info.param_types[runtime_param_index];
- const opt_opv = sema.typeHasOnePossibleValue(&inner_block, param.src, param_type) catch |err| switch (err) {
+
+ const arg_val = if (arg_tv.val.tag() != .generic_poison)
+ arg_tv.val
+ else if (arg_tv.ty.onePossibleValue()) |opv|
+ opv
+ else
+ break :t arg_tv.ty;
+
+ const arg = try sema.addConstant(arg_tv.ty, arg_val);
+ sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
+ total_param_index += 1;
+ continue;
+ } else fn_ty_info.param_types[runtime_param_index];
+
+ const opt_opv = sema.typeHasOnePossibleValue(&inner_block, param.src, param_ty) catch |err| switch (err) {
error.NeededSourceLocation => unreachable,
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
@@ -4801,7 +4815,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
else => |e| return e,
};
if (opt_opv) |opv| {
- const arg = try sema.addConstant(param_type, opv);
+ const arg = try sema.addConstant(param_ty, opv);
sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
total_param_index += 1;
runtime_param_index += 1;
@@ -4811,7 +4825,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
inner_block.instructions.appendAssumeCapacity(arg_index);
sema.air_instructions.appendAssumeCapacity(.{
.tag = .arg,
- .data = .{ .ty = param_type },
+ .data = .{ .ty = param_ty },
});
sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
total_param_index += 1;
@@ -4961,7 +4975,7 @@ pub fn allocateNewDecl(
.c => .{ .c = {} },
.wasm => .{ .wasm = link.File.Wasm.FnData.empty },
.spirv => .{ .spirv = .{} },
- .nvptx => .{ .nvptx = .{} },
+ .nvptx => .{ .nvptx = {} },
},
.generation = 0,
.is_pub = false,
diff --git a/src/Sema.zig b/src/Sema.zig
index ae13298337..1562b5d6f8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -4722,6 +4722,8 @@ const GenericCallAdapter = struct {
generic_fn: *Module.Fn,
precomputed_hash: u64,
func_ty_info: Type.Payload.Function.Data,
+ /// Unlike comptime_args, the Type here is not always present.
+ /// .generic_poison is used to communicate non-anytype parameters.
comptime_tvs: []const TypedValue,
target: std.Target,
@@ -4734,20 +4736,29 @@ const GenericCallAdapter = struct {
const other_comptime_args = other_key.comptime_args.?;
for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| {
- if (other_arg.ty.tag() != .generic_poison) {
- // anytype parameter
- if (!other_arg.ty.eql(ctx.comptime_tvs[i].ty, ctx.target)) {
+ const this_arg = ctx.comptime_tvs[i];
+ const this_is_comptime = this_arg.val.tag() != .generic_poison;
+ const other_is_comptime = other_arg.val.tag() != .generic_poison;
+ const this_is_anytype = this_arg.ty.tag() != .generic_poison;
+ const other_is_anytype = other_key.anytype_args[i];
+
+ if (other_is_anytype != this_is_anytype) return false;
+ if (other_is_comptime != this_is_comptime) return false;
+
+ if (this_is_anytype) {
+ // Both are anytype parameters.
+ if (!this_arg.ty.eql(other_arg.ty, ctx.target)) {
return false;
}
- }
- if (other_arg.val.tag() != .generic_poison) {
- // comptime parameter
- if (ctx.comptime_tvs[i].val.tag() == .generic_poison) {
- // No match because the instantiation has a comptime parameter
- // but the callsite does not.
- return false;
+ if (this_is_comptime) {
+ // Both are comptime and anytype parameters with matching types.
+ if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.target)) {
+ return false;
+ }
}
- if (!other_arg.val.eql(ctx.comptime_tvs[i].val, other_arg.ty, ctx.target)) {
+ } else if (this_is_comptime) {
+ // Both are comptime parameters but not anytype parameters.
+ if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.target)) {
return false;
}
}
@@ -5242,28 +5253,61 @@ fn instantiateGenericCall(
const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len);
const target = sema.mod.getTarget();
- for (func_ty_info.param_types) |param_ty, i| {
- const is_comptime = func_ty_info.paramIsComptime(i);
- if (is_comptime) {
- const arg_src = call_src; // TODO better source location
- const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src);
- if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| {
- if (param_ty.tag() != .generic_poison) {
- arg_val.hash(param_ty, &hasher, target);
+ {
+ var i: usize = 0;
+ for (fn_info.param_body) |inst| {
+ var is_comptime = false;
+ var is_anytype = false;
+ switch (zir_tags[inst]) {
+ .param => {
+ is_comptime = func_ty_info.paramIsComptime(i);
+ },
+ .param_comptime => {
+ is_comptime = true;
+ },
+ .param_anytype => {
+ is_anytype = true;
+ is_comptime = func_ty_info.paramIsComptime(i);
+ },
+ .param_anytype_comptime => {
+ is_anytype = true;
+ is_comptime = true;
+ },
+ else => continue,
+ }
+
+ if (is_comptime) {
+ const arg_src = call_src; // TODO better source location
+ const arg_ty = sema.typeOf(uncasted_args[i]);
+ const arg_val = try sema.resolveValue(block, arg_src, uncasted_args[i]);
+ arg_val.hash(arg_ty, &hasher, target);
+ if (is_anytype) {
+ arg_ty.hashWithHasher(&hasher, target);
+ comptime_tvs[i] = .{
+ .ty = arg_ty,
+ .val = arg_val,
+ };
+ } else {
+ comptime_tvs[i] = .{
+ .ty = Type.initTag(.generic_poison),
+ .val = arg_val,
+ };
}
+ } else if (is_anytype) {
+ const arg_ty = sema.typeOf(uncasted_args[i]);
+ arg_ty.hashWithHasher(&hasher, target);
comptime_tvs[i] = .{
- // This will be different than `param_ty` in the case of `generic_poison`.
- .ty = sema.typeOf(casted_arg),
- .val = arg_val,
+ .ty = arg_ty,
+ .val = Value.initTag(.generic_poison),
};
} else {
- return sema.failWithNeededComptime(block, arg_src);
+ comptime_tvs[i] = .{
+ .ty = Type.initTag(.generic_poison),
+ .val = Value.initTag(.generic_poison),
+ };
}
- } else {
- comptime_tvs[i] = .{
- .ty = sema.typeOf(uncasted_args[i]),
- .val = Value.initTag(.generic_poison),
- };
+
+ i += 1;
}
}
@@ -5426,19 +5470,48 @@ fn instantiateGenericCall(
errdefer new_func.deinit(gpa);
assert(new_func == new_module_func);
+ const anytype_args = try new_decl_arena_allocator.alloc(bool, func_ty_info.param_types.len);
+ new_func.anytype_args = anytype_args.ptr;
arg_i = 0;
for (fn_info.param_body) |inst| {
+ var is_comptime = false;
+ var is_anytype = false;
switch (zir_tags[inst]) {
- .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
+ .param => {
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_comptime => {
+ is_comptime = true;
+ },
+ .param_anytype => {
+ is_anytype = true;
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_anytype_comptime => {
+ is_anytype = true;
+ is_comptime = true;
+ },
else => continue,
}
+
+ // We populate the Type here regardless because it is needed by
+ // `GenericCallAdapter.eql` as well as function body analysis.
+ // Whether it is anytype is communicated by `anytype_args`.
const arg = child_sema.inst_map.get(inst).?;
const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
- if (child_sema.resolveMaybeUndefValAllowVariables(
- &child_block,
- .unneeded,
- arg,
- ) catch unreachable) |arg_val| {
+ anytype_args[arg_i] = is_anytype;
+
+ const arg_src = call_src; // TODO: better source location
+ if (try sema.typeRequiresComptime(block, arg_src, copied_arg_ty)) {
+ is_comptime = true;
+ }
+
+ if (is_comptime) {
+ const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(
+ &child_block,
+ .unneeded,
+ arg,
+ ) catch unreachable).?;
child_sema.comptime_args[arg_i] = .{
.ty = copied_arg_ty,
.val = try arg_val.copy(new_decl_arena_allocator),
@@ -5495,22 +5568,7 @@ fn instantiateGenericCall(
const comptime_args = callee.comptime_args.?;
const new_fn_info = callee.owner_decl.ty.fnInfo();
- const runtime_args_len = count: {
- var count: u32 = 0;
- var arg_i: usize = 0;
- for (fn_info.param_body) |inst| {
- switch (zir_tags[inst]) {
- .param_comptime, .param_anytype_comptime, .param, .param_anytype => {
- if (comptime_args[arg_i].val.tag() == .generic_poison) {
- count += 1;
- }
- arg_i += 1;
- },
- else => continue,
- }
- }
- break :count count;
- };
+ const runtime_args_len = @intCast(u32, new_fn_info.param_types.len);
const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
{
var runtime_i: u32 = 0;
@@ -5520,7 +5578,9 @@ fn instantiateGenericCall(
.param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
else => continue,
}
- const is_runtime = comptime_args[total_i].val.tag() == .generic_poison;
+ const is_runtime = comptime_args[total_i].val.tag() == .generic_poison and
+ comptime_args[total_i].ty.hasRuntimeBits() and
+ !comptime_args[total_i].ty.comptimeOnly();
if (is_runtime) {
const param_ty = new_fn_info.param_types[runtime_i];
const arg_src = call_src; // TODO: better source location
@@ -6577,6 +6637,7 @@ fn funcCommon(
.zir_body_inst = func_inst,
.owner_decl = sema.owner_decl,
.comptime_args = comptime_args,
+ .anytype_args = undefined,
.hash = hash,
.lbrace_line = src_locs.lbrace_line,
.rbrace_line = src_locs.rbrace_line,
@@ -6629,7 +6690,9 @@ fn zirParam(
// partial type for generic functions but we still need to
// detect if a function parameter is a generic function
// to force the parent function to also be generic.
- break :err error.GenericPoison;
+ if (!sema.inst_map.contains(inst)) {
+ break :err error.GenericPoison;
+ }
}
break :param_ty param_ty;
} else |err| break :err err;
@@ -7288,9 +7351,14 @@ fn zirSwitchCapture(
}
},
else => {
- return sema.fail(block, operand_src, "switch on type '{}' provides no capture value", .{
- operand_ty.fmt(target),
- });
+ // In this case the capture value is just the passed-through value of the
+ // switch condition.
+ if (is_ref) {
+ assert(operand_is_ref);
+ return operand_ptr;
+ } else {
+ return operand;
+ }
},
}
}
@@ -12702,7 +12770,12 @@ fn finishStructInit(
}
if (is_ref) {
- const alloc = try block.addTy(.alloc, struct_ty);
+ const target = sema.mod.getTarget();
+ const alloc_ty = try Type.ptr(sema.arena, target, .{
+ .pointee_type = struct_ty,
+ .@"addrspace" = target_util.defaultAddressSpace(target, .local),
+ });
+ const alloc = try block.addTy(.alloc, alloc_ty);
for (field_inits) |field_init, i_usize| {
const i = @intCast(u32, i_usize);
const field_src = src;
@@ -14052,21 +14125,27 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
try sema.checkPtrType(block, dest_ty_src, dest_ty);
try sema.checkPtrOperand(block, operand_src, operand_ty);
- if (dest_ty.isSlice()) {
+
+ const dest_is_slice = dest_ty.isSlice();
+ const operand_is_slice = operand_ty.isSlice();
+ if (dest_is_slice and !operand_is_slice) {
return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
}
- const ptr = if (operand_ty.isSlice())
+ const ptr = if (operand_is_slice and !dest_is_slice)
try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)
else
operand;
- try sema.resolveTypeLayout(block, dest_ty_src, dest_ty.elemType2());
+ const dest_elem_ty = dest_ty.elemType2();
+ try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
const dest_align = dest_ty.ptrAlignment(target);
- try sema.resolveTypeLayout(block, operand_src, operand_ty.elemType2());
+
+ const operand_elem_ty = operand_ty.elemType2();
+ try sema.resolveTypeLayout(block, operand_src, operand_elem_ty);
const operand_align = operand_ty.ptrAlignment(target);
// If the destination is less aligned than the source, preserve the source alignment
- var aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
+ const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
// Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result
if (dest_ty.zigTypeTag() == .Optional) {
var buf: Type.Payload.ElemType = undefined;
@@ -14080,6 +14159,16 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
}
};
+ if (dest_is_slice) {
+ const operand_elem_size = operand_elem_ty.abiSize(target);
+ const dest_elem_size = dest_elem_ty.abiSize(target);
+ if (operand_elem_size != dest_elem_size) {
+ // note that this is not implemented in stage1 so we should probably wait
+ // until that codebase is replaced before implementing this in stage2.
+ return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{});
+ }
+ }
+
return sema.coerceCompatiblePtrs(block, aligned_dest_ty, ptr, operand_src);
}
@@ -15685,7 +15774,7 @@ fn zirMinMax(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
- air_tag: Air.Inst.Tag,
+ comptime air_tag: Air.Inst.Tag,
) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
@@ -15705,7 +15794,7 @@ fn analyzeMinMax(
src: LazySrcLoc,
lhs: Air.Inst.Ref,
rhs: Air.Inst.Ref,
- air_tag: Air.Inst.Tag,
+ comptime air_tag: Air.Inst.Tag,
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
@@ -18042,8 +18131,7 @@ fn coerce(
const array_ty = inst_ty.childType();
if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
const len0 = array_ty.arrayLen() == 0;
- // We resolve here so that the backend has the layout of the elem type.
- const array_elem_type = try sema.resolveTypeFields(block, inst_src, array_ty.childType());
+ const array_elem_type = array_ty.childType();
const dest_is_mut = dest_info.mutable;
if (inst_ty.isConstPtr() and dest_is_mut and !len0) break :src_array_ptr;
if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;
@@ -18187,6 +18275,19 @@ fn coerce(
{
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
}
+
+ // empty tuple to zero-length slice
+ // note that this allows coercing to a mutable slice.
+ if (inst_ty.isSinglePointer() and
+ inst_ty.childType().tag() == .empty_struct_literal and
+ dest_info.size == .Slice)
+ {
+ const slice_val = try Value.Tag.slice.create(sema.arena, .{
+ .ptr = Value.undef,
+ .len = Value.zero,
+ });
+ return sema.addConstant(dest_ty, slice_val);
+ }
},
.Many => p: {
if (!inst_ty.isSlice()) break :p;
@@ -18461,6 +18562,17 @@ fn coerceInMemoryAllowed(
if (dest_ty.eql(src_ty, target))
return .ok;
+ // Differently-named integers with the same number of bits.
+ if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {
+ const dest_info = dest_ty.intInfo(target);
+ const src_info = src_ty.intInfo(target);
+ if (dest_info.signedness == src_info.signedness and
+ dest_info.bits == src_info.bits)
+ {
+ return .ok;
+ }
+ }
+
// Pointers / Pointer-like Optionals
var dest_buf: Type.Payload.ElemType = undefined;
var src_buf: Type.Payload.ElemType = undefined;
@@ -20913,7 +21025,7 @@ fn resolvePeerTypes(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- instructions: []Air.Inst.Ref,
+ instructions: []const Air.Inst.Ref,
candidate_srcs: Module.PeerTypeCandidateSrc,
) !Type {
switch (instructions.len) {
@@ -21562,6 +21674,8 @@ fn resolveUnionLayout(
union_obj.status = .have_layout;
}
+/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
+/// be resolved.
pub fn resolveTypeFully(
sema: *Sema,
block: *Block,
@@ -21610,18 +21724,29 @@ fn resolveStructFully(
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const payload = resolved_ty.castTag(.@"struct") orelse return;
const struct_obj = payload.data;
+
switch (struct_obj.status) {
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
.fully_resolved_wip, .fully_resolved => return,
}
- // After we have resolve struct layout we have to go over the fields again to
- // make sure pointer fields get their child types resolved as well
- struct_obj.status = .fully_resolved_wip;
- for (struct_obj.fields.values()) |field| {
- try sema.resolveTypeFully(block, src, field.ty);
+ log.debug("resolveStructFully {*} ('{s}')", .{
+ struct_obj.owner_decl, struct_obj.owner_decl.name,
+ });
+
+ {
+ // After we have resolve struct layout we have to go over the fields again to
+ // make sure pointer fields get their child types resolved as well.
+ // See also similar code for unions.
+ const prev_status = struct_obj.status;
+ errdefer struct_obj.status = prev_status;
+
+ struct_obj.status = .fully_resolved_wip;
+ for (struct_obj.fields.values()) |field| {
+ try sema.resolveTypeFully(block, src, field.ty);
+ }
+ struct_obj.status = .fully_resolved;
}
- struct_obj.status = .fully_resolved;
// And let's not forget comptime-only status.
_ = try sema.typeRequiresComptime(block, src, ty);
@@ -21642,12 +21767,19 @@ fn resolveUnionFully(
.fully_resolved_wip, .fully_resolved => return,
}
- // Same goes for unions (see comment about structs)
- union_obj.status = .fully_resolved_wip;
- for (union_obj.fields.values()) |field| {
- try sema.resolveTypeFully(block, src, field.ty);
+ {
+ // After we have resolve union layout we have to go over the fields again to
+ // make sure pointer fields get their child types resolved as well.
+ // See also similar code for structs.
+ const prev_status = union_obj.status;
+ errdefer union_obj.status = prev_status;
+
+ union_obj.status = .fully_resolved_wip;
+ for (union_obj.fields.values()) |field| {
+ try sema.resolveTypeFully(block, src, field.ty);
+ }
+ union_obj.status = .fully_resolved;
}
- union_obj.status = .fully_resolved;
// And let's not forget comptime-only status.
_ = try sema.typeRequiresComptime(block, src, ty);
@@ -22776,7 +22908,7 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 {
}
fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void {
- const coerced = @bitCast([]const u32, refs);
+ const coerced = @ptrCast([]const u32, refs);
sema.air_extra.appendSliceAssumeCapacity(coerced);
}
diff --git a/src/ThreadPool.zig b/src/ThreadPool.zig
index ac95def319..36d004cfc6 100644
--- a/src/ThreadPool.zig
+++ b/src/ThreadPool.zig
@@ -12,7 +12,12 @@ idle_queue: IdleQueue = .{},
const IdleQueue = std.SinglyLinkedList(std.Thread.ResetEvent);
const RunQueue = std.SinglyLinkedList(Runnable);
const Runnable = struct {
- runFn: fn (*Runnable) void,
+ runFn: RunProto,
+};
+
+const RunProto = switch (builtin.zig_backend) {
+ .stage1 => fn (*Runnable) void,
+ else => *const fn (*Runnable) void,
};
const Worker = struct {
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index ea946d6ba6..95d2a8a607 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -202,26 +202,12 @@ const BlockData = struct {
const BigTomb = struct {
function: *Self,
inst: Air.Inst.Index,
- tomb_bits: Liveness.Bpi,
- big_tomb_bits: u32,
- bit_index: usize,
+ lbt: Liveness.BigTomb,
fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
- const this_bit_index = bt.bit_index;
- bt.bit_index += 1;
-
- const op_int = @enumToInt(op_ref);
- if (op_int < Air.Inst.Ref.typed_value_map.len) return;
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
-
- if (this_bit_index < Liveness.bpi - 1) {
- const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
- if (!dies) return;
- } else {
- const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
- const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
- if (!dies) return;
- }
+ const dies = bt.lbt.feed();
+ const op_index = Air.refToIndex(op_ref) orelse return;
+ if (!dies) return;
bt.function.processDeath(op_index);
}
@@ -2412,7 +2398,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const callee = pl_op.operand;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
const ty = self.air.typeOf(callee);
const fn_ty = switch (ty.zigTypeTag()) {
@@ -2879,7 +2865,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
// TODO track the new register / stack allocation
}
- self.branch_stack.pop().deinit(self.gpa);
+ {
+ var item = self.branch_stack.pop();
+ item.deinit(self.gpa);
+ }
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -3176,9 +3165,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
const dead = !is_volatile and self.liveness.isUnused(inst);
@@ -3291,9 +3280,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
return BigTomb{
.function = self,
.inst = inst,
- .tomb_bits = self.liveness.getTombBits(inst),
- .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
- .bit_index = 0,
+ .lbt = self.liveness.iterateBigTomb(inst),
};
}
@@ -3702,7 +3689,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
const vector_ty = self.air.typeOfIndex(inst);
const len = vector_ty.vectorLen();
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
const result: MCValue = res: {
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
return self.fail("TODO implement airAggregateInit for {}", .{self.target.cpu.arch});
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 9a660ceff6..f71ceaba89 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -224,26 +224,12 @@ const BlockData = struct {
const BigTomb = struct {
function: *Self,
inst: Air.Inst.Index,
- tomb_bits: Liveness.Bpi,
- big_tomb_bits: u32,
- bit_index: usize,
+ lbt: Liveness.BigTomb,
fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
- const this_bit_index = bt.bit_index;
- bt.bit_index += 1;
-
- const op_int = @enumToInt(op_ref);
- if (op_int < Air.Inst.Ref.typed_value_map.len) return;
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
-
- if (this_bit_index < Liveness.bpi - 1) {
- const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
- if (!dies) return;
- } else {
- const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
- const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
- if (!dies) return;
- }
+ const dies = bt.lbt.feed();
+ const op_index = Air.refToIndex(op_ref) orelse return;
+ if (!dies) return;
bt.function.processDeath(op_index);
}
@@ -3158,7 +3144,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const callee = pl_op.operand;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
const ty = self.air.typeOf(callee);
const fn_ty = switch (ty.zigTypeTag()) {
@@ -3664,7 +3650,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
// TODO track the new register / stack allocation
}
- self.branch_stack.pop().deinit(self.gpa);
+ {
+ var item = self.branch_stack.pop();
+ item.deinit(self.gpa);
+ }
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -3965,9 +3954,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
const dead = !is_volatile and self.liveness.isUnused(inst);
@@ -4076,9 +4065,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
return BigTomb{
.function = self,
.inst = inst,
- .tomb_bits = self.liveness.getTombBits(inst),
- .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
- .bit_index = 0,
+ .lbt = self.liveness.iterateBigTomb(inst),
};
}
@@ -4751,7 +4738,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
const vector_ty = self.air.typeOfIndex(inst);
const len = vector_ty.vectorLen();
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
const result: MCValue = res: {
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
return self.fail("TODO implement airAggregateInit for arm", .{});
diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig
index 77fa82d1d2..209ab137a6 100644
--- a/src/arch/arm/Emit.zig
+++ b/src/arch/arm/Emit.zig
@@ -2,6 +2,7 @@
//! machine code
const Emit = @This();
+const builtin = @import("builtin");
const std = @import("std");
const math = std.math;
const Mir = @import("Mir.zig");
@@ -417,7 +418,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
@@ -449,7 +450,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
};
const dbg_info = &dw.dbg_info;
- try dbg_info.append(link.File.Dwarf.abbrev_parameter);
+ try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
@@ -622,12 +623,17 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
const ldr = switch (tag) {
- .ldr_stack_argument => Instruction.ldr,
- .ldrb_stack_argument => Instruction.ldrb,
+ .ldr_stack_argument => &Instruction.ldr,
+ .ldrb_stack_argument => &Instruction.ldrb,
else => unreachable,
};
- try emit.writeInstruction(ldr(
+ const ldr_workaround = switch (builtin.zig_backend) {
+ .stage1 => ldr.*,
+ else => ldr,
+ };
+
+ try emit.writeInstruction(ldr_workaround(
cond,
r_stack_offset.rt,
.fp,
@@ -643,13 +649,18 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
const ldr = switch (tag) {
- .ldrh_stack_argument => Instruction.ldrh,
- .ldrsb_stack_argument => Instruction.ldrsb,
- .ldrsh_stack_argument => Instruction.ldrsh,
+ .ldrh_stack_argument => &Instruction.ldrh,
+ .ldrsb_stack_argument => &Instruction.ldrsb,
+ .ldrsh_stack_argument => &Instruction.ldrsh,
else => unreachable,
};
- try emit.writeInstruction(ldr(
+ const ldr_workaround = switch (builtin.zig_backend) {
+ .stage1 => ldr.*,
+ else => ldr,
+ };
+
+ try emit.writeInstruction(ldr_workaround(
cond,
r_stack_offset.rt,
.fp,
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig
index ac12bbceaf..cf9e5fefcd 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -194,26 +194,12 @@ const Reloc = union(enum) {
const BigTomb = struct {
function: *Self,
inst: Air.Inst.Index,
- tomb_bits: Liveness.Bpi,
- big_tomb_bits: u32,
- bit_index: usize,
+ lbt: Liveness.BigTomb,
fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
- const this_bit_index = bt.bit_index;
- bt.bit_index += 1;
-
- const op_int = @enumToInt(op_ref);
- if (op_int < Air.Inst.Ref.typed_value_map.len) return;
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
-
- if (this_bit_index < Liveness.bpi - 1) {
- const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
- if (!dies) return;
- } else {
- const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
- const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
- if (!dies) return;
- }
+ const dies = bt.lbt.feed();
+ const op_index = Air.refToIndex(op_ref) orelse return;
+ if (!dies) return;
bt.function.processDeath(op_index);
}
@@ -1574,7 +1560,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
@@ -1654,7 +1640,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const fn_ty = self.air.typeOf(pl_op.operand);
const callee = pl_op.operand;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
var info = try self.resolveCallingConventionValues(fn_ty);
defer info.deinit(self);
@@ -2089,9 +2075,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
const dead = !is_volatile and self.liveness.isUnused(inst);
@@ -2198,9 +2184,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
return BigTomb{
.function = self,
.inst = inst,
- .tomb_bits = self.liveness.getTombBits(inst),
- .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
- .bit_index = 0,
+ .lbt = self.liveness.iterateBigTomb(inst),
};
}
@@ -2429,7 +2413,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
const vector_ty = self.air.typeOfIndex(inst);
const len = vector_ty.vectorLen();
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
const result: MCValue = res: {
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
return self.fail("TODO implement airAggregateInit for riscv64", .{});
diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig
index db5811dfda..7de035bc5c 100644
--- a/src/arch/sparcv9/CodeGen.zig
+++ b/src/arch/sparcv9/CodeGen.zig
@@ -1,23 +1,235 @@
//! SPARCv9 codegen.
//! This lowers AIR into MIR.
const std = @import("std");
+const assert = std.debug.assert;
+const log = std.log.scoped(.codegen);
+const math = std.math;
+const mem = std.mem;
+const Allocator = mem.Allocator;
const builtin = @import("builtin");
const link = @import("../../link.zig");
const Module = @import("../../Module.zig");
+const TypedValue = @import("../../TypedValue.zig");
+const ErrorMsg = Module.ErrorMsg;
const Air = @import("../../Air.zig");
const Mir = @import("Mir.zig");
const Emit = @import("Emit.zig");
const Liveness = @import("../../Liveness.zig");
-
+const Type = @import("../../type.zig").Type;
const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
const FnResult = @import("../../codegen.zig").FnResult;
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
+const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
+const RegisterManager = RegisterManagerFn(Self, Register, &abi.allocatable_regs);
+
+const build_options = @import("build_options");
const bits = @import("bits.zig");
const abi = @import("abi.zig");
+const Register = bits.Register;
const Self = @This();
+const InnerError = error{
+ OutOfMemory,
+ CodegenFail,
+ OutOfRegisters,
+};
+
+const RegisterView = enum(u1) {
+ caller,
+ callee,
+};
+
+gpa: Allocator,
+air: Air,
+liveness: Liveness,
+bin_file: *link.File,
+target: *const std.Target,
+mod_fn: *const Module.Fn,
+code: *std.ArrayList(u8),
+debug_output: DebugInfoOutput,
+err_msg: ?*ErrorMsg,
+args: []MCValue,
+ret_mcv: MCValue,
+fn_type: Type,
+arg_index: usize,
+src_loc: Module.SrcLoc,
+stack_align: u32,
+
+/// MIR Instructions
+mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
+/// MIR extra data
+mir_extra: std.ArrayListUnmanaged(u32) = .{},
+
+/// Byte offset within the source file of the ending curly.
+end_di_line: u32,
+end_di_column: u32,
+
+/// The value is an offset into the `Function` `code` from the beginning.
+/// To perform the reloc, write 32-bit signed little-endian integer
+/// which is a relative jump, based on the address following the reloc.
+exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
+
+/// Whenever there is a runtime branch, we push a Branch onto this stack,
+/// and pop it off when the runtime branch joins. This provides an "overlay"
+/// of the table of mappings from instructions to `MCValue` from within the branch.
+/// This way we can modify the `MCValue` for an instruction in different ways
+/// within different branches. Special consideration is needed when a branch
+/// joins with its parent, to make sure all instructions have the same MCValue
+/// across each runtime branch upon joining.
+branch_stack: *std.ArrayList(Branch),
+
+// Key is the block instruction
+blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
+
+register_manager: RegisterManager = .{},
+
+/// Maps offset to what is stored there.
+stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
+
+/// Offset from the stack base, representing the end of the stack frame.
+max_end_stack: u32 = 0,
+/// Represents the current end stack offset. If there is no existing slot
+/// to place a new stack allocation, it goes here, and then bumps `max_end_stack`.
+next_stack_offset: u32 = 0,
+
+/// Debug field, used to find bugs in the compiler.
+air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
+
+const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
+
+const MCValue = union(enum) {
+ /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
+ /// TODO Look into deleting this tag and using `dead` instead, since every use
+ /// of MCValue.none should be instead looking at the type and noticing it is 0 bits.
+ none,
+ /// Control flow will not allow this value to be observed.
+ unreach,
+ /// No more references to this value remain.
+ dead,
+ /// The value is undefined.
+ undef,
+ /// A pointer-sized integer that fits in a register.
+ /// If the type is a pointer, this is the pointer address in virtual address space.
+ immediate: u64,
+ /// The value is in a target-specific register.
+ register: Register,
+ /// The value is in memory at a hard-coded address.
+ /// If the type is a pointer, it means the pointer address is at this memory location.
+ memory: u64,
+ /// The value is one of the stack variables.
+ /// If the type is a pointer, it means the pointer address is in the stack at this offset.
+ stack_offset: u32,
+ /// The value is a pointer to one of the stack variables (payload is stack offset).
+ ptr_stack_offset: u32,
+
+ fn isMemory(mcv: MCValue) bool {
+ return switch (mcv) {
+ .memory, .stack_offset => true,
+ else => false,
+ };
+ }
+
+ fn isImmediate(mcv: MCValue) bool {
+ return switch (mcv) {
+ .immediate => true,
+ else => false,
+ };
+ }
+
+ fn isMutable(mcv: MCValue) bool {
+ return switch (mcv) {
+ .none => unreachable,
+ .unreach => unreachable,
+ .dead => unreachable,
+
+ .immediate,
+ .memory,
+ .ptr_stack_offset,
+ .undef,
+ => false,
+
+ .register,
+ .stack_offset,
+ => true,
+ };
+ }
+};
+
+const Branch = struct {
+ inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},
+
+ fn deinit(self: *Branch, gpa: Allocator) void {
+ self.inst_table.deinit(gpa);
+ self.* = undefined;
+ }
+};
+
+const StackAllocation = struct {
+ inst: Air.Inst.Index,
+ /// TODO do we need size? should be determined by inst.ty.abiSize()
+ size: u32,
+};
+
+const BlockData = struct {
+ relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
+ /// The first break instruction encounters `null` here and chooses a
+ /// machine code value for the block result, populating this field.
+ /// Following break instructions encounter that value and use it for
+ /// the location to store their block results.
+ mcv: MCValue,
+};
+
+const CallMCValues = struct {
+ args: []MCValue,
+ return_value: MCValue,
+ stack_byte_count: u32,
+ stack_align: u32,
+
+ fn deinit(self: *CallMCValues, func: *Self) void {
+ func.gpa.free(self.args);
+ self.* = undefined;
+ }
+};
+
+const BigTomb = struct {
+ function: *Self,
+ inst: Air.Inst.Index,
+ tomb_bits: Liveness.Bpi,
+ big_tomb_bits: u32,
+ bit_index: usize,
+
+ fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
+ const this_bit_index = bt.bit_index;
+ bt.bit_index += 1;
+
+ const op_int = @enumToInt(op_ref);
+ if (op_int < Air.Inst.Ref.typed_value_map.len) return;
+ const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
+
+ if (this_bit_index < Liveness.bpi - 1) {
+ const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
+ if (!dies) return;
+ } else {
+ const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
+ const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
+ if (!dies) return;
+ }
+ bt.function.processDeath(op_index);
+ }
+
+ fn finishAir(bt: *BigTomb, result: MCValue) void {
+ const is_used = !bt.function.liveness.isUnused(bt.inst);
+ if (is_used) {
+ log.debug("%{d} => {}", .{ bt.inst, result });
+ const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
+ }
+ bt.function.finishAirBookkeeping();
+ }
+};
+
pub fn generate(
bin_file: *link.File,
src_loc: Module.SrcLoc,
@@ -27,13 +239,1439 @@ pub fn generate(
code: *std.ArrayList(u8),
debug_output: DebugInfoOutput,
) GenerateSymbolError!FnResult {
- _ = bin_file;
- _ = src_loc;
- _ = module_fn;
- _ = air;
- _ = liveness;
- _ = code;
- _ = debug_output;
-
- @panic("TODO implement SPARCv9 codegen");
+ if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) {
+ @panic("Attempted to compile for architecture that was disabled by build configuration");
+ }
+
+ assert(module_fn.owner_decl.has_tv);
+ const fn_type = module_fn.owner_decl.ty;
+
+ var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
+ defer {
+ assert(branch_stack.items.len == 1);
+ branch_stack.items[0].deinit(bin_file.allocator);
+ branch_stack.deinit();
+ }
+ try branch_stack.append(.{});
+
+ var function = Self{
+ .gpa = bin_file.allocator,
+ .air = air,
+ .liveness = liveness,
+ .target = &bin_file.options.target,
+ .bin_file = bin_file,
+ .mod_fn = module_fn,
+ .code = code,
+ .debug_output = debug_output,
+ .err_msg = null,
+ .args = undefined, // populated after `resolveCallingConventionValues`
+ .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
+ .fn_type = fn_type,
+ .arg_index = 0,
+ .branch_stack = &branch_stack,
+ .src_loc = src_loc,
+ .stack_align = undefined,
+ .end_di_line = module_fn.rbrace_line,
+ .end_di_column = module_fn.rbrace_column,
+ };
+ defer function.stack.deinit(bin_file.allocator);
+ defer function.blocks.deinit(bin_file.allocator);
+ defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
+
+ var call_info = function.resolveCallingConventionValues(fn_type, .callee) catch |err| switch (err) {
+ error.CodegenFail => return FnResult{ .fail = function.err_msg.? },
+ error.OutOfRegisters => return FnResult{
+ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
+ },
+ else => |e| return e,
+ };
+ defer call_info.deinit(&function);
+
+ function.args = call_info.args;
+ function.ret_mcv = call_info.return_value;
+ function.stack_align = call_info.stack_align;
+ function.max_end_stack = call_info.stack_byte_count;
+
+ function.gen() catch |err| switch (err) {
+ error.CodegenFail => return FnResult{ .fail = function.err_msg.? },
+ error.OutOfRegisters => return FnResult{
+ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
+ },
+ else => |e| return e,
+ };
+
+ var mir = Mir{
+ .instructions = function.mir_instructions.toOwnedSlice(),
+ .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
+ };
+ defer mir.deinit(bin_file.allocator);
+
+ var emit = Emit{
+ .mir = mir,
+ .bin_file = bin_file,
+ .debug_output = debug_output,
+ .target = &bin_file.options.target,
+ .src_loc = src_loc,
+ .code = code,
+ .prev_di_pc = 0,
+ .prev_di_line = module_fn.lbrace_line,
+ .prev_di_column = module_fn.lbrace_column,
+ };
+ defer emit.deinit();
+
+ emit.emitMir() catch |err| switch (err) {
+ error.EmitFail => return FnResult{ .fail = emit.err_msg.? },
+ else => |e| return e,
+ };
+
+ if (function.err_msg) |em| {
+ return FnResult{ .fail = em };
+ } else {
+ return FnResult{ .appended = {} };
+ }
+}
+
+fn gen(self: *Self) !void {
+ const cc = self.fn_type.fnCallingConvention();
+ if (cc != .Naked) {
+ // TODO Finish function prologue and epilogue for sparcv9.
+
+ // TODO Backpatch stack offset
+ // save %sp, -176, %sp
+ _ = try self.addInst(.{
+ .tag = .save,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = true,
+ .rd = .sp,
+ .rs1 = .sp,
+ .rs2_or_imm = .{ .imm = -176 },
+ },
+ },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .dbg_prologue_end,
+ .data = .{ .nop = {} },
+ });
+
+ try self.genBody(self.air.getMainBody());
+
+ _ = try self.addInst(.{
+ .tag = .dbg_epilogue_begin,
+ .data = .{ .nop = {} },
+ });
+
+ // exitlude jumps
+ if (self.exitlude_jump_relocs.items.len > 0 and
+ self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2)
+ {
+ // If the last Mir instruction (apart from the
+ // dbg_epilogue_begin) is the last exitlude jump
+ // relocation (which would just jump one instruction
+ // further), it can be safely removed
+ self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop());
+ }
+
+ for (self.exitlude_jump_relocs.items) |jmp_reloc| {
+ _ = jmp_reloc;
+ return self.fail("TODO add branches in sparcv9", .{});
+ }
+
+ // return %i7 + 8
+ _ = try self.addInst(.{
+ .tag = .@"return",
+ .data = .{
+ .arithmetic_2op = .{
+ .is_imm = true,
+ .rs1 = .@"i7",
+ .rs2_or_imm = .{ .imm = 8 },
+ },
+ },
+ });
+
+ // TODO Find a way to fill this slot
+ // nop
+ _ = try self.addInst(.{
+ .tag = .nop,
+ .data = .{ .nop = {} },
+ });
+ } else {
+ _ = try self.addInst(.{
+ .tag = .dbg_prologue_end,
+ .data = .{ .nop = {} },
+ });
+
+ try self.genBody(self.air.getMainBody());
+
+ _ = try self.addInst(.{
+ .tag = .dbg_epilogue_begin,
+ .data = .{ .nop = {} },
+ });
+ }
+
+ // Drop them off at the rbrace.
+ _ = try self.addInst(.{
+ .tag = .dbg_line,
+ .data = .{ .dbg_line_column = .{
+ .line = self.end_di_line,
+ .column = self.end_di_column,
+ } },
+ });
+}
+
+fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
+ const air_tags = self.air.instructions.items(.tag);
+
+ for (body) |inst| {
+ const old_air_bookkeeping = self.air_bookkeeping;
+ try self.ensureProcessDeathCapacity(Liveness.bpi);
+
+ switch (air_tags[inst]) {
+ // zig fmt: off
+ .add, .ptr_add => @panic("TODO try self.airBinOp(inst)"),
+ .addwrap => @panic("TODO try self.airAddWrap(inst)"),
+ .add_sat => @panic("TODO try self.airAddSat(inst)"),
+ .sub, .ptr_sub => @panic("TODO try self.airBinOp(inst)"),
+ .subwrap => @panic("TODO try self.airSubWrap(inst)"),
+ .sub_sat => @panic("TODO try self.airSubSat(inst)"),
+ .mul => @panic("TODO try self.airMul(inst)"),
+ .mulwrap => @panic("TODO try self.airMulWrap(inst)"),
+ .mul_sat => @panic("TODO try self.airMulSat(inst)"),
+ .rem => @panic("TODO try self.airRem(inst)"),
+ .mod => @panic("TODO try self.airMod(inst)"),
+ .shl, .shl_exact => @panic("TODO try self.airShl(inst)"),
+ .shl_sat => @panic("TODO try self.airShlSat(inst)"),
+ .min => @panic("TODO try self.airMin(inst)"),
+ .max => @panic("TODO try self.airMax(inst)"),
+ .slice => @panic("TODO try self.airSlice(inst)"),
+
+ .sqrt,
+ .sin,
+ .cos,
+ .exp,
+ .exp2,
+ .log,
+ .log2,
+ .log10,
+ .fabs,
+ .floor,
+ .ceil,
+ .round,
+ .trunc_float,
+ => @panic("TODO try self.airUnaryMath(inst)"),
+
+ .add_with_overflow => @panic("TODO try self.airAddWithOverflow(inst)"),
+ .sub_with_overflow => @panic("TODO try self.airSubWithOverflow(inst)"),
+ .mul_with_overflow => @panic("TODO try self.airMulWithOverflow(inst)"),
+ .shl_with_overflow => @panic("TODO try self.airShlWithOverflow(inst)"),
+
+ .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
+
+ .cmp_lt => @panic("TODO try self.airCmp(inst, .lt)"),
+ .cmp_lte => @panic("TODO try self.airCmp(inst, .lte)"),
+ .cmp_eq => @panic("TODO try self.airCmp(inst, .eq)"),
+ .cmp_gte => @panic("TODO try self.airCmp(inst, .gte)"),
+ .cmp_gt => @panic("TODO try self.airCmp(inst, .gt)"),
+ .cmp_neq => @panic("TODO try self.airCmp(inst, .neq)"),
+ .cmp_vector => @panic("TODO try self.airCmpVector(inst)"),
+ .cmp_lt_errors_len => @panic("TODO try self.airCmpLtErrorsLen(inst)"),
+
+ .bool_and => @panic("TODO try self.airBoolOp(inst)"),
+ .bool_or => @panic("TODO try self.airBoolOp(inst)"),
+ .bit_and => @panic("TODO try self.airBitAnd(inst)"),
+ .bit_or => @panic("TODO try self.airBitOr(inst)"),
+ .xor => @panic("TODO try self.airXor(inst)"),
+ .shr, .shr_exact => @panic("TODO try self.airShr(inst)"),
+
+ .alloc => @panic("TODO try self.airAlloc(inst)"),
+ .ret_ptr => try self.airRetPtr(inst),
+ .arg => try self.airArg(inst),
+ .assembly => try self.airAsm(inst),
+ .bitcast => @panic("TODO try self.airBitCast(inst)"),
+ .block => try self.airBlock(inst),
+ .br => @panic("TODO try self.airBr(inst)"),
+ .breakpoint => try self.airBreakpoint(),
+ .ret_addr => @panic("TODO try self.airRetAddr(inst)"),
+ .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
+ .fence => @panic("TODO try self.airFence()"),
+ .cond_br => @panic("TODO try self.airCondBr(inst)"),
+ .dbg_stmt => try self.airDbgStmt(inst),
+ .fptrunc => @panic("TODO try self.airFptrunc(inst)"),
+ .fpext => @panic("TODO try self.airFpext(inst)"),
+ .intcast => @panic("TODO try self.airIntCast(inst)"),
+ .trunc => @panic("TODO try self.airTrunc(inst)"),
+ .bool_to_int => @panic("TODO try self.airBoolToInt(inst)"),
+ .is_non_null => @panic("TODO try self.airIsNonNull(inst)"),
+ .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"),
+ .is_null => @panic("TODO try self.airIsNull(inst)"),
+ .is_null_ptr => @panic("TODO try self.airIsNullPtr(inst)"),
+ .is_non_err => @panic("TODO try self.airIsNonErr(inst)"),
+ .is_non_err_ptr => @panic("TODO try self.airIsNonErrPtr(inst)"),
+ .is_err => @panic("TODO try self.airIsErr(inst)"),
+ .is_err_ptr => @panic("TODO try self.airIsErrPtr(inst)"),
+ .load => @panic("TODO try self.airLoad(inst)"),
+ .loop => @panic("TODO try self.airLoop(inst)"),
+ .not => @panic("TODO try self.airNot(inst)"),
+ .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"),
+ .ret => try self.airRet(inst),
+ .ret_load => try self.airRetLoad(inst),
+ .store => try self.airStore(inst),
+ .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"),
+ .struct_field_val=> @panic("TODO try self.airStructFieldVal(inst)"),
+ .array_to_slice => @panic("TODO try self.airArrayToSlice(inst)"),
+ .int_to_float => @panic("TODO try self.airIntToFloat(inst)"),
+ .float_to_int => @panic("TODO try self.airFloatToInt(inst)"),
+ .cmpxchg_strong => @panic("TODO try self.airCmpxchg(inst)"),
+ .cmpxchg_weak => @panic("TODO try self.airCmpxchg(inst)"),
+ .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"),
+ .atomic_load => @panic("TODO try self.airAtomicLoad(inst)"),
+ .memcpy => @panic("TODO try self.airMemcpy(inst)"),
+ .memset => @panic("TODO try self.airMemset(inst)"),
+ .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"),
+ .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"),
+ .clz => @panic("TODO try self.airClz(inst)"),
+ .ctz => @panic("TODO try self.airCtz(inst)"),
+ .popcount => @panic("TODO try self.airPopcount(inst)"),
+ .byte_swap => @panic("TODO try self.airByteSwap(inst)"),
+ .bit_reverse => @panic("TODO try self.airBitReverse(inst)"),
+ .tag_name => @panic("TODO try self.airTagName(inst)"),
+ .error_name => @panic("TODO try self.airErrorName(inst)"),
+ .splat => @panic("TODO try self.airSplat(inst)"),
+ .select => @panic("TODO try self.airSelect(inst)"),
+ .shuffle => @panic("TODO try self.airShuffle(inst)"),
+ .reduce => @panic("TODO try self.airReduce(inst)"),
+ .aggregate_init => @panic("TODO try self.airAggregateInit(inst)"),
+ .union_init => @panic("TODO try self.airUnionInit(inst)"),
+ .prefetch => @panic("TODO try self.airPrefetch(inst)"),
+ .mul_add => @panic("TODO try self.airMulAdd(inst)"),
+
+ .dbg_var_ptr,
+ .dbg_var_val,
+ => try self.airDbgVar(inst),
+
+ .dbg_inline_begin,
+ .dbg_inline_end,
+ => try self.airDbgInline(inst),
+
+ .dbg_block_begin,
+ .dbg_block_end,
+ => try self.airDbgBlock(inst),
+
+ .call => try self.airCall(inst, .auto),
+ .call_always_tail => try self.airCall(inst, .always_tail),
+ .call_never_tail => try self.airCall(inst, .never_tail),
+ .call_never_inline => try self.airCall(inst, .never_inline),
+
+ .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"),
+ .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"),
+ .atomic_store_release => @panic("TODO try self.airAtomicStore(inst, .Release)"),
+ .atomic_store_seq_cst => @panic("TODO try self.airAtomicStore(inst, .SeqCst)"),
+
+ .struct_field_ptr_index_0 => @panic("TODO try self.airStructFieldPtrIndex(inst, 0)"),
+ .struct_field_ptr_index_1 => @panic("TODO try self.airStructFieldPtrIndex(inst, 1)"),
+ .struct_field_ptr_index_2 => @panic("TODO try self.airStructFieldPtrIndex(inst, 2)"),
+ .struct_field_ptr_index_3 => @panic("TODO try self.airStructFieldPtrIndex(inst, 3)"),
+
+ .field_parent_ptr => @panic("TODO try self.airFieldParentPtr(inst)"),
+
+ .switch_br => try self.airSwitch(inst),
+ .slice_ptr => @panic("TODO try self.airSlicePtr(inst)"),
+ .slice_len => @panic("TODO try self.airSliceLen(inst)"),
+
+ .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"),
+ .ptr_slice_ptr_ptr => @panic("TODO try self.airPtrSlicePtrPtr(inst)"),
+
+ .array_elem_val => @panic("TODO try self.airArrayElemVal(inst)"),
+ .slice_elem_val => @panic("TODO try self.airSliceElemVal(inst)"),
+ .slice_elem_ptr => @panic("TODO try self.airSliceElemPtr(inst)"),
+ .ptr_elem_val => @panic("TODO try self.airPtrElemVal(inst)"),
+ .ptr_elem_ptr => @panic("TODO try self.airPtrElemPtr(inst)"),
+
+ .constant => unreachable, // excluded from function bodies
+ .const_ty => unreachable, // excluded from function bodies
+ .unreach => self.finishAirBookkeeping(),
+
+ .optional_payload => @panic("TODO try self.airOptionalPayload(inst)"),
+ .optional_payload_ptr => @panic("TODO try self.airOptionalPayloadPtr(inst)"),
+ .optional_payload_ptr_set => @panic("TODO try self.airOptionalPayloadPtrSet(inst)"),
+ .unwrap_errunion_err => @panic("TODO try self.airUnwrapErrErr(inst)"),
+ .unwrap_errunion_payload => @panic("TODO try self.airUnwrapErrPayload(inst)"),
+ .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"),
+ .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"),
+ .errunion_payload_ptr_set => @panic("TODO try self.airErrUnionPayloadPtrSet(inst)"),
+
+ .wrap_optional => @panic("TODO try self.airWrapOptional(inst)"),
+ .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
+ .wrap_errunion_err => @panic("TODO try self.airWrapErrUnionErr(inst)"),
+
+ .wasm_memory_size => unreachable,
+ .wasm_memory_grow => unreachable,
+ // zig fmt: on
+ }
+
+ if (std.debug.runtime_safety) {
+ if (self.air_bookkeeping < old_air_bookkeeping + 1) {
+ std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
+ }
+ }
+ }
+}
+
+fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.Asm, ty_pl.payload);
+ const is_volatile = (extra.data.flags & 0x80000000) != 0;
+ const clobbers_len = @truncate(u31, extra.data.flags);
+ var extra_i: usize = extra.end;
+ const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i .. extra_i + extra.data.outputs_len]);
+ extra_i += outputs.len;
+ const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i .. extra_i + extra.data.inputs_len]);
+ extra_i += inputs.len;
+
+ const dead = !is_volatile and self.liveness.isUnused(inst);
+ const result: MCValue = if (dead) .dead else result: {
+ if (outputs.len > 1) {
+ return self.fail("TODO implement codegen for asm with more than 1 output", .{});
+ }
+
+ const output_constraint: ?[]const u8 = for (outputs) |output| {
+ if (output != .none) {
+ return self.fail("TODO implement codegen for non-expr asm", .{});
+ }
+ const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+ // This equation accounts for the fact that even if we have exactly 4 bytes
+ // for the string, we still use the next u32 for the null terminator.
+ extra_i += constraint.len / 4 + 1;
+
+ break constraint;
+ } else null;
+
+ for (inputs) |input| {
+ const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+ const constraint = std.mem.sliceTo(input_bytes, 0);
+ const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
+ // This equation accounts for the fact that even if we have exactly 4 bytes
+ // for the string, we still use the next u32 for the null terminator.
+ extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
+
+ if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
+ return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
+ }
+ const reg_name = constraint[1 .. constraint.len - 1];
+ const reg = parseRegName(reg_name) orelse
+ return self.fail("unrecognized register: '{s}'", .{reg_name});
+
+ const arg_mcv = try self.resolveInst(input);
+ try self.register_manager.getReg(reg, null);
+ try self.genSetReg(self.air.typeOf(input), reg, arg_mcv);
+ }
+
+ {
+ var clobber_i: u32 = 0;
+ while (clobber_i < clobbers_len) : (clobber_i += 1) {
+ const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+ // This equation accounts for the fact that even if we have exactly 4 bytes
+ // for the string, we still use the next u32 for the null terminator.
+ extra_i += clobber.len / 4 + 1;
+
+ // TODO honor these
+ }
+ }
+
+ const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
+
+ if (mem.eql(u8, asm_source, "ta 0x6d")) {
+ _ = try self.addInst(.{
+ .tag = .tcc,
+ .data = .{
+ .trap = .{
+ .is_imm = true,
+ .cond = 0b1000, // TODO need to look into changing this into an enum
+ .rs2_or_imm = .{ .imm = 0x6d },
+ },
+ },
+ });
+ } else {
+ return self.fail("TODO implement a full SPARCv9 assembly parsing", .{});
+ }
+
+ if (output_constraint) |output| {
+ if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
+ return self.fail("unrecognized asm output constraint: '{s}'", .{output});
+ }
+ const reg_name = output[2 .. output.len - 1];
+ const reg = parseRegName(reg_name) orelse
+ return self.fail("unrecognized register: '{s}'", .{reg_name});
+ break :result MCValue{ .register = reg };
+ } else {
+ break :result MCValue{ .none = {} };
+ }
+ };
+
+ simple: {
+ var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
+ var buf_index: usize = 0;
+ for (outputs) |output| {
+ if (output == .none) continue;
+
+ if (buf_index >= buf.len) break :simple;
+ buf[buf_index] = output;
+ buf_index += 1;
+ }
+ if (buf_index + inputs.len > buf.len) break :simple;
+ std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs);
+ return self.finishAir(inst, result, buf);
+ }
+
+ var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len);
+ for (outputs) |output| {
+ if (output == .none) continue;
+
+ bt.feed(output);
+ }
+ for (inputs) |input| {
+ bt.feed(input);
+ }
+ return bt.finishAir(result);
+}
+
+fn airArg(self: *Self, inst: Air.Inst.Index) !void {
+ const arg_index = self.arg_index;
+ self.arg_index += 1;
+
+ const ty = self.air.typeOfIndex(inst);
+ _ = ty;
+
+ const result = self.args[arg_index];
+ // TODO support stack-only arguments
+ // TODO Copy registers to the stack
+ const mcv = result;
+
+ _ = try self.addInst(.{
+ .tag = .dbg_arg,
+ .data = .{
+ .dbg_arg_info = .{
+ .air_inst = inst,
+ .arg_index = arg_index,
+ },
+ },
+ });
+
+ if (self.liveness.isUnused(inst))
+ return self.finishAirBookkeeping();
+
+ switch (mcv) {
+ .register => |reg| {
+ self.register_manager.getRegAssumeFree(reg, inst);
+ },
+ else => {},
+ }
+
+ return self.finishAir(inst, mcv, .{ .none, .none, .none });
+}
+
+fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
+ try self.blocks.putNoClobber(self.gpa, inst, .{
+ // A block is a setup to be able to jump to the end.
+ .relocs = .{},
+ // It also acts as a receptacle for break operands.
+ // Here we use `MCValue.none` to represent a null value so that the first
+ // break instruction will choose a MCValue for the block result and overwrite
+ // this field. Following break instructions will use that MCValue to put their
+ // block results.
+ .mcv = MCValue{ .none = {} },
+ });
+ defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
+
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.Block, ty_pl.payload);
+ const body = self.air.extra[extra.end..][0..extra.data.body_len];
+ try self.genBody(body);
+
+ // relocations for `bpcc` instructions
+ const relocs = &self.blocks.getPtr(inst).?.relocs;
+ if (relocs.items.len > 0 and relocs.items[relocs.items.len - 1] == self.mir_instructions.len - 1) {
+ // If the last Mir instruction is the last relocation (which
+ // would just jump one instruction further), it can be safely
+ // removed
+ self.mir_instructions.orderedRemove(relocs.pop());
+ }
+ for (relocs.items) |reloc| {
+ try self.performReloc(reloc);
+ }
+
+ const result = self.blocks.getPtr(inst).?.mcv;
+ return self.finishAir(inst, result, .{ .none, .none, .none });
+}
+
+fn airBreakpoint(self: *Self) !void {
+ // ta 0x01
+ _ = try self.addInst(.{
+ .tag = .tcc,
+ .data = .{
+ .trap = .{
+ .is_imm = true,
+ .cond = 0b1000, // TODO need to look into changing this into an enum
+ .rs2_or_imm = .{ .imm = 0x01 },
+ },
+ },
+ });
+ return self.finishAirBookkeeping();
+}
+
+fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void {
+ if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});
+
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const callee = pl_op.operand;
+ const extra = self.air.extraData(Air.Call, pl_op.payload);
+ const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end .. extra.end + extra.data.args_len]);
+ const ty = self.air.typeOf(callee);
+ const fn_ty = switch (ty.zigTypeTag()) {
+ .Fn => ty,
+ .Pointer => ty.childType(),
+ else => unreachable,
+ };
+
+ var info = try self.resolveCallingConventionValues(fn_ty, .caller);
+ defer info.deinit(self);
+ for (info.args) |mc_arg, arg_i| {
+ const arg = args[arg_i];
+ const arg_ty = self.air.typeOf(arg);
+ const arg_mcv = try self.resolveInst(arg);
+
+ switch (mc_arg) {
+ .none => continue,
+ .undef => unreachable,
+ .immediate => unreachable,
+ .unreach => unreachable,
+ .dead => unreachable,
+ .memory => unreachable,
+ .register => |reg| {
+ try self.register_manager.getReg(reg, null);
+ try self.genSetReg(arg_ty, reg, arg_mcv);
+ },
+ .stack_offset => {
+ return self.fail("TODO implement calling with parameters in memory", .{});
+ },
+ .ptr_stack_offset => {
+ return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
+ },
+ }
+ }
+
+ // Due to incremental compilation, how function calls are generated depends
+ // on linking.
+ if (self.air.value(callee)) |func_value| {
+ if (self.bin_file.tag == link.File.Elf.base_tag) {
+ if (func_value.castTag(.function)) |func_payload| {
+ const func = func_payload.data;
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+ const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ break :blk @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
+ } else unreachable;
+
+ try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });
+
+ _ = try self.addInst(.{
+ .tag = .jmpl,
+ .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
+ });
+ } else if (func_value.castTag(.extern_fn)) |_| {
+ return self.fail("TODO implement calling extern functions", .{});
+ } else {
+ return self.fail("TODO implement calling bitcasted functions", .{});
+ }
+ } else @panic("TODO SPARCv9 currently does not support non-ELF binaries");
+ } else {
+ assert(ty.zigTypeTag() == .Pointer);
+ const mcv = try self.resolveInst(callee);
+ try self.genSetReg(ty, .o7, mcv);
+
+ _ = try self.addInst(.{
+ .tag = .jmpl,
+ .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
+ });
+ }
+
+ const result = info.return_value;
+
+ if (args.len + 1 <= Liveness.bpi - 1) {
+ var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
+ buf[0] = callee;
+ std.mem.copy(Air.Inst.Ref, buf[1..], args);
+ return self.finishAir(inst, result, buf);
+ }
+
+ @panic("TODO handle return value with BigTomb");
+}
+
+fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
+ // TODO emit debug info lexical block
+ return self.finishAir(inst, .dead, .{ .none, .none, .none });
+}
+
+fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
+ // TODO emit debug info for function change
+ _ = function;
+ return self.finishAir(inst, .dead, .{ .none, .none, .none });
+}
+
+fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
+ const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
+
+ _ = try self.addInst(.{
+ .tag = .dbg_line,
+ .data = .{
+ .dbg_line_column = .{
+ .line = dbg_stmt.line,
+ .column = dbg_stmt.column,
+ },
+ },
+ });
+
+ return self.finishAirBookkeeping();
+}
+
+fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const name = self.air.nullTerminatedString(pl_op.payload);
+ const operand = pl_op.operand;
+ // TODO emit debug info for this variable
+ _ = name;
+ return self.finishAir(inst, .dead, .{ operand, .none, .none });
+}
+
+fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
+ return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
+}
+
+fn airRet(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ try self.ret(operand);
+ return self.finishAir(inst, .dead, .{ un_op, .none, .none });
+}
+
+fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const ptr = try self.resolveInst(un_op);
+ _ = ptr;
+ return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch});
+ //return self.finishAir(inst, .dead, .{ un_op, .none, .none });
+}
+
+fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
+ const stack_offset = try self.allocMemPtr(inst);
+ return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
+}
+
+fn airStore(self: *Self, inst: Air.Inst.Index) !void {
+ _ = self;
+ _ = inst;
+
+ return self.fail("TODO implement store for {}", .{self.target.cpu.arch});
+}
+
+fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
+ _ = self;
+ _ = inst;
+
+ return self.fail("TODO implement switch for {}", .{self.target.cpu.arch});
+}
+
+// Common helper functions
+
+fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
+ const gpa = self.gpa;
+
+ try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
+
+ const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len);
+ self.mir_instructions.appendAssumeCapacity(inst);
+ return result_index;
+}
+
+fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
+ if (abi_align > self.stack_align)
+ self.stack_align = abi_align;
+ // TODO find a free slot instead of always appending
+ const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
+ self.next_stack_offset = offset + abi_size;
+ if (self.next_stack_offset > self.max_end_stack)
+ self.max_end_stack = self.next_stack_offset;
+ try self.stack.putNoClobber(self.gpa, offset, .{
+ .inst = inst,
+ .size = abi_size,
+ });
+ return offset;
+}
+
+/// Use a pointer instruction as the basis for allocating stack memory.
+fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
+ const elem_ty = self.air.typeOfIndex(inst).elemType();
+
+ if (!elem_ty.hasRuntimeBits()) {
+ // As this stack item will never be dereferenced at runtime,
+ // return the stack offset 0. Stack offset 0 will be where all
+ // zero-sized stack allocations live as non-zero-sized
+ // allocations will always have an offset > 0.
+ return @as(u32, 0);
+ }
+
+ const target = self.target.*;
+ const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
+ return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)});
+ };
+ // TODO swap this for inst.ty.ptrAlign
+ const abi_align = elem_ty.abiAlignment(self.target.*);
+ return self.allocMem(inst, abi_size, abi_align);
+}
+
+fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
+ const elem_ty = self.air.typeOfIndex(inst);
+ const target = self.target.*;
+ const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
+ return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)});
+ };
+ const abi_align = elem_ty.abiAlignment(self.target.*);
+ if (abi_align > self.stack_align)
+ self.stack_align = abi_align;
+
+ if (reg_ok) {
+ // Make sure the type can fit in a register before we try to allocate one.
+ if (abi_size <= 8) {
+ if (self.register_manager.tryAllocReg(inst)) |reg| {
+ return MCValue{ .register = reg };
+ }
+ }
+ }
+ const stack_offset = try self.allocMem(inst, abi_size, abi_align);
+ return MCValue{ .stack_offset = stack_offset };
+}
+
+/// Copies a value to a register without tracking the register. The register is not considered
+/// allocated. A second call to `copyToTmpRegister` may return the same register.
+/// This can have a side effect of spilling instructions to the stack to free up a register.
+fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
+ const reg = try self.register_manager.allocReg(null);
+ try self.genSetReg(ty, reg, mcv);
+ return reg;
+}
+
+fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
+ const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table;
+ try table.ensureUnusedCapacity(self.gpa, additional_count);
+}
+
+fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
+ @setCold(true);
+ assert(self.err_msg == null);
+ self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args);
+ return error.CodegenFail;
+}
+
+/// Called when there are no operands, and the instruction is always unreferenced.
+fn finishAirBookkeeping(self: *Self) void {
+ if (std.debug.runtime_safety) {
+ self.air_bookkeeping += 1;
+ }
+}
+
+fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
+ var tomb_bits = self.liveness.getTombBits(inst);
+ for (operands) |op| {
+ const dies = @truncate(u1, tomb_bits) != 0;
+ tomb_bits >>= 1;
+ if (!dies) continue;
+ const op_int = @enumToInt(op);
+ if (op_int < Air.Inst.Ref.typed_value_map.len) continue;
+ const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
+ self.processDeath(op_index);
+ }
+ const is_used = @truncate(u1, tomb_bits) == 0;
+ if (is_used) {
+ log.debug("%{d} => {}", .{ inst, result });
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacityNoClobber(inst, result);
+
+ switch (result) {
+ .register => |reg| {
+ // In some cases (such as bitcast), an operand
+ // may be the same MCValue as the result. If
+ // that operand died and was a register, it
+ // was freed by processDeath. We have to
+ // "re-allocate" the register.
+ if (self.register_manager.isRegFree(reg)) {
+ self.register_manager.getRegAssumeFree(reg, inst);
+ }
+ },
+ else => {},
+ }
+ }
+ self.finishAirBookkeeping();
+}
+
+fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void {
+ assert(off_type == Register or off_type == i13);
+
+ const is_imm = (off_type == i13);
+ const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
+
+ switch (abi_size) {
+ 1 => {
+ _ = try self.addInst(.{
+ .tag = .ldub,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 2 => {
+ _ = try self.addInst(.{
+ .tag = .lduh,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 4 => {
+ _ = try self.addInst(.{
+ .tag = .lduw,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 8 => {
+ _ = try self.addInst(.{
+ .tag = .ldx,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}),
+ else => unreachable,
+ }
+}
+
+fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
+ switch (mcv) {
+ .dead => unreachable,
+ .unreach, .none => return, // Nothing to do.
+ .undef => {
+ if (!self.wantSafety())
+ return; // The already existing value will do just fine.
+ // Write the debug undefined value.
+ return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
+ },
+ .ptr_stack_offset => |off| {
+ const simm13 = math.cast(u12, off) catch
+ return self.fail("TODO larger stack offsets", .{});
+
+ _ = try self.addInst(.{
+ .tag = .add,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = true,
+ .rd = reg,
+ .rs1 = .sp,
+ .rs2_or_imm = .{ .imm = simm13 },
+ },
+ },
+ });
+ },
+ .immediate => |x| {
+ if (x <= math.maxInt(u12)) {
+ _ = try self.addInst(.{
+ .tag = .@"or",
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = true,
+ .rd = reg,
+ .rs1 = .g0,
+ .rs2_or_imm = .{ .imm = @truncate(u12, x) },
+ },
+ },
+ });
+ } else if (x <= math.maxInt(u32)) {
+ _ = try self.addInst(.{
+ .tag = .sethi,
+ .data = .{
+ .sethi = .{
+ .rd = reg,
+ .imm = @truncate(u22, x >> 10),
+ },
+ },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .@"or",
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = true,
+ .rd = reg,
+ .rs1 = reg,
+ .rs2_or_imm = .{ .imm = @truncate(u10, x) },
+ },
+ },
+ });
+ } else if (x <= math.maxInt(u44)) {
+ try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 12) });
+
+ _ = try self.addInst(.{
+ .tag = .sllx,
+ .data = .{
+ .shift = .{
+ .is_imm = true,
+ .width = .shift64,
+ .rd = reg,
+ .rs1 = reg,
+ .rs2_or_imm = .{ .imm = 12 },
+ },
+ },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .@"or",
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = true,
+ .rd = reg,
+ .rs1 = reg,
+ .rs2_or_imm = .{ .imm = @truncate(u12, x) },
+ },
+ },
+ });
+ } else {
+ // Need to allocate a temporary register to load 64-bit immediates.
+ const tmp_reg = try self.register_manager.allocReg(null);
+
+ try self.genSetReg(ty, tmp_reg, .{ .immediate = @truncate(u32, x) });
+ try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 32) });
+
+ _ = try self.addInst(.{
+ .tag = .sllx,
+ .data = .{
+ .shift = .{
+ .is_imm = true,
+ .width = .shift64,
+ .rd = reg,
+ .rs1 = reg,
+ .rs2_or_imm = .{ .imm = 32 },
+ },
+ },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .@"or",
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = false,
+ .rd = reg,
+ .rs1 = reg,
+ .rs2_or_imm = .{ .rs2 = tmp_reg },
+ },
+ },
+ });
+ }
+ },
+ .register => |src_reg| {
+ // If the registers are the same, nothing to do.
+ if (src_reg.id() == reg.id())
+ return;
+
+ // or %g0, src, dst (aka mov src, dst)
+ _ = try self.addInst(.{
+ .tag = .@"or",
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = false,
+ .rd = reg,
+ .rs1 = .g0,
+ .rs2_or_imm = .{ .rs2 = src_reg },
+ },
+ },
+ });
+ },
+ .memory => |addr| {
+ // The value is in memory at a hard-coded address.
+ // If the type is a pointer, it means the pointer address is at this memory location.
+ try self.genSetReg(ty, reg, .{ .immediate = addr });
+ try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));
+ },
+ .stack_offset => |off| {
+ const simm13 = math.cast(u12, off) catch
+ return self.fail("TODO larger stack offsets", .{});
+ try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));
+ },
+ }
+}
+
+fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
+ const abi_size = ty.abiSize(self.target.*);
+ switch (mcv) {
+ .dead => unreachable,
+ .unreach, .none => return, // Nothing to do.
+ .undef => {
+ if (!self.wantSafety())
+ return; // The already existing value will do just fine.
+ // TODO Upgrade this to a memset call when we have that available.
+ switch (ty.abiSize(self.target.*)) {
+ 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
+ 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
+ 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
+ 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
+ else => return self.fail("TODO implement memset", .{}),
+ }
+ },
+ .immediate,
+ .ptr_stack_offset,
+ => {
+ const reg = try self.copyToTmpRegister(ty, mcv);
+ return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
+ },
+ .register => return self.fail("TODO implement storing types abi_size={}", .{abi_size}),
+ .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}),
+ }
+}
+
+fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+ if (typed_value.val.isUndef())
+ return MCValue{ .undef = {} };
+
+ if (typed_value.val.castTag(.decl_ref)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data);
+ }
+ if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data.decl);
+ }
+ const target = self.target.*;
+
+ switch (typed_value.ty.zigTypeTag()) {
+ .Int => {
+ const info = typed_value.ty.intInfo(self.target.*);
+ if (info.bits <= 64) {
+ const unsigned = switch (info.signedness) {
+ .signed => blk: {
+ const signed = typed_value.val.toSignedInt();
+ break :blk @bitCast(u64, signed);
+ },
+ .unsigned => typed_value.val.toUnsignedInt(target),
+ };
+
+ return MCValue{ .immediate = unsigned };
+ } else {
+ return self.fail("TODO implement int genTypedValue of > 64 bits", .{});
+ }
+ },
+ .ComptimeInt => unreachable, // semantic analysis prevents this
+ .ComptimeFloat => unreachable, // semantic analysis prevents this
+ else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}),
+ }
+}
+
+fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
+ // Treat each stack item as a "layer" on top of the previous one.
+ var i: usize = self.branch_stack.items.len;
+ while (true) {
+ i -= 1;
+ if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {
+ assert(mcv != .dead);
+ return mcv;
+ }
+ }
+}
+
+fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
+ try self.ensureProcessDeathCapacity(operand_count + 1);
+ return BigTomb{
+ .function = self,
+ .inst = inst,
+ .tomb_bits = self.liveness.getTombBits(inst),
+ .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
+ .bit_index = 0,
+ };
+}
+
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
+ if (tv.ty.zigTypeTag() == .Pointer) blk: {
+ if (tv.ty.castPtrToFn()) |_| break :blk;
+ if (!tv.ty.elemType2().hasRuntimeBits()) {
+ return MCValue.none;
+ }
+ }
+
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+}
+
+fn parseRegName(name: []const u8) ?Register {
+ if (@hasDecl(Register, "parseRegName")) {
+ return Register.parseRegName(name);
+ }
+ return std.meta.stringToEnum(Register, name);
+}
+
+fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
+ const tag = self.mir_instructions.items(.tag)[inst];
+ switch (tag) {
+ .bpcc => self.mir_instructions.items(.data)[inst].branch_predict.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),
+ else => unreachable,
+ }
+}
+
+/// Asserts there is already capacity to insert into top branch inst_table.
+fn processDeath(self: *Self, inst: Air.Inst.Index) void {
+ const air_tags = self.air.instructions.items(.tag);
+ if (air_tags[inst] == .constant) return; // Constants are immortal.
+ // When editing this function, note that the logic must synchronize with `reuseOperand`.
+ const prev_value = self.getResolvedInstValue(inst);
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacity(inst, .dead);
+ switch (prev_value) {
+ .register => |reg| {
+ self.register_manager.freeReg(reg);
+ },
+ else => {}, // TODO process stack allocation death
+ }
+}
+
+/// Caller must call `CallMCValues.deinit`.
+fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues {
+ const cc = fn_ty.fnCallingConvention();
+ const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen());
+ defer self.gpa.free(param_types);
+ fn_ty.fnParamTypes(param_types);
+ var result: CallMCValues = .{
+ .args = try self.gpa.alloc(MCValue, param_types.len),
+ // These undefined values must be populated before returning from this function.
+ .return_value = undefined,
+ .stack_byte_count = undefined,
+ .stack_align = undefined,
+ };
+ errdefer self.gpa.free(result.args);
+
+ const ret_ty = fn_ty.fnReturnType();
+
+ switch (cc) {
+ .Naked => {
+ assert(result.args.len == 0);
+ result.return_value = .{ .unreach = {} };
+ result.stack_byte_count = 0;
+ result.stack_align = 1;
+ return result;
+ },
+ .Unspecified, .C => {
+ // SPARC Compliance Definition 2.4.1, Chapter 3
+ // Low-Level System Information (64-bit psABI) - Function Calling Sequence
+
+ var next_register: usize = 0;
+ var next_stack_offset: u32 = 0;
+
+ // The caller puts the argument in %o0-%o5, which becomes %i0-%i5 inside the callee.
+ const argument_registers = switch (role) {
+ .caller => abi.c_abi_int_param_regs_caller_view,
+ .callee => abi.c_abi_int_param_regs_callee_view,
+ };
+
+ for (param_types) |ty, i| {
+ const param_size = @intCast(u32, ty.abiSize(self.target.*));
+ if (param_size <= 8) {
+ if (next_register < argument_registers.len) {
+ result.args[i] = .{ .register = argument_registers[next_register] };
+ next_register += 1;
+ } else {
+ result.args[i] = .{ .stack_offset = next_stack_offset };
+ next_register += next_stack_offset;
+ }
+ } else if (param_size <= 16) {
+ if (next_register < argument_registers.len - 1) {
+ return self.fail("TODO MCValues with 2 registers", .{});
+ } else if (next_register < argument_registers.len) {
+ return self.fail("TODO MCValues split register + stack", .{});
+ } else {
+ result.args[i] = .{ .stack_offset = next_stack_offset };
+ next_register += next_stack_offset;
+ }
+ } else {
+ result.args[i] = .{ .stack_offset = next_stack_offset };
+ next_register += next_stack_offset;
+ }
+ }
+
+ result.stack_byte_count = next_stack_offset;
+ result.stack_align = 16;
+
+ if (ret_ty.zigTypeTag() == .NoReturn) {
+ result.return_value = .{ .unreach = {} };
+ } else if (!ret_ty.hasRuntimeBits()) {
+ result.return_value = .{ .none = {} };
+ } else {
+ const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
+ // The callee puts the return values in %i0-%i3, which becomes %o0-%o3 inside the caller.
+ if (ret_ty_size <= 8) {
+ result.return_value = switch (role) {
+ .caller => .{ .register = abi.c_abi_int_return_regs_caller_view[0] },
+ .callee => .{ .register = abi.c_abi_int_return_regs_callee_view[0] },
+ };
+ } else {
+ return self.fail("TODO support more return values for sparcv9", .{});
+ }
+ }
+ },
+ else => return self.fail("TODO implement function parameters for {} on sparcv9", .{cc}),
+ }
+
+ return result;
+}
+
+fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
+ // First section of indexes correspond to a set number of constant values.
+ const ref_int = @enumToInt(inst);
+ if (ref_int < Air.Inst.Ref.typed_value_map.len) {
+ const tv = Air.Inst.Ref.typed_value_map[ref_int];
+ if (!tv.ty.hasRuntimeBits()) {
+ return MCValue{ .none = {} };
+ }
+ return self.genTypedValue(tv);
+ }
+
+ // If the type has no codegen bits, no need to store it.
+ const inst_ty = self.air.typeOf(inst);
+ if (!inst_ty.hasRuntimeBits())
+ return MCValue{ .none = {} };
+
+ const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
+ switch (self.air.instructions.items(.tag)[inst_index]) {
+ .constant => {
+ // Constants have static lifetimes, so they are always memoized in the outer most table.
+ const branch = &self.branch_stack.items[0];
+ const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);
+ if (!gop.found_existing) {
+ const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
+ gop.value_ptr.* = try self.genTypedValue(.{
+ .ty = inst_ty,
+ .val = self.air.values[ty_pl.payload],
+ });
+ }
+ return gop.value_ptr.*;
+ },
+ .const_ty => unreachable,
+ else => return self.getResolvedInstValue(inst_index),
+ }
+}
+
+fn ret(self: *Self, mcv: MCValue) !void {
+ const ret_ty = self.fn_type.fnReturnType();
+ try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
+
+ // Just add space for an instruction, patch this later
+ const index = try self.addInst(.{
+ .tag = .nop,
+ .data = .{ .nop = {} },
+ });
+ try self.exitlude_jump_relocs.append(self.gpa, index);
+}
+
+fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
+ if (!self.liveness.operandDies(inst, op_index))
+ return false;
+
+ switch (mcv) {
+ .register => |reg| {
+ // If it's in the registers table, need to associate the register with the
+ // new instruction.
+ if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
+ if (!self.register_manager.isRegFree(reg)) {
+ self.register_manager.registers[index] = inst;
+ }
+ }
+ log.debug("%{d} => {} (reused)", .{ inst, reg });
+ },
+ .stack_offset => |off| {
+ log.debug("%{d} => stack offset {d} (reused)", .{ inst, off });
+ },
+ else => return false,
+ }
+
+ // Prevent the operand deaths processing code from deallocating it.
+ self.liveness.clearOperandDeath(inst, op_index);
+
+ // That makes us responsible for doing the rest of the stuff that processDeath would have done.
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacity(Air.refToIndex(operand).?, .dead);
+
+ return true;
+}
+
+/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
+fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
+ switch (loc) {
+ .none => return,
+ .register => |reg| return self.genSetReg(ty, reg, val),
+ .stack_offset => |off| return self.genSetStack(ty, off, val),
+ .memory => {
+ return self.fail("TODO implement setRegOrMem for memory", .{});
+ },
+ else => unreachable,
+ }
+}
+
+pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
+ const stack_mcv = try self.allocRegOrMem(inst, false);
+ log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
+ const reg_mcv = self.getResolvedInstValue(inst);
+ assert(reg == reg_mcv.register);
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ try branch.inst_table.put(self.gpa, inst, stack_mcv);
+ try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);
+}
+
+/// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
+fn wantSafety(self: *Self) bool {
+ return switch (self.bin_file.options.optimize_mode) {
+ .Debug => true,
+ .ReleaseSafe => true,
+ .ReleaseFast => false,
+ .ReleaseSmall => false,
+ };
}
diff --git a/src/arch/sparcv9/Emit.zig b/src/arch/sparcv9/Emit.zig
index ba644ede7e..b811a3567f 100644
--- a/src/arch/sparcv9/Emit.zig
+++ b/src/arch/sparcv9/Emit.zig
@@ -1,6 +1,298 @@
//! This file contains the functionality for lowering SPARCv9 MIR into
//! machine code
+const std = @import("std");
+const Endian = std.builtin.Endian;
+const assert = std.debug.assert;
+const link = @import("../../link.zig");
+const Module = @import("../../Module.zig");
+const ErrorMsg = Module.ErrorMsg;
+const Liveness = @import("../../Liveness.zig");
+const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
+const DW = std.dwarf;
+const leb128 = std.leb;
+
const Emit = @This();
const Mir = @import("Mir.zig");
const bits = @import("bits.zig");
+const Instruction = bits.Instruction;
+const Register = bits.Register;
+
+mir: Mir,
+bin_file: *link.File,
+debug_output: DebugInfoOutput,
+target: *const std.Target,
+err_msg: ?*ErrorMsg = null,
+src_loc: Module.SrcLoc,
+code: *std.ArrayList(u8),
+
+prev_di_line: u32,
+prev_di_column: u32,
+/// Relative to the beginning of `code`.
+prev_di_pc: usize,
+
+const InnerError = error{
+ OutOfMemory,
+ EmitFail,
+};
+
+pub fn emitMir(
+ emit: *Emit,
+) InnerError!void {
+ const mir_tags = emit.mir.instructions.items(.tag);
+
+ // Emit machine code
+ for (mir_tags) |tag, index| {
+ const inst = @intCast(u32, index);
+ switch (tag) {
+ .dbg_arg => try emit.mirDbgArg(inst),
+ .dbg_line => try emit.mirDbgLine(inst),
+ .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
+ .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
+
+ .add => try emit.mirArithmetic3Op(inst),
+
+ .bpcc => @panic("TODO implement sparcv9 bpcc"),
+
+ .call => @panic("TODO implement sparcv9 call"),
+
+ .jmpl => @panic("TODO implement sparcv9 jmpl"),
+ .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
+
+ .ldub => try emit.mirArithmetic3Op(inst),
+ .lduh => try emit.mirArithmetic3Op(inst),
+ .lduw => try emit.mirArithmetic3Op(inst),
+ .ldx => try emit.mirArithmetic3Op(inst),
+
+ .@"or" => try emit.mirArithmetic3Op(inst),
+
+ .nop => try emit.mirNop(),
+
+ .@"return" => try emit.mirArithmetic2Op(inst),
+
+ .save => try emit.mirArithmetic3Op(inst),
+ .restore => try emit.mirArithmetic3Op(inst),
+
+ .sethi => try emit.mirSethi(inst),
+
+ .sllx => @panic("TODO implement sparcv9 sllx"),
+
+ .sub => try emit.mirArithmetic3Op(inst),
+
+ .tcc => try emit.mirTrap(inst),
+ }
+ }
+}
+
+pub fn deinit(emit: *Emit) void {
+ emit.* = undefined;
+}
+
+fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
+ _ = dbg_arg_info;
+
+ switch (tag) {
+ .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
+ else => unreachable,
+ }
+}
+
+fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
+
+ switch (tag) {
+ .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column),
+ else => unreachable,
+ }
+}
+
+fn mirDebugPrologueEnd(self: *Emit) !void {
+ switch (self.debug_output) {
+ .dwarf => |dbg_out| {
+ try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
+ try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+}
+
+fn mirDebugEpilogueBegin(self: *Emit) !void {
+ switch (self.debug_output) {
+ .dwarf => |dbg_out| {
+ try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
+ try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+}
+
+fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const data = emit.mir.instructions.items(.data)[inst].arithmetic_2op;
+
+ const rs1 = data.rs1;
+
+ if (data.is_imm) {
+ const imm = data.rs2_or_imm.imm;
+ switch (tag) {
+ .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)),
+ else => unreachable,
+ }
+ } else {
+ const rs2 = data.rs2_or_imm.rs2;
+ switch (tag) {
+ .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),
+ else => unreachable,
+ }
+ }
+}
+
+fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const data = emit.mir.instructions.items(.data)[inst].arithmetic_3op;
+
+ const rd = data.rd;
+ const rs1 = data.rs1;
+
+ if (data.is_imm) {
+ const imm = data.rs2_or_imm.imm;
+ switch (tag) {
+ .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
+ .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)),
+ .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
+ .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
+ .ldx => try emit.writeInstruction(Instruction.ldx(i13, rs1, imm, rd)),
+ .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
+ .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
+ .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
+ .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)),
+ else => unreachable,
+ }
+ } else {
+ const rs2 = data.rs2_or_imm.rs2;
+ switch (tag) {
+ .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
+ .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)),
+ .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
+ .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
+ .ldx => try emit.writeInstruction(Instruction.ldx(Register, rs1, rs2, rd)),
+ .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
+ .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
+ .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
+ .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)),
+ else => unreachable,
+ }
+ }
+}
+
+fn mirNop(emit: *Emit) !void {
+ try emit.writeInstruction(Instruction.nop());
+}
+
+fn mirSethi(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const data = emit.mir.instructions.items(.data)[inst].sethi;
+
+ const imm = data.imm;
+ const rd = data.rd;
+
+ assert(tag == .sethi);
+ try emit.writeInstruction(Instruction.sethi(imm, rd));
+}
+
+fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const data = emit.mir.instructions.items(.data)[inst].trap;
+
+ const cond = data.cond;
+ const ccr = data.ccr;
+ const rs1 = data.rs1;
+
+ if (data.is_imm) {
+ const imm = data.rs2_or_imm.imm;
+ switch (tag) {
+ .tcc => try emit.writeInstruction(Instruction.trap(u7, cond, ccr, rs1, imm)),
+ else => unreachable,
+ }
+ } else {
+ const rs2 = data.rs2_or_imm.rs2;
+ switch (tag) {
+ .tcc => try emit.writeInstruction(Instruction.trap(Register, cond, ccr, rs1, rs2)),
+ else => unreachable,
+ }
+ }
+}
+
+// Common helper functions
+
+fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
+ const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
+ const delta_pc: usize = self.code.items.len - self.prev_di_pc;
+ switch (self.debug_output) {
+ .dwarf => |dbg_out| {
+ // TODO Look into using the DWARF special opcodes to compress this data.
+ // It lets you emit single-byte opcodes that add different numbers to
+ // both the PC and the line number at the same time.
+ try dbg_out.dbg_line.ensureUnusedCapacity(11);
+ dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
+ leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
+ if (delta_line != 0) {
+ dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
+ leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
+ }
+ dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
+ self.prev_di_pc = self.code.items.len;
+ self.prev_di_line = line;
+ self.prev_di_column = column;
+ self.prev_di_pc = self.code.items.len;
+ },
+ .plan9 => |dbg_out| {
+ if (delta_pc <= 0) return; // only do this when the pc changes
+ // we have already checked the target in the linker to make sure it is compatable
+ const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
+
+ // increasing the line number
+ try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
+ // increasing the pc
+ const d_pc_p9 = @intCast(i64, delta_pc) - quant;
+ if (d_pc_p9 > 0) {
+ // minus one because if its the last one, we want to leave space to change the line which is one quanta
+ try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant);
+ if (dbg_out.pcop_change_index.*) |pci|
+ dbg_out.dbg_line.items[pci] += 1;
+ dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1);
+ } else if (d_pc_p9 == 0) {
+ // we don't need to do anything, because adding the quant does it for us
+ } else unreachable;
+ if (dbg_out.start_line.* == null)
+ dbg_out.start_line.* = self.prev_di_line;
+ dbg_out.end_line.* = line;
+ // only do this if the pc changed
+ self.prev_di_line = line;
+ self.prev_di_column = column;
+ self.prev_di_pc = self.code.items.len;
+ },
+ .none => {},
+ }
+}
+
+fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
+ @setCold(true);
+ assert(emit.err_msg == null);
+ emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);
+ return error.EmitFail;
+}
+
+fn writeInstruction(emit: *Emit, instruction: Instruction) !void {
+ // SPARCv9 instructions are always arranged in BE regardless of the
+ // endianness mode the CPU is running in (Section 3.1 of the ISA specification).
+ // This is to ease porting in case someone wants to do a LE SPARCv9 backend.
+ const endian = Endian.Big;
+
+ std.mem.writeInt(u32, try emit.code.addManyAsArray(4), instruction.toU32(), endian);
+}
diff --git a/src/arch/sparcv9/Mir.zig b/src/arch/sparcv9/Mir.zig
index f0d3b1dfbd..c79ebdcac1 100644
--- a/src/arch/sparcv9/Mir.zig
+++ b/src/arch/sparcv9/Mir.zig
@@ -6,6 +6,264 @@
//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
//! so that, for example, the smaller encodings of jump instructions can be used.
+const std = @import("std");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+
const Mir = @This();
const bits = @import("bits.zig");
+const Air = @import("../../Air.zig");
+
+const Instruction = bits.Instruction;
const Register = bits.Register;
+
+instructions: std.MultiArrayList(Inst).Slice,
+
+/// The meaning of this data is determined by `Inst.Tag` value.
+extra: []const u32,
+
+pub const Inst = struct {
+ tag: Tag,
+ /// The meaning of this depends on `tag`.
+ data: Data,
+
+ pub const Tag = enum(u16) {
+ /// Pseudo-instruction: Argument
+ dbg_arg,
+ /// Pseudo-instruction: End of prologue
+ dbg_prologue_end,
+ /// Pseudo-instruction: Beginning of epilogue
+ dbg_epilogue_begin,
+ /// Pseudo-instruction: Update debug line
+ dbg_line,
+
+ // All the real instructions are ordered by their section number
+ // in The SPARC Architecture Manual, Version 9.
+
+ /// A.2 Add
+ /// Those uses the arithmetic_3op field.
+ // TODO add other operations.
+ add,
+
+ /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
+ /// It uses the branch_predict field.
+ bpcc,
+
+ /// A.8 Call and Link
+ /// It uses the branch_link field.
+ call,
+
+ /// A.24 Jump and Link
+ /// jmpl (far direct jump) uses the branch_link field,
+ /// while jmpl_i (indirect jump) uses the branch_link_indirect field.
+ /// Those two MIR instructions will be lowered into SPARCv9 jmpl instruction.
+ jmpl,
+ jmpl_i,
+
+ /// A.27 Load Integer
+ /// Those uses the arithmetic_3op field.
+ /// Note that the ldd variant of this instruction is deprecated, so do not emit
+ /// it unless specifically requested (e.g. by inline assembly).
+ // TODO add other operations.
+ ldub,
+ lduh,
+ lduw,
+ ldx,
+
+ /// A.31 Logical Operations
+ /// Those uses the arithmetic_3op field.
+ // TODO add other operations.
+ @"or",
+
+ /// A.40 No Operation
+ /// It uses the nop field.
+ nop,
+
+ /// A.45 RETURN
+ /// It uses the arithmetic_2op field.
+ @"return",
+
+ /// A.46 SAVE and RESTORE
+ /// Those uses the arithmetic_3op field.
+ save,
+ restore,
+
+ /// A.48 SETHI
+ /// It uses the sethi field.
+ sethi,
+
+ /// A.49 Shift
+ /// Those uses the shift field.
+ // TODO add other operations.
+ sllx,
+
+ /// A.56 Subtract
+ /// Those uses the arithmetic_3op field.
+ // TODO add other operations.
+ sub,
+
+ /// A.61 Trap on Integer Condition Codes (Tcc)
+ /// It uses the trap field.
+ tcc,
+ };
+
+ /// The position of an MIR instruction within the `Mir` instructions array.
+ pub const Index = u32;
+
+ /// All instructions have a 8-byte payload, which is contained within
+ /// this union. `Tag` determines which union field is active, as well as
+ /// how to interpret the data within.
+ // TODO this is a quick-n-dirty solution that needs to be cleaned up.
+ pub const Data = union {
+ /// Debug info: argument
+ ///
+ /// Used by e.g. dbg_arg
+ dbg_arg_info: struct {
+ air_inst: Air.Inst.Index,
+ arg_index: usize,
+ },
+
+ /// Debug info: line and column
+ ///
+ /// Used by e.g. dbg_line
+ dbg_line_column: struct {
+ line: u32,
+ column: u32,
+ },
+
+ /// Two operand arithmetic.
+ /// if is_imm true then it uses the imm field of rs2_or_imm,
+ /// otherwise it uses rs2 field.
+ ///
+ /// Used by e.g. return
+ arithmetic_2op: struct {
+ is_imm: bool,
+ rs1: Register,
+ rs2_or_imm: union {
+ rs2: Register,
+ imm: i13,
+ },
+ },
+
+ /// Three operand arithmetic.
+ /// if is_imm true then it uses the imm field of rs2_or_imm,
+ /// otherwise it uses rs2 field.
+ ///
+ /// Used by e.g. add, sub
+ arithmetic_3op: struct {
+ is_imm: bool,
+ rd: Register,
+ rs1: Register,
+ rs2_or_imm: union {
+ rs2: Register,
+ imm: i13,
+ },
+ },
+
+ /// Branch and link (always unconditional).
+ /// Used by e.g. call
+ branch_link: struct {
+ inst: Index,
+ link: Register = .o7,
+ },
+
+ /// Indirect branch and link (always unconditional).
+ /// Used by e.g. jmpl_i
+ branch_link_indirect: struct {
+ reg: Register,
+ link: Register = .o7,
+ },
+
+ /// Branch with prediction.
+ /// Used by e.g. bpcc
+ branch_predict: struct {
+ annul: bool = false,
+ pt: bool = true,
+ ccr: Instruction.CCR,
+ cond: Instruction.Condition,
+ inst: Index,
+ },
+
+ /// No additional data
+ ///
+ /// Used by e.g. flushw
+ nop: void,
+
+ /// SETHI operands.
+ ///
+ /// Used by sethi
+ sethi: struct {
+ rd: Register,
+ imm: u22,
+ },
+
+ /// Shift operands.
+ /// if is_imm true then it uses the imm field of rs2_or_imm,
+ /// otherwise it uses rs2 field.
+ ///
+ /// Used by e.g. add, sub
+ shift: struct {
+ is_imm: bool,
+ width: Instruction.ShiftWidth,
+ rd: Register,
+ rs1: Register,
+ rs2_or_imm: union {
+ rs2: Register,
+ imm: u6,
+ },
+ },
+
+ /// Trap.
+ /// if is_imm true then it uses the imm field of rs2_or_imm,
+ /// otherwise it uses rs2 field.
+ ///
+ /// Used by e.g. tcc
+ trap: struct {
+ is_imm: bool = true,
+ cond: Instruction.Condition,
+ ccr: Instruction.CCR = .icc,
+ rs1: Register = .g0,
+ rs2_or_imm: union {
+ rs2: Register,
+ imm: u7,
+ },
+ },
+ };
+
+ // Make sure we don't accidentally make instructions bigger than expected.
+ // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
+ comptime {
+ if (builtin.mode != .Debug) {
+ // TODO clean up the definition of Data before enabling this.
+ // I'll do that after the PoC backend can produce usable binaries.
+
+ // assert(@sizeOf(Data) == 8);
+ }
+ }
+};
+
+pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
+ mir.instructions.deinit(gpa);
+ gpa.free(mir.extra);
+ mir.* = undefined;
+}
+
+/// Returns the requested data, as well as the new index which is at the start of the
+/// trailers for the object.
+pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
+ const fields = std.meta.fields(T);
+ var i: usize = index;
+ var result: T = undefined;
+ inline for (fields) |field| {
+ @field(result, field.name) = switch (field.field_type) {
+ u32 => mir.extra[i],
+ i32 => @bitCast(i32, mir.extra[i]),
+ else => @compileError("bad field type"),
+ };
+ i += 1;
+ }
+ return .{
+ .data = result,
+ .end = i,
+ };
+}
diff --git a/src/arch/sparcv9/abi.zig b/src/arch/sparcv9/abi.zig
index 5c9ea979fc..4cb10a99ea 100644
--- a/src/arch/sparcv9/abi.zig
+++ b/src/arch/sparcv9/abi.zig
@@ -1,12 +1,25 @@
const bits = @import("bits.zig");
const Register = bits.Register;
-// Register windowing mechanism will take care of preserving registers
-// so no need to do it manually
-pub const callee_preserved_regs = [_]Register{};
+// There are no callee-preserved registers since the windowing
+// mechanism already takes care of them.
+// We still need to preserve %o0-%o5, %g1, %g4, and %g5 before calling
+// something, though, as those are shared with the callee and might be
+// thrashed by it.
+pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 };
+
+// Try to allocate i, l, o, then g sets of registers, in order of priority.
+pub const allocatable_regs = [_]Register{
+ // zig fmt: off
+ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5",
+ .l0, .l1, .l2, .l3, .l4, .l5, .l6, .l7,
+ .o0, .o1, .o2, .o3, .o4, .o5,
+ .g1, .g4, .g5,
+ // zig fmt: on
+};
pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };
pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };
-pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };
-pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };
+pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 };
+pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" };
diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig
index 07cbf7fc91..bc8b8822b7 100644
--- a/src/arch/sparcv9/bits.zig
+++ b/src/arch/sparcv9/bits.zig
@@ -164,27 +164,33 @@ pub const Instruction = union(enum) {
// name them with letters since there's no official naming scheme.
// TODO: need to rename the minor formats to a more descriptive name.
+ // I am using regular structs instead of packed ones to avoid
+ // endianness-dependent behavior when constructing the actual
+ // assembly instructions.
+ // See also: https://github.com/ziglang/zig/issues/10113
+ // TODO: change it back to packed structs once the issue is resolved.
+
// Format 1 (op = 1): CALL
- format_1: packed struct {
+ format_1: struct {
op: u2 = 0b01,
disp30: u30,
},
// Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
- format_2a: packed struct {
+ format_2a: struct {
op: u2 = 0b00,
rd: u5,
op2: u3,
imm22: u22,
},
- format_2b: packed struct {
+ format_2b: struct {
op: u2 = 0b00,
a: u1,
cond: u4,
op2: u3,
disp22: u22,
},
- format_2c: packed struct {
+ format_2c: struct {
op: u2 = 0b00,
a: u1,
cond: u4,
@@ -194,7 +200,7 @@ pub const Instruction = union(enum) {
p: u1,
disp19: u19,
},
- format_2d: packed struct {
+ format_2d: struct {
op: u2 = 0b00,
a: u1,
fixed: u1 = 0b0,
@@ -207,7 +213,7 @@ pub const Instruction = union(enum) {
},
// Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
- format_3a: packed struct {
+ format_3a: struct {
op: u2,
rd: u5,
op3: u6,
@@ -224,7 +230,7 @@ pub const Instruction = union(enum) {
i: u1 = 0b1,
simm13: u13,
},
- format_3c: packed struct {
+ format_3c: struct {
op: u2,
reserved1: u5 = 0b00000,
op3: u6,
@@ -241,7 +247,7 @@ pub const Instruction = union(enum) {
i: u1 = 0b1,
simm13: u13,
},
- format_3e: packed struct {
+ format_3e: struct {
op: u2,
rd: u5,
op3: u6,
@@ -260,7 +266,7 @@ pub const Instruction = union(enum) {
rcond: u3,
simm10: u10,
},
- format_3g: packed struct {
+ format_3g: struct {
op: u2,
rd: u5,
op3: u6,
@@ -269,7 +275,7 @@ pub const Instruction = union(enum) {
reserved: u8 = 0b00000000,
rs2: u5,
},
- format_3h: packed struct {
+ format_3h: struct {
op: u2 = 0b10,
fixed1: u5 = 0b00000,
op3: u6 = 0b101000,
@@ -279,7 +285,7 @@ pub const Instruction = union(enum) {
cmask: u3,
mmask: u4,
},
- format_3i: packed struct {
+ format_3i: struct {
op: u2,
rd: u5,
op3: u6,
@@ -288,13 +294,13 @@ pub const Instruction = union(enum) {
imm_asi: u8,
rs2: u5,
},
- format_3j: packed struct {
+ format_3j: struct {
op: u2,
impl_dep1: u5,
op3: u6,
impl_dep2: u19,
},
- format_3k: packed struct {
+ format_3k: struct {
op: u2,
rd: u5,
op3: u6,
@@ -304,7 +310,7 @@ pub const Instruction = union(enum) {
reserved: u7 = 0b0000000,
rs2: u5,
},
- format_3l: packed struct {
+ format_3l: struct {
op: u2,
rd: u5,
op3: u6,
@@ -314,7 +320,7 @@ pub const Instruction = union(enum) {
reserved: u7 = 0b0000000,
shcnt32: u5,
},
- format_3m: packed struct {
+ format_3m: struct {
op: u2,
rd: u5,
op3: u6,
@@ -324,7 +330,7 @@ pub const Instruction = union(enum) {
reserved: u6 = 0b000000,
shcnt64: u6,
},
- format_3n: packed struct {
+ format_3n: struct {
op: u2,
rd: u5,
op3: u6,
@@ -332,7 +338,7 @@ pub const Instruction = union(enum) {
opf: u9,
rs2: u5,
},
- format_3o: packed struct {
+ format_3o: struct {
op: u2,
fixed: u3 = 0b000,
cc1: u1,
@@ -342,7 +348,7 @@ pub const Instruction = union(enum) {
opf: u9,
rs2: u5,
},
- format_3p: packed struct {
+ format_3p: struct {
op: u2,
rd: u5,
op3: u6,
@@ -350,20 +356,20 @@ pub const Instruction = union(enum) {
opf: u9,
rs2: u5,
},
- format_3q: packed struct {
+ format_3q: struct {
op: u2,
rd: u5,
op3: u6,
rs1: u5,
reserved: u14 = 0b00000000000000,
},
- format_3r: packed struct {
+ format_3r: struct {
op: u2,
fcn: u5,
op3: u6,
reserved: u19 = 0b0000000000000000000,
},
- format_3s: packed struct {
+ format_3s: struct {
op: u2,
rd: u5,
op3: u6,
@@ -371,7 +377,7 @@ pub const Instruction = union(enum) {
},
//Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
- format_4a: packed struct {
+ format_4a: struct {
op: u2 = 0b10,
rd: u5,
op3: u6,
@@ -392,7 +398,7 @@ pub const Instruction = union(enum) {
cc0: u1,
simm11: u11,
},
- format_4c: packed struct {
+ format_4c: struct {
op: u2 = 0b10,
rd: u5,
op3: u6,
@@ -415,7 +421,7 @@ pub const Instruction = union(enum) {
cc0: u1,
simm11: u11,
},
- format_4e: packed struct {
+ format_4e: struct {
op: u2 = 0b10,
rd: u5,
op3: u6,
@@ -426,7 +432,7 @@ pub const Instruction = union(enum) {
reserved: u4 = 0b0000,
sw_trap: u7,
},
- format_4f: packed struct {
+ format_4f: struct {
op: u2 = 0b10,
rd: u5,
op3: u6,
@@ -436,7 +442,7 @@ pub const Instruction = union(enum) {
opf_low: u5,
rs2: u5,
},
- format_4g: packed struct {
+ format_4g: struct {
op: u2 = 0b10,
rd: u5,
op3: u6,
@@ -512,40 +518,43 @@ pub const Instruction = union(enum) {
pub fn toU32(self: Instruction) u32 {
// TODO: Remove this once packed structs work.
return switch (self) {
- .format_1 => |v| @bitCast(u32, v),
- .format_2a => |v| @bitCast(u32, v),
- .format_2b => |v| @bitCast(u32, v),
- .format_2c => |v| @bitCast(u32, v),
- .format_2d => |v| @bitCast(u32, v),
- .format_3a => |v| @bitCast(u32, v),
+ .format_1 => |v| (@as(u32, v.op) << 30) | @as(u32, v.disp30),
+ .format_2a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.imm22),
+ .format_2b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.disp22),
+ .format_2c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.cc1) << 21) | (@as(u32, v.cc0) << 20) | (@as(u32, v.p) << 19) | @as(u32, v.disp19),
+ .format_2d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.fixed) << 28) | (@as(u32, v.rcond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.d16hi) << 20) | (@as(u32, v.p) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.d16lo),
+ .format_3a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
.format_3b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
- .format_3c => |v| @bitCast(u32, v),
+ .format_3c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved2) << 5) | @as(u32, v.rs2),
.format_3d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
- .format_3e => |v| @bitCast(u32, v),
+ .format_3e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
.format_3f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | @as(u32, v.simm10),
- .format_3g => |v| @bitCast(u32, v),
- .format_3h => |v| @bitCast(u32, v),
- .format_3i => |v| @bitCast(u32, v),
- .format_3j => |v| @bitCast(u32, v),
- .format_3k => |v| @bitCast(u32, v),
- .format_3l => |v| @bitCast(u32, v),
- .format_3m => |v| @bitCast(u32, v),
- .format_3n => |v| @bitCast(u32, v),
- .format_3o => |v| @bitCast(u32, v),
- .format_3p => |v| @bitCast(u32, v),
- .format_3q => |v| @bitCast(u32, v),
- .format_3r => |v| @bitCast(u32, v),
- .format_3s => |v| @bitCast(u32, v),
- .format_4a => |v| @bitCast(u32, v),
+ .format_3g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
+ .format_3h => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed2) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 7) | (@as(u32, v.cmask) << 4) | @as(u32, v.mmask),
+ .format_3i => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.imm_asi) << 5) | @as(u32, v.rs2),
+ .format_3j => |v| (@as(u32, v.op) << 30) | (@as(u32, v.impl_dep1) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.impl_dep2),
+ .format_3k => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
+ .format_3l => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.shcnt32),
+ .format_3m => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 6) | @as(u32, v.shcnt64),
+ .format_3n => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.reserved) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+ .format_3o => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed) << 27) | (@as(u32, v.cc1) << 26) | (@as(u32, v.cc0) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+ .format_3p => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+ .format_3q => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.reserved),
+ .format_3r => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fcn) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
+ .format_3s => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
+ .format_4a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
.format_4b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
- .format_4c => |v| @bitCast(u32, v),
+ .format_4c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
.format_4d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
- .format_4e => |v| @bitCast(u32, v),
- .format_4f => |v| @bitCast(u32, v),
- .format_4g => |v| @bitCast(u32, v),
+ .format_4e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 7) | @as(u32, v.sw_trap),
+ .format_4f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.fixed) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
+ .format_4g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.opf_cc) << 11) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
};
}
+ // SPARCv9 Instruction formats.
+ // See section 6.2 of the SPARCv9 ISA manual.
+
fn format1(disp: i32) Instruction {
const udisp = @bitCast(u32, disp);
@@ -561,7 +570,7 @@ pub const Instruction = union(enum) {
};
}
- fn format2a(op2: u3, rd: Register, imm: u22) Instruction {
+ fn format2a(op2: u3, imm: u22, rd: Register) Instruction {
return Instruction{
.format_2a = .{
.rd = rd.enc(),
@@ -956,6 +965,106 @@ pub const Instruction = union(enum) {
},
};
}
+
+ // SPARCv9 Instruction definition.
+ // See appendix A of the SPARCv9 ISA manual.
+
+ pub fn add(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b10, 0b00_0000, rs1, rs2, rd),
+ i13 => format3b(0b10, 0b00_0000, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
+ i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn ldub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0001, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0001, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn lduh(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0010, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0010, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn lduw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0000, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0000, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn ldx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_1011, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_1011, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn nop() Instruction {
+ return sethi(0, .g0);
+ }
+
+ pub fn @"return"(comptime s2: type, rs1: Register, rs2: s2) Instruction {
+ return switch (s2) {
+ Register => format3c(0b10, 0b11_1001, rs1, rs2),
+ i13 => format3d(0b10, 0b11_1001, rs1, rs2),
+ else => unreachable,
+ };
+ }
+
+ pub fn save(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b10, 0b11_1100, rs1, rs2, rd),
+ i13 => format3b(0b10, 0b11_1100, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn restore(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b10, 0b11_1101, rs1, rs2, rd),
+ i13 => format3b(0b10, 0b11_1101, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn sethi(imm: u22, rd: Register) Instruction {
+ return format2a(0b100, imm, rd);
+ }
+
+ pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b10, 0b00_0100, rs1, rs2, rd),
+ i13 => format3b(0b10, 0b00_0100, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn trap(comptime s2: type, cond: Condition, ccr: CCR, rs1: Register, rs2: s2) Instruction {
+ // Tcc instructions abuse the rd field to store the conditionals.
+ return switch (s2) {
+ Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, cond)),
+ u7 => format4e(0b11_1010, ccr, rs1, @intToEnum(Register, cond), rs2),
+ else => unreachable,
+ };
+ }
};
test "Serialize formats" {
@@ -973,7 +1082,7 @@ test "Serialize formats" {
.expected = 0b01_000000000000000000000000000001,
},
.{
- .inst = Instruction.format2a(4, .g0, 0),
+ .inst = Instruction.format2a(4, 0, .g0),
.expected = 0b00_00000_100_0000000000000000000000,
},
.{
@@ -1096,6 +1205,10 @@ test "Serialize formats" {
for (testcases) |case| {
const actual = case.inst.toU32();
- try testing.expectEqual(case.expected, actual);
+ testing.expectEqual(case.expected, actual) catch |err| {
+ std.debug.print("error: {x}\n", .{err});
+ std.debug.print("case: {x}\n", .{case});
+ return err;
+ };
}
}
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index f52506c393..b701299e73 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -2425,7 +2425,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
var highest_maybe: ?i32 = null;
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
+ const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + items.len + case_body.len;
const values = try self.gpa.alloc(CaseValue, items.len);
@@ -3328,7 +3328,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const result_ty = self.air.typeOfIndex(inst);
const len = @intCast(usize, result_ty.arrayLen());
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
switch (result_ty.zigTypeTag()) {
.Vector => return self.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
@@ -3889,27 +3889,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- const result = try self.allocLocal(ty);
-
- try self.startBlock(.block, wasm.block_empty);
- try self.startBlock(.block, wasm.block_empty);
-
- // check if LHS is greater/lesser than RHS
- const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
- try self.addLabel(.local_get, cmp_result.local);
- try self.addLabel(.br_if, 0); // break to outer loop if LHS is greater/lesser than RHS
-
- // set RHS as max/min
+ // operands to select from
+ try self.emitWValue(lhs);
try self.emitWValue(rhs);
- try self.addLabel(.local_set, result.local);
- try self.addLabel(.br, 1); // break out of all blocks
- try self.endBlock();
- // set LHS as max/min
+ // operands to compare
try self.emitWValue(lhs);
- try self.addLabel(.local_set, result.local);
- try self.endBlock();
+ try self.emitWValue(rhs);
+ const opcode = buildOpcode(.{
+ .op = if (op == .max) .gt else .lt,
+ .signedness = if (ty.isSignedInt()) .signed else .unsigned,
+ .valtype1 = typeToValtype(ty, self.target),
+ });
+ try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
+
+ // based on the result from comparison, return operand 0 or 1.
+ try self.addTag(.select);
+ // store result in local
+ const result = try self.allocLocal(ty);
+ try self.addLabel(.local_set, result.local);
return result;
}
diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig
index 6fc2dfa3b3..bcbff8d195 100644
--- a/src/arch/wasm/Emit.zig
+++ b/src/arch/wasm/Emit.zig
@@ -96,6 +96,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.@"return" => try emit.emitTag(tag),
.@"unreachable" => try emit.emitTag(tag),
+ .select => try emit.emitTag(tag),
+
// arithmetic
.i32_eqz => try emit.emitTag(tag),
.i32_eq => try emit.emitTag(tag),
diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig
index 27f683cf1e..87e64ce9e0 100644
--- a/src/arch/wasm/Mir.zig
+++ b/src/arch/wasm/Mir.zig
@@ -10,7 +10,7 @@ const Mir = @This();
const std = @import("std");
-/// A struct of array that represents each individual wasm
+/// A struct of array that represents each individual wasm
instructions: std.MultiArrayList(Inst).Slice,
/// A slice of indexes where the meaning of the data is determined by the
/// `Inst.Tag` value.
@@ -77,6 +77,10 @@ pub const Inst = struct {
///
/// Uses `label`
call_indirect = 0x11,
+ /// Pops three values from the stack and pushes
+ /// the first or second value dependent on the third value.
+ /// Uses `tag`
+ select = 0x1B,
/// Loads a local at given index onto the stack.
///
/// Uses `label`
@@ -538,7 +542,7 @@ pub const Inst = struct {
/// Contains an u32 index into a wasm section entry, such as a local.
/// Note: This is not an index to another instruction.
///
- /// Used by e.g. `local_get`, `local_set`, etc.
+ /// Used by e.g. `local_get`, `local_set`, etc.
label: u32,
/// A 32-bit immediate value.
///
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 0a11c1480f..10271df122 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -48,6 +48,7 @@ gpa: Allocator,
air: Air,
liveness: Liveness,
bin_file: *link.File,
+debug_output: DebugInfoOutput,
target: *const std.Target,
mod_fn: *const Module.Fn,
err_msg: ?*ErrorMsg,
@@ -271,26 +272,12 @@ const BlockData = struct {
const BigTomb = struct {
function: *Self,
inst: Air.Inst.Index,
- tomb_bits: Liveness.Bpi,
- big_tomb_bits: u32,
- bit_index: usize,
+ lbt: Liveness.BigTomb,
fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
- const this_bit_index = bt.bit_index;
- bt.bit_index += 1;
-
- const op_int = @enumToInt(op_ref);
- if (op_int < Air.Inst.Ref.typed_value_map.len) return;
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
-
- if (this_bit_index < Liveness.bpi - 1) {
- const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
- if (!dies) return;
- } else {
- const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
- const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
- if (!dies) return;
- }
+ const dies = bt.lbt.feed();
+ const op_index = Air.refToIndex(op_ref) orelse return;
+ if (!dies) return;
bt.function.processDeath(op_index);
}
@@ -337,6 +324,7 @@ pub fn generate(
.liveness = liveness,
.target = &bin_file.options.target,
.bin_file = bin_file,
+ .debug_output = debug_output,
.mod_fn = module_fn,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
@@ -382,7 +370,6 @@ pub fn generate(
};
var mir = Mir{
- .function = &function,
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
};
@@ -391,7 +378,6 @@ pub fn generate(
var emit = Emit{
.mir = mir,
.bin_file = bin_file,
- .function = &function,
.debug_output = debug_output,
.target = &bin_file.options.target,
.src_loc = src_loc,
@@ -3425,17 +3411,11 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const arg_index = self.arg_index;
self.arg_index += 1;
+ const ty = self.air.typeOfIndex(inst);
const mcv = self.args[arg_index];
- const payload = try self.addExtra(Mir.ArgDbgInfo{
- .air_inst = inst,
- .arg_index = arg_index,
- .max_stack = self.max_end_stack,
- });
- _ = try self.addInst(.{
- .tag = .arg_dbg_info,
- .ops = undefined,
- .data = .{ .payload = payload },
- });
+ const name = self.mod_fn.getParamName(arg_index);
+ const name_with_null = name.ptr[0 .. name.len + 1];
+
if (self.liveness.isUnused(inst))
return self.finishAirBookkeeping();
@@ -3443,10 +3423,46 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
switch (mcv) {
.register => |reg| {
self.register_manager.getRegAssumeFree(reg.to64(), inst);
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ const dbg_info = &dw.dbg_info;
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // ULEB128 dwarf expression length
+ reg.dwarfLocOp(),
+ });
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ },
+ .plan9 => {},
+ .none => {},
+ }
break :blk mcv;
},
.stack_offset => |off| {
const offset = @intCast(i32, self.max_end_stack) - off + 16;
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ const dbg_info = &dw.dbg_info;
+ try dbg_info.ensureUnusedCapacity(8);
+ dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // we will backpatch it after we encode the displacement in LEB128
+ DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
+ });
+ leb128.writeILEB128(dbg_info.writer(), offset) catch unreachable;
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+
+ },
+ .plan9 => {},
+ .none => {},
+ }
break :blk MCValue{ .stack_offset = -offset };
},
else => return self.fail("TODO implement arg for {}", .{mcv}),
@@ -3485,7 +3501,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const callee = pl_op.operand;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
const ty = self.air.typeOf(callee);
const fn_ty = switch (ty.zigTypeTag()) {
@@ -3668,7 +3684,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
.ops = (Mir.Ops{
.flags = 0b01,
}).encode(),
- .data = .{ .imm = @bitCast(i32, @intCast(u32, fn_got_addr)) },
+ .data = .{ .imm = @intCast(u32, fn_got_addr) },
});
} else return self.fail("TODO implement calling extern fn on plan9", .{});
} else {
@@ -3885,13 +3901,126 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
- const name = self.air.nullTerminatedString(pl_op.payload);
const operand = pl_op.operand;
- // TODO emit debug info for this variable
- _ = name;
+ const ty = self.air.typeOf(operand);
+ const mcv = try self.resolveInst(operand);
+
+ log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
+
+ const name = self.air.nullTerminatedString(pl_op.payload);
+
+ const tag = self.air.instructions.items(.tag)[inst];
+ switch (tag) {
+ .dbg_var_ptr => try self.genVarDbgInfo(tag, ty.childType(), mcv, name),
+ .dbg_var_val => try self.genVarDbgInfo(tag, ty, mcv, name),
+ else => unreachable,
+ }
+
return self.finishAir(inst, .dead, .{ operand, .none, .none });
}
+fn genVarDbgInfo(
+ self: *Self,
+ tag: Air.Inst.Tag,
+ ty: Type,
+ mcv: MCValue,
+ name: [:0]const u8,
+) !void {
+ const name_with_null = name.ptr[0 .. name.len + 1];
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ const dbg_info = &dw.dbg_info;
+ try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
+
+ switch (mcv) {
+ .register => |reg| {
+ try dbg_info.ensureUnusedCapacity(2);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // ULEB128 dwarf expression length
+ reg.dwarfLocOp(),
+ });
+ },
+ .ptr_stack_offset, .stack_offset => |off| {
+ try dbg_info.ensureUnusedCapacity(7);
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // we will backpatch it after we encode the displacement in LEB128
+ DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
+ });
+ leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ },
+ .memory, .got_load, .direct_load => {
+ const endian = self.target.cpu.arch.endian();
+ const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
+ const is_ptr = switch (tag) {
+ .dbg_var_ptr => true,
+ .dbg_var_val => false,
+ else => unreachable,
+ };
+ try dbg_info.ensureUnusedCapacity(2 + ptr_width);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1 + ptr_width + @boolToInt(is_ptr),
+ DW.OP.addr, // literal address
+ });
+ const offset = @intCast(u32, dbg_info.items.len);
+ const addr = switch (mcv) {
+ .memory => |addr| addr,
+ else => 0,
+ };
+ switch (ptr_width) {
+ 0...4 => {
+ try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
+ },
+ 5...8 => {
+ try dbg_info.writer().writeInt(u64, addr, endian);
+ },
+ else => unreachable,
+ }
+ if (is_ptr) {
+ // We need deref the address as we point to the value via GOT entry.
+ try dbg_info.append(DW.OP.deref);
+ }
+ switch (mcv) {
+ .got_load, .direct_load => |index| try dw.addExprlocReloc(index, offset, is_ptr),
+ else => {},
+ }
+ },
+ else => {
+ log.debug("TODO generate debug info for {}", .{mcv});
+ },
+ }
+
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ },
+ .plan9 => {},
+ .none => {},
+ }
+}
+
+/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
+/// after codegen for this symbol is done.
+fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ assert(ty.hasRuntimeBits());
+ const dbg_info = &dw.dbg_info;
+ const index = dbg_info.items.len;
+ try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
+ const atom = switch (self.bin_file.tag) {
+ .elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom,
+ .macho => &self.mod_fn.owner_decl.link.macho.dbg_info_atom,
+ else => unreachable,
+ };
+ try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+}
+
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
const abi_size = ty.abiSize(self.target.*);
switch (mcv) {
@@ -4091,7 +4220,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
// TODO track the new register / stack allocation
}
- self.branch_stack.pop().deinit(self.gpa);
+ {
+ var item = self.branch_stack.pop();
+ item.deinit(self.gpa);
+ }
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -4433,7 +4565,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
+ const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + items.len + case_body.len;
@@ -4486,7 +4618,10 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
if (switch_br.data.else_body_len > 0) {
const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
try self.branch_stack.append(.{});
- defer self.branch_stack.pop().deinit(self.gpa);
+ defer {
+ var item = self.branch_stack.pop();
+ item.deinit(self.gpa);
+ }
const else_deaths = liveness.deaths.len - 1;
try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len);
@@ -4576,9 +4711,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
const dead = !is_volatile and self.liveness.isUnused(inst);
@@ -4731,9 +4866,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
return BigTomb{
.function = self,
.inst = inst,
- .tomb_bits = self.liveness.getTombBits(inst),
- .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
- .bit_index = 0,
+ .lbt = self.liveness.iterateBigTomb(inst),
};
}
@@ -5848,7 +5981,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
const result_ty = self.air.typeOfIndex(inst);
const len = @intCast(usize, result_ty.arrayLen());
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
const abi_size = @intCast(u32, result_ty.abiSize(self.target.*));
const abi_align = result_ty.abiAlignment(self.target.*);
const result: MCValue = res: {
@@ -5919,7 +6052,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
}
-fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
+pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
@@ -5989,6 +6122,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
}
fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ log.debug("lowerDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() });
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
@@ -6000,7 +6134,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
}
}
- decl.alive = true;
+ decl.markAlive();
+
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
@@ -6020,8 +6155,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
} else {
return self.fail("TODO codegen non-ELF const Decl pointer", .{});
}
-
- _ = tv;
}
fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
@@ -6044,6 +6177,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
}
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
+ log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
@@ -6081,8 +6215,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
.Bool => {
return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) };
},
- .ComptimeInt => unreachable, // semantic analysis prevents this
- .ComptimeFloat => unreachable, // semantic analysis prevents this
.Optional => {
if (typed_value.ty.isPtrLikeOptional()) {
if (typed_value.val.isNull())
@@ -6143,6 +6275,18 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
}
}
},
+
+ .ComptimeInt => unreachable,
+ .ComptimeFloat => unreachable,
+ .Type => unreachable,
+ .EnumLiteral => unreachable,
+ .Void => unreachable,
+ .NoReturn => unreachable,
+ .Undefined => unreachable,
+ .Null => unreachable,
+ .BoundFn => unreachable,
+ .Opaque => unreachable,
+
else => {},
}
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 3296339419..6af2c07974 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -30,7 +30,6 @@ const Type = @import("../../type.zig").Type;
mir: Mir,
bin_file: *link.File,
-function: *const CodeGen,
debug_output: DebugInfoOutput,
target: *const std.Target,
err_msg: ?*ErrorMsg = null,
@@ -187,7 +186,6 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.dbg_line => try emit.mirDbgLine(inst),
.dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
.dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
- .arg_dbg_info => try emit.mirArgDbgInfo(inst),
.push_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.push, inst),
.pop_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.pop, inst),
@@ -1057,92 +1055,6 @@ fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
}
}
-fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
- const tag = emit.mir.instructions.items(.tag)[inst];
- assert(tag == .arg_dbg_info);
- const payload = emit.mir.instructions.items(.data)[inst].payload;
- const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
- const mcv = emit.mir.function.args[arg_dbg_info.arg_index];
- try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.max_stack, arg_dbg_info.arg_index);
-}
-
-fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32, arg_index: u32) !void {
- const ty = emit.mir.function.air.instructions.items(.data)[inst].ty;
- const name = emit.mir.function.mod_fn.getParamName(arg_index);
- const name_with_null = name.ptr[0 .. name.len + 1];
-
- switch (mcv) {
- .register => |reg| {
- switch (emit.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
- .plan9 => {},
- .none => {},
- }
- },
- .stack_offset => |off| {
- switch (emit.debug_output) {
- .dwarf => |dw| {
- // we add here +16 like we do in airArg in CodeGen since we refer directly to
- // rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the
- // prologue, and 8 bytes for return address.
- // TODO we need to make this more generic if we don't use rbp as the frame pointer
- // for example when -fomit-frame-pointer is set.
- const disp = @intCast(i32, max_stack) - off + 16;
- const dbg_info = &dw.dbg_info;
- try dbg_info.ensureUnusedCapacity(8);
- dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // we will backpatch it after we encode the displacement in LEB128
- DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
- });
- leb128.writeILEB128(dbg_info.writer(), disp) catch unreachable;
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
-
- },
- .plan9 => {},
- .none => {},
- }
- },
- else => {},
- }
-}
-
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
- switch (emit.debug_output) {
- .dwarf => |dw| {
- assert(ty.hasRuntimeBits());
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const atom = switch (emit.bin_file.tag) {
- .elf => &emit.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
- .macho => &emit.function.mod_fn.owner_decl.link.macho.dbg_info_atom,
- else => unreachable,
- };
- try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
- },
- .plan9 => {},
- .none => {},
- }
-}
-
const Tag = enum {
adc,
add,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 183a76e4b7..50f28d7f19 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -16,7 +16,6 @@ const Air = @import("../../Air.zig");
const CodeGen = @import("CodeGen.zig");
const Register = bits.Register;
-function: *const CodeGen,
instructions: std.MultiArrayList(Inst).Slice,
/// The meaning of this data is determined by `Inst.Tag` value.
extra: []const u32,
@@ -364,11 +363,8 @@ pub const Inst = struct {
/// update debug line
dbg_line,
- /// arg debug info
- arg_dbg_info,
-
/// push registers from the callee_preserved_regs
- /// data is the bitfield of which regs to push
+ /// data is the bitfield of which regs to push
/// for example on x86_64, the callee_preserved_regs are [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; };
/// so to push rcx and r8 one would make data 0b00000000_00000000_00000000_00001001 (the first and fourth bits are set)
/// ops is unused
@@ -453,18 +449,6 @@ pub const DbgLineColumn = struct {
column: u32,
};
-pub const ArgDbgInfo = struct {
- air_inst: Air.Inst.Index,
- arg_index: u32,
- max_stack: u32,
-};
-
-pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
- mir.instructions.deinit(gpa);
- gpa.free(mir.extra);
- mir.* = undefined;
-}
-
pub const Ops = struct {
reg1: Register = .none,
reg2: Register = .none,
@@ -490,6 +474,12 @@ pub const Ops = struct {
}
};
+pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
+ mir.instructions.deinit(gpa);
+ gpa.free(mir.extra);
+ mir.* = undefined;
+}
+
pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
const fields = std.meta.fields(T);
var i: usize = index;
diff --git a/src/arch/x86_64/PrintMir.zig b/src/arch/x86_64/PrintMir.zig
index 8c07350c2d..e457d859ea 100644
--- a/src/arch/x86_64/PrintMir.zig
+++ b/src/arch/x86_64/PrintMir.zig
@@ -147,7 +147,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
.call_extern => try print.mirCallExtern(inst, w),
- .dbg_line, .dbg_prologue_end, .dbg_epilogue_begin, .arg_dbg_info => try w.print("{s}\n", .{@tagName(tag)}),
+ .dbg_line, .dbg_prologue_end, .dbg_epilogue_begin => try w.print("{s}\n", .{@tagName(tag)}),
.push_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.push, inst, w),
.pop_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.pop, inst, w),
diff --git a/src/codegen.zig b/src/codegen.zig
index 2ace45c8cb..68e1f3697f 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -203,7 +203,6 @@ pub fn generateSymbol(
},
.Array => switch (typed_value.val.tag()) {
.bytes => {
- // TODO populate .debug_info for the array
const payload = typed_value.val.castTag(.bytes).?;
const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());
// The bytes payload already includes the sentinel, if any
@@ -212,7 +211,6 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.aggregate => {
- // TODO populate .debug_info for the array
const elem_vals = typed_value.val.castTag(.aggregate).?.data;
const elem_ty = typed_value.ty.elemType();
const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 4085305941..54f8285291 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -220,6 +220,9 @@ fn formatIdent(
}
pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
+ if (builtin.zig_backend != .stage1) {
+ @panic("TODO");
+ }
return .{ .data = ident };
}
@@ -1348,7 +1351,7 @@ pub const DeclGen = struct {
return w.writeAll(name);
},
.ErrorSet => {
- comptime std.debug.assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);
+ comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);
return w.writeAll("uint16_t");
},
.ErrorUnion => {
@@ -2310,7 +2313,6 @@ fn airWrapOp(
const val = -1 * std.math.pow(i64, 2, @intCast(i64, bits - 1));
break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
},
},
@@ -2336,7 +2338,6 @@ fn airWrapOp(
const val = std.math.pow(u64, 2, pow_bits) - 1;
break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
},
};
@@ -2418,7 +2419,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
const val = -1 * std.math.pow(i65, 2, @intCast(i65, bits - 1));
break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
},
},
@@ -2444,7 +2444,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
const val = std.math.pow(u65, 2, pow_bits) - 1;
break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
- else => |e| return e,
};
},
};
@@ -2702,7 +2701,7 @@ fn airCall(
}
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const extra = f.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
const callee_ty = f.air.typeOf(pl_op.operand);
const fn_ty = switch (callee_ty.zigTypeTag()) {
.Fn => callee_ty,
@@ -2959,7 +2958,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
var case_i: u32 = 0;
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @bitCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
+ const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + case.data.items_len + case_body.len;
@@ -2990,9 +2989,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- const outputs = @bitCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none;
@@ -3860,7 +3859,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const vector_ty = f.air.getRefType(ty_pl.ty);
const len = vector_ty.vectorLen();
- const elements = @bitCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
const writer = f.object.writer();
const local = try f.allocLocal(inst_ty, .Const);
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index db4c08f86f..f55d326a47 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -3657,7 +3657,7 @@ pub const FuncGen = struct {
fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*const llvm.Value {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
const callee_ty = self.air.typeOf(pl_op.operand);
const zig_fn_ty = switch (callee_ty.zigTypeTag()) {
.Fn => callee_ty,
@@ -4037,7 +4037,7 @@ pub const FuncGen = struct {
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
+ const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + case.data.items_len + case_body.len;
@@ -4538,9 +4538,9 @@ pub const FuncGen = struct {
if (!is_volatile and self.liveness.isUnused(inst)) return null;
- const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
if (outputs.len > 1) {
@@ -6660,7 +6660,7 @@ pub const FuncGen = struct {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const result_ty = self.air.typeOfIndex(inst);
const len = @intCast(usize, result_ty.arrayLen());
- const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
const llvm_result_ty = try self.dg.llvmType(result_ty);
const target = self.dg.module.getTarget();
diff --git a/src/link.zig b/src/link.zig
index 7c135a7405..dbef400189 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -649,6 +649,11 @@ pub const File = struct {
}
}
+ pub const UpdateDeclExportsError = error{
+ OutOfMemory,
+ AnalysisFail,
+ };
+
/// May be called before or after updateDecl, but must be called after
/// allocateDeclIndexes for any given Decl.
pub fn updateDeclExports(
@@ -656,7 +661,7 @@ pub const File = struct {
module: *Module,
decl: *Module.Decl,
exports: []const *Module.Export,
- ) !void {
+ ) UpdateDeclExportsError!void {
log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name });
assert(decl.has_tv);
switch (base.tag) {
@@ -717,19 +722,38 @@ pub const File = struct {
// directly, and remove this function from link.zig.
_ = base;
while (true) {
- std.fs.rename(
- cache_directory.handle,
- tmp_dir_sub_path,
- cache_directory.handle,
- o_sub_path,
- ) catch |err| switch (err) {
- error.PathAlreadyExists => {
+ if (builtin.os.tag == .windows) {
+ // workaround windows `renameW` can't fail with `PathAlreadyExists`
+ // See https://github.com/ziglang/zig/issues/8362
+ if (cache_directory.handle.access(o_sub_path, .{})) |_| {
try cache_directory.handle.deleteTree(o_sub_path);
continue;
- },
- else => |e| return e,
- };
- break;
+ } else |err| switch (err) {
+ error.FileNotFound => {},
+ else => |e| return e,
+ }
+ try std.fs.rename(
+ cache_directory.handle,
+ tmp_dir_sub_path,
+ cache_directory.handle,
+ o_sub_path,
+ );
+ break;
+ } else {
+ std.fs.rename(
+ cache_directory.handle,
+ tmp_dir_sub_path,
+ cache_directory.handle,
+ o_sub_path,
+ ) catch |err| switch (err) {
+ error.PathAlreadyExists => {
+ try cache_directory.handle.deleteTree(o_sub_path);
+ continue;
+ },
+ else => |e| return e,
+ };
+ break;
+ }
}
}
diff --git a/src/link/C.zig b/src/link/C.zig
index 85b7c24487..229990fc8e 100644
--- a/src/link/C.zig
+++ b/src/link/C.zig
@@ -89,8 +89,9 @@ pub fn deinit(self: *C) void {
pub fn freeDecl(self: *C, decl: *Module.Decl) void {
const gpa = self.base.allocator;
- if (self.decl_table.fetchSwapRemove(decl)) |*kv| {
- kv.value.deinit(gpa);
+ if (self.decl_table.fetchSwapRemove(decl)) |kv| {
+ var decl_block = kv.value;
+ decl_block.deinit(gpa);
}
}
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 907a21b774..248521c544 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -39,7 +39,7 @@ atom_last: ?*Atom = null,
abbrev_table_offset: ?u64 = null,
-/// TODO replace with InternArena
+/// TODO replace with InternPool
/// Table of debug symbol names.
strtab: std.ArrayListUnmanaged(u8) = .{},
@@ -79,6 +79,7 @@ pub const DeclState = struct {
std.hash_map.default_max_load_percentage,
) = .{},
abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
+ exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},
fn init(gpa: Allocator, target: std.Target) DeclState {
return .{
@@ -97,6 +98,16 @@ pub const DeclState = struct {
self.abbrev_table.deinit(self.gpa);
self.abbrev_resolver.deinit(self.gpa);
self.abbrev_relocs.deinit(self.gpa);
+ self.exprloc_relocs.deinit(self.gpa);
+ }
+
+ pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
+ log.debug("{x}: target sym @{d}, via GOT {}", .{ offset, target, is_ptr });
+ try self.exprloc_relocs.append(self.gpa, .{
+ .@"type" = if (is_ptr) .got_load else .direct_load,
+ .target = target,
+ .offset = offset,
+ });
}
pub fn addTypeReloc(
@@ -148,11 +159,11 @@ pub const DeclState = struct {
switch (ty.zigTypeTag()) {
.NoReturn => unreachable,
.Void => {
- try dbg_info_buffer.append(abbrev_pad1);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1));
},
.Bool => {
try dbg_info_buffer.appendSlice(&[_]u8{
- abbrev_base_type,
+ @enumToInt(AbbrevKind.base_type),
DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1
1, // DW.AT.byte_size, DW.FORM.data1
'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string
@@ -161,7 +172,7 @@ pub const DeclState = struct {
.Int => {
const info = ty.intInfo(target);
try dbg_info_buffer.ensureUnusedCapacity(12);
- dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type));
// DW.AT.encoding, DW.FORM.data1
dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) {
.signed => DW.ATE.signed,
@@ -175,7 +186,7 @@ pub const DeclState = struct {
.Optional => {
if (ty.isPtrLikeOptional()) {
try dbg_info_buffer.ensureUnusedCapacity(12);
- dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type));
// DW.AT.encoding, DW.FORM.data1
dbg_info_buffer.appendAssumeCapacity(DW.ATE.address);
// DW.AT.byte_size, DW.FORM.data1
@@ -187,7 +198,7 @@ pub const DeclState = struct {
var buf = try arena.create(Type.Payload.ElemType);
const payload_ty = ty.optionalChild(buf);
// DW.AT.structure_type
- try dbg_info_buffer.append(abbrev_struct_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
// DW.AT.byte_size, DW.FORM.sdata
const abi_size = ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
@@ -195,7 +206,7 @@ pub const DeclState = struct {
try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)});
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(7);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("maybe");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -207,7 +218,7 @@ pub const DeclState = struct {
try dbg_info_buffer.ensureUnusedCapacity(6);
dbg_info_buffer.appendAssumeCapacity(0);
// DW.AT.member
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("val");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -227,14 +238,14 @@ pub const DeclState = struct {
// Slices are structs: struct { .ptr = *, .len = N }
// DW.AT.structure_type
try dbg_info_buffer.ensureUnusedCapacity(2);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_type);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type));
// DW.AT.byte_size, DW.FORM.sdata
dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2);
// DW.AT.name, DW.FORM.string
try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)});
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(5);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("ptr");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -248,7 +259,7 @@ pub const DeclState = struct {
try dbg_info_buffer.ensureUnusedCapacity(6);
dbg_info_buffer.appendAssumeCapacity(0);
// DW.AT.member
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("len");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -263,16 +274,37 @@ pub const DeclState = struct {
dbg_info_buffer.appendAssumeCapacity(0);
} else {
try dbg_info_buffer.ensureUnusedCapacity(5);
- dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.ptr_type));
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
}
},
+ .Array => {
+ // DW.AT.array_type
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_type));
+ // DW.AT.name, DW.FORM.string
+ try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)});
+ // DW.AT.type, DW.FORM.ref4
+ var index = dbg_info_buffer.items.len;
+ try dbg_info_buffer.resize(index + 4);
+ try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
+ // DW.AT.subrange_type
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
+ // DW.AT.type, DW.FORM.ref4
+ index = dbg_info_buffer.items.len;
+ try dbg_info_buffer.resize(index + 4);
+ try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null);
+ // DW.AT.count, DW.FORM.udata
+ const len = ty.arrayLenIncludingSentinel();
+ try leb128.writeULEB128(dbg_info_buffer.writer(), len);
+ // DW.AT.array_type delimit children
+ try dbg_info_buffer.append(0);
+ },
.Struct => blk: {
// DW.AT.structure_type
- try dbg_info_buffer.append(abbrev_struct_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
// DW.AT.byte_size, DW.FORM.sdata
const abi_size = ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
@@ -285,7 +317,7 @@ pub const DeclState = struct {
const fields = ty.tupleFields();
for (fields.types) |field, field_index| {
// DW.AT.member
- try dbg_info_buffer.append(abbrev_struct_member);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
// DW.AT.type, DW.FORM.ref4
@@ -315,7 +347,7 @@ pub const DeclState = struct {
const field = fields.get(field_name).?;
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity(field_name);
dbg_info_buffer.appendAssumeCapacity(0);
@@ -335,7 +367,7 @@ pub const DeclState = struct {
},
.Enum => {
// DW.AT.enumeration_type
- try dbg_info_buffer.append(abbrev_enum_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type));
// DW.AT.byte_size, DW.FORM.sdata
const abi_size = ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
@@ -355,7 +387,7 @@ pub const DeclState = struct {
for (fields.keys()) |field_name, field_i| {
// DW.AT.enumerator
try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
- dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity(field_name);
dbg_info_buffer.appendAssumeCapacity(0);
@@ -385,7 +417,7 @@ pub const DeclState = struct {
// for untagged unions.
if (is_tagged) {
// DW.AT.structure_type
- try dbg_info_buffer.append(abbrev_struct_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
// DW.AT.byte_size, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), layout.abi_size);
// DW.AT.name, DW.FORM.string
@@ -395,7 +427,7 @@ pub const DeclState = struct {
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(9);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("payload");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -408,7 +440,7 @@ pub const DeclState = struct {
}
// DW.AT.union_type
- try dbg_info_buffer.append(abbrev_union_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.union_type));
// DW.AT.byte_size, DW.FORM.sdata,
try leb128.writeULEB128(dbg_info_buffer.writer(), layout.payload_size);
// DW.AT.name, DW.FORM.string
@@ -423,7 +455,7 @@ pub const DeclState = struct {
const field = fields.get(field_name).?;
if (!field.ty.hasRuntimeBits()) continue;
// DW.AT.member
- try dbg_info_buffer.append(abbrev_struct_member);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
try dbg_info_buffer.writer().print("{s}\x00", .{field_name});
// DW.AT.type, DW.FORM.ref4
@@ -439,7 +471,7 @@ pub const DeclState = struct {
if (is_tagged) {
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(5);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("tag");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -471,7 +503,7 @@ pub const DeclState = struct {
const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align);
// DW.AT.structure_type
- try dbg_info_buffer.append(abbrev_struct_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
// DW.AT.byte_size, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
// DW.AT.name, DW.FORM.string
@@ -480,7 +512,7 @@ pub const DeclState = struct {
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(7);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("value");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -493,7 +525,7 @@ pub const DeclState = struct {
// DW.AT.member
try dbg_info_buffer.ensureUnusedCapacity(5);
- dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity("err");
dbg_info_buffer.appendAssumeCapacity(0);
@@ -509,7 +541,7 @@ pub const DeclState = struct {
},
else => {
log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});
- try dbg_info_buffer.append(abbrev_pad1);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1));
},
}
}
@@ -528,6 +560,18 @@ pub const AbbrevRelocation = struct {
addend: u32,
};
+pub const ExprlocRelocation = struct {
+ /// Type of the relocation: direct load ref, or GOT load ref (via GOT table)
+ @"type": enum {
+ direct_load,
+ got_load,
+ },
+ /// Index of the target in the linker's locals symbol table.
+ target: u32,
+ /// Offset within the debug info buffer where to patch up the address value.
+ offset: u32,
+};
+
pub const SrcFn = struct {
/// Offset from the beginning of the Debug Line Program header that contains this function.
off: u32,
@@ -550,18 +594,23 @@ pub const SrcFn = struct {
pub const PtrWidth = enum { p32, p64 };
-pub const abbrev_compile_unit = 1;
-pub const abbrev_subprogram = 2;
-pub const abbrev_subprogram_retvoid = 3;
-pub const abbrev_base_type = 4;
-pub const abbrev_ptr_type = 5;
-pub const abbrev_struct_type = 6;
-pub const abbrev_struct_member = 7;
-pub const abbrev_enum_type = 8;
-pub const abbrev_enum_variant = 9;
-pub const abbrev_union_type = 10;
-pub const abbrev_pad1 = 11;
-pub const abbrev_parameter = 12;
+pub const AbbrevKind = enum(u8) {
+ compile_unit = 1,
+ subprogram,
+ subprogram_retvoid,
+ base_type,
+ ptr_type,
+ struct_type,
+ struct_member,
+ enum_type,
+ enum_variant,
+ union_type,
+ pad1,
+ parameter,
+ variable,
+ array_type,
+ array_dim,
+};
/// The reloc offset for the virtual address of a function in its Line Number Program.
/// Size is a virtual address integer.
@@ -670,9 +719,9 @@ pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !DeclState {
const fn_ret_type = decl.ty.fnReturnType();
const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
if (fn_ret_has_bits) {
- dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.subprogram));
} else {
- dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.subprogram_retvoid));
}
// These get overwritten after generating the machine code. These values are
// "relocations" and have to be in this fixed place so that functions can be
@@ -926,7 +975,7 @@ pub fn commitDeclState(
else => unreachable,
};
- {
+ if (decl_state.abbrev_table.items.len > 0) {
// Now we emit the .debug_info types of the Decl. These will count towards the size of
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
// relocations yet.
@@ -983,6 +1032,26 @@ pub fn commitDeclState(
}
}
+ while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
+ switch (self.tag) {
+ .macho => {
+ const macho_file = file.cast(File.MachO).?;
+ const d_sym = &macho_file.d_sym.?;
+ try d_sym.relocs.append(d_sym.base.base.allocator, .{
+ .@"type" = switch (reloc.@"type") {
+ .direct_load => .direct_load,
+ .got_load => .got_load,
+ },
+ .target = reloc.target,
+ .offset = reloc.offset + atom.off,
+ .addend = 0,
+ .prev_vaddr = 0,
+ });
+ },
+ else => unreachable,
+ }
+ }
+
try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
}
@@ -1244,14 +1313,14 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
// These are LEB encoded but since the values are all less than 127
// we can simply append these bytes.
const abbrev_buf = [_]u8{
- abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header
- DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc,
- DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr,
- DW.AT.name, DW.FORM.strp, DW.AT.comp_dir,
- DW.FORM.strp, DW.AT.producer, DW.FORM.strp,
- DW.AT.language, DW.FORM.data2, 0,
+ @enumToInt(AbbrevKind.compile_unit), DW.TAG.compile_unit, DW.CHILDREN.yes, // header
+ DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc,
+ DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr,
+ DW.AT.name, DW.FORM.strp, DW.AT.comp_dir,
+ DW.FORM.strp, DW.AT.producer, DW.FORM.strp,
+ DW.AT.language, DW.FORM.data2, 0,
0, // table sentinel
- abbrev_subprogram,
+ @enumToInt(AbbrevKind.subprogram),
DW.TAG.subprogram,
DW.CHILDREN.yes, // header
DW.AT.low_pc,
@@ -1262,15 +1331,15 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.ref4,
DW.AT.name,
DW.FORM.string,
- 0, 0, // table sentinel
- abbrev_subprogram_retvoid,
+ 0, 0, // table sentinel
+ @enumToInt(AbbrevKind.subprogram_retvoid),
DW.TAG.subprogram, DW.CHILDREN.yes, // header
DW.AT.low_pc, DW.FORM.addr,
DW.AT.high_pc, DW.FORM.data4,
DW.AT.name, DW.FORM.string,
0,
0, // table sentinel
- abbrev_base_type,
+ @enumToInt(AbbrevKind.base_type),
DW.TAG.base_type,
DW.CHILDREN.no, // header
DW.AT.encoding,
@@ -1281,14 +1350,14 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.string,
0,
0, // table sentinel
- abbrev_ptr_type,
+ @enumToInt(AbbrevKind.ptr_type),
DW.TAG.pointer_type,
DW.CHILDREN.no, // header
DW.AT.type,
DW.FORM.ref4,
0,
0, // table sentinel
- abbrev_struct_type,
+ @enumToInt(AbbrevKind.struct_type),
DW.TAG.structure_type,
DW.CHILDREN.yes, // header
DW.AT.byte_size,
@@ -1297,7 +1366,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.string,
0,
0, // table sentinel
- abbrev_struct_member,
+ @enumToInt(AbbrevKind.struct_member),
DW.TAG.member,
DW.CHILDREN.no, // header
DW.AT.name,
@@ -1308,7 +1377,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.sdata,
0,
0, // table sentinel
- abbrev_enum_type,
+ @enumToInt(AbbrevKind.enum_type),
DW.TAG.enumeration_type,
DW.CHILDREN.yes, // header
DW.AT.byte_size,
@@ -1317,7 +1386,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.string,
0,
0, // table sentinel
- abbrev_enum_variant,
+ @enumToInt(AbbrevKind.enum_variant),
DW.TAG.enumerator,
DW.CHILDREN.no, // header
DW.AT.name,
@@ -1326,7 +1395,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.data8,
0,
0, // table sentinel
- abbrev_union_type,
+ @enumToInt(AbbrevKind.union_type),
DW.TAG.union_type,
DW.CHILDREN.yes, // header
DW.AT.byte_size,
@@ -1335,18 +1404,37 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
DW.FORM.string,
0,
0, // table sentinel
- abbrev_pad1,
+ @enumToInt(AbbrevKind.pad1),
DW.TAG.unspecified_type,
DW.CHILDREN.no, // header
0,
0, // table sentinel
- abbrev_parameter,
+ @enumToInt(AbbrevKind.parameter),
DW.TAG.formal_parameter, DW.CHILDREN.no, // header
DW.AT.location, DW.FORM.exprloc,
DW.AT.type, DW.FORM.ref4,
DW.AT.name, DW.FORM.string,
0,
0, // table sentinel
+ @enumToInt(AbbrevKind.variable),
+ DW.TAG.variable, DW.CHILDREN.no, // header
+ DW.AT.location, DW.FORM.exprloc,
+ DW.AT.type, DW.FORM.ref4,
+ DW.AT.name, DW.FORM.string,
+ 0,
+ 0, // table sentinel
+ @enumToInt(AbbrevKind.array_type),
+ DW.TAG.array_type, DW.CHILDREN.yes, // header
+ DW.AT.name, DW.FORM.string,
+ DW.AT.type, DW.FORM.ref4,
+ 0,
+ 0, // table sentinel
+ @enumToInt(AbbrevKind.array_dim),
+ DW.TAG.subrange_type, DW.CHILDREN.no, // header
+ DW.AT.type, DW.FORM.ref4,
+ DW.AT.count, DW.FORM.udata,
+ 0,
+ 0, // table sentinel
0,
0,
0, // section sentinel
@@ -1459,7 +1547,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
const comp_dir_strp = try self.makeString(module.root_pkg.root_src_directory.path orelse ".");
const producer_strp = try self.makeString(link.producer_string);
- di_buf.appendAssumeCapacity(abbrev_compile_unit);
+ di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));
if (self.tag == .macho) {
mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc);
@@ -1606,7 +1694,7 @@ fn pwriteDbgInfoNops(
const tracy = trace(@src());
defer tracy.end();
- const page_of_nops = [1]u8{abbrev_pad1} ** 4096;
+ const page_of_nops = [1]u8{@enumToInt(AbbrevKind.pad1)} ** 4096;
var vecs: [32]std.os.iovec_const = undefined;
var vec_index: usize = 0;
{
@@ -1673,7 +1761,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
.p32 => @as(usize, 4),
.p64 => 12,
};
- const ptr_width_bytes: u8 = self.ptrWidthBytes();
+ const ptr_width_bytes = self.ptrWidthBytes();
// Enough for all the data without resizing. When support for more compilation units
// is added, the size of this section will become more variable.
@@ -2040,7 +2128,7 @@ fn addDbgInfoErrorSet(
const target_endian = target.cpu.arch.endian();
// DW.AT.enumeration_type
- try dbg_info_buffer.append(abbrev_enum_type);
+ try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type));
// DW.AT.byte_size, DW.FORM.sdata
const abi_size = ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
@@ -2051,7 +2139,7 @@ fn addDbgInfoErrorSet(
// DW.AT.enumerator
const no_error = "(no error)";
try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64));
- dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity(no_error);
dbg_info_buffer.appendAssumeCapacity(0);
@@ -2063,7 +2151,7 @@ fn addDbgInfoErrorSet(
const kv = module.getErrorValue(error_name) catch unreachable;
// DW.AT.enumerator
try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64));
- dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
+ dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant));
// DW.AT.name, DW.FORM.string
dbg_info_buffer.appendSliceAssumeCapacity(error_name);
dbg_info_buffer.appendAssumeCapacity(0);
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 636b2ba7df..e5e65011cd 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -65,7 +65,7 @@ phdr_load_rw_index: ?u16 = null,
phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
entry_addr: ?u64 = null,
-page_size: u16,
+page_size: u32,
shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
shstrtab_index: ?u16 = null,
@@ -100,11 +100,11 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
phdr_table_dirty: bool = false,
shdr_table_dirty: bool = false,
shstrtab_dirty: bool = false,
-debug_strtab_dirty: bool = false,
offset_table_count_dirty: bool = false,
+
+debug_strtab_dirty: bool = false,
debug_abbrev_section_dirty: bool = false,
debug_aranges_section_dirty: bool = false,
-
debug_info_header_dirty: bool = false,
debug_line_header_dirty: bool = false,
@@ -154,7 +154,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
/// const Foo = struct{
/// a: u8,
/// };
-///
+///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
@@ -304,7 +304,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
};
const self = try gpa.create(Elf);
errdefer gpa.destroy(self);
- const page_size: u16 = 0x1000; // TODO ppc64le requires 64KB
+
+ const page_size: u32 = switch (options.target.cpu.arch) {
+ .powerpc64le => 0x10000,
+ .sparcv9 => 0x2000,
+ else => 0x1000,
+ };
var dwarf: ?Dwarf = if (!options.strip and options.module != null)
Dwarf.init(gpa, .elf, options.target)
@@ -472,7 +477,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
return min_pos - start;
}
-pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 {
+pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
var start: u64 = 0;
while (self.detectAllocCollision(start, object_size)) |item_end| {
start = mem.alignForwardGeneric(u64, item_end, min_alignment);
@@ -749,127 +754,129 @@ pub fn populateMissingMetadata(self: *Elf) !void {
try self.writeSymbol(0);
}
- if (self.debug_str_section_index == null) {
- self.debug_str_section_index = @intCast(u16, self.sections.items.len);
- assert(self.dwarf.?.strtab.items.len == 0);
- try self.sections.append(self.base.allocator, .{
- .sh_name = try self.makeString(".debug_str"),
- .sh_type = elf.SHT_PROGBITS,
- .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = 1,
- .sh_entsize = 1,
- });
- self.debug_strtab_dirty = true;
- self.shdr_table_dirty = true;
- }
+ if (self.dwarf) |dw| {
+ if (self.debug_str_section_index == null) {
+ self.debug_str_section_index = @intCast(u16, self.sections.items.len);
+ assert(dw.strtab.items.len == 0);
+ try self.sections.append(self.base.allocator, .{
+ .sh_name = try self.makeString(".debug_str"),
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = 1,
+ .sh_entsize = 1,
+ });
+ self.debug_strtab_dirty = true;
+ self.shdr_table_dirty = true;
+ }
- if (self.debug_info_section_index == null) {
- self.debug_info_section_index = @intCast(u16, self.sections.items.len);
+ if (self.debug_info_section_index == null) {
+ self.debug_info_section_index = @intCast(u16, self.sections.items.len);
- const file_size_hint = 200;
- const p_align = 1;
- const off = self.findFreeSpace(file_size_hint, p_align);
- log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
- off,
- off + file_size_hint,
- });
- try self.sections.append(self.base.allocator, .{
- .sh_name = try self.makeString(".debug_info"),
- .sh_type = elf.SHT_PROGBITS,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = off,
- .sh_size = file_size_hint,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = p_align,
- .sh_entsize = 0,
- });
- self.shdr_table_dirty = true;
- self.debug_info_header_dirty = true;
- }
+ const file_size_hint = 200;
+ const p_align = 1;
+ const off = self.findFreeSpace(file_size_hint, p_align);
+ log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
+ off,
+ off + file_size_hint,
+ });
+ try self.sections.append(self.base.allocator, .{
+ .sh_name = try self.makeString(".debug_info"),
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = off,
+ .sh_size = file_size_hint,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = p_align,
+ .sh_entsize = 0,
+ });
+ self.shdr_table_dirty = true;
+ self.debug_info_header_dirty = true;
+ }
- if (self.debug_abbrev_section_index == null) {
- self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
+ if (self.debug_abbrev_section_index == null) {
+ self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
- const file_size_hint = 128;
- const p_align = 1;
- const off = self.findFreeSpace(file_size_hint, p_align);
- log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
- off,
- off + file_size_hint,
- });
- try self.sections.append(self.base.allocator, .{
- .sh_name = try self.makeString(".debug_abbrev"),
- .sh_type = elf.SHT_PROGBITS,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = off,
- .sh_size = file_size_hint,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = p_align,
- .sh_entsize = 0,
- });
- self.shdr_table_dirty = true;
- self.debug_abbrev_section_dirty = true;
- }
+ const file_size_hint = 128;
+ const p_align = 1;
+ const off = self.findFreeSpace(file_size_hint, p_align);
+ log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
+ off,
+ off + file_size_hint,
+ });
+ try self.sections.append(self.base.allocator, .{
+ .sh_name = try self.makeString(".debug_abbrev"),
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = off,
+ .sh_size = file_size_hint,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = p_align,
+ .sh_entsize = 0,
+ });
+ self.shdr_table_dirty = true;
+ self.debug_abbrev_section_dirty = true;
+ }
- if (self.debug_aranges_section_index == null) {
- self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
+ if (self.debug_aranges_section_index == null) {
+ self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
- const file_size_hint = 160;
- const p_align = 16;
- const off = self.findFreeSpace(file_size_hint, p_align);
- log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
- off,
- off + file_size_hint,
- });
- try self.sections.append(self.base.allocator, .{
- .sh_name = try self.makeString(".debug_aranges"),
- .sh_type = elf.SHT_PROGBITS,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = off,
- .sh_size = file_size_hint,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = p_align,
- .sh_entsize = 0,
- });
- self.shdr_table_dirty = true;
- self.debug_aranges_section_dirty = true;
- }
+ const file_size_hint = 160;
+ const p_align = 16;
+ const off = self.findFreeSpace(file_size_hint, p_align);
+ log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
+ off,
+ off + file_size_hint,
+ });
+ try self.sections.append(self.base.allocator, .{
+ .sh_name = try self.makeString(".debug_aranges"),
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = off,
+ .sh_size = file_size_hint,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = p_align,
+ .sh_entsize = 0,
+ });
+ self.shdr_table_dirty = true;
+ self.debug_aranges_section_dirty = true;
+ }
- if (self.debug_line_section_index == null) {
- self.debug_line_section_index = @intCast(u16, self.sections.items.len);
+ if (self.debug_line_section_index == null) {
+ self.debug_line_section_index = @intCast(u16, self.sections.items.len);
- const file_size_hint = 250;
- const p_align = 1;
- const off = self.findFreeSpace(file_size_hint, p_align);
- log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
- off,
- off + file_size_hint,
- });
- try self.sections.append(self.base.allocator, .{
- .sh_name = try self.makeString(".debug_line"),
- .sh_type = elf.SHT_PROGBITS,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = off,
- .sh_size = file_size_hint,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = p_align,
- .sh_entsize = 0,
- });
- self.shdr_table_dirty = true;
- self.debug_line_header_dirty = true;
+ const file_size_hint = 250;
+ const p_align = 1;
+ const off = self.findFreeSpace(file_size_hint, p_align);
+ log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
+ off,
+ off + file_size_hint,
+ });
+ try self.sections.append(self.base.allocator, .{
+ .sh_name = try self.makeString(".debug_line"),
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = off,
+ .sh_size = file_size_hint,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = p_align,
+ .sh_entsize = 0,
+ });
+ self.shdr_table_dirty = true;
+ self.debug_line_header_dirty = true;
+ }
}
const shsize: u64 = switch (self.ptr_width) {
@@ -1001,40 +1008,42 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
// mixing local and global symbols within a symbol table.
try self.writeAllGlobalSymbols();
- if (self.debug_abbrev_section_dirty) {
- try self.dwarf.?.writeDbgAbbrev(&self.base);
- if (!self.shdr_table_dirty) {
- // Then it won't get written with the others and we need to do it.
- try self.writeSectHeader(self.debug_abbrev_section_index.?);
+ if (self.dwarf) |*dw| {
+ if (self.debug_abbrev_section_dirty) {
+ try dw.writeDbgAbbrev(&self.base);
+ if (!self.shdr_table_dirty) {
+ // Then it won't get written with the others and we need to do it.
+ try self.writeSectHeader(self.debug_abbrev_section_index.?);
+ }
+ self.debug_abbrev_section_dirty = false;
}
- self.debug_abbrev_section_dirty = false;
- }
- if (self.debug_info_header_dirty) {
- // Currently only one compilation unit is supported, so the address range is simply
- // identical to the main program header virtual address and memory size.
- const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
- const low_pc = text_phdr.p_vaddr;
- const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
- try self.dwarf.?.writeDbgInfoHeader(&self.base, module, low_pc, high_pc);
- self.debug_info_header_dirty = false;
- }
+ if (self.debug_info_header_dirty) {
+ // Currently only one compilation unit is supported, so the address range is simply
+ // identical to the main program header virtual address and memory size.
+ const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+ const low_pc = text_phdr.p_vaddr;
+ const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
+ try dw.writeDbgInfoHeader(&self.base, module, low_pc, high_pc);
+ self.debug_info_header_dirty = false;
+ }
- if (self.debug_aranges_section_dirty) {
- // Currently only one compilation unit is supported, so the address range is simply
- // identical to the main program header virtual address and memory size.
- const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
- try self.dwarf.?.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz);
- if (!self.shdr_table_dirty) {
- // Then it won't get written with the others and we need to do it.
- try self.writeSectHeader(self.debug_aranges_section_index.?);
+ if (self.debug_aranges_section_dirty) {
+ // Currently only one compilation unit is supported, so the address range is simply
+ // identical to the main program header virtual address and memory size.
+ const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+ try dw.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz);
+ if (!self.shdr_table_dirty) {
+ // Then it won't get written with the others and we need to do it.
+ try self.writeSectHeader(self.debug_aranges_section_index.?);
+ }
+ self.debug_aranges_section_dirty = false;
}
- self.debug_aranges_section_dirty = false;
- }
- if (self.debug_line_header_dirty) {
- try self.dwarf.?.writeDbgLineHeader(&self.base, module);
- self.debug_line_header_dirty = false;
+ if (self.debug_line_header_dirty) {
+ try dw.writeDbgLineHeader(&self.base, module);
+ self.debug_line_header_dirty = false;
+ }
}
if (self.phdr_table_dirty) {
@@ -1105,9 +1114,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
}
}
- {
+ if (self.dwarf) |dwarf| {
const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
- const dwarf = self.dwarf.?;
if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) {
const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);
const needed_size = dwarf.strtab.items.len;
@@ -1827,7 +1835,7 @@ fn writeElfHeader(self: *Elf) !void {
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
var index: usize = 0;
- hdr_buf[0..4].* = "\x7fELF".*;
+ hdr_buf[0..4].* = elf.MAGIC.*;
index += 4;
hdr_buf[index] = switch (self.ptr_width) {
@@ -2105,14 +2113,16 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
phdr.p_memsz = needed_size;
phdr.p_filesz = needed_size;
- // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
- // range of the compilation unit. When we expand the text section, this range changes,
- // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
- self.debug_info_header_dirty = true;
- // This becomes dirty for the same reason. We could potentially make this more
- // fine-grained with the addition of support for more compilation units. It is planned to
- // model each package as a different compilation unit.
- self.debug_aranges_section_dirty = true;
+ if (self.dwarf) |_| {
+ // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
+ // range of the compilation unit. When we expand the text section, this range changes,
+ // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
+ self.debug_info_header_dirty = true;
+ // This becomes dirty for the same reason. We could potentially make this more
+ // fine-grained with the addition of support for more compilation units. It is planned to
+ // model each package as a different compilation unit.
+ self.debug_aranges_section_dirty = true;
+ }
self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
self.shdr_table_dirty = true; // TODO look into making only the one section dirty
@@ -2482,7 +2492,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom);
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
- .none = .{},
+ .none = {},
}, .{
.parent_atom_index = atom.local_sym_index,
});
@@ -2794,6 +2804,22 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
.p32 => @sizeOf(elf.Elf32_Sym),
.p64 => @sizeOf(elf.Elf64_Sym),
};
+ const sym_align: u16 = switch (self.ptr_width) {
+ .p32 => @alignOf(elf.Elf32_Sym),
+ .p64 => @alignOf(elf.Elf64_Sym),
+ };
+ const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
+ if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
+ // Move all the symbols to a new file location.
+ const new_offset = self.findFreeSpace(needed_size, sym_align);
+ const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
+ const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size);
+ if (amt != existing_size) return error.InputOutput;
+ syms_sect.sh_offset = new_offset;
+ }
+ syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
+ self.shdr_table_dirty = true; // TODO look into only writing one section
+
const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
switch (self.ptr_width) {
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 1d75eb442a..d359a3fd5d 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -232,7 +232,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
/// const Foo = struct{
/// a: u8,
/// };
-///
+///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
@@ -3472,6 +3472,9 @@ pub fn closeFiles(self: MachO) void {
for (self.dylibs.items) |dylib| {
dylib.file.close();
}
+ if (self.d_sym) |ds| {
+ ds.file.close();
+ }
}
fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool) void {
@@ -4274,6 +4277,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};
self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };
_ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });
+
+ if (self.d_sym) |*d_sym| {
+ d_sym.swapRemoveRelocs(decl.link.macho.local_sym_index);
+ }
+
log.debug(" adding GOT index {d} to free list (target local@{d})", .{
got_index,
decl.link.macho.local_sym_index,
diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig
index 885f0ca6a8..aa7a29fcd1 100644
--- a/src/link/MachO/DebugSymbols.zig
+++ b/src/link/MachO/DebugSymbols.zig
@@ -59,6 +59,19 @@ debug_aranges_section_dirty: bool = false,
debug_info_header_dirty: bool = false,
debug_line_header_dirty: bool = false,
+relocs: std.ArrayListUnmanaged(Reloc) = .{},
+
+pub const Reloc = struct {
+ @"type": enum {
+ direct_load,
+ got_load,
+ },
+ target: u32,
+ offset: u64,
+ addend: u32,
+ prev_vaddr: u64,
+};
+
/// You must call this function *after* `MachO.populateMissingMetadata()`
/// has been called to get a viable debug symbols output.
pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
@@ -254,6 +267,30 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
// Zig source code.
const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
+ for (self.relocs.items) |*reloc| {
+ const sym = switch (reloc.@"type") {
+ .direct_load => self.base.locals.items[reloc.target],
+ .got_load => blk: {
+ const got_index = self.base.got_entries_table.get(.{ .local = reloc.target }).?;
+ const got_entry = self.base.got_entries.items[got_index];
+ break :blk self.base.locals.items[got_entry.atom.local_sym_index];
+ },
+ };
+ if (sym.n_value == reloc.prev_vaddr) continue;
+
+ const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
+ const sect = &seg.sections.items[self.debug_info_section_index.?];
+ const file_offset = sect.offset + reloc.offset;
+ log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{
+ reloc.target,
+ sym.n_value,
+ self.base.getString(sym.n_strx),
+ file_offset,
+ });
+ try self.file.pwriteAll(mem.asBytes(&sym.n_value), file_offset);
+ reloc.prev_vaddr = sym.n_value;
+ }
+
if (self.debug_abbrev_section_dirty) {
try self.dwarf.writeDbgAbbrev(&self.base.base);
self.load_commands_dirty = true;
@@ -330,7 +367,20 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
}
self.load_commands.deinit(allocator);
self.dwarf.deinit();
- self.file.close();
+ self.relocs.deinit(allocator);
+}
+
+pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
+ // TODO re-implement using a hashmap with free lists
+ var last_index: usize = 0;
+ while (last_index < self.relocs.items.len) {
+ const reloc = self.relocs.items[last_index];
+ if (reloc.target == target) {
+ _ = self.relocs.swapRemove(last_index);
+ } else {
+ last_index += 1;
+ }
+ }
}
fn copySegmentCommand(
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 6620c99b49..255d7053d4 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -625,7 +625,6 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
while (true) {
const dice = reader.readStruct(macho.data_in_code_entry) catch |err| switch (err) {
error.EndOfStream => break,
- else => |e| return e,
};
try self.data_in_code_entries.append(allocator, dice);
}
diff --git a/src/link/MachO/fat.zig b/src/link/MachO/fat.zig
index 89a2272dd1..1f8a6a2e84 100644
--- a/src/link/MachO/fat.zig
+++ b/src/link/MachO/fat.zig
@@ -40,7 +40,6 @@ pub fn getLibraryOffset(reader: anytype, target: std.Target) !u64 {
// fine because we can keep looking for one that might match.
const lib_arch = decodeArch(fat_arch.cputype, false) catch |err| switch (err) {
error.UnsupportedCpuArchitecture => continue,
- else => |e| return e,
};
if (lib_arch == target.cpu.arch) {
// We have found a matching architecture!
diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig
index 8096b2d38c..3269cb67d4 100644
--- a/src/link/Plan9.zig
+++ b/src/link/Plan9.zig
@@ -307,7 +307,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty,
.val = decl_val,
- }, &code_buffer, .{ .none = .{} }, .{
+ }, &code_buffer, .{ .none = {} }, .{
.parent_atom_index = @intCast(u32, sym_index),
});
const code = switch (res) {
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index c717b42bb6..961e382112 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -101,8 +101,8 @@ exports: std.ArrayListUnmanaged(types.Export) = .{},
/// When this is non-zero, we must emit a table entry,
/// as well as an 'elements' section.
///
-/// Note: Key is symbol index, value represents the index into the table
-function_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
+/// Note: Key is symbol location, value represents the index into the table
+function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
/// All object files and their data which are linked into the final binary
objects: std.ArrayListUnmanaged(Object) = .{},
@@ -363,6 +363,9 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
.index = sym_index,
};
const sym_name = object.string_table.get(symbol.name);
+ if (mem.eql(u8, sym_name, "__indirect_function_table")) {
+ continue;
+ }
const sym_name_index = try self.string_table.put(self.base.allocator, sym_name);
if (symbol.isLocal()) {
@@ -837,7 +840,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
/// Appends a new entry to the indirect function table
pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {
const index = @intCast(u32, self.function_table.count());
- try self.function_table.put(self.base.allocator, symbol_index, index);
+ try self.function_table.put(self.base.allocator, .{ .file = null, .index = symbol_index }, index);
}
/// Assigns indexes to all indirect functions.
@@ -959,11 +962,6 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
const segment: *Segment = &self.segments.items[final_index];
segment.alignment = std.math.max(segment.alignment, atom.alignment);
- segment.size = std.mem.alignForwardGeneric(
- u32,
- std.mem.alignForwardGeneric(u32, segment.size, atom.alignment) + atom.size,
- segment.alignment,
- );
if (self.atoms.getPtr(final_index)) |last| {
last.*.next = atom;
@@ -975,9 +973,10 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
}
fn allocateAtoms(self: *Wasm) !void {
- var it = self.atoms.valueIterator();
- while (it.next()) |current_atom| {
- var atom: *Atom = current_atom.*.getFirst();
+ var it = self.atoms.iterator();
+ while (it.next()) |entry| {
+ const segment = &self.segments.items[entry.key_ptr.*];
+ var atom: *Atom = entry.value_ptr.*.getFirst();
var offset: u32 = 0;
while (true) {
offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment);
@@ -993,6 +992,7 @@ fn allocateAtoms(self: *Wasm) !void {
self.symbol_atom.putAssumeCapacity(atom.symbolLoc(), atom); // Update atom pointers
atom = atom.next orelse break;
}
+ segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
}
}
@@ -1017,6 +1017,9 @@ fn setupImports(self: *Wasm) !void {
}
const symbol = symbol_loc.getSymbol(self);
+ if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {
+ continue;
+ }
if (symbol.tag == .data or !symbol.requiresImport()) {
continue;
}
@@ -1166,13 +1169,20 @@ fn setupExports(self: *Wasm) !void {
if (!symbol.isExported()) continue;
const sym_name = sym_loc.getName(self);
- const export_name = if (self.export_names.get(sym_loc)) |name| name else symbol.name;
+ const export_name = if (self.export_names.get(sym_loc)) |name| name else blk: {
+ if (sym_loc.file == null) break :blk symbol.name;
+ break :blk try self.string_table.put(self.base.allocator, sym_name);
+ };
const exp: types.Export = .{
.name = export_name,
.kind = symbol.tag.externalType(),
.index = symbol.index,
};
- log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ sym_name, self.string_table.get(exp.name), exp.index });
+ log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
+ sym_name,
+ self.string_table.get(exp.name),
+ exp.index,
+ });
try self.exports.append(self.base.allocator, exp);
}
@@ -1553,8 +1563,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
try self.objects.items[object_index].parseIntoAtoms(self.base.allocator, object_index, self);
}
- try self.setupMemory();
try self.allocateAtoms();
+ try self.setupMemory();
self.mapFunctionTable();
try self.mergeSections();
try self.mergeTypes();
@@ -1767,8 +1777,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
try leb.writeULEB128(writer, @as(u8, 0));
try leb.writeULEB128(writer, @intCast(u32, self.function_table.count()));
var symbol_it = self.function_table.keyIterator();
- while (symbol_it.next()) |symbol_index_ptr| {
- try leb.writeULEB128(writer, self.symbols.items[symbol_index_ptr.*].index);
+ while (symbol_it.next()) |symbol_loc_ptr| {
+ try leb.writeULEB128(writer, symbol_loc_ptr.*.getSymbol(self).index);
}
try writeVecSectionHeader(
@@ -1819,7 +1829,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
segment_count += 1;
const atom_index = entry.value_ptr.*;
var atom: *Atom = self.atoms.getPtr(atom_index).?.*.getFirst();
- var segment = self.segments.items[atom_index];
+ const segment = self.segments.items[atom_index];
// flag and index to memory section (currently, there can only be 1 memory section in wasm)
try leb.writeULEB128(writer, @as(u32, 0));
@@ -2551,7 +2561,8 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
.iov_base = payload.items.ptr,
.iov_len = payload.items.len,
};
- try file.writevAll(&.{iovec});
+ var iovecs = [_]std.os.iovec_const{iovec};
+ try file.writevAll(&iovecs);
}
fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {
@@ -2576,7 +2587,8 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {
.iov_base = payload.items.ptr,
.iov_len = payload.items.len,
};
- try file.writevAll(&.{iovec});
+ var iovecs = [_]std.os.iovec_const{iovec};
+ try file.writevAll(&iovecs);
}
fn getULEB128Size(uint_value: anytype) u32 {
@@ -2635,12 +2647,14 @@ fn emitCodeRelocations(
var buf: [5]u8 = undefined;
leb.writeUnsignedFixed(5, &buf, count);
try payload.insertSlice(reloc_start, &buf);
- const iovec: std.os.iovec_const = .{
- .iov_base = payload.items.ptr,
- .iov_len = payload.items.len,
+ var iovecs = [_]std.os.iovec_const{
+ .{
+ .iov_base = payload.items.ptr,
+ .iov_len = payload.items.len,
+ },
};
const header_offset = try reserveCustomSectionHeader(file);
- try file.writevAll(&.{iovec});
+ try file.writevAll(&iovecs);
const size = @intCast(u32, payload.items.len);
try writeCustomSectionHeader(file, header_offset, size);
}
@@ -2694,12 +2708,14 @@ fn emitDataRelocations(
var buf: [5]u8 = undefined;
leb.writeUnsignedFixed(5, &buf, count);
try payload.insertSlice(reloc_start, &buf);
- const iovec: std.os.iovec_const = .{
- .iov_base = payload.items.ptr,
- .iov_len = payload.items.len,
+ var iovecs = [_]std.os.iovec_const{
+ .{
+ .iov_base = payload.items.ptr,
+ .iov_len = payload.items.len,
+ },
};
const header_offset = try reserveCustomSectionHeader(file);
- try file.writevAll(&.{iovec});
+ try file.writevAll(&iovecs);
const size = @intCast(u32, payload.items.len);
try writeCustomSectionHeader(file, header_offset, size);
}
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig
index a3e1c25190..fc45648d9a 100644
--- a/src/link/Wasm/Atom.zig
+++ b/src/link/Wasm/Atom.zig
@@ -158,7 +158,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
.R_WASM_TABLE_INDEX_I64,
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_INDEX_SLEB64,
- => return wasm_bin.function_table.get(relocation.index) orelse 0,
+ => return wasm_bin.function_table.get(target_loc) orelse 0,
.R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.items[symbol.index].type_index,
.R_WASM_GLOBAL_INDEX_I32,
.R_WASM_GLOBAL_INDEX_LEB,
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index 011ec2e9e4..9f8c046275 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -133,6 +133,9 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
gpa.free(self.memories);
gpa.free(self.globals);
gpa.free(self.exports);
+ for (self.elements) |el| {
+ gpa.free(el.func_indexes);
+ }
gpa.free(self.elements);
gpa.free(self.features);
for (self.relocations.values()) |val| {
@@ -848,15 +851,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
reloc.offset -= relocatable_data.offset;
try atom.relocs.append(gpa, reloc);
- // TODO: Automatically append the target symbol to the indirect
- // function table when the relocation is a table index.
- //
- // if (relocation.isTableIndex()) {
- // try wasm_bin.elements.appendSymbol(gpa, .{
- // .file = object_index,
- // .sym_index = relocation.index,
- // });
- // }
+ if (relocation.isTableIndex()) {
+ try wasm_bin.function_table.putNoClobber(gpa, .{
+ .file = object_index,
+ .index = relocation.index,
+ }, 0);
+ }
}
}
@@ -865,11 +865,6 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
segment.alignment = std.math.max(segment.alignment, atom.alignment);
- segment.size = std.mem.alignForwardGeneric(
- u32,
- std.mem.alignForwardGeneric(u32, segment.size, atom.alignment) + atom.size,
- segment.alignment,
- );
if (wasm_bin.atoms.getPtr(final_index)) |last| {
last.*.next = atom;
diff --git a/src/link/Wasm/types.zig b/src/link/Wasm/types.zig
index 1dda5cdb5c..2c99f0f003 100644
--- a/src/link/Wasm/types.zig
+++ b/src/link/Wasm/types.zig
@@ -67,6 +67,18 @@ pub const Relocation = struct {
};
}
+ /// Returns true when the relocation represents a table index relocatable
+ pub fn isTableIndex(self: Relocation) bool {
+ return switch (self.relocation_type) {
+ .R_WASM_TABLE_INDEX_I32,
+ .R_WASM_TABLE_INDEX_I64,
+ .R_WASM_TABLE_INDEX_SLEB,
+ .R_WASM_TABLE_INDEX_SLEB64,
+ => true,
+ else => false,
+ };
+ }
+
pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
_ = options;
diff --git a/src/print_air.zig b/src/print_air.zig
index 69d7b63b2a..8a1a8fa950 100644
--- a/src/print_air.zig
+++ b/src/print_air.zig
@@ -328,7 +328,7 @@ const Writer = struct {
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const vector_ty = w.air.getRefType(ty_pl.ty);
const len = @intCast(usize, vector_ty.arrayLen());
- const elements = @bitCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]);
+ const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]);
try s.print("{}, [", .{vector_ty.fmtDebug()});
for (elements) |elem, i| {
@@ -533,9 +533,9 @@ const Writer = struct {
try s.writeAll(", volatile");
}
- const outputs = @bitCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.outputs_len]);
+ const outputs = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
- const inputs = @bitCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.inputs_len]);
+ const inputs = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
for (outputs) |output| {
@@ -604,7 +604,7 @@ const Writer = struct {
fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
const extra = w.air.extraData(Air.Call, pl_op.payload);
- const args = @bitCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]);
+ const args = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]);
try w.writeOperand(s, inst, 0, pl_op.operand);
try s.writeAll(", [");
for (args) |arg, i| {
@@ -674,7 +674,7 @@ const Writer = struct {
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = w.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @bitCast([]const Air.Inst.Ref, w.air.extra[case.end..][0..case.data.items_len]);
+ const items = @ptrCast([]const Air.Inst.Ref, w.air.extra[case.end..][0..case.data.items_len]);
const case_body = w.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + case.data.items_len + case_body.len;
@@ -724,11 +724,21 @@ const Writer = struct {
op_index: usize,
operand: Air.Inst.Ref,
) @TypeOf(s).Error!void {
- const dies = if (op_index < Liveness.bpi - 1)
+ const small_tomb_bits = Liveness.bpi - 1;
+ const dies = if (op_index < small_tomb_bits)
w.liveness.operandDies(inst, @intCast(Liveness.OperandInt, op_index))
else blk: {
- // TODO
- break :blk false;
+ var extra_index = w.liveness.special.get(inst).?;
+ var tomb_op_index: usize = small_tomb_bits;
+ while (true) {
+ const bits = w.liveness.extra[extra_index];
+ if (op_index < tomb_op_index + 31) {
+ break :blk @truncate(u1, bits >> @intCast(u5, op_index - tomb_op_index)) != 0;
+ }
+ if ((bits >> 31) != 0) break :blk false;
+ extra_index += 1;
+ tomb_op_index += 31;
+ } else unreachable;
};
return w.writeInstRef(s, operand, dies);
}
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
index 11f47c592b..c3157b6539 100644
--- a/src/stage1/ir.cpp
+++ b/src/stage1/ir.cpp
@@ -23052,6 +23052,12 @@ static Stage1AirInst *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, Stage1ZirI
if (type_is_invalid(src_type))
return ira->codegen->invalid_inst_gen;
+ // This logic is not quite right; this is just to get stage1 to accept valid code
+ // we use in the self-hosted compiler.
+ if (is_slice(dest_type) && is_slice(src_type)) {
+ return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, dest_type);
+ }
+
bool keep_bigger_alignment = true;
return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, ptr,
instruction->ptr->source_node, dest_type, dest_type_value->source_node,
diff --git a/src/target.zig b/src/target.zig
index 2eff4f8445..aafd65e327 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -669,6 +669,7 @@ pub fn defaultFunctionAlignment(target: std.Target) u32 {
return switch (target.cpu.arch) {
.arm, .armeb => 4,
.aarch64, .aarch64_32, .aarch64_be => 4,
+ .sparc, .sparcel, .sparcv9 => 4,
.riscv64 => 2,
else => 1,
};
diff --git a/src/test.zig b/src/test.zig
index a0d0d202d1..8c2a15e844 100644
--- a/src/test.zig
+++ b/src/test.zig
@@ -46,6 +46,7 @@ test {
defer stage2_dir.close();
// TODO make this incremental once the bug is solved that it triggers
+ // See: https://github.com/ziglang/zig/issues/11344
ctx.addErrorCasesFromDir("stage2", stage2_dir, .stage2, .Obj, false, .independent);
}
@@ -653,7 +654,14 @@ pub const TestContext = struct {
case.compiles(fixed_src);
}
- const Strategy = enum { incremental, independent };
+ const Strategy = enum {
+ /// Execute tests as independent compilations, unless they are explicitly
+ /// incremental ("foo.0.zig", "foo.1.zig", etc.)
+ independent,
+ /// Execute all tests as incremental updates to a single compilation. Explicitly
+ /// incremental tests ("foo.0.zig", "foo.1.zig", etc.) still execute in order
+ incremental,
+ };
/// Adds a compile-error test for each file in the provided directory, using the
/// selected backend and output mode. If `one_test_case_per_file` is true, a new
@@ -681,6 +689,66 @@ pub const TestContext = struct {
};
}
+ /// For a filename in the format "<filename>.X.<ext>" or "<filename>.<ext>", returns
+ /// "<filename>", "<ext>" and X parsed as a decimal number. If X is not present, or
+ /// cannot be parsed as a decimal number, it is treated as part of <filename>
+ fn getTestFileNameParts(name: []const u8) struct {
+ base_name: []const u8,
+ file_ext: []const u8,
+ test_index: ?usize,
+ } {
+ const file_ext = std.fs.path.extension(name);
+ const trimmed = name[0 .. name.len - file_ext.len]; // Trim off ".<ext>"
+ const maybe_index = std.fs.path.extension(trimmed); // Extract ".X"
+
+ // Attempt to parse index
+ const index: ?usize = if (maybe_index.len > 0)
+ std.fmt.parseInt(usize, maybe_index[1..], 10) catch null
+ else
+ null;
+
+ // Adjust "<filename>" extent based on parsing success
+ const base_name_end = trimmed.len - if (index != null) maybe_index.len else 0;
+ return .{
+ .base_name = name[0..base_name_end],
+ .file_ext = if (file_ext.len > 0) file_ext[1..] else file_ext,
+ .test_index = index,
+ };
+ }
+
+ /// Sort test filenames in-place, so that incremental test cases ("foo.0.zig",
+ /// "foo.1.zig", etc.) are contiguous and appear in numerical order.
+ fn sortTestFilenames(
+ filenames: [][]const u8,
+ ) void {
+ const Context = struct {
+ pub fn lessThan(_: @This(), a: []const u8, b: []const u8) bool {
+ const a_parts = getTestFileNameParts(a);
+ const b_parts = getTestFileNameParts(b);
+
+ // Sort "<base_name>.X.<file_ext>" based on "<base_name>" and "<file_ext>" first
+ return switch (std.mem.order(u8, a_parts.base_name, b_parts.base_name)) {
+ .lt => true,
+ .gt => false,
+ .eq => switch (std.mem.order(u8, a_parts.file_ext, b_parts.file_ext)) {
+ .lt => true,
+ .gt => false,
+ .eq => b: { // a and b differ only in their ".X" part
+
+ // Sort "<base_name>.<file_ext>" before any "<base_name>.X.<file_ext>"
+ if (a_parts.test_index == null) break :b true;
+ if (b_parts.test_index == null) break :b false;
+
+ // Make sure that incremental tests appear in linear order
+ return a_parts.test_index.? < b_parts.test_index.?;
+ },
+ },
+ };
+ }
+ };
+ std.sort.sort([]const u8, filenames, Context{}, Context.lessThan);
+ }
+
fn addErrorCasesFromDirInner(
ctx: *TestContext,
name: []const u8,
@@ -696,6 +764,9 @@ pub const TestContext = struct {
var opt_case: ?*Case = null;
var it = dir.iterate();
+ var filenames = std.ArrayList([]const u8).init(ctx.arena);
+ defer filenames.deinit();
+
while (try it.next()) |entry| {
if (entry.kind != .File) continue;
@@ -704,11 +775,46 @@ pub const TestContext = struct {
.unknown => continue,
else => {},
}
+ try filenames.append(try ctx.arena.dupe(u8, entry.name));
+ }
- current_file.* = try ctx.arena.dupe(u8, entry.name);
+ // Sort filenames, so that incremental tests are contiguous and in-order
+ sortTestFilenames(filenames.items);
+
+ var prev_filename: []const u8 = "";
+ for (filenames.items) |filename| {
+ current_file.* = filename;
+
+ { // First, check if this file is part of an incremental update sequence
+
+ // Split filename into "<base_name>.<index>.<file_ext>"
+ const prev_parts = getTestFileNameParts(prev_filename);
+ const new_parts = getTestFileNameParts(filename);
+
+ // If base_name and file_ext match, these files are in the same test sequence
+ // and the new one should be the incremented version of the previous test
+ if (std.mem.eql(u8, prev_parts.base_name, new_parts.base_name) and
+ std.mem.eql(u8, prev_parts.file_ext, new_parts.file_ext))
+ {
+
+ // This is "foo.X.zig" followed by "foo.Y.zig". Make sure that X = Y + 1
+ if (prev_parts.test_index == null) return error.InvalidIncrementalTestIndex;
+ if (new_parts.test_index == null) return error.InvalidIncrementalTestIndex;
+ if (new_parts.test_index.? != prev_parts.test_index.? + 1) return error.InvalidIncrementalTestIndex;
+ } else {
+
+ // This is not the same test sequence, so the new file must be the first file
+ // in a new sequence ("*.0.zig") or an independent test file ("*.zig")
+ if (new_parts.test_index != null and new_parts.test_index.? != 0) return error.InvalidIncrementalTestIndex;
+
+ if (strategy == .independent)
+ opt_case = null; // Generate a new independent test case for this update
+ }
+ }
+ prev_filename = filename;
const max_file_size = 10 * 1024 * 1024;
- const src = try dir.readFileAllocOptions(ctx.arena, entry.name, max_file_size, null, 1, 0);
+ const src = try dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0);
// The manifest is the last contiguous block of comments in the file
// We scan for the beginning by searching backward for the first non-empty line that does not start with "//"
@@ -720,14 +826,17 @@ pub const TestContext = struct {
// Move to beginning of line
while (cursor > 0 and src[cursor - 1] != '\n') cursor -= 1;
- // Check if line is non-empty and does not start with "//"
- if (cursor + 1 < src.len and src[cursor + 1] != '\n' and src[cursor + 1] != '\r') {
- if (std.mem.startsWith(u8, src[cursor..], "//")) {
- manifest_start = cursor;
- } else {
- break;
- }
- } else manifest_end = cursor;
+ if (std.mem.startsWith(u8, src[cursor..], "//")) {
+ manifest_start = cursor; // Contiguous comment line, include in manifest
+ } else {
+ if (manifest_start != null) break; // Encountered non-comment line, end of manifest
+
+ // We ignore all-whitespace lines following the comment block, but anything else
+ // means that there is no manifest present.
+ if (std.mem.trim(u8, src[cursor..manifest_end], " \r\n\t").len == 0) {
+ manifest_end = cursor;
+ } else break; // If it's not whitespace, there is no manifest
+ }
// Move to previous line
if (cursor != 0) cursor -= 1 else break;
@@ -738,6 +847,7 @@ pub const TestContext = struct {
if (manifest_start) |start| {
// Due to the above processing, we know that this is a contiguous block of comments
+ // and do not need to re-validate the leading "//" on each line
var manifest_it = std.mem.tokenize(u8, src[start..manifest_end], "\r\n");
// First line is the test case name
@@ -770,7 +880,6 @@ pub const TestContext = struct {
.independent => {
case.name = case_name;
case.addError(src, errors.items);
- opt_case = null;
},
.incremental => {
case.addErrorNamed(case_name, src, errors.items);
@@ -1292,7 +1401,7 @@ pub const TestContext = struct {
}
if (any_failed) {
- print("\nupdate_index={d} ", .{update_index});
+ print("\nupdate_index={d}\n", .{update_index});
return error.WrongCompileErrors;
}
},
diff --git a/src/type.zig b/src/type.zig
index 735227f9d2..b087f7ab23 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -1451,7 +1451,7 @@ pub const Type = extern union {
var duped_names = Module.ErrorSet.NameMap{};
try duped_names.ensureTotalCapacity(allocator, names.len);
for (names) |name| {
- duped_names.putAssumeCapacityNoClobber(name, .{});
+ duped_names.putAssumeCapacityNoClobber(name, {});
}
return Tag.error_set_merged.create(allocator, duped_names);
},
@@ -1520,6 +1520,13 @@ pub const Type = extern union {
) @TypeOf(writer).Error!void {
_ = options;
comptime assert(unused_format_string.len == 0);
+ if (@import("builtin").zig_backend != .stage1) {
+ // This is disabled to work around a stage2 bug where this function recursively
+ // causes more generic function instantiations resulting in an infinite loop
+ // in the compiler.
+ try writer.writeAll("[TODO fix internal compiler bug regarding dump]");
+ return;
+ }
var ty = start_type;
while (true) {
const t = ty.tag();
diff --git a/src/value.zig b/src/value.zig
index c7960741f6..713cacb7b0 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -954,6 +954,10 @@ pub const Value = extern union {
assert(ty.enumFieldCount() == 1);
break :blk 0;
},
+ .enum_literal => i: {
+ const name = val.castTag(.enum_literal).?.data;
+ break :i ty.enumFieldIndex(name).?;
+ },
// Assume it is already an integer and return it directly.
else => return val,
};
@@ -2023,6 +2027,11 @@ pub const Value = extern union {
/// This function is used by hash maps and so treats floating-point NaNs as equal
/// to each other, and not equal to other floating-point values.
/// Similarly, it treats `undef` as a distinct value from all other values.
+ /// This function has to be able to support implicit coercion of `a` to `ty`. That is,
+ /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type
+ /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
+ /// is required in order to make generic function instantiation effecient - specifically
+ /// the insertion into the monomorphized function table.
pub fn eql(a: Value, b: Value, ty: Type, target: Target) bool {
const a_tag = a.tag();
const b_tag = b.tag();
@@ -2122,19 +2131,22 @@ pub const Value = extern union {
const b_union = b.castTag(.@"union").?.data;
switch (ty.containerLayout()) {
.Packed, .Extern => {
- // In this case, we must disregard mismatching tags and compare
- // based on the in-memory bytes of the payloads.
- @panic("TODO implement comparison of extern union values");
+ const tag_ty = ty.unionTagTypeHypothetical();
+ if (!a_union.tag.eql(b_union.tag, tag_ty, target)) {
+ // In this case, we must disregard mismatching tags and compare
+ // based on the in-memory bytes of the payloads.
+ @panic("TODO comptime comparison of extern union values with mismatching tags");
+ }
},
.Auto => {
const tag_ty = ty.unionTagTypeHypothetical();
if (!a_union.tag.eql(b_union.tag, tag_ty, target)) {
return false;
}
- const active_field_ty = ty.unionFieldType(a_union.tag, target);
- return a_union.val.eql(b_union.val, active_field_ty, target);
},
}
+ const active_field_ty = ty.unionFieldType(a_union.tag, target);
+ return a_union.val.eql(b_union.val, active_field_ty, target);
},
else => {},
} else if (a_tag == .null_value or b_tag == .null_value) {
@@ -2197,8 +2209,18 @@ pub const Value = extern union {
}
return order(a, b, target).compare(.eq);
},
- else => return order(a, b, target).compare(.eq),
+ .Optional => {
+ if (a.tag() != .opt_payload and b.tag() == .opt_payload) {
+ var buffer: Payload.SubValue = .{
+ .base = .{ .tag = .opt_payload },
+ .data = a,
+ };
+ return eql(Value.initPayload(&buffer.base), b, ty, target);
+ }
+ },
+ else => {},
}
+ return order(a, b, target).compare(.eq);
}
/// This function is used by hash maps and so treats floating-point NaNs as equal
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index 119dc289b1..27d0bbf1d6 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -118,3 +118,144 @@ test "result location of function call argument through runtime condition and st
.e = if (!runtime) .a else .b,
});
}
+
+test "function call with 40 arguments" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest(thirty_nine: i32) !void {
+ const result = add(
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ thirty_nine,
+ 40,
+ );
+ try expect(result == 820);
+ try expect(thirty_nine == 39);
+ }
+
+ fn add(
+ a0: i32,
+ a1: i32,
+ a2: i32,
+ a3: i32,
+ a4: i32,
+ a5: i32,
+ a6: i32,
+ a7: i32,
+ a8: i32,
+ a9: i32,
+ a10: i32,
+ a11: i32,
+ a12: i32,
+ a13: i32,
+ a14: i32,
+ a15: i32,
+ a16: i32,
+ a17: i32,
+ a18: i32,
+ a19: i32,
+ a20: i32,
+ a21: i32,
+ a22: i32,
+ a23: i32,
+ a24: i32,
+ a25: i32,
+ a26: i32,
+ a27: i32,
+ a28: i32,
+ a29: i32,
+ a30: i32,
+ a31: i32,
+ a32: i32,
+ a33: i32,
+ a34: i32,
+ a35: i32,
+ a36: i32,
+ a37: i32,
+ a38: i32,
+ a39: i32,
+ a40: i32,
+ ) i32 {
+ return a0 +
+ a1 +
+ a2 +
+ a3 +
+ a4 +
+ a5 +
+ a6 +
+ a7 +
+ a8 +
+ a9 +
+ a10 +
+ a11 +
+ a12 +
+ a13 +
+ a14 +
+ a15 +
+ a16 +
+ a17 +
+ a18 +
+ a19 +
+ a20 +
+ a21 +
+ a22 +
+ a23 +
+ a24 +
+ a25 +
+ a26 +
+ a27 +
+ a28 +
+ a29 +
+ a30 +
+ a31 +
+ a32 +
+ a33 +
+ a34 +
+ a35 +
+ a36 +
+ a37 +
+ a38 +
+ a39 +
+ a40;
+ }
+ };
+ try S.doTheTest(39);
+}
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index 4e952828c5..8793e7cb19 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -973,7 +973,8 @@ test "variable initialization uses result locations properly with regards to the
}
test "cast between C pointer with different but compatible types" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn foo(arg: [*]c_ushort) u16 {
@@ -985,6 +986,7 @@ test "cast between C pointer with different but compatible types" {
}
};
try S.doTheTest();
+ comptime try S.doTheTest();
}
test "peer type resolve string lit with sentinel-terminated mutable slice" {
@@ -1386,3 +1388,8 @@ test "coerce undefined single-item pointer of array to error union of slice" {
const s = try b;
try expect(s.len == 0);
}
+
+test "pointer to empty struct literal to mutable slice" {
+ var x: []i32 = &.{};
+ try expect(x.len == 0);
+}
diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig
index 08f1e5bad9..2a18135fe0 100644
--- a/test/behavior/generics.zig
+++ b/test/behavior/generics.zig
@@ -306,3 +306,21 @@ test "anonymous struct return type referencing comptime parameter" {
try expect(s.data == 1234);
try expect(s.end == 5678);
}
+
+test "generic function instantiation non-duplicates" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+ const S = struct {
+ fn copy(comptime T: type, dest: []T, source: []const T) void {
+ @export(foo, .{ .name = "test_generic_instantiation_non_dupe" });
+ for (source) |s, i| dest[i] = s;
+ }
+
+ fn foo() callconv(.C) void {}
+ };
+ var buffer: [100]u8 = undefined;
+ S.copy(u8, &buffer, "hello");
+ S.copy(u8, &buffer, "hello2");
+}
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
index 32945e452d..a41f638396 100644
--- a/test/behavior/math.zig
+++ b/test/behavior/math.zig
@@ -923,6 +923,8 @@ test "comptime float rem int" {
}
test "remainder division" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
comptime try remdiv(f16);
comptime try remdiv(f32);
comptime try remdiv(f64);
@@ -938,11 +940,7 @@ fn remdiv(comptime T: type) !void {
}
test "float remainder division using @rem" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
comptime try frem(f16);
comptime try frem(f32);
@@ -973,11 +971,7 @@ fn frem(comptime T: type) !void {
}
test "float modulo division using @mod" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
comptime try fmod(f16);
comptime try fmod(f32);
diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig
index d9a3892664..10138cff01 100644
--- a/test/behavior/ptrcast.zig
+++ b/test/behavior/ptrcast.zig
@@ -217,3 +217,19 @@ test "implicit optional pointer to optional anyopaque pointer" {
var z = @ptrCast(*[4]u8, y);
try expect(std.mem.eql(u8, z, "aoeu"));
}
+
+test "@ptrCast slice to slice" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo(slice: []u32) []i32 {
+ return @ptrCast([]i32, slice);
+ }
+ };
+ var buf: [4]u32 = .{ 0, 0, 0, 0 };
+ const alias = S.foo(&buf);
+ alias[1] = 42;
+ try expect(buf[1] == 42);
+ try expect(alias.len == 4);
+}
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index b988f32a38..2d10ad0a13 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -656,3 +656,25 @@ test "switch capture copies its payload" {
try S.doTheTest();
comptime try S.doTheTest();
}
+
+test "capture of integer forwards the switch condition directly" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo(x: u8) !void {
+ switch (x) {
+ 40...45 => |capture| {
+ try expect(capture == 42);
+ },
+ else => |capture| {
+ try expect(capture == 100);
+ },
+ }
+ }
+ };
+ try S.foo(42);
+ try S.foo(100);
+ comptime try S.foo(42);
+ comptime try S.foo(100);
+}
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index 87efcbd5f1..8315ea8a22 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1168,3 +1168,18 @@ test "union with a large struct field" {
var s: S = undefined;
U.foo(U{ .s = s });
}
+
+test "comptime equality of extern unions with same tag" {
+ const S = struct {
+ const U = extern union {
+ a: i32,
+ b: f32,
+ };
+ fn foo(comptime x: U) i32 {
+ return x.a;
+ }
+ };
+ const a = S.U{ .a = 1234 };
+ const b = S.U{ .a = 1234 };
+ try expect(S.foo(a) == S.foo(b));
+}
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
index ccf22a2094..aaf61745b0 100644
--- a/test/behavior/vector.zig
+++ b/test/behavior/vector.zig
@@ -641,7 +641,7 @@ test "vector reduce operation" {
// equal.
} else {
const F = @TypeOf(expected);
- const tolerance = @sqrt(math.epsilon(TX));
+ const tolerance = @sqrt(math.floatEps(TX));
try expect(std.math.approxEqRel(F, expected, r, tolerance));
}
},
diff --git a/test/cases.zig b/test/cases.zig
index 942119f780..0fb6f381dd 100644
--- a/test/cases.zig
+++ b/test/cases.zig
@@ -16,6 +16,7 @@ pub fn addCases(ctx: *TestContext) !void {
try @import("stage2/riscv64.zig").addCases(ctx);
try @import("stage2/plan9.zig").addCases(ctx);
try @import("stage2/x86_64.zig").addCases(ctx);
+ try @import("stage2/sparcv9.zig").addCases(ctx);
// https://github.com/ziglang/zig/issues/10968
//try @import("stage2/nvptx.zig").addCases(ctx);
}
diff --git a/test/stage2/aarch64.zig b/test/stage2/aarch64.zig
index d2f40d922c..84334c2a29 100644
--- a/test/stage2/aarch64.zig
+++ b/test/stage2/aarch64.zig
@@ -159,7 +159,7 @@ pub fn addCases(ctx: *TestContext) !void {
{
var case = ctx.exe("hello world with updates", macos_aarch64);
case.addError("", &[_][]const u8{
- ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
+ ":109:9: error: struct 'tmp.tmp' has no member named 'main'",
});
// Incorrect return type
diff --git a/test/stage2/sparcv9.zig b/test/stage2/sparcv9.zig
new file mode 100644
index 0000000000..d5611a7fae
--- /dev/null
+++ b/test/stage2/sparcv9.zig
@@ -0,0 +1,39 @@
+const std = @import("std");
+const TestContext = @import("../../src/test.zig").TestContext;
+
+const linux_sparcv9 = std.zig.CrossTarget{
+ .cpu_arch = .sparcv9,
+ .os_tag = .linux,
+};
+
+pub fn addCases(ctx: *TestContext) !void {
+ {
+ var case = ctx.exe("sparcv9 hello world", linux_sparcv9);
+ // Regular old hello world
+ case.addCompareOutput(
+ \\const msg = "Hello, World!\n";
+ \\
+ \\pub export fn _start() noreturn {
+ \\ asm volatile ("ta 0x6d"
+ \\ :
+ \\ : [number] "{g1}" (4),
+ \\ [arg1] "{o0}" (1),
+ \\ [arg2] "{o1}" (@ptrToInt(msg)),
+ \\ [arg3] "{o2}" (msg.len)
+ \\ : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory"
+ \\ );
+ \\
+ \\ asm volatile ("ta 0x6d"
+ \\ :
+ \\ : [number] "{g1}" (1),
+ \\ [arg1] "{o0}" (0)
+ \\ : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory"
+ \\ );
+ \\
+ \\ unreachable;
+ \\}
+ ,
+ "Hello, World!\n",
+ );
+ }
+}
diff --git a/test/stage2/x86_64.zig b/test/stage2/x86_64.zig
index a7ebce36d3..214b32b025 100644
--- a/test/stage2/x86_64.zig
+++ b/test/stage2/x86_64.zig
@@ -1925,7 +1925,7 @@ fn addLinuxTestCases(ctx: *TestContext) !void {
var case = ctx.exe("hello world with updates", linux_x64);
case.addError("", &[_][]const u8{
- ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
+ ":109:9: error: struct 'tmp.tmp' has no member named 'main'",
});
// Incorrect return type
@@ -2176,7 +2176,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void {
{
var case = ctx.exe("darwin hello world with updates", macos_x64);
case.addError("", &[_][]const u8{
- ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
+ ":109:9: error: struct 'tmp.tmp' has no member named 'main'",
});
// Incorrect return type