Skip to content

Commit 5783b49

Browse files
authored
Merge pull request swiftlang#79758 from atrick/addressable-deps
Support enforcement of '@'_addressable under -enable-address-dependencies
2 parents a7de6ec + 346b7e7 commit 5783b49

17 files changed

+411
-36
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift

+9-3
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,16 @@ extension LifetimeDependentApply {
130130
var info = LifetimeSourceInfo()
131131
let hasScopedYield = applySite.parameterOperands.contains {
132132
if let dep = applySite.resultDependence(on: $0) {
133-
return dep == .scope
133+
return dep.isScoped
134134
}
135135
return false
136136
}
137137
if hasScopedYield {
138-
// for consistency, we you yieldAddress if any yielded value is an address.
138+
// for consistency, we use yieldAddress if any yielded value is an address.
139139
let targetKind = beginApply.yieldedValues.contains(where: { $0.type.isAddress })
140140
? TargetKind.yieldAddress : TargetKind.yield
141-
info.sources.push(LifetimeSource(targetKind: targetKind, convention: .scope, value: beginApply.token))
141+
info.sources.push(LifetimeSource(targetKind: targetKind, convention: .scope(addressable: false),
142+
value: beginApply.token))
142143
}
143144
for operand in applySite.parameterOperands {
144145
guard let dep = applySite.resultDependence(on: operand) else {
@@ -216,6 +217,11 @@ private extension LifetimeDependentApply.LifetimeSourceInfo {
216217
// A coroutine creates its own borrow scope, nested within its borrowed operand.
217218
bases.append(source.value)
218219
case .result, .inParameter, .inoutParameter:
220+
// addressable dependencies directly depend on the incoming address.
221+
if context.options.enableAddressDependencies() && source.convention.isAddressable {
222+
bases.append(source.value)
223+
return
224+
}
219225
// Create a new dependence on the apply's access to the argument.
220226
for varIntoducer in gatherVariableIntroducers(for: source.value, context) {
221227
let scope = LifetimeDependence.Scope(base: varIntoducer, context)

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift

+54-13
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ private struct ScopeExtension {
249249

250250
private extension LifetimeDependence.Scope {
251251
/// The instruction that introduces an extendable scope. This returns a non-nil scope introducer for
252-
/// Extendable.nestedScopes.
252+
/// ScopeExtension.nestedScopes.
253253
var extendableBegin: Instruction? {
254254
switch self {
255255
case let .access(beginAccess):
@@ -258,6 +258,17 @@ private extension LifetimeDependence.Scope {
258258
return beginBorrow.value.definingInstruction!
259259
case let .yield(yieldedValue):
260260
return yieldedValue.definingInstruction!
261+
case let .initialized(initializer):
262+
switch initializer {
263+
case let .store(initializingStore: store, initialAddress: _):
264+
if let sb = store as? StoreBorrowInst {
265+
return sb
266+
}
267+
return nil
268+
case .argument, .yield:
269+
// TODO: extend indirectly yielded scopes.
270+
return nil
271+
}
261272
default:
262273
return nil
263274
}
@@ -277,29 +288,31 @@ private extension LifetimeDependence.Scope {
277288
let accessExtension = gatherAccessExtension(beginAccess: beginAccess, innerScopes: &innerScopes)
278289
return SingleInlineArray(element: accessExtension)
279290
case let .borrowed(beginBorrow):
280-
let borrowedValue = beginBorrow.baseOperand!.value
281-
let enclosingScope = LifetimeDependence.Scope(base: borrowedValue, context)
282-
innerScopes.push(self)
283-
var innerBorrowScopes = innerScopes
284-
innerBorrowScopes.push(enclosingScope)
285-
if let extensions = enclosingScope.gatherExtensions(innerScopes: innerBorrowScopes, context) {
286-
return extensions
287-
}
288-
// This is the outermost scope to be extended because gatherExtensions did not find an enclosing scope.
289-
return SingleInlineArray(element: getOuterExtension(owner: enclosingScope.parentValue, nestedScopes: innerScopes,
290-
context))
291+
return gatherBorrowExtension(borrowedValue: beginBorrow.baseOperand!.value, innerScopes: &innerScopes, context)
292+
291293
case let .yield(yieldedValue):
292294
innerScopes.push(self)
293295
var extensions = SingleInlineArray<ScopeExtension>()
294296
let applySite = yieldedValue.definingInstruction as! BeginApplyInst
295297
for operand in applySite.parameterOperands {
296-
guard let dep = applySite.resultDependence(on: operand), dep == .scope else {
298+
guard let dep = applySite.resultDependence(on: operand), dep.isScoped else {
297299
continue
298300
}
299301
// Pass a copy of innerScopes without modifying this one.
300302
extensions.append(contentsOf: gatherOperandExtension(on: operand, innerScopes: innerScopes, context))
301303
}
302304
return extensions
305+
case let .initialized(initializer):
306+
switch initializer {
307+
case let .store(initializingStore: store, initialAddress: _):
308+
if let sb = store as? StoreBorrowInst {
309+
return gatherBorrowExtension(borrowedValue: sb.source, innerScopes: &innerScopes, context)
310+
}
311+
return nil
312+
case .argument, .yield:
313+
// TODO: extend indirectly yielded scopes.
314+
return nil
315+
}
303316
default:
304317
return nil
305318
}
@@ -360,6 +373,23 @@ private extension LifetimeDependence.Scope {
360373
}
361374
return ScopeExtension(owner: outerBeginAccess, nestedScopes: innerScopes, dependsOnArg: nil)
362375
}
376+
377+
func gatherBorrowExtension(borrowedValue: Value,
378+
innerScopes: inout SingleInlineArray<LifetimeDependence.Scope>,
379+
_ context: FunctionPassContext)
380+
-> SingleInlineArray<ScopeExtension> {
381+
382+
let enclosingScope = LifetimeDependence.Scope(base: borrowedValue, context)
383+
innerScopes.push(self)
384+
var innerBorrowScopes = innerScopes
385+
innerBorrowScopes.push(enclosingScope)
386+
if let extensions = enclosingScope.gatherExtensions(innerScopes: innerBorrowScopes, context) {
387+
return extensions
388+
}
389+
// This is the outermost scope to be extended because gatherExtensions did not find an enclosing scope.
390+
return SingleInlineArray(element: getOuterExtension(owner: enclosingScope.parentValue, nestedScopes: innerScopes,
391+
context))
392+
}
363393
}
364394

365395
/// Compute the range of the a scope owner. Nested scopes must stay within this range.
@@ -584,6 +614,17 @@ private extension LifetimeDependence.Scope {
584614
case let .yield(yieldedValue):
585615
let beginApply = yieldedValue.definingInstruction as! BeginApplyInst
586616
return beginApply.createEnd(builder, context)
617+
case let .initialized(initializer):
618+
switch initializer {
619+
case let .store(initializingStore: store, initialAddress: _):
620+
if let sb = store as? StoreBorrowInst {
621+
return builder.createEndBorrow(of: sb)
622+
}
623+
return nil
624+
case .argument, .yield:
625+
// TODO: extend indirectly yielded scopes.
626+
return nil
627+
}
587628
default:
588629
return nil
589630
}

SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ struct Options {
3232
_bridged.enableSimplificationFor(inst.bridged)
3333
}
3434

35+
func enableAddressDependencies() -> Bool {
36+
_bridged.enableAddressDependencies()
37+
}
38+
3539
var enableEmbeddedSwift: Bool {
3640
_bridged.hasFeature(.Embedded)
3741
}

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

+9-6
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ struct LifetimeDependence : CustomStringConvertible {
105105
case let .initialized(initializer):
106106
let initialAddress = initializer.initialAddress
107107
precondition(initialAddress.type.isAddress, "expected an address")
108-
precondition(initialAddress is AllocStackInst || initialAddress is FunctionArgument,
108+
precondition(initialAddress is AllocStackInst || initialAddress is FunctionArgument
109+
|| initialAddress is StoreBorrowInst,
109110
"expected storage for a a local 'let'")
110111
if case let .store(store, _) = initializer {
111-
precondition(store is StoringInstruction || store is SourceDestAddrInstruction || store is FullApplySite,
112+
precondition(store is StoringInstruction || store is SourceDestAddrInstruction || store is FullApplySite
113+
|| store is StoreBorrowInst,
112114
"expected a store")
113115
}
114116
}
@@ -217,8 +219,8 @@ extension LifetimeDependence.Scope {
217219
/// Construct a lifetime dependence scope from the base value that other values depend on. This derives the kind of
218220
/// dependence scope and its parentValue from `base`.
219221
///
220-
/// The returned Scope must be the only scope for the given 'base' value. This is generally non-recursive, except
221-
/// that finds the single borrow introducer. Use-def walking is handled by a utility such as
222+
/// The returned Scope must be the only scope for the given 'base' value. This is generally non-recursive, except
223+
/// that it tries to find the single borrow introducer. General use-def walking is handled by a utility such as
222224
/// VariableIntroducerUseDefWalker, which can handle multiple introducers.
223225
///
224226
/// `base` represents the OSSA lifetime that the dependent value must be used within. If `base` is owned, then it
@@ -291,7 +293,8 @@ extension LifetimeDependence.Scope {
291293
case let .yield(result):
292294
self.init(yield: result)
293295
case .storeBorrow(let sb):
294-
self = Self(base: sb.source, context)
296+
// Don't follow the stored value in case the dependence requires addressability.
297+
self = .initialized(.store(initializingStore: sb, initialAddress: sb))
295298
}
296299
}
297300

@@ -905,7 +908,7 @@ extension LifetimeDependenceDefUseWalker {
905908
return leafUse(of: operand)
906909
}
907910
if let dep = apply.resultDependence(on: operand),
908-
dep == .inherit {
911+
!dep.isScoped {
909912
// Operand is nonescapable and passed as a call argument. If the
910913
// result inherits its lifetime, then consider any nonescapable
911914
// result value to be a dependent use.

SwiftCompilerSources/Sources/SIL/FunctionConvention.swift

+21-2
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,25 @@ extension FunctionConvention {
237237

238238
public enum LifetimeDependenceConvention : CustomStringConvertible {
239239
case inherit
240-
case scope
240+
case scope(addressable: Bool)
241+
242+
public var isScoped: Bool {
243+
switch self {
244+
case .inherit:
245+
return false
246+
case .scope:
247+
return true
248+
}
249+
}
250+
251+
public var isAddressable: Bool {
252+
switch self {
253+
case .inherit:
254+
return false
255+
case let .scope(addressable):
256+
return addressable
257+
}
258+
}
241259

242260
public var description: String {
243261
switch self {
@@ -294,7 +312,8 @@ extension FunctionConvention {
294312
return .inherit
295313
}
296314
if scope {
297-
return .scope
315+
let addressable = bridged.checkAddressable(bridgedIndex(parameterIndex: index))
316+
return .scope(addressable: addressable)
298317
}
299318
return nil
300319
}

include/swift/AST/LifetimeDependence.h

+5
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ class LifetimeDependenceInfo {
300300
&& scopeLifetimeParamIndices->contains(index);
301301
}
302302

303+
bool checkAddressable(int index) const {
304+
return hasAddressableParamIndices()
305+
&& getAddressableIndices()->contains(index);
306+
}
307+
303308
std::string getString() const;
304309
void Profile(llvm::FoldingSetNodeID &ID) const;
305310
void getConcatenatedData(SmallVectorImpl<bool> &concatenatedData) const;

include/swift/AST/SILOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ class SILOptions {
331331
/// optimizer.
332332
bool UseAggressiveReg2MemForCodeSize = true;
333333

334+
/// Enable enforcement of lifetime dependencies on addressable arguments.
335+
/// Temporarily used to bootstrap the AddressableParameters feature.
336+
bool EnableAddressDependencies = false;
337+
334338
SILOptions() {}
335339

336340
/// Return a hash code of any components from these options that should

include/swift/Option/FrontendOptions.td

+3
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,9 @@ def platform_availability_inheritance_map_path
14891489
: Separate<["-"], "platform-availability-inheritance-map-path">, MetaVarName<"<path>">,
14901490
HelpText<"Path of the platform inheritance platform map">;
14911491

1492+
def enable_address_dependencies : Flag<["-"], "enable-address-dependencies">,
1493+
HelpText<"Enable enforcement of lifetime dependencies on addressable values.">;
1494+
14921495
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]
14931496

14941497
def disable_experimental_parser_round_trip : Flag<["-"],

include/swift/SIL/SILBridging.h

+2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ struct BridgedYieldInfoArray {
156156
struct BridgedLifetimeDependenceInfo {
157157
swift::IndexSubset *_Nullable inheritLifetimeParamIndices;
158158
swift::IndexSubset *_Nullable scopeLifetimeParamIndices;
159+
swift::IndexSubset *_Nullable addressableParamIndices;
159160
SwiftUInt targetIndex;
160161
bool immortal;
161162

@@ -164,6 +165,7 @@ struct BridgedLifetimeDependenceInfo {
164165
BRIDGED_INLINE bool empty() const;
165166
BRIDGED_INLINE bool checkInherit(SwiftInt index) const;
166167
BRIDGED_INLINE bool checkScope(SwiftInt index) const;
168+
BRIDGED_INLINE bool checkAddressable(SwiftInt index) const;
167169
BRIDGED_INLINE SwiftInt getTargetIndex() const;
168170

169171
BRIDGED_INLINE BridgedOwnedString getDebugDescription() const;

include/swift/SIL/SILBridgingImpl.h

+5
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ BridgedParameterInfo BridgedParameterInfoArray::at(SwiftInt parameterIndex) cons
146146
BridgedLifetimeDependenceInfo::BridgedLifetimeDependenceInfo(swift::LifetimeDependenceInfo info)
147147
: inheritLifetimeParamIndices(info.getInheritIndices()),
148148
scopeLifetimeParamIndices(info.getScopeIndices()),
149+
addressableParamIndices(info.getAddressableIndices()),
149150
targetIndex(info.getTargetIndex()), immortal(info.isImmortal()) {}
150151

151152
SwiftInt BridgedLifetimeDependenceInfoArray::count() const {
@@ -172,6 +173,10 @@ bool BridgedLifetimeDependenceInfo::checkScope(SwiftInt index) const {
172173
scopeLifetimeParamIndices->contains(index);
173174
}
174175

176+
bool BridgedLifetimeDependenceInfo::checkAddressable(SwiftInt index) const {
177+
return addressableParamIndices && addressableParamIndices->contains(index);
178+
}
179+
175180
SwiftInt BridgedLifetimeDependenceInfo::getTargetIndex() const {
176181
return targetIndex;
177182
}

include/swift/SILOptimizer/OptimizerBridging.h

+3
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ struct BridgedPassContext {
382382
bool enableSimplificationFor(BridgedInstruction inst) const;
383383
BRIDGED_INLINE bool enableWMORequiredDiagnostics() const;
384384

385+
// Temporary for AddressableParameters Bootstrapping.
386+
BRIDGED_INLINE bool enableAddressDependencies() const;
387+
385388
// Closure specializer
386389
SWIFT_IMPORT_UNSAFE BridgedFunction ClosureSpecializer_createEmptyFunctionWithSpecializedSignature(BridgedStringRef specializedName,
387390
const BridgedParameterInfo * _Nullable specializedBridgedParams,

include/swift/SILOptimizer/OptimizerBridgingImpl.h

+5
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,11 @@ bool BridgedPassContext::enableWMORequiredDiagnostics() const {
573573
return mod->getOptions().EnableWMORequiredDiagnostics;
574574
}
575575

576+
bool BridgedPassContext::enableAddressDependencies() const {
577+
swift::SILModule *mod = invocation->getPassManager()->getModule();
578+
return mod->getOptions().EnableAddressDependencies;
579+
}
580+
576581
static_assert((int)BridgedPassContext::SILStage::Raw == (int)swift::SILStage::Raw);
577582
static_assert((int)BridgedPassContext::SILStage::Canonical == (int)swift::SILStage::Canonical);
578583
static_assert((int)BridgedPassContext::SILStage::Lowered == (int)swift::SILStage::Lowered);

lib/DriverTool/sil_opt_main.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,10 @@ struct SILOptOptions {
592592
"swift-version",
593593
llvm::cl::desc(
594594
"The swift version to assume AST declarations correspond to"));
595+
596+
llvm::cl::opt<bool> EnableAddressDependencies = llvm::cl::opt<bool>(
597+
"enable-address-dependencies",
598+
llvm::cl::desc("Enable enforcement of lifetime dependencies on addressable values."));
595599
};
596600

597601
/// Regular expression corresponding to the value given in one of the
@@ -909,6 +913,8 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
909913
SILOpts.EnablePackMetadataStackPromotion =
910914
options.EnablePackMetadataStackPromotion;
911915

916+
SILOpts.EnableAddressDependencies = options.EnableAddressDependencies;
917+
912918
if (options.OptModeFlag == OptimizationMode::NotSet) {
913919
if (options.OptimizationGroup == OptGroup::Diagnostics)
914920
SILOpts.OptMode = OptimizationMode::NoOptimization;

lib/Frontend/CompilerInvocation.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3013,6 +3013,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
30133013
Opts.ShouldFunctionsBePreservedToDebugger &=
30143014
LTOKind.value() == IRGenLLVMLTOKind::None;
30153015

3016+
3017+
Opts.EnableAddressDependencies = Args.hasArg(OPT_enable_address_dependencies);
3018+
30163019
return false;
30173020
}
30183021

0 commit comments

Comments
 (0)