Skip to content

Commit 671df74

Browse files
Use the truncatingIfNeeded init on the result of these runtime funcs. (#28426)
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.
1 parent 6f34903 commit 671df74

File tree

1 file changed

+31
-19
lines changed

1 file changed

+31
-19
lines changed

stdlib/public/core/Runtime.swift.gyb

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ internal struct _Buffer72 {
156156
#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64))
157157
% end
158158

159+
// Returns a UInt64, but that value is the length of the string, so it's
160+
// guaranteed to fit into an Int. This is part of the ABI, so we can't
161+
// trivially change it to Int. Callers can safely convert the result
162+
// to any integer type without checks, however.
159163
@_silgen_name("swift_float${bits}ToString")
160164
internal func _float${bits}ToStringImpl(
161165
_ buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
@@ -168,9 +172,9 @@ internal func _float${bits}ToString(
168172
) -> (buffer: _Buffer32, length: Int) {
169173
_internalInvariant(MemoryLayout<_Buffer32>.size == 32)
170174
var buffer = _Buffer32()
171-
let length = buffer.withBytes { (bufferPtr) in
172-
Int(_float${bits}ToStringImpl(bufferPtr, 32, value, debug))
173-
}
175+
let length = buffer.withBytes { (bufferPtr) in Int(
176+
truncatingIfNeeded: _float${bits}ToStringImpl(bufferPtr, 32, value, debug)
177+
)}
174178
return (buffer, length)
175179
}
176180

@@ -180,6 +184,10 @@ internal func _float${bits}ToString(
180184

181185
% end
182186

187+
// Returns a UInt64, but that value is the length of the string, so it's
188+
// guaranteed to fit into an Int. This is part of the ABI, so we can't
189+
// trivially change it to Int. Callers can safely convert the result
190+
// to any integer type without checks, however.
183191
@_silgen_name("swift_int64ToString")
184192
internal func _int64ToStringImpl(
185193
_ buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
@@ -193,22 +201,26 @@ internal func _int64ToString(
193201
if radix >= 10 {
194202
var buffer = _Buffer32()
195203
return buffer.withBytes { (bufferPtr) in
196-
let actualLength
197-
= _int64ToStringImpl(bufferPtr, 32, value, radix, uppercase)
198-
return String._fromASCII(
199-
UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength)))
204+
let actualLength = _int64ToStringImpl(bufferPtr, 32, value, radix, uppercase)
205+
return String._fromASCII(UnsafeBufferPointer(
206+
start: bufferPtr, count: Int(truncatingIfNeeded: actualLength)
207+
))
200208
}
201209
} else {
202210
var buffer = _Buffer72()
203211
return buffer.withBytes { (bufferPtr) in
204-
let actualLength
205-
= _int64ToStringImpl(bufferPtr, 72, value, radix, uppercase)
206-
return String._fromASCII(
207-
UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength)))
212+
let actualLength = _int64ToStringImpl(bufferPtr, 72, value, radix, uppercase)
213+
return String._fromASCII(UnsafeBufferPointer(
214+
start: bufferPtr, count: Int(truncatingIfNeeded: actualLength)
215+
))
208216
}
209217
}
210218
}
211219

220+
// Returns a UInt64, but that value is the length of the string, so it's
221+
// guaranteed to fit into an Int. This is part of the ABI, so we can't
222+
// trivially change it to Int. Callers can safely convert the result
223+
// to any integer type without checks, however.
212224
@_silgen_name("swift_uint64ToString")
213225
internal func _uint64ToStringImpl(
214226
_ buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
@@ -222,18 +234,18 @@ func _uint64ToString(
222234
if radix >= 10 {
223235
var buffer = _Buffer32()
224236
return buffer.withBytes { (bufferPtr) in
225-
let actualLength
226-
= _uint64ToStringImpl(bufferPtr, 32, value, radix, uppercase)
227-
return String._fromASCII(
228-
UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength)))
237+
let actualLength = _uint64ToStringImpl(bufferPtr, 32, value, radix, uppercase)
238+
return String._fromASCII(UnsafeBufferPointer(
239+
start: bufferPtr, count: Int(truncatingIfNeeded: actualLength)
240+
))
229241
}
230242
} else {
231243
var buffer = _Buffer72()
232244
return buffer.withBytes { (bufferPtr) in
233-
let actualLength
234-
= _uint64ToStringImpl(bufferPtr, 72, value, radix, uppercase)
235-
return String._fromASCII(
236-
UnsafeBufferPointer(start: bufferPtr, count: Int(actualLength)))
245+
let actualLength = _uint64ToStringImpl(bufferPtr, 72, value, radix, uppercase)
246+
return String._fromASCII(UnsafeBufferPointer(
247+
start: bufferPtr, count: Int(truncatingIfNeeded: actualLength)
248+
))
237249
}
238250
}
239251
}

0 commit comments

Comments
 (0)