From dc2247186688ed9499dc9511d3896d3780d2f3bd Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Thu, 21 Nov 2019 18:58:05 -0500 Subject: [PATCH] Use the `truncatingIfNeeded` init on the result of these runtime funcs. The swift_floatNToString, swift_int64ToString, and swift_uint64ToString functions all return a uint64_t from c++. This is a historical accident, but these are SWIFT_RUNTIME_STDLIB_API, which means that we can't trivially change the return type. The result should naturally be size_t or int (it's always small enough to fit into *any* c integer type). However, we can elide the check in the caller at the point that the result is converted to Int, because we know that the check will always pass. This makes it so that the only overhead the wrong type introduces on 32b platforms is zeroing a register, which is free or nearly-free. --- stdlib/public/core/Runtime.swift.gyb | 50 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/stdlib/public/core/Runtime.swift.gyb b/stdlib/public/core/Runtime.swift.gyb index a68ba7488f43e..cc0c3d445e216 100644 --- a/stdlib/public/core/Runtime.swift.gyb +++ b/stdlib/public/core/Runtime.swift.gyb @@ -156,6 +156,10 @@ internal struct _Buffer72 { #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) % end +// Returns a UInt64, but that value is the length of the string, so it's +// guaranteed to fit into an Int. This is part of the ABI, so we can't +// trivially change it to Int. Callers can safely convert the result +// to any integer type without checks, however. @_silgen_name("swift_float${bits}ToString") internal func _float${bits}ToStringImpl( _ buffer: UnsafeMutablePointer, @@ -168,9 +172,9 @@ internal func _float${bits}ToString( ) -> (buffer: _Buffer32, length: Int) { _internalInvariant(MemoryLayout<_Buffer32>.size == 32) var buffer = _Buffer32() - let length = buffer.withBytes { (bufferPtr) in - Int(_float${bits}ToStringImpl(bufferPtr, 32, value, debug)) - } + let length = buffer.withBytes { (bufferPtr) in Int( + truncatingIfNeeded: _float${bits}ToStringImpl(bufferPtr, 32, value, debug) + )} return (buffer, length) } @@ -180,6 +184,10 @@ internal func _float${bits}ToString( % end +// Returns a UInt64, but that value is the length of the string, so it's +// guaranteed to fit into an Int. This is part of the ABI, so we can't +// trivially change it to Int. Callers can safely convert the result +// to any integer type without checks, however. @_silgen_name("swift_int64ToString") internal func _int64ToStringImpl( _ buffer: UnsafeMutablePointer, @@ -193,22 +201,26 @@ internal func _int64ToString( if radix >= 10 { var buffer = _Buffer32() return buffer.withBytes { (bufferPtr) in - let actualLength - = _int64ToStringImpl(bufferPtr, 32, value, radix, uppercase) - return String._fromASCII( - UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength))) + let actualLength = _int64ToStringImpl(bufferPtr, 32, value, radix, uppercase) + return String._fromASCII(UnsafeBufferPointer( + start: bufferPtr, count: Int(truncatingIfNeeded: actualLength) + )) } } else { var buffer = _Buffer72() return buffer.withBytes { (bufferPtr) in - let actualLength - = _int64ToStringImpl(bufferPtr, 72, value, radix, uppercase) - return String._fromASCII( - UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength))) + let actualLength = _int64ToStringImpl(bufferPtr, 72, value, radix, uppercase) + return String._fromASCII(UnsafeBufferPointer( + start: bufferPtr, count: Int(truncatingIfNeeded: actualLength) + )) } } } +// Returns a UInt64, but that value is the length of the string, so it's +// guaranteed to fit into an Int. This is part of the ABI, so we can't +// trivially change it to Int. Callers can safely convert the result +// to any integer type without checks, however. @_silgen_name("swift_uint64ToString") internal func _uint64ToStringImpl( _ buffer: UnsafeMutablePointer, @@ -222,18 +234,18 @@ func _uint64ToString( if radix >= 10 { var buffer = _Buffer32() return buffer.withBytes { (bufferPtr) in - let actualLength - = _uint64ToStringImpl(bufferPtr, 32, value, radix, uppercase) - return String._fromASCII( - UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength))) + let actualLength = _uint64ToStringImpl(bufferPtr, 32, value, radix, uppercase) + return String._fromASCII(UnsafeBufferPointer( + start: bufferPtr, count: Int(truncatingIfNeeded: actualLength) + )) } } else { var buffer = _Buffer72() return buffer.withBytes { (bufferPtr) in - let actualLength - = _uint64ToStringImpl(bufferPtr, 72, value, radix, uppercase) - return String._fromASCII( - UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength))) + let actualLength = _uint64ToStringImpl(bufferPtr, 72, value, radix, uppercase) + return String._fromASCII(UnsafeBufferPointer( + start: bufferPtr, count: Int(truncatingIfNeeded: actualLength) + )) } } }