Skip to content

Commit af9e5e6

Browse files
authored
Merge branch 'main' into elsh/pcmo-fixes
2 parents 5a0c73c + 6216ec6 commit af9e5e6

File tree

163 files changed

+3218
-1743
lines changed

Some content is hidden

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

163 files changed

+3218
-1743
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ And the module structure to support such applications looks like this:
7575
checking, and now even an actor which is "on a queue which is targeting
7676
another specific queue" can be properly detected using these APIs.
7777

78+
* Closures can now appear in pack expansion expressions, which allows you to
79+
construct a parameter pack of closures where each closure captures the
80+
corresponding element of some other parameter pack. For example:
81+
82+
```swift
83+
struct Manager<each T> {
84+
let fn: (repeat () -> (each T))
85+
86+
init(_ t: repeat each T) {
87+
fn = (repeat { each t })
88+
}
89+
}
90+
```
91+
7892
* [SE-0431][]:
7993
You can now require a function value to carry its actor isolation
8094
dynamically in a way that can be directly read by clients:

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private func transitivelyErase(load: LoadInst, _ context: SimplifyContext) {
281281

282282
private extension Value {
283283
func canBeCopied(into function: Function, _ context: SimplifyContext) -> Bool {
284-
if !function.isSerialized {
284+
if !function.isAnySerialized {
285285
return true
286286
}
287287

@@ -297,7 +297,7 @@ private extension Value {
297297

298298
while let value = worklist.pop() {
299299
if let fri = value as? FunctionRefInst {
300-
if !fri.referencedFunction.hasValidLinkageForFragileRef {
300+
if !fri.referencedFunction.hasValidLinkageForFragileRef(function.serializedKind) {
301301
return false
302302
}
303303
}

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,9 +655,8 @@ extension FullApplySite {
655655
return false
656656
}
657657
// Cannot inline a non-inlinable function it an inlinable function.
658-
if parentFunction.isSerialized,
659-
let calleeFunction = referencedFunction,
660-
!calleeFunction.isSerialized {
658+
if let calleeFunction = referencedFunction,
659+
!calleeFunction.canBeInlinedIntoCaller(parentFunction.serializedKind) {
661660
return false
662661
}
663662

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,37 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
136136
}
137137
public var isSerialized: Bool { bridged.isSerialized() }
138138

139-
public var hasValidLinkageForFragileRef: Bool { bridged.hasValidLinkageForFragileRef() }
139+
public var isAnySerialized: Bool { bridged.isAnySerialized() }
140+
141+
public enum SerializedKind {
142+
case notSerialized, serialized, serializedForPackage
143+
}
144+
145+
public var serializedKind: SerializedKind {
146+
switch bridged.getSerializedKind() {
147+
case .IsNotSerialized: return .notSerialized
148+
case .IsSerialized: return .serialized
149+
case .IsSerializedForPackage: return .serializedForPackage
150+
default: fatalError()
151+
}
152+
}
153+
154+
private func serializedKindBridged(_ arg: SerializedKind) -> BridgedFunction.SerializedKind {
155+
switch arg {
156+
case .notSerialized: return .IsNotSerialized
157+
case .serialized: return .IsSerialized
158+
case .serializedForPackage: return .IsSerializedForPackage
159+
default: fatalError()
160+
}
161+
}
162+
163+
public func canBeInlinedIntoCaller(_ kind: SerializedKind) -> Bool {
164+
bridged.canBeInlinedIntoCaller(serializedKindBridged(kind))
165+
}
166+
167+
public func hasValidLinkageForFragileRef(_ kind: SerializedKind) -> Bool {
168+
bridged.hasValidLinkageForFragileRef(serializedKindBridged(kind))
169+
}
140170

141171
public enum ThunkKind {
142172
case noThunk, thunk, reabstractionThunk, signatureOptimizedThunk

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ set(SWIFT_BENCH_MODULES
4040
single-source/ArrayRemoveAll
4141
single-source/ArraySetElement
4242
single-source/ArraySubscript
43+
single-source/AsyncTree
4344
single-source/BinaryFloatingPointConversionFromBinaryInteger
4445
single-source/BinaryFloatingPointProperties
4546
single-source/BitCount
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===--- AsyncTree.swift -------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 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+
import TestsUtils
14+
import Dispatch
15+
16+
public var benchmarks: [BenchmarkInfo] {
17+
guard #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) else {
18+
return []
19+
}
20+
return [
21+
BenchmarkInfo(
22+
name: "AsyncTree.100",
23+
runFunction: run_AsyncTree(treeSize: 100),
24+
tags: [.concurrency]
25+
),
26+
BenchmarkInfo(
27+
name: "AsyncTree.5000",
28+
runFunction: run_AsyncTree(treeSize: 5000),
29+
tags: [.concurrency]
30+
)
31+
]
32+
}
33+
34+
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
35+
private actor MyActor {
36+
let g: DispatchGroup
37+
38+
init(_ g: DispatchGroup) {
39+
self.g = g
40+
}
41+
42+
func test(_ n: Int) {
43+
let L = n / 2
44+
let R = n - 1 - L
45+
46+
if L > 0 {
47+
Task {
48+
self.test(L)
49+
}
50+
}
51+
52+
if R > 0 {
53+
Task {
54+
self.test(R)
55+
}
56+
}
57+
58+
g.leave()
59+
}
60+
}
61+
62+
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
63+
private func run_AsyncTree(treeSize: Int) -> (Int) -> Void {
64+
return { n in
65+
for _ in 0..<n {
66+
let g = DispatchGroup()
67+
for _ in 0..<treeSize {
68+
g.enter()
69+
}
70+
let actor = MyActor(g)
71+
Task {
72+
await actor.test(treeSize)
73+
}
74+
g.wait()
75+
}
76+
}
77+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import ArrayOfRef
2828
import ArrayRemoveAll
2929
import ArraySetElement
3030
import ArraySubscript
31+
import AsyncTree
3132
import BinaryFloatingPointConversionFromBinaryInteger
3233
import BinaryFloatingPointProperties
3334
import BitCount
@@ -223,6 +224,7 @@ register(ArrayOfRef.benchmarks)
223224
register(ArrayRemoveAll.benchmarks)
224225
register(ArraySetElement.benchmarks)
225226
register(ArraySubscript.benchmarks)
227+
register(AsyncTree.benchmarks)
226228
register(BinaryFloatingPointConversionFromBinaryInteger.benchmarks)
227229
register(BinaryFloatingPointProperties.benchmarks)
228230
register(BitCount.benchmarks)

include/swift/ABI/MetadataValues.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,6 +2511,32 @@ inline int descendingPriorityOrder(JobPriority lhs,
25112511
return (lhs == rhs ? 0 : lhs > rhs ? -1 : 1);
25122512
}
25132513

2514+
enum { PriorityBucketCount = 5 };
2515+
2516+
inline int getPriorityBucketIndex(JobPriority priority) {
2517+
// Any unknown priorities will be rounded up to a known one.
2518+
// Priorities higher than UserInteractive are clamped to UserInteractive.
2519+
// Jobs of unknown priorities will end up in the same bucket as jobs of a
2520+
// corresponding known priority. Within the bucket they will be sorted in
2521+
// FIFO order.
2522+
if (priority > JobPriority::UserInitiated) {
2523+
// UserInteractive and higher
2524+
return 0;
2525+
} else if (priority > JobPriority::Default) {
2526+
// UserInitiated
2527+
return 1;
2528+
} else if (priority > JobPriority::Utility) {
2529+
// Default
2530+
return 2;
2531+
} else if (priority > JobPriority::Background) {
2532+
// Utility
2533+
return 3;
2534+
} else {
2535+
// Background and lower
2536+
return 4;
2537+
}
2538+
}
2539+
25142540
inline JobPriority withUserInteractivePriorityDowngrade(JobPriority priority) {
25152541
return (priority == JobPriority::UserInteractive) ? JobPriority::UserInitiated
25162542
: priority;

include/swift/ABI/TaskLocal.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ class TaskLocal {
129129
return reinterpret_cast<Item *>(next & ~statusMask);
130130
}
131131

132-
void relinkNext(Item* nextOverride) {
132+
void relinkTaskGroupLocalHeadToSafeNext(Item* nextOverride) {
133133
assert(!getNext() &&
134134
"Can only relink task local item that was not pointing at anything yet");
135-
assert(nextOverride->isNextLinkPointer() ||
136-
nextOverride->isParentPointer() &&
135+
assert((nextOverride->isNextLinkPointer() ||
136+
nextOverride->isParentPointer()) &&
137137
"Currently relinking is only done within a task group to "
138138
"avoid within-taskgroup next pointers; attempted to point at "
139139
"task local declared within task group body though!");
@@ -230,6 +230,10 @@ class TaskLocal {
230230

231231
public:
232232

233+
/// Get the "current" task local storage from either the passed in
234+
/// task, or fall back to the *thread* local stored storage.
235+
static Storage* getCurrent(AsyncTask *task);
236+
233237
void initializeLinkParent(AsyncTask *task, AsyncTask *parent);
234238

235239
void pushValue(AsyncTask *task,
@@ -258,7 +262,9 @@ class TaskLocal {
258262
/// "pop" of the `B` value - it was spawned from a scope where only B was observable.
259263
void copyTo(AsyncTask *target);
260264

261-
void copyToOnlyOnlyFromCurrent(AsyncTask *target);
265+
// FIXME(concurrency): We currently copy from "all" task groups we encounter
266+
// however in practice we only
267+
void copyToOnlyOnlyFromCurrentGroup(AsyncTask *target);
262268

263269
/// Destroy and deallocate all items stored by this specific task.
264270
///

include/swift/AST/ASTContext.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "llvm/ADT/TinyPtrVector.h"
4848
#include "llvm/Support/Allocator.h"
4949
#include "llvm/Support/DataTypes.h"
50+
#include "llvm/Support/VersionTuple.h"
5051
#include "llvm/Support/VirtualOutputBackend.h"
5152
#include <functional>
5253
#include <memory>
@@ -409,9 +410,17 @@ class ASTContext final {
409410
/// Cache of module names that fail the 'canImport' test in this context.
410411
mutable llvm::StringSet<> FailedModuleImportNames;
411412

413+
/// Versions of the modules found during versioned canImport checks.
414+
struct ImportedModuleVersionInfo {
415+
llvm::VersionTuple Version;
416+
llvm::VersionTuple UnderlyingVersion;
417+
};
418+
412419
/// Cache of module names that passed the 'canImport' test. This cannot be
413-
/// mutable since it needs to be queried for dependency discovery.
414-
llvm::StringSet<> SucceededModuleImportNames;
420+
/// mutable since it needs to be queried for dependency discovery. Keep sorted
421+
/// so caller of `forEachCanImportVersionCheck` can expect deterministic
422+
/// ordering.
423+
std::map<std::string, ImportedModuleVersionInfo> CanImportModuleVersions;
415424

416425
/// Set if a `-module-alias` was passed. Used to store mapping between module aliases and
417426
/// their corresponding real names, and vice versa for a reverse lookup, which is needed to check
@@ -1102,7 +1111,12 @@ class ASTContext final {
11021111
/// module is loaded in full.
11031112
bool canImportModuleImpl(ImportPath::Module ModulePath,
11041113
llvm::VersionTuple version, bool underlyingVersion,
1105-
bool updateFailingList) const;
1114+
bool updateFailingList,
1115+
llvm::VersionTuple &foundVersion) const;
1116+
1117+
/// Add successful canImport modules.
1118+
void addSucceededCanImportModule(StringRef moduleName, bool underlyingVersion,
1119+
const llvm::VersionTuple &versionInfo);
11061120

11071121
public:
11081122
namelookup::ImportCache &getImportCache() const;
@@ -1144,10 +1158,10 @@ class ASTContext final {
11441158
llvm::VersionTuple version = llvm::VersionTuple(),
11451159
bool underlyingVersion = false) const;
11461160

1147-
/// \returns a set of names from all successfully canImport module checks.
1148-
const llvm::StringSet<> &getSuccessfulCanImportCheckNames() const {
1149-
return SucceededModuleImportNames;
1150-
}
1161+
/// Callback on each successful imported.
1162+
void forEachCanImportVersionCheck(
1163+
std::function<void(StringRef, const llvm::VersionTuple &,
1164+
const llvm::VersionTuple &)>) const;
11511165

11521166
/// \returns a module with a given name that was already loaded. If the
11531167
/// module was not loaded, returns nullptr.

0 commit comments

Comments
 (0)