Skip to content

Commit 210c68d

Browse files
authored
[SILOptimizer] Add prespecialization for arbitray reference types (#58846)
* [SILOptimizer] Add prespecialization for arbitray reference types * Fix benchmark Package.swift * Move SimpleArray to utils * Fix multiple indirect result case * Remove leftover code from previous attempt * Fix test after rebase * Move code to compute type replacements to SpecializedFunction * Fix ownership when OSSA is enabled * Fixes after rebase * Changes after rebasing * Add feature flag for layout pre-specialization * Fix pre_specialize-macos.swift * Add compiler flag to benchmark build * Fix benchmark SwiftPM flags
1 parent 6b586b6 commit 210c68d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1200
-181
lines changed

benchmark/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ set(SWIFT_BENCH_MODULES
162162
single-source/RomanNumbers
163163
single-source/SIMDRandomMask
164164
single-source/SIMDReduceInteger
165+
single-source/SimpleArraySpecialization
165166
single-source/SequenceAlgos
166167
single-source/SetTests
167168
single-source/SevenBoom
@@ -215,6 +216,7 @@ endif()
215216

216217
set(BENCH_LIBRARY_MODULES
217218
utils/TestsUtils
219+
utils/SimpleArray
218220
)
219221

220222
set(BENCH_DRIVER_LIBRARY_MODULES

benchmark/Package.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ var multiSourceLibraries: [(parentSubDir: String, name: String)] = multiSourceLi
7878

7979
var products: [Product] = []
8080
products.append(.library(name: "TestsUtils", type: .static, targets: ["TestsUtils"]))
81+
products.append(.library(name: "SimpleArray", type: .static, targets: ["SimpleArray"]))
8182
products.append(.library(name: "DriverUtils", type: .static, targets: ["DriverUtils"]))
8283
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
8384
products.append(.library(name: "ObjectiveCTests", type: .static, targets: ["ObjectiveCTests"]))
@@ -96,6 +97,12 @@ products += multiSourceLibraries.map {
9697

9798
var targets: [Target] = []
9899
targets.append(.target(name: "TestsUtils", path: "utils", sources: ["TestsUtils.swift"]))
100+
targets.append(.target(
101+
name: "SimpleArray",
102+
path: "utils",
103+
sources: ["SimpleArray.swift"],
104+
swiftSettings: [.unsafeFlags(["-Xfrontend",
105+
"-enable-experimental-layout-prespecialization"])]))
99106
targets.append(.systemLibrary(name: "LibProc", path: "utils/LibProc"))
100107
targets.append(
101108
.target(name: "DriverUtils",
@@ -129,7 +136,7 @@ targets.append(
129136
publicHeadersPath: "."))
130137
#endif
131138

132-
var singleSourceDeps: [Target.Dependency] = [.target(name: "TestsUtils")]
139+
var singleSourceDeps: [Target.Dependency] = [.target(name: "TestsUtils"), .target(name: "SimpleArray")]
133140
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
134141
singleSourceDeps.append(.target(name: "ObjectiveCTests"))
135142
#endif
@@ -147,7 +154,9 @@ targets += singleSourceLibraries.map { name in
147154
return .target(name: name,
148155
dependencies: singleSourceDeps,
149156
path: "single-source",
150-
sources: ["\(name).swift"])
157+
sources: ["\(name).swift"],
158+
swiftSettings: [.unsafeFlags(["-Xfrontend",
159+
"-enable-experimental-layout-prespecialization"])])
151160
}
152161

153162
targets += cxxSingleSourceLibraries.map { name in

benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ function (swift_benchmark_compile_archopts)
354354
set(common_options
355355
"-c"
356356
"-target" "${target}"
357-
"-${BENCH_COMPILE_ARCHOPTS_OPT}" ${PAGE_ALIGNMENT_OPTION})
357+
"-${BENCH_COMPILE_ARCHOPTS_OPT}" ${PAGE_ALIGNMENT_OPTION}
358+
"-Xfrontend -enable-experimental-layout-prespecialization")
358359

359360
if(SWIFT_BENCHMARK_GENERATE_DEBUG_INFO)
360361
list(APPEND common_options "-g")
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// This benchmark tests prespecialization of a simplified array type
14+
15+
import TestsUtils
16+
import SimpleArray
17+
18+
public let benchmarks = [
19+
BenchmarkInfo(
20+
name: "SimpleArraySpecialization",
21+
runFunction: run_SimpleArraySpecializationBenchmarks,
22+
tags: [.abstraction, .runtime, .cpubench]
23+
),
24+
BenchmarkInfo(
25+
name: "SimpleArraySpecialization2",
26+
runFunction: run_SimpleArraySpecializationBenchmarks2,
27+
tags: [.abstraction, .runtime, .cpubench]
28+
),
29+
BenchmarkInfo(
30+
name: "SimpleArraySpecialization3",
31+
runFunction: run_SimpleArraySpecializationBenchmarks3,
32+
tags: [.abstraction, .runtime, .cpubench]
33+
),
34+
BenchmarkInfo(
35+
name: "SimpleArraySpecialization4",
36+
runFunction: run_SimpleArraySpecializationBenchmarks4,
37+
tags: [.abstraction, .runtime, .cpubench]
38+
),
39+
]
40+
41+
let xs = SimpleArray<MyClass>(capacity: 100_000)
42+
43+
@_silgen_name("_swift_stdlib_immortalize")
44+
func _stdlib_immortalize(_ obj: AnyObject)
45+
46+
import Foundation
47+
48+
49+
public final class MyClass {
50+
public var x: Int = 23
51+
}
52+
53+
54+
@inline(never)
55+
public func run_SimpleArraySpecializationBenchmarks(_ n: Int) {
56+
let myObject = MyClass()
57+
58+
// prevent refcount overflow
59+
_stdlib_immortalize(myObject)
60+
61+
for _ in 0..<n {
62+
for i in 0..<100_000 {
63+
xs.append(myObject)
64+
}
65+
xs.clear()
66+
}
67+
68+
blackHole(xs)
69+
}
70+
71+
@inline(never)
72+
public func run_SimpleArraySpecializationBenchmarks2(_ n: Int) {
73+
let myObject = MyClass()
74+
75+
// prevent refcount overflow
76+
_stdlib_immortalize(myObject)
77+
78+
for _ in 0..<n {
79+
for i in 0..<100_000 {
80+
xs.append2(myObject)
81+
}
82+
xs.clear()
83+
}
84+
85+
blackHole(xs)
86+
}
87+
88+
@inline(never)
89+
public func run_SimpleArraySpecializationBenchmarks3(_ n: Int) {
90+
let myObject = MyClass()
91+
92+
// prevent refcount overflow
93+
_stdlib_immortalize(myObject)
94+
95+
for _ in 0..<n {
96+
for i in 0..<100_000 {
97+
xs.append3(myObject)
98+
}
99+
xs.clear()
100+
}
101+
102+
blackHole(xs)
103+
}
104+
105+
@inline(never)
106+
public func run_SimpleArraySpecializationBenchmarks4(_ n: Int) {
107+
let myObject = MyClass()
108+
109+
// prevent refcount overflow
110+
_stdlib_immortalize(myObject)
111+
112+
for _ in 0..<n {
113+
for i in 0..<100_000 {
114+
xs.append4(myObject)
115+
}
116+
xs.clear()
117+
}
118+
119+
blackHole(xs)
120+
}

benchmark/utils/SimpleArray.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
@usableFromInline
2+
@frozen
3+
struct Header {
4+
@usableFromInline
5+
let capacity: Int
6+
7+
@usableFromInline
8+
var count: Int
9+
}
10+
11+
public final class SimpleArray<T> {
12+
@usableFromInline let storage: ManagedBuffer<Header, T>
13+
14+
@_alwaysEmitIntoClient
15+
@inline(__always)
16+
@inlinable
17+
var count: Int {
18+
get {
19+
return self.storage.withUnsafeMutablePointerToHeader { return $0.pointee.count }
20+
}
21+
set {
22+
return self.storage.withUnsafeMutablePointerToHeader { $0.pointee.count = newValue }
23+
}
24+
}
25+
26+
@_alwaysEmitIntoClient
27+
@inline(__always)
28+
@inlinable
29+
var capacity: Int {
30+
return self.storage.withUnsafeMutablePointerToHeader { return $0.pointee.capacity }
31+
}
32+
33+
public init(capacity: Int) {
34+
self.storage = .create(minimumCapacity: capacity) { _ in
35+
return Header(capacity: capacity, count: 0)
36+
}
37+
}
38+
39+
@_alwaysEmitIntoClient
40+
@inline(__always)
41+
@inlinable
42+
func append_internal(_ element: __owned T) {
43+
guard count < capacity else {
44+
fatalError("Array is full")
45+
}
46+
storage.withUnsafeMutablePointerToElements { ($0 + count).initialize(to: element) }
47+
count += 1
48+
}
49+
50+
@inline(never)
51+
@_effects(notEscaping self.**)
52+
@_specialize(exported: true, where @_noMetadata T : _Class)
53+
public func append(_ element: __owned T) {
54+
append_internal(element)
55+
}
56+
57+
@inline(never)
58+
@inlinable
59+
@_effects(notEscaping self.**)
60+
public func append2(_ element: __owned T) {
61+
append_internal(element)
62+
}
63+
64+
@inline(__always)
65+
@inlinable
66+
@_effects(notEscaping self.**)
67+
public func append3(_ element: __owned T) {
68+
append_internal(element)
69+
}
70+
71+
@inline(never)
72+
@_effects(notEscaping self.**)
73+
public func append4(_ element: __owned T) {
74+
append_internal(element)
75+
}
76+
77+
public func clear() {
78+
// only reset the count to avoid measuring deinitialization
79+
// overhead in benchmark
80+
self.count = 0
81+
}
82+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ import SequenceAlgos
165165
import SetTests
166166
import SevenBoom
167167
import Sim2DArray
168+
import SimpleArraySpecialization
168169
import SortArrayInClass
169170
import SortIntPyramids
170171
import SortLargeExistentials
@@ -348,6 +349,7 @@ register(SequenceAlgos.benchmarks)
348349
register(SetTests.benchmarks)
349350
register(SevenBoom.benchmarks)
350351
register(Sim2DArray.benchmarks)
352+
register(SimpleArraySpecialization.benchmarks)
351353
register(SortArrayInClass.benchmarks)
352354
register(SortIntPyramids.benchmarks)
353355
register(SortLargeExistentials.benchmarks)

include/swift/AST/Attr.h

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ class SynthesizedProtocolAttr : public DeclAttribute {
13961396
class SpecializeAttr final
13971397
: public DeclAttribute,
13981398
private llvm::TrailingObjects<SpecializeAttr, Identifier,
1399-
AvailableAttr *> {
1399+
AvailableAttr *, Type> {
14001400
friend class SpecializeAttrTargetDeclRequest;
14011401
friend TrailingObjects;
14021402

@@ -1416,19 +1416,23 @@ class SpecializeAttr final
14161416
uint64_t resolverContextData;
14171417
size_t numSPIGroups;
14181418
size_t numAvailableAttrs;
1419+
size_t numTypeErasedParams;
1420+
bool typeErasedParamsInitialized;
14191421

14201422
SpecializeAttr(SourceLoc atLoc, SourceRange Range,
14211423
TrailingWhereClause *clause, bool exported,
14221424
SpecializationKind kind, GenericSignature specializedSignature,
14231425
DeclNameRef targetFunctionName, ArrayRef<Identifier> spiGroups,
1424-
ArrayRef<AvailableAttr *> availabilityAttrs);
1426+
ArrayRef<AvailableAttr *> availabilityAttrs,
1427+
size_t typeErasedParamsCount);
14251428

14261429
public:
14271430
static SpecializeAttr *
14281431
create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range,
14291432
TrailingWhereClause *clause, bool exported, SpecializationKind kind,
14301433
DeclNameRef targetFunctionName, ArrayRef<Identifier> spiGroups,
14311434
ArrayRef<AvailableAttr *> availabilityAttrs,
1435+
size_t typeErasedParamsCount,
14321436
GenericSignature specializedSignature = nullptr);
14331437

14341438
static SpecializeAttr *create(ASTContext &ctx, bool exported,
@@ -1442,6 +1446,7 @@ class SpecializeAttr final
14421446
SpecializationKind kind,
14431447
ArrayRef<Identifier> spiGroups,
14441448
ArrayRef<AvailableAttr *> availabilityAttrs,
1449+
ArrayRef<Type> typeErasedParams,
14451450
GenericSignature specializedSignature,
14461451
DeclNameRef replacedFunction,
14471452
LazyMemberLoader *resolver, uint64_t data);
@@ -1467,6 +1472,22 @@ class SpecializeAttr final
14671472
numAvailableAttrs};
14681473
}
14691474

1475+
ArrayRef<Type> getTypeErasedParams() const {
1476+
if (!typeErasedParamsInitialized)
1477+
return {};
1478+
1479+
return {this->template getTrailingObjects<Type>(),
1480+
numTypeErasedParams};
1481+
}
1482+
1483+
void setTypeErasedParams(const ArrayRef<Type> typeErasedParams) {
1484+
assert(typeErasedParams.size() == numTypeErasedParams);
1485+
if (!typeErasedParamsInitialized) {
1486+
std::uninitialized_copy(typeErasedParams.begin(), typeErasedParams.end(), getTrailingObjects<Type>());
1487+
typeErasedParamsInitialized = true;
1488+
}
1489+
}
1490+
14701491
TrailingWhereClause *getTrailingWhereClause() const;
14711492

14721493
GenericSignature getSpecializedSignature() const {
@@ -2183,6 +2204,19 @@ class TypeSequenceAttr : public DeclAttribute {
21832204
}
21842205
};
21852206

2207+
// /// The @_noMetadata attribute, which marks a generic param as not providing metadata
2208+
// class NoMetadataAttr : public DeclAttribute {
2209+
// NoMetadataAttr(SourceLoc atLoc, SourceRange Range);
2210+
2211+
// public:
2212+
// static NoMetadataAttr *create(ASTContext &Ctx, SourceLoc atLoc,
2213+
// SourceRange Range);
2214+
2215+
// static bool classof(const DeclAttribute *DA) {
2216+
// return DA->getKind() == DAK_NoMetadata;
2217+
// }
2218+
// };
2219+
21862220
/// The @_unavailableFromAsync attribute, used to make function declarations
21872221
/// unavailable from async contexts.
21882222
class UnavailableFromAsyncAttr : public DeclAttribute {

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6601,5 +6601,18 @@ ERROR(has_symbol_invalid_expr,none,
66016601
ERROR(has_symbol_unsupported_in_closures,none,
66026602
"#_hasSymbol is not supported in closures", ())
66036603

6604+
//------------------------------------------------------------------------------
6605+
// MARK: Type erasure
6606+
//------------------------------------------------------------------------------
6607+
6608+
ERROR(no_metadata_on_non_generic_param, none,
6609+
"'@_noMetadata' must appear on a generic parameter",
6610+
())
6611+
ERROR(experimental_no_metadata_feature_can_only_be_used_when_enabled,
6612+
none, "Can not use feature when experimental layout based"
6613+
" pre-specializations are disabled! Pass the frontend flag"
6614+
" -enable-experimental-layout-prespecialization to swift to enable "
6615+
" the usage of this language feature", ())
6616+
66046617
#define UNDEFINE_DIAGNOSTIC_MACROS
66056618
#include "DefineDiagnosticMacros.h"

0 commit comments

Comments
 (0)