mirror of
https://github.com/apple/swift.git
synced 2025-12-25 12:15:36 +01:00
This replaces a number of `#include`-s like this:
```
#include "../../../stdlib/public/SwiftShims/Visibility.h"
```
with this:
```
#include "swift/shims/Visibility.h"
```
This is needed to allow SwiftCompilerSources to use C++ headers which include SwiftShims headers. Currently trying to do that results in errors:
```
swift/swift/include/swift/Demangling/../../../stdlib/public/SwiftShims/module.modulemap:1:8: error: redefinition of module 'SwiftShims'
module SwiftShims {
^
Builds.noindex/swift/swift/bootstrapping0/lib/swift/shims/module.modulemap:1:8: note: previously defined here
module SwiftShims {
^
```
This happens because the headers in both the source dir and the build dir refer to SwiftShims headers by relative path, and both the source root and the build root contain SwiftShims headers (which are equivalent, but since they are located in different dirs, Clang treats them as different modules).
160 lines
6.5 KiB
C++
160 lines
6.5 KiB
C++
//===------------- Float16Support.cpp - Swift Float16 Support -------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implementations of:
|
|
//
|
|
// __gnu_h2f_ieee
|
|
// __gnu_f2h_ieee
|
|
// __truncdfhf2
|
|
//
|
|
// On Darwin platforms, these are provided by the host compiler-rt, but we
|
|
// can't depend on that everywhere, so we have to provide them in the Swift
|
|
// runtime. Calls to these symbols are automatically generated by LLVM when
|
|
// operating on Float16, so they are used *even though they appear to have
|
|
// no call sites anywhere in Swift*.
|
|
//
|
|
// These may require different naming or mangling on other targets; what I've
|
|
// setup here is correct for Linux/x86.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Android NDK <r21 do not provide `__aeabi_d2h` in the compiler runtime,
|
|
// provide shims in that case.
|
|
#if (defined(__ANDROID__) && defined(__ARM_ARCH_7A__) && defined(__ARM_EABI__)) || \
|
|
((defined(__i386__) || defined(__i686__) || defined(__x86_64__)) && !defined(__APPLE__))
|
|
|
|
#include "swift/shims/Visibility.h"
|
|
|
|
static unsigned toEncoding(float f) {
|
|
unsigned e;
|
|
static_assert(sizeof e == sizeof f, "float and int must have the same size");
|
|
__builtin_memcpy(&e, &f, sizeof f);
|
|
return e;
|
|
}
|
|
|
|
static float fromEncoding(unsigned int e) {
|
|
float f;
|
|
static_assert(sizeof f == sizeof e, "float and int must have the same size");
|
|
__builtin_memcpy(&f, &e, sizeof f);
|
|
return f;
|
|
}
|
|
|
|
#if defined(__x86_64__) && defined(__F16C__)
|
|
|
|
// If we're compiling the runtime for a target that has the conversion
|
|
// instruction, we might as well just use those. In theory, we'd also be
|
|
// compiling Swift for that target and not need these builtins at all,
|
|
// but who knows what could go wrong, and they're tiny functions.
|
|
# include <immintrin.h>
|
|
|
|
SWIFT_RUNTIME_EXPORT float __gnu_h2f_ieee(short h) {
|
|
return _mm_cvtss_f32(_mm_cvtph_ps(_mm_set_epi64x(0,h)));
|
|
}
|
|
|
|
SWIFT_RUNTIME_EXPORT short __gnu_f2h_ieee(float f) {
|
|
return (unsigned short)_mm_cvtsi128_si32(
|
|
_mm_cvtps_ph(_mm_set_ss(f), _MM_FROUND_CUR_DIRECTION)
|
|
);
|
|
}
|
|
|
|
#else
|
|
|
|
// Input in di, result in xmm0. We can get that calling convention in C++
|
|
// by taking a int16 arg instead of Float16, which we don't have (or else
|
|
// we wouldn't need this function).
|
|
SWIFT_RUNTIME_EXPORT float __gnu_h2f_ieee(unsigned short h) {
|
|
// We need to have two cases; subnormals and zeros, and everything else.
|
|
// We are in the first case if the exponent field (bits 14:10) is zero:
|
|
if ((h & 0x7c00) == 0) {
|
|
// Sign-extend and mask so that we get a subnormal or zero in f32
|
|
// with the appropriate sign, then multiply by the appropriate scale
|
|
// factor to produce the f32 result.
|
|
return 0x1.0p125f * fromEncoding((int)(short)h & 0x80007fffU);
|
|
}
|
|
// We have either a normal number of an infinity or NaN. All of these
|
|
// can be handled by shifting the significand into the correct position,
|
|
// extending the exponent, and then multiplying by the correct scale.
|
|
return 0x1.0p-112f * fromEncoding((int)(short)h << 13 | 0x70000000U);
|
|
}
|
|
|
|
// Input in xmm0, result in di. We can get that calling convention in C++
|
|
// by returning int16 instead of Float16, which we don't have (or else
|
|
// we wouldn't need this function).
|
|
SWIFT_RUNTIME_EXPORT unsigned short __gnu_f2h_ieee(float f) {
|
|
unsigned signbit = toEncoding(f) & 0x80000000U;
|
|
// Construct a "magic" rounding constant for f; this is a value that
|
|
// we will add and subtract from f to force rounding to occur in the
|
|
// correct position for half-precision. Half has 10 significand bits,
|
|
// float has 23, so we need to add 2**(e+13) to get the desired rounding.
|
|
float magic;
|
|
unsigned exponent = toEncoding(f) & 0x7f800000;
|
|
// Subnormals all round in the same place as the minimum normal binade,
|
|
// so treat anything below 0x1.0p-14 as 0x1.0p-14.
|
|
if (exponent < 0x38800000) exponent = 0x38800000;
|
|
// In the overflow, inf, and NaN cases, magic doesn't contribute, so we
|
|
// just use zero for anything bigger than 0x1.0p16.
|
|
if (exponent > 0x47000000) magic = fromEncoding(signbit);
|
|
else magic = fromEncoding(signbit | exponent + 0x06800000);
|
|
// Map anything with an exponent larger than 15 to infinity; this will
|
|
// avoid special-casing overflow later on.
|
|
f = 0x1.0p112f*f;
|
|
f = 0x1.0p-112f*f + magic;
|
|
f -= magic;
|
|
// We've now rounded in the correct place. One more scaling and we have
|
|
// all the bits we need (this multiply does not change anything for
|
|
// normal results, but denormalizes tiny results exactly as needed).
|
|
f *= 0x1.0p-112f;
|
|
short magnitude = toEncoding(f) >> 13 & 0x7fff;
|
|
return (int)signbit >> 16 | magnitude;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Input in xmm0, result in di. We can get that calling convention in C++
|
|
// by returning uint16 instead of Float16, which we don't have (or else
|
|
// we wouldn't need this function).
|
|
//
|
|
// Note that F16C doesn't provide this operation, so we still need a software
|
|
// implementation on those cores.
|
|
SWIFT_RUNTIME_EXPORT unsigned short __truncdfhf2(double d) {
|
|
// You can't just do (half)(float)x, because that makes the result
|
|
// susceptible to double-rounding. Instead we need to make the first
|
|
// rounding use round-to-odd, but that doesn't exist on x86, so we have
|
|
// to fake it.
|
|
float f = (float)d;
|
|
// Double-rounding can only occur if the result of rounding to float is
|
|
// an exact-halfway case for the subsequent rounding to float16. We
|
|
// can check for that significand bit pattern quickly (though we need
|
|
// to be careful about values that will result in a subnormal float16,
|
|
// as those will round in a different position):
|
|
unsigned e = toEncoding(f);
|
|
bool exactHalfway = (e & 0x1fff) == 0x1000;
|
|
double fabs = __builtin_fabsf(f);
|
|
if (exactHalfway || __builtin_fabsf(f) < 0x1.0p-14f) {
|
|
// We might be in a double-rounding case, so simulate sticky-rounding
|
|
// by comparing f and x and adjusting as needed.
|
|
double dabs = __builtin_fabs(d);
|
|
if (fabs > dabs) e -= ~e & 1;
|
|
if (fabs < dabs) e |= 1;
|
|
f = fromEncoding(e);
|
|
}
|
|
return __gnu_f2h_ieee(f);
|
|
}
|
|
|
|
#if defined(__ARM_EABI__)
|
|
SWIFT_RUNTIME_EXPORT unsigned short __aeabi_d2h(double d) {
|
|
return __truncdfhf2(d);
|
|
}
|
|
#endif
|
|
|
|
#endif // defined(__x86_64__) && !defined(__APPLE__)
|