Skip to content

Commit 2715c70

Browse files
authored
Merge pull request #29220 from eeckstein/improve-array-append
stdlib: add a shortcut for Array.append(contentsOf:) in case the argument is an Array, too.
2 parents 8269522 + 172c72b commit 2715c70

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

stdlib/public/core/Array.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,7 +1220,18 @@ extension Array: RangeReplaceableCollection {
12201220
_buffer.count += writtenCount
12211221
}
12221222

1223-
if writtenUpTo == buf.endIndex {
1223+
if _slowPath(writtenUpTo == buf.endIndex) {
1224+
1225+
// A shortcut for appending an Array: If newElements is an Array then it's
1226+
// guaranteed that buf.initialize(from: newElements) already appended all
1227+
// elements. It reduces code size, because the following code
1228+
// can be removed by the optimizer by constant folding this check in a
1229+
// generic specialization.
1230+
if newElements is [Element] {
1231+
_internalInvariant(remainder.next() == nil)
1232+
return
1233+
}
1234+
12241235
// there may be elements that didn't fit in the existing buffer,
12251236
// append them in slow sequence-only mode
12261237
var newCount = _getCount()

test/SILOptimizer/array_contentof_opt.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,20 @@ public func testString(_ a: inout [String], s: String) {
5454
public func dontPropagateContiguousArray(_ a: inout ContiguousArray<UInt8>) {
5555
a += [4]
5656
}
57+
58+
// Check if the specialized Array.append<A>(contentsOf:) is reasonably optimized for Array<Int>.
59+
60+
// CHECK-LABEL: sil shared {{.*}}@$sSa6append10contentsOfyqd__n_t7ElementQyd__RszSTRd__lFSi_SaySiGTg5
61+
62+
// There should only be a single call to _createNewBuffer or reserveCapacityForAppend/reserveCapacityImpl.
63+
64+
// CHECK-NOT: apply
65+
// CHECK: [[F:%[0-9]+]] = function_ref @{{.*(_createNewBuffer|reserveCapacity).*}}
66+
// CHECK-NEXT: apply [[F]]
67+
// CHECK-NOT: apply
68+
69+
// The number of basic blocks should not exceed 20 (ideally there are no more than 16 blocks in this function).
70+
// CHECK-NOT: bb20:
71+
72+
// CHECK: } // end sil function '$sSa6append10contentsOfyqd__n_t7ElementQyd__RszSTRd__lFSi_SaySiGTg5
73+

0 commit comments

Comments
 (0)