Skip to content

Use builtins instead of shims in FloatingPointTypes. #3454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 14, 2016
Merged
2 changes: 1 addition & 1 deletion lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3263,7 +3263,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
assert(F->isAvailableExternally() &&
"external declaration of internal SILFunction not allowed");
assert(!hasSharedVisibility(F->getLinkage()) &&
"external declarations of SILFunctions with shared visibility is not "
"external declaration of SILFunction with shared visibility is not "
"allowed");
// If F is an external declaration, there is nothing further to do,
// return.
Expand Down
85 changes: 52 additions & 33 deletions stdlib/public/SwiftShims/LibcShims.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,48 +83,67 @@ SWIFT_RUNTIME_STDLIB_INTERFACE
__swift_uint32_t
_swift_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound);

// Math library functions
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_remainderf(float, float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_squareRootf(float);
#if defined __APPLE__
static inline float _swift_stdlib_remainderf(float x, float y) {
return __builtin_remainderf(x, y);
}

static inline float _swift_stdlib_sqrtf(float x) {
return __builtin_sqrtf(x);
}

static inline double _swift_stdlib_remainder(double x, double y) {
return __builtin_remainder(x, y);
}

static inline double _swift_stdlib_sqrt(double x) {
return __builtin_sqrt(x);
}

# if defined __i386__ || defined __x86_64__
// We use void* for these because the importer doesn't know how to map Float80
// to long double.
static inline void _swift_stdlib_remainderl(void *x, const void *y) {
long double *ptr = (long double *)x;
*ptr = __builtin_remainderl(*ptr, *(const long double *)y);
}

static inline void _swift_stdlib_sqrtl(void *x) {
long double *ptr = (long double *)x;
*ptr = __builtin_sqrtl(*ptr);
}
# endif // defined __i386__ || defined __x86_64__
#else
// We want the math shims to be static inline for performance reasons, but
// that causes test failures on Linux at present, and depends on a compiler
// feature (__builtin_xxxx) that may not be available on other platforms.
// They are therefore declared as SWIFT_RUNTIME_STDLIB_INTERFACE functions
// on non-Apple platforms for now.
SWIFT_RUNTIME_STDLIB_INTERFACE
float _swift_stdlib_addProductf(float, float, float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundf(float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundevenf(float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_truncf(float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundawayf(float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_ceilf(float);
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_floorf(float);

SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_remainder(double, double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_squareRoot(double);
float _swift_stdlib_remainderf(float x, float y);

SWIFT_RUNTIME_STDLIB_INTERFACE
double _swift_stdlib_addProduct(double, double, double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_round(double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_roundeven(double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_trunc(double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_roundaway(double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_ceil(double);
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_floor(double);

// TODO: Remove horrible workaround when importer does Float80 <-> long double.
#if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
float _swift_stdlib_sqrtf(float x);

SWIFT_RUNTIME_STDLIB_INTERFACE
void _swift_stdlib_remainderl(void *_self, const void *_other);
double _swift_stdlib_remainder(double x, double y);

SWIFT_RUNTIME_STDLIB_INTERFACE
void _swift_stdlib_squareRootl(void *_self);
double _swift_stdlib_sqrt(double x);

# if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
// We use void* for these because the importer doesn't know how to map Float80
// to long double.
SWIFT_RUNTIME_STDLIB_INTERFACE
void _swift_stdlib_addProductl(void *_self, const void *_lhs, const void *_rhs);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundl(void *_self);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundevenl(void *_self);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_truncl(void *_self);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundawayl(void *_self);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_ceill(void *_self);
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_floorl(void *_self);
void _swift_stdlib_remainderl(void *x, const void *y);

SWIFT_RUNTIME_STDLIB_INTERFACE
void _swift_stdlib_sqrtl(void *x);
# endif // defined __i386__ || defined __x86_64__
#endif

#ifdef __cplusplus
}} // extern "C", namespace swift
#endif

#endif // SWIFT_STDLIB_SHIMS_LIBCSHIMS_H

52 changes: 20 additions & 32 deletions stdlib/public/core/FloatingPointTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -510,37 +510,30 @@ extension ${Self}: BinaryFloatingPoint {

@_transparent
public mutating func round(_ rule: FloatingPointRoundingRule) {
%if bits == 80:
switch rule {
case .toNearestOrAwayFromZero:
_swift_stdlib_roundl(&self)
_value = Builtin.int_round_FPIEEE${bits}(_value)
case .toNearestOrEven:
_swift_stdlib_roundevenl(&self)
// TODO: switch to roundeven( ) or corresponding builtin when
// available; rint assumes default floating-point environment.
// This is pretty OK at present, since there's no Swifty way
// to fuss with the environment, but we should fix it in the
// long term.
_value = Builtin.int_rint_FPIEEE${bits}(_value)
case .towardZero:
_swift_stdlib_truncl(&self)
_value = Builtin.int_trunc_FPIEEE${bits}(_value)
case .awayFromZero:
_swift_stdlib_roundawayl(&self)
case .up:
_swift_stdlib_ceill(&self)
case .down:
_swift_stdlib_floorl(&self)
}
%else:
switch rule {
case .toNearestOrAwayFromZero:
self = _swift_stdlib_round${cFuncSuffix(bits)}(self)
case .toNearestOrEven:
self = _swift_stdlib_roundeven${cFuncSuffix(bits)}(self)
case .towardZero:
self = _swift_stdlib_trunc${cFuncSuffix(bits)}(self)
case .awayFromZero:
self = _swift_stdlib_roundaway${cFuncSuffix(bits)}(self)
if sign == .minus {
_value = Builtin.int_floor_FPIEEE${bits}(_value)
}
else {
_value = Builtin.int_ceil_FPIEEE${bits}(_value)
}
case .up:
self = _swift_stdlib_ceil${cFuncSuffix(bits)}(self)
_value = Builtin.int_ceil_FPIEEE${bits}(_value)
case .down:
self = _swift_stdlib_floor${cFuncSuffix(bits)}(self)
_value = Builtin.int_floor_FPIEEE${bits}(_value)
}
%end
}

@_transparent
Expand Down Expand Up @@ -586,21 +579,16 @@ extension ${Self}: BinaryFloatingPoint {
@_transparent
public mutating func formSquareRoot( ) {
%if bits == 80:
_swift_stdlib_squareRootl(&self)
_swift_stdlib_sqrtl(&self)
%else:
self = _swift_stdlib_squareRoot${cFuncSuffix(bits)}(self)
self = _swift_stdlib_sqrt${cFuncSuffix(bits)}(self)
%end

}

@_transparent
public mutating func addProduct(_ lhs: ${Self}, _ rhs: ${Self}) {
%if bits == 80:
var lhs = lhs
var rhs = rhs
_swift_stdlib_addProductl(&self, &lhs, &rhs)
%else:
self = _swift_stdlib_addProduct${cFuncSuffix(bits)}(self, lhs, rhs)
%end
_value = Builtin.int_fma_FPIEEE${bits}(lhs._value, rhs._value, _value)
}

@_transparent
Expand Down
113 changes: 23 additions & 90 deletions stdlib/public/stubs/LibcShims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,104 +125,37 @@ swift::_swift_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound) {
return RandomUniform(getGlobalMT19937());
}

float swift::_swift_stdlib_remainderf(float dividend, float divisor) {
return std::remainder(dividend, divisor);
#if !defined __APPLE__
// These functions are static inline on Apple platforms, and therefore
// function bodies are not needed here. They should ideally be made static
// inlines on other platforms as well.
float swift::_swift_stdlib_remainderf(float x, float y) {
return std::remainder(x, y);
}

float swift::_swift_stdlib_squareRootf(float x) { return std::sqrt(x); }

float swift::_swift_stdlib_addProductf(float addend, float lhs, float rhs) {
return std::fma(lhs, rhs, addend);
}

float swift::_swift_stdlib_roundf(float x) { return std::round(x); }

float swift::_swift_stdlib_roundevenf(float x) {
// TODO: switch to roundevenf( ) when available in backing C libraries, or
// open-code here to correctly handle non-default fenv.
return std::rint(x);
}

float swift::_swift_stdlib_truncf(float x) { return std::trunc(x); }

float swift::_swift_stdlib_roundawayf(float x) {
// No corresponding C function, but trivial to fake.
return x < 0 ? std::floor(x) : std::ceil(x);
}

float swift::_swift_stdlib_ceilf(float x) { return std::ceil(x); }

float swift::_swift_stdlib_floorf(float x) { return std::floor(x); }

double swift::_swift_stdlib_remainder(double dividend, double divisor) {
return std::remainder(dividend, divisor);
}

double swift::_swift_stdlib_squareRoot(double x) { return std::sqrt(x); }

double swift::_swift_stdlib_addProduct(double addend, double lhs, double rhs) {
return std::fma(lhs, rhs, addend);
}

double swift::_swift_stdlib_round(double x) { return std::round(x); }

double swift::_swift_stdlib_roundeven(double x) {
// TODO: switch to roundevenf( ) when available in backing C libraries, or
// open-code here to correctly handle non-default fenv.
return std::rint(x);
}

double swift::_swift_stdlib_trunc(double x) { return std::trunc(x); }

double swift::_swift_stdlib_roundaway(double x) {
// No corresponding C function, but trivial to fake.
return x < 0 ? std::floor(x) : std::ceil(x);
}

double swift::_swift_stdlib_ceil(double x) { return std::ceil(x); }

double swift::_swift_stdlib_floor(double x) { return std::floor(x); }

#if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
void swift::_swift_stdlib_remainderl(void *_self, const void *_other) {
*(long double *)_self = std::remainder(*(long double *)_self,
*(const long double *)_other);
}

void swift::_swift_stdlib_squareRootl(void *_self) {
*(long double *)_self = std::sqrt(*(long double *)_self);
}

void
swift::_swift_stdlib_addProductl(void *_self,
const void *_lhs, const void *_rhs) {
*(long double *)_self = std::fma(*(const long double *)_lhs,
*(const long double *)_rhs,
*(long double *)_self);
}

void swift::_swift_stdlib_roundl(void *_self) {
*(long double *)_self = std::round(*(long double *)_self);
}

void swift::_swift_stdlib_roundevenl(void *_self) {
*(long double *)_self = std::rint(*(long double *)_self);
float swift::_swift_stdlib_sqrtf(float x) {
return std::sqrt(x);
}

void swift::_swift_stdlib_truncl(void *_self) {
*(long double *)_self = std::trunc(*(long double *)_self);
double swift::_swift_stdlib_remainder(double x, double y) {
return std::remainder(x, y);
}

void swift::_swift_stdlib_roundawayl(void *_self) {
long double *ptr = (long double *)_self;
*ptr = *ptr < 0 ? std::floor(*ptr) : std::ceil(*ptr);
double swift::_swift_stdlib_sqrt(double x) {
return std::sqrt(x);
}

void swift::_swift_stdlib_ceill(void *_self) {
*(long double *)_self = std::ceil(*(long double *)_self);
# if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
// We use void* for these because the importer doesn't know how to map Float80
// to long double.
void swift::_swift_stdlib_remainderl(void *x, const void *y) {
long double *ptr = (long double *)x;
*ptr = std::remainder(*ptr, *(const long double *)y);
}

void swift::_swift_stdlib_floorl(void *_self) {
*(long double *)_self = std::floor(*(long double *)_self);
void swift::_swift_stdlib_sqrtl(void *x) {
long double *ptr = (long double *)x;
*ptr = std::sqrt(*ptr);
}
#endif // Have Float80
# endif
#endif // !defined __APPLE__