From c32c7f55fed2678f90d7e9377bd8aaaa82ecb5c8 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 6 Apr 2024 11:20:54 +0000 Subject: [PATCH] [wasm] Fix build failure due to lack of _Float16 support WebAssembly does not support _Float16 type, so we need to guard the use of the type. Unfortunately, Clang does not provide a good way to detect the support of _Float16 type at compile time, so just disable for wasm targets. --- include/swift/Runtime/SwiftDtoa.h | 13 ++++++++++++- stdlib/public/core/Runtime.swift | 12 ++++++++++-- stdlib/public/runtime/SwiftDtoa.cpp | 2 +- stdlib/public/stubs/Stubs.cpp | 13 ++++++++++++- test/stdlib/PrintFloat16.swift | 4 ++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/include/swift/Runtime/SwiftDtoa.h b/include/swift/Runtime/SwiftDtoa.h index e15d2aa1b1c3b..3b95cbe3e1775 100644 --- a/include/swift/Runtime/SwiftDtoa.h +++ b/include/swift/Runtime/SwiftDtoa.h @@ -93,6 +93,17 @@ #define SWIFT_DTOA_BINARY16_SUPPORT 1 #endif +/// Does this platform support needs to pass _Float16 as a float in +/// C function? +#ifndef SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT +// Windows does not define FLT16_MAX even though it supports _Float16 as argument. +# if (!defined(FLT16_MAX) || defined(__wasm__)) && !defined(_WIN32) +# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 1 +# else +# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 0 +# endif +#endif + // // IEEE 754 Binary32 support (also known as "single-precision") // @@ -239,7 +250,7 @@ extern "C" { #if SWIFT_DTOA_BINARY16_SUPPORT size_t swift_dtoa_optimal_binary16_p(const void *, char *dest, size_t length); -#if defined FLT16_MAX +#if !SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT // If `_Float16` is defined, provide this convenience wrapper. size_t swift_dtoa_optimal_binary16(_Float16, char *dest, size_t length); #endif diff --git a/stdlib/public/core/Runtime.swift b/stdlib/public/core/Runtime.swift index 283341188a3a6..7f0f945188fbd 100644 --- a/stdlib/public/core/Runtime.swift +++ b/stdlib/public/core/Runtime.swift @@ -350,14 +350,22 @@ internal struct _Buffer72 { } #if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64)) +#if arch(wasm32) // Note that this takes a Float32 argument instead of Float16, because clang // doesn't have _Float16 on all platforms yet. +@available(SwiftStdlib 5.3, *) +typealias _CFloat16Argument = Float32 +#else +@available(SwiftStdlib 5.3, *) +typealias _CFloat16Argument = Float16 +#endif + @available(SwiftStdlib 5.3, *) @_silgen_name("swift_float16ToString") internal func _float16ToStringImpl( _ buffer: UnsafeMutablePointer, _ bufferLength: UInt, - _ value: Float16, + _ value: _CFloat16Argument, _ debug: Bool ) -> Int @@ -370,7 +378,7 @@ internal func _float16ToString( _internalInvariant(MemoryLayout<_Buffer32>.size == 32) var buffer = _Buffer32() let length = buffer.withBytes { (bufferPtr) in - _float16ToStringImpl(bufferPtr, 32, value, debug) + _float16ToStringImpl(bufferPtr, 32, _CFloat16Argument(value), debug) } return (buffer, length) } diff --git a/stdlib/public/runtime/SwiftDtoa.cpp b/stdlib/public/runtime/SwiftDtoa.cpp index 8c38eb6f1dc43..9dda6d7fcaed4 100644 --- a/stdlib/public/runtime/SwiftDtoa.cpp +++ b/stdlib/public/runtime/SwiftDtoa.cpp @@ -343,7 +343,7 @@ static size_t nan_details(char *dest, size_t len, int negative, int quiet, uint6 #if SWIFT_DTOA_BINARY16_SUPPORT -#if defined FLT16_MAX +#if !SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT // Format a C `_Float16` size_t swift_dtoa_optimal_binary16(_Float16 d, char *dest, size_t length) { return swift_dtoa_optimal_binary16_p(&d, dest, length); diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 6343fc997be44..c44fbd7e226d6 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -173,10 +173,21 @@ static locale_t getCLocale() { #endif #endif // SWIFT_STDLIB_HAS_LOCALE +#if SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT +using _CFloat16Argument = float; +#else +using _CFloat16Argument = _Float16; +#endif + SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API __swift_ssize_t swift_float16ToString(char *Buffer, size_t BufferLength, - _Float16 Value, bool Debug) { + _CFloat16Argument Value, bool Debug) { +#if SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT + __fp16 v = Value; + return swift_dtoa_optimal_binary16_p(&v, Buffer, BufferLength); +#else return swift_dtoa_optimal_binary16_p(&Value, Buffer, BufferLength); +#endif } SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API diff --git a/test/stdlib/PrintFloat16.swift b/test/stdlib/PrintFloat16.swift index e30cce6234791..dc7683354d375 100644 --- a/test/stdlib/PrintFloat16.swift +++ b/test/stdlib/PrintFloat16.swift @@ -127,6 +127,9 @@ PrintTests.test("Printable_Float16") { expectEqual(Float16.infinity.debugDescription, "inf") expectEqual((-Float16.infinity).debugDescription, "-inf") + // Platforms without float 16 argument passing can cause NaNs to be changed + // while being passed. + #if !arch(wasm32) for bitPattern in (0x7c01 as UInt16) ... 0x7fff { expectEqual(Float16(bitPattern: bitPattern).description, "nan") expectEqual(Float16(bitPattern: 0x8000 | bitPattern).description, "nan") @@ -144,6 +147,7 @@ PrintTests.test("Printable_Float16") { expectEqual(Float16(bitPattern: bitPattern).debugDescription, expected) expectEqual(Float16(bitPattern: 0x8000 | bitPattern).debugDescription, "-\(expected)") } + #endif #endif }