From 6898e33edda28d79347ee9493b2625eee3d0744d Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Fri, 4 Apr 2025 16:01:26 -0700 Subject: [PATCH 1/5] [NFC] fix a dropUnusedArguments parameter name --- include/swift/SILOptimizer/Utils/Generics.h | 2 +- lib/SILOptimizer/IPO/CapturePropagation.cpp | 2 +- lib/SILOptimizer/IPO/UsePrespecialized.cpp | 2 +- lib/SILOptimizer/Utils/Generics.cpp | 11 +++++++---- lib/SILOptimizer/Utils/OptimizerBridging.cpp | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 493dbcd1c0b..ff9113c042a 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -204,7 +204,7 @@ public: ReabstractionInfo(ModuleDecl *targetModule, bool isModuleWholeModule, ApplySite Apply, SILFunction *Callee, SubstitutionMap ParamSubs, SerializedKind_t Serialized, - bool ConvertIndirectToDirect, bool dropMetatypeArgs, + bool ConvertIndirectToDirect, bool dropUnusedArguments, OptRemark::Emitter *ORE = nullptr); /// Constructs the ReabstractionInfo for generic function \p Callee with diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index 6227e4a84fe..57fe19e6cda 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -496,7 +496,7 @@ static SILFunction *getSpecializedWithDeadParams( FuncBuilder.getModule().getSwiftModule(), FuncBuilder.getModule().isWholeModule(), ApplySite(), Specialized, PAI->getSubstitutionMap(), Specialized->getSerializedKind(), - /* ConvertIndirectToDirect */ false, /*dropMetatypeArgs=*/false); + /* ConvertIndirectToDirect */ false, /*dropUnusedArguments=*/false); GenericFuncSpecializer FuncSpecializer(FuncBuilder, Specialized, ReInfo.getClonerParamSubstitutionMap(), diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index 83178343118..0ee9236aa36 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -96,7 +96,7 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) { ReabstractionInfo ReInfo(M.getSwiftModule(), M.isWholeModule(), AI, ReferencedF, Subs, IsNotSerialized, /*ConvertIndirectToDirect=*/ true, - /*dropMetatypeArgs=*/ false); + /*dropUnusedArguments=*/ false); if (!ReInfo.canBeSpecialized()) continue; diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 2e6c0512a7b..24d4ad31e4e 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -2916,7 +2916,8 @@ static bool createPrespecialized(StringRef UnspecializedName, ReabstractionInfo ReInfo(M.getSwiftModule(), M.isWholeModule(), ApplySite(), UnspecFunc, Apply.getSubstitutionMap(), IsNotSerialized, - /*ConvertIndirectToDirect= */true, /*dropMetatypeArgs=*/ false); + /*ConvertIndirectToDirect= */true, + /*dropUnusedArguments=*/ false); if (!ReInfo.canBeSpecialized()) return false; @@ -3005,7 +3006,7 @@ static bool usePrespecialized( funcBuilder.getModule().isWholeModule(), apply, refF, apply.getSubstitutionMap(), IsNotSerialized, /*ConvertIndirectToDirect=*/ true, - /*dropMetatypeArgs=*/ false); + /*dropUnusedArguments=*/ false); for (auto *SA : refF->getSpecializeAttrs()) { if (!SA->isExported()) @@ -3149,7 +3150,8 @@ static bool usePrespecialized( funcBuilder.getModule().getSwiftModule(), funcBuilder.getModule().isWholeModule(), apply, refF, newSubstMap, apply.getFunction()->getSerializedKind(), - /*ConvertIndirectToDirect=*/ true, /*dropMetatypeArgs=*/ false, nullptr); + /*ConvertIndirectToDirect=*/ true, + /*dropUnusedArguments=*/ false, nullptr); if (layoutReInfo.getSpecializedType() == reInfo.getSpecializedType()) { layoutMatches.push_back( @@ -3312,7 +3314,8 @@ void swift::trySpecializeApplyOfGeneric( FuncBuilder.getModule().isWholeModule(), Apply, RefF, Apply.getSubstitutionMap(), serializedKind, /*ConvertIndirectToDirect=*/ true, - /*dropMetatypeArgs=*/ canDropMetatypeArgs(Apply, RefF), + /*dropUnusedArguments=*/ + canDropMetatypeArgs(Apply, RefF), &ORE); if (!ReInfo.canBeSpecialized()) return; diff --git a/lib/SILOptimizer/Utils/OptimizerBridging.cpp b/lib/SILOptimizer/Utils/OptimizerBridging.cpp index e52352ced1c..02390165da1 100644 --- a/lib/SILOptimizer/Utils/OptimizerBridging.cpp +++ b/lib/SILOptimizer/Utils/OptimizerBridging.cpp @@ -206,7 +206,7 @@ OptionalBridgedFunction BridgedPassContext::specializeFunction(BridgedFunction f ReabstractionInfo ReInfo(mod->getSwiftModule(), mod->isWholeModule(), ApplySite(), origFunc, subs, IsNotSerialized, /*ConvertIndirectToDirect=*/true, - /*dropMetatypeArgs=*/false); + /*dropUnusedArguments=*/false); if (!ReInfo.canBeSpecialized()) { return {nullptr}; From 501abb09754499f0931ab31ccf346f9735677b15 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 00:51:08 -0700 Subject: [PATCH 2/5] Add SILFunctionType::isAddressable & ApplySite::isAddressable. --- include/swift/AST/LifetimeDependence.h | 5 ----- include/swift/AST/Types.h | 7 +++++++ include/swift/SIL/ApplySite.h | 4 ++++ lib/SIL/IR/ApplySite.cpp | 9 +++++++++ lib/SIL/IR/SILType.cpp | 23 +++++++++++++++++++++++ 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index 56681d4fc08..ba86fb4c734 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -289,11 +289,6 @@ public: && scopeLifetimeParamIndices->contains(index); } - bool checkAddressable(int index) const { - return hasAddressableParamIndices() - && getAddressableIndices()->contains(index); - } - std::string getString() const; void Profile(llvm::FoldingSetNodeID &ID) const; void getConcatenatedData(SmallVectorImpl &concatenatedData) const; diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index b5a94988ced..7dc36c98bcb 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -5649,6 +5649,13 @@ public: return getLifetimeDependenceFor(getNumParameters()); } + /// Return true of the specified parameter is addressable based on its type + /// lowering in 'caller's context. This includes @_addressableForDependencies + /// parameter types. + /// + /// Defined in SILType.cpp. + bool isAddressable(unsigned paramIdx, SILFunction *caller); + /// Returns true if the function type stores a Clang type that cannot /// be derived from its Swift type. Returns false otherwise, including if /// the function type is not @convention(c) or @convention(block). diff --git a/include/swift/SIL/ApplySite.h b/include/swift/SIL/ApplySite.h index 5fcf3ffa0be..0dbd1c7f2e8 100644 --- a/include/swift/SIL/ApplySite.h +++ b/include/swift/SIL/ApplySite.h @@ -641,6 +641,10 @@ public: return getArgumentParameterInfo(oper).hasOption(SILParameterInfo::Sending); } + /// Return true if 'operand' is addressable after type substitution in the + /// caller's context. + bool isAddressable(const Operand &operand) const; + static ApplySite getFromOpaqueValue(void *p) { return ApplySite(p); } friend bool operator==(ApplySite lhs, ApplySite rhs) { diff --git a/lib/SIL/IR/ApplySite.cpp b/lib/SIL/IR/ApplySite.cpp index 264ed5dd66d..dfdbde25998 100644 --- a/lib/SIL/IR/ApplySite.cpp +++ b/lib/SIL/IR/ApplySite.cpp @@ -45,3 +45,12 @@ void ApplySite::insertAfterApplication( llvm_unreachable("covered switch isn't covered"); } +bool ApplySite::isAddressable(const Operand &operand) const { + unsigned calleeArgIndex = getCalleeArgIndex(operand); + assert(calleeArgIndex >= getSubstCalleeConv().getSILArgIndexOfFirstParam()); + unsigned paramIdx = + calleeArgIndex - getSubstCalleeConv().getSILArgIndexOfFirstParam(); + + CanSILFunctionType calleeType = getSubstCalleeType(); + return calleeType->isAddressable(paramIdx, getFunction()); +} diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index f12c27d4742..52c21c45797 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -706,6 +706,29 @@ bool SILFunctionType::isNoReturnFunction(SILModule &M, return false; } +bool SILFunctionType::isAddressable(unsigned paramIdx, SILFunction *caller) { + SILParameterInfo paramInfo = getParameters()[paramIdx]; + for (auto &depInfo : getLifetimeDependencies()) { + auto *addressableIndices = depInfo.getAddressableIndices(); + if (addressableIndices && addressableIndices->contains(paramIdx)) { + return true; + } + auto *condAddressableIndices = depInfo.getConditionallyAddressableIndices(); + if (condAddressableIndices && condAddressableIndices->contains(paramIdx)) { + CanType argType = paramInfo.getArgumentType( + caller->getModule(), this, caller->getTypeExpansionContext()); + CanType contextType = + argType->hasTypeParameter() + ? caller->mapTypeIntoContext(argType)->getCanonicalType() + : argType; + auto &tl = caller->getTypeLowering(contextType); + if (tl.getRecursiveProperties().isAddressableForDependencies()) + return true; + } + } + return false; +} + #ifndef NDEBUG static bool areOnlyAbstractionDifferent(CanType type1, CanType type2) { assert(type1->isLegalSILType()); From 935b5e7ea2f919cce13027a2abfd2b429d511257 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 00:51:41 -0700 Subject: [PATCH 3/5] Fix GenericSpecializer for addressable parameters. Addressable parameters must remain indirect. Incidentally also fixes an obvious latent bug in which all specialization was disabled if any metatypes could not be specialized. Fixes rdar://145687827 (Crash of inline-stored Span properties with optimizations) --- include/swift/SILOptimizer/Utils/Generics.h | 3 +- lib/SILOptimizer/Utils/Generics.cpp | 160 +++++++++++--------- 2 files changed, 91 insertions(+), 72 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index ff9113c042a..0dc4743ef38 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -84,7 +84,8 @@ class ReabstractionInfo { /// specializer. bool ConvertIndirectToDirect = true; - /// If true, drop unused arguments. + /// If true, drop unused arguments. Dropping unused arguments is a + /// prerequisite before promoting an indirect argument to a direct argument. /// See `droppedArguments`. bool dropUnusedArguments = false; diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 24d4ad31e4e..656132f5a3b 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -455,6 +455,82 @@ static bool shouldNotSpecialize(SILFunction *Callee, SILFunction *Caller, return false; } +// Addressable parameters cannot be dropped because the address may +// escape. They also can't be promoted to direct convention, so there +// is no danger in preserving them. +static bool canConvertArg(CanSILFunctionType substType, unsigned paramIdx, + SILFunction *caller) { + return !substType->isAddressable(paramIdx, caller); +} + +// If there is no read from an indirect argument, this argument has to be +// dropped. At the call site the store to the argument's memory location could +// have been removed (based on the callee's memory effects). Therefore, +// converting such an unused indirect argument to a direct argument, would load +// an uninitialized value at the call site. This would lead to verifier errors +// and in worst case to a miscompile because IRGen can implicitly use dead +// arguments, e.g. for getting the type of a class reference. +static bool canDropUnusedArg(ApplySite apply, SILFunction *callee, + CanSILFunctionType substType, + unsigned paramIdx) { + FullApplySite fas = apply.asFullApplySite(); + if (!fas) { + return false; + } + Operand &op = fas.getOperandsWithoutIndirectResults()[paramIdx]; + return !callee->argumentMayRead(&op, op.get()); +} + +static bool isUsedAsDynamicSelf(SILArgument *arg) { + for (Operand *use : arg->getUses()) { + if (use->isTypeDependent()) + return true; + } + return false; +} + +static bool canDropMetatypeArg(ApplySite apply, SILFunction *callee, + unsigned paramIdx) { + if (!callee->isDefinition()) + return false; + + unsigned calleeArgIdx = + apply.getSubstCalleeConv().getSILArgIndexOfFirstParam() + paramIdx; + SILArgument *calleeArg = callee->getArguments()[calleeArgIdx]; + + if (isUsedAsDynamicSelf(calleeArg)) + return false; + + if (calleeArg->getType().getASTType()->hasDynamicSelfType()) + return false; + + // We don't drop metatype arguments of not applied arguments (in case of + // `partial_apply`). + unsigned firstAppliedArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg(); + if (firstAppliedArgIdx > calleeArgIdx) + return false; + + auto mt = calleeArg->getType().castTo(); + if (mt->hasRepresentation() + && mt->getRepresentation() == MetatypeRepresentation::Thin) { + return true; + } + // If the passed thick metatype value is not a `metatype` instruction + // we don't know the real metatype at runtime. It's not necessarily the + // same as the declared metatype. It could e.g. be an upcast of a class + // metatype. + SILValue callerArg = apply.getArguments()[calleeArgIdx - firstAppliedArgIdx]; + if (isa(callerArg)) + return true; + + // But: if the metatype is not used in the callee we don't have to care + // what metatype value is passed. We can just remove it. + if (onlyHaveDebugUses(calleeArg)) + return true; + + return false; +} + /// Prepares the ReabstractionInfo object for further processing and checks /// if the current function can be specialized at all. /// Returns false, if the current function cannot be specialized. @@ -771,7 +847,7 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() { for (SILParameterInfo PI : SubstitutedType->getParameters()) { auto IdxToInsert = IdxForParam; ++IdxForParam; - unsigned argIdx = i++; + unsigned paramIdx = i++; SILFunctionConventions substConv(SubstitutedType, getModule()); TypeCategory tc = getParamTypeCategory(PI, substConv, getResilienceExpansion()); @@ -782,22 +858,14 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() { case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: { - if (Callee && Apply && dropUnusedArguments) { - // If there is no read from an indirect argument, this argument has to - // be dropped. At the call site the store to the argument's memory location - // could have been removed (based on the callee's memory effects). - // Therefore, converting such an unused indirect argument to a direct - // argument, would load an uninitialized value at the call site. - // This would lead to verifier errors and in worst case to a miscompile - // because IRGen can implicitly use dead arguments, e.g. for getting the - // type of a class reference. - if (FullApplySite fas = Apply.asFullApplySite()) { - Operand &op = fas.getOperandsWithoutIndirectResults()[argIdx]; - if (!Callee->argumentMayRead(&op, op.get())) { - droppedArguments.set(IdxToInsert); - break; - } - } + if (Apply && !canConvertArg(SubstitutedType, paramIdx, + Apply.getFunction())) { + continue; + } + if (Callee && Apply && dropUnusedArguments + && canDropUnusedArg(Apply, Callee, SubstitutedType, paramIdx)) { + droppedArguments.set(IdxToInsert); + break; } Conversions.set(IdxToInsert); if (tc == LoadableAndTrivial) @@ -822,8 +890,10 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() { case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Guaranteed: { CanType ty = PI.getInterfaceType(); - if (dropUnusedArguments && isa(ty) && !ty->hasArchetype()) + if (dropUnusedArguments && isa(ty) && !ty->hasArchetype() + && Apply && Callee && canDropMetatypeArg(Apply, Callee, paramIdx)) { droppedArguments.set(IdxToInsert); + } break; } } @@ -3211,57 +3281,6 @@ static bool usePrespecialized( return false; } -static bool isUsedAsDynamicSelf(SILArgument *arg) { - for (Operand *use : arg->getUses()) { - if (use->isTypeDependent()) - return true; - } - return false; -} - -static bool canDropMetatypeArgs(ApplySite apply, SILFunction *callee) { - if (!callee->isDefinition()) - return false; - - auto calleeArgs = callee->getArguments(); - unsigned firstAppliedArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg(); - for (unsigned calleeArgIdx = 0; calleeArgIdx < calleeArgs.size(); ++calleeArgIdx) { - SILArgument *calleeArg = calleeArgs[calleeArgIdx]; - auto mt = calleeArg->getType().getAs(); - if (!mt) - continue; - - if (isUsedAsDynamicSelf(calleeArg)) - return false; - - if (calleeArg->getType().getASTType()->hasDynamicSelfType()) - return false; - - // We don't drop metatype arguments of not applied arguments (in case of `partial_apply`). - if (firstAppliedArgIdx > calleeArgIdx) - return false; - - if (mt->hasRepresentation() && mt->getRepresentation() == MetatypeRepresentation::Thin) - continue; - - // If the passed thick metatype value is not a `metatype` instruction - // we don't know the real metatype at runtime. It's not necessarily the - // same as the declared metatype. It could e.g. be an upcast of a class - // metatype. - SILValue callerArg = apply.getArguments()[calleeArgIdx - firstAppliedArgIdx]; - if (isa(callerArg)) - continue; - - // But: if the metatype is not used in the callee we don't have to care - // what metatype value is passed. We can just remove it. - if (callee->isDefinition() && onlyHaveDebugUses(calleeArg)) - continue; - - return false; - } - return true; -} - void swift::trySpecializeApplyOfGeneric( SILOptFunctionBuilder &FuncBuilder, ApplySite Apply, DeadInstructionSet &DeadApplies, @@ -3314,8 +3333,7 @@ void swift::trySpecializeApplyOfGeneric( FuncBuilder.getModule().isWholeModule(), Apply, RefF, Apply.getSubstitutionMap(), serializedKind, /*ConvertIndirectToDirect=*/ true, - /*dropUnusedArguments=*/ - canDropMetatypeArgs(Apply, RefF), + /*dropUnusedArguments=*/ true, &ORE); if (!ReInfo.canBeSpecialized()) return; From f5d7c03ff403f9fb1f6106938da0b24ae53c86e0 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 00:31:00 -0700 Subject: [PATCH 4/5] Add a test case for generic specialization and addressableForDeps. --- .../lifetime_dependence/specialize.sil | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/SILOptimizer/lifetime_dependence/specialize.sil diff --git a/test/SILOptimizer/lifetime_dependence/specialize.sil b/test/SILOptimizer/lifetime_dependence/specialize.sil new file mode 100644 index 00000000000..8574cfed4b7 --- /dev/null +++ b/test/SILOptimizer/lifetime_dependence/specialize.sil @@ -0,0 +1,54 @@ +// RUN: %target-sil-opt \ +// RUN: -generic-specializer \ +// RUN: -sil-verify-all \ +// RUN: -enable-experimental-feature LifetimeDependence \ +// RUN: -enable-experimental-feature AddressableParameters \ +// RUN: -enable-experimental-feature AddressableTypes \ +// RUN: %s | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: swift_feature_LifetimeDependence +// REQUIRES: swift_feature_AddressableParameters +// REQUIRES: swift_feature_AddressableTypes + +// Test the SIL representation for lifetime dependence scope fixup. + +sil_stage raw + +import Builtin +import Swift + +sil @makeSpan : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafePointer<τ_0_0>, Int, @thin Span<τ_0_0>.Type) -> @lifetime(borrow 0) @owned Span<τ_0_0> + +// Ensure that the addressable argument is not deleted. +// +// CHECK-LABEL: sil shared [ossa] @$s12getSpanOfOneSi_Tg5 : $@convention(thin) (@in_guaranteed CollectionOfOne) -> @lifetime(borrow address_for_deps 0) @owned Span { +sil shared [ossa] @getSpanOfOne : $@convention(thin) (@in_guaranteed CollectionOfOne) -> @lifetime(borrow address_for_deps 0) @owned Span { +[global: ] +bb0(%0 : $*CollectionOfOne): + %1 = address_to_pointer [stack_protection] %0 : $*CollectionOfOne to $Builtin.RawPointer + %2 = struct $UnsafePointer (%1 : $Builtin.RawPointer) + %3 = metatype $@thin Span.Type + %4 = integer_literal $Builtin.Int64, 1 + %5 = struct $Int (%4 : $Builtin.Int64) + %6 = function_ref @makeSpan : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafePointer<τ_0_0>, Int, @thin Span<τ_0_0>.Type) -> @lifetime(borrow 0) @owned Span<τ_0_0> + %7 = apply %6(%2, %5, %3) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafePointer<τ_0_0>, Int, @thin Span<τ_0_0>.Type) -> @lifetime(borrow 0) @owned Span<τ_0_0> + return %7 : $Span +} + +sil hidden [ossa] @testGetSpanOfOne : $@convention(thin) (@in_guaranteed CollectionOfOne) -> () { +bb0(%0 : $*CollectionOfOne): + %temp = alloc_stack $CollectionOfOne + %load = load [trivial] %0 : $*CollectionOfOne + %borrow = store_borrow %load to %temp : $*CollectionOfOne + + %fget = function_ref @getSpanOfOne : $@convention(thin) (@in_guaranteed CollectionOfOne) -> @lifetime(borrow address_for_deps 0) @owned Span + %span = apply %fget(%borrow) : $@convention(thin) <τ_0_0> (@in_guaranteed CollectionOfOne<τ_0_0>) -> @lifetime(borrow address_for_deps 0) @owned Span<τ_0_0> + + destroy_value %span : $Span + end_borrow %borrow : $*CollectionOfOne + dealloc_stack %temp : $*CollectionOfOne + + %99 = tuple () + return %99 : $() +} From 5914369b655d870d28a95f1b45a7685ba9e33cc3 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 14:21:08 -0700 Subject: [PATCH 5/5] Add a source-level optimizer test for addressable dependencies. --- .../addressable_dependency_optimization.swift | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/SILOptimizer/addressable_dependency_optimization.swift diff --git a/test/SILOptimizer/addressable_dependency_optimization.swift b/test/SILOptimizer/addressable_dependency_optimization.swift new file mode 100644 index 00000000000..3d5cb4cccfd --- /dev/null +++ b/test/SILOptimizer/addressable_dependency_optimization.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -emit-sil -parse-as-library -O -module-name=test \ +// RUN: -enable-experimental-feature LifetimeDependence \ +// RUN: -enable-experimental-feature AddressableTypes \ +// RUN: %s | %FileCheck %s + +// REQUIRES: swift_feature_AddressableTypes +// REQUIRES: swift_feature_LifetimeDependence + +// Enable this test as soon as CollectionOfOne is marked @_addressableForDependencies. +// REQUIRES: rdar145687827 + +// CHECK-LABEL: sil {{.*}}@$s4test0A10OneIntSpan1cs0D0VySiGs012CollectionOfB0VySiG_tF : $@convention(thin) (@in_guaranteed CollectionOfOne) -> @lifetime(borrow address_for_deps 0) @owned Span { +// CHECK: bb0(%0 : $*CollectionOfOne): +// CHECK: [[RP:%.*]] = address_to_pointer {{.*}}%0 to $Builtin.RawPointer +// CHECK: [[UP:%.*]] = struct $UnsafeRawPointer ([[RP]]) +// CHECK: [[OP:%.*]] = enum $Optional, #Optional.some!enumelt, [[UP]] +// CHECK: [[SPAN:%.*]] = struct $Span ([[OP]] +// CHECK: return [[SPAN]] +// CHECK-LABEL: } // end sil function '$s4test0A10OneIntSpan1cs0D0VySiGs012CollectionOfB0VySiG_tF' +@available(SwiftStdlib 6.2, *) +@lifetime(borrow c) +public func testOneIntSpan(c: CollectionOfOne) -> Span { + c.span +}