[SILOptimizer] Preserve arg attrs at cloning.

Arguments are copied into new cloned functions in a number of places.
Wherever that happens, be sure to transfer the attributes as well.
This commit is contained in:
Nate Chandler
2022-09-13 10:15:45 -07:00
parent e03c5683b1
commit 5d14610043
19 changed files with 480 additions and 16 deletions

View File

@@ -123,8 +123,10 @@ void SILBasicBlock::cloneArgumentList(SILBasicBlock *Other) {
if (isEntry()) { if (isEntry()) {
assert(args_empty() && "Expected to have no arguments"); assert(args_empty() && "Expected to have no arguments");
for (auto *FuncArg : Other->getSILFunctionArguments()) { for (auto *FuncArg : Other->getSILFunctionArguments()) {
createFunctionArgument(FuncArg->getType(), auto *NewArg =
FuncArg->getDecl()); createFunctionArgument(FuncArg->getType(), FuncArg->getDecl());
NewArg->setNoImplicitCopy(FuncArg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(FuncArg->getLifetimeAnnotation());
} }
return; return;
} }

View File

@@ -390,9 +390,12 @@ void FunctionSignatureTransform::ArgumentExplosionFinalizeOptimizedFunction() {
for (auto *Node : LeafNodes) { for (auto *Node : LeafNodes) {
auto OwnershipKind = *AD.getTransformedOwnershipKind(Node->getType()); auto OwnershipKind = *AD.getTransformedOwnershipKind(Node->getType());
LeafValues.push_back( auto *Argument =
BB->insertFunctionArgument(ArgOffset, Node->getType(), OwnershipKind, BB->insertFunctionArgument(ArgOffset, Node->getType(), OwnershipKind,
BB->getArgument(OldArgIndex)->getDecl())); BB->getArgument(OldArgIndex)->getDecl());
Argument->setNoImplicitCopy(AD.Arg->isNoImplicitCopy());
Argument->setLifetimeAnnotation(AD.Arg->getLifetimeAnnotation());
LeafValues.push_back(Argument);
TransformDescriptor.AIM[TotalArgIndex - 1] = AD.Index; TransformDescriptor.AIM[TotalArgIndex - 1] = AD.Index;
++ArgOffset; ++ArgOffset;
++TotalArgIndex; ++TotalArgIndex;

View File

@@ -165,6 +165,8 @@ void ExistentialSpecializerCloner::cloneArguments(
LoweredTy.getCategoryType(ArgDesc.Arg->getType().getCategory()); LoweredTy.getCategoryType(ArgDesc.Arg->getType().getCategory());
auto *NewArg = auto *NewArg =
ClonedEntryBB->createFunctionArgument(MappedTy, ArgDesc.Decl); ClonedEntryBB->createFunctionArgument(MappedTy, ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
NewArg->setOwnershipKind(ValueOwnershipKind( NewArg->setOwnershipKind(ValueOwnershipKind(
NewF, MappedTy, ArgDesc.Arg->getArgumentConvention())); NewF, MappedTy, ArgDesc.Arg->getArgumentConvention()));
entryArgs.push_back(NewArg); entryArgs.push_back(NewArg);
@@ -180,6 +182,8 @@ void ExistentialSpecializerCloner::cloneArguments(
GenericSILType, ArgDesc.Decl, GenericSILType, ArgDesc.Decl,
ValueOwnershipKind(NewF, GenericSILType, ValueOwnershipKind(NewF, GenericSILType,
ArgDesc.Arg->getArgumentConvention())); ArgDesc.Arg->getArgumentConvention()));
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
// Determine the Conformances. // Determine the Conformances.
SILType ExistentialType = ArgDesc.Arg->getType().getObjectType(); SILType ExistentialType = ArgDesc.Arg->getType().getObjectType();
CanType OpenedType = NewArg->getType().getASTType(); CanType OpenedType = NewArg->getType().getASTType();
@@ -402,7 +406,10 @@ void ExistentialTransform::populateThunkBody() {
auto *ThunkBody = F->createBasicBlock(); auto *ThunkBody = F->createBasicBlock();
for (auto &ArgDesc : ArgumentDescList) { for (auto &ArgDesc : ArgumentDescList) {
auto argumentType = ArgDesc.Arg->getType(); auto argumentType = ArgDesc.Arg->getType();
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl); auto *NewArg =
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
} }
/// Builder to add new instructions in the Thunk. /// Builder to add new instructions in the Thunk.

View File

@@ -566,7 +566,10 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
F->setInlineStrategy(AlwaysInline); F->setInlineStrategy(AlwaysInline);
SILBasicBlock *ThunkBody = F->createBasicBlock(); SILBasicBlock *ThunkBody = F->createBasicBlock();
for (auto &ArgDesc : TransformDescriptor.ArgumentDescList) { for (auto &ArgDesc : TransformDescriptor.ArgumentDescList) {
ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl); auto *NewArg =
ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
} }
SILLocation Loc = RegularLocation::getAutoGeneratedLocation(); SILLocation Loc = RegularLocation::getAutoGeneratedLocation();

View File

@@ -197,8 +197,12 @@ void CapturePropagationCloner::cloneClosure(
SILArgument *Arg = OrigEntryBB->getArgument(ArgIdx); SILArgument *Arg = OrigEntryBB->getArgument(ArgIdx);
SILValue MappedValue = ClonedEntryBB->createFunctionArgument( auto *MappedValue = ClonedEntryBB->createFunctionArgument(
remapType(Arg->getType()), Arg->getDecl()); remapType(Arg->getType()), Arg->getDecl());
MappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(Arg)->isNoImplicitCopy());
MappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(Arg)->getLifetimeAnnotation());
entryArgs.push_back(MappedValue); entryArgs.push_back(MappedValue);
} }
assert(OrigEntryBB->args_size() - ArgIdx == PartialApplyArgs.size() assert(OrigEntryBB->args_size() - ArgIdx == PartialApplyArgs.size()

View File

@@ -806,8 +806,12 @@ void ClosureSpecCloner::populateCloned() {
// Otherwise, create a new argument which copies the original argument // Otherwise, create a new argument which copies the original argument
auto typeInContext = Cloned->getLoweredType(Arg->getType()); auto typeInContext = Cloned->getLoweredType(Arg->getType());
SILValue MappedValue = auto *MappedValue =
ClonedEntryBB->createFunctionArgument(typeInContext, Arg->getDecl()); ClonedEntryBB->createFunctionArgument(typeInContext, Arg->getDecl());
MappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(Arg)->isNoImplicitCopy());
MappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(Arg)->getLifetimeAnnotation());
entryArgs.push_back(MappedValue); entryArgs.push_back(MappedValue);
} }

View File

@@ -491,8 +491,12 @@ void ClosureCloner::populateCloned() {
for (; ai != ae; ++argNo, ++ai) { for (; ai != ae; ++argNo, ++ai) {
if (!promotableIndices.count(argNo)) { if (!promotableIndices.count(argNo)) {
// Simply create a new argument which copies the original argument // Simply create a new argument which copies the original argument
SILValue mappedValue = clonedEntryBB->createFunctionArgument( auto *mappedValue = clonedEntryBB->createFunctionArgument(
(*ai)->getType(), (*ai)->getDecl()); (*ai)->getType(), (*ai)->getDecl());
mappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(*ai)->isNoImplicitCopy());
mappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(*ai)->getLifetimeAnnotation());
entryArgs.push_back(mappedValue); entryArgs.push_back(mappedValue);
continue; continue;
} }
@@ -504,8 +508,13 @@ void ClosureCloner::populateCloned() {
auto boxedTy = getSILBoxFieldType(TypeExpansionContext(*cloned), boxTy, auto boxedTy = getSILBoxFieldType(TypeExpansionContext(*cloned), boxTy,
cloned->getModule().Types, 0) cloned->getModule().Types, 0)
.getObjectType(); .getObjectType();
SILValue mappedValue = auto *newArg =
clonedEntryBB->createFunctionArgument(boxedTy, (*ai)->getDecl()); clonedEntryBB->createFunctionArgument(boxedTy, (*ai)->getDecl());
newArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*ai)->isNoImplicitCopy());
newArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*ai)->getLifetimeAnnotation());
SILValue mappedValue = newArg;
// If SIL ownership is enabled, we need to perform a borrow here if we have // If SIL ownership is enabled, we need to perform a borrow here if we have
// a non-trivial value. We know that our value is not written to and it does // a non-trivial value. We know that our value is not written to and it does

View File

@@ -799,6 +799,10 @@ PromotedParamCloner::populateCloned() {
Cloned->getModule().Types, 0); Cloned->getModule().Types, 0);
auto *promotedArg = auto *promotedArg =
ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl()); ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl());
promotedArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*I)->isNoImplicitCopy());
promotedArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*I)->getLifetimeAnnotation());
OrigPromotedParameters.insert(*I); OrigPromotedParameters.insert(*I);
NewPromotedArgs[ArgNo] = promotedArg; NewPromotedArgs[ArgNo] = promotedArg;
@@ -811,8 +815,13 @@ PromotedParamCloner::populateCloned() {
entryArgs.push_back(SILValue()); entryArgs.push_back(SILValue());
} else { } else {
// Create a new argument which copies the original argument. // Create a new argument which copies the original argument.
entryArgs.push_back(ClonedEntryBB->createFunctionArgument( auto *newArg = ClonedEntryBB->createFunctionArgument((*I)->getType(),
(*I)->getType(), (*I)->getDecl())); (*I)->getDecl());
newArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*I)->isNoImplicitCopy());
newArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*I)->getLifetimeAnnotation());
entryArgs.push_back(newArg);
} }
++ArgNo; ++ArgNo;
++I; ++I;

View File

@@ -88,6 +88,10 @@ void MapOpaqueArchetypes::replace() {
SILType mappedType = remapType(origArg->getType()); SILType mappedType = remapType(origArg->getType());
auto *NewArg = clonedEntryBlock->createFunctionArgument( auto *NewArg = clonedEntryBlock->createFunctionArgument(
mappedType, origArg->getDecl(), true); mappedType, origArg->getDecl(), true);
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(origArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(origArg)->getLifetimeAnnotation());
entryArgs.push_back(NewArg); entryArgs.push_back(NewArg);
} }

View File

@@ -120,6 +120,10 @@ void GenericCloner::populateCloned() {
mappedType = mappedType.getObjectType(); mappedType = mappedType.getObjectType();
auto *NewArg = ClonedEntryBB->createFunctionArgument( auto *NewArg = ClonedEntryBB->createFunctionArgument(
mappedType, OrigArg->getDecl()); mappedType, OrigArg->getDecl());
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(OrigArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(OrigArg)->getLifetimeAnnotation());
// Try to create a new debug_value from an existing debug_value w/ // Try to create a new debug_value from an existing debug_value w/
// address value for the argument. We do this before storing to // address value for the argument. We do this before storing to
@@ -164,6 +168,10 @@ void GenericCloner::populateCloned() {
if (!handleConversion()) { if (!handleConversion()) {
auto *NewArg = auto *NewArg =
ClonedEntryBB->createFunctionArgument(mappedType, OrigArg->getDecl()); ClonedEntryBB->createFunctionArgument(mappedType, OrigArg->getDecl());
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(OrigArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(OrigArg)->getLifetimeAnnotation());
entryArgs.push_back(NewArg); entryArgs.push_back(NewArg);
} }
++ArgIdx; ++ArgIdx;

View File

@@ -2544,8 +2544,12 @@ SILFunction *ReabstractionThunkGenerator::createThunk() {
if (!SILModuleConventions(M).useLoweredAddresses()) { if (!SILModuleConventions(M).useLoweredAddresses()) {
for (auto SpecArg : SpecializedFunc->getArguments()) { for (auto SpecArg : SpecializedFunc->getArguments()) {
SILArgument *NewArg = EntryBB->createFunctionArgument(SpecArg->getType(), auto *NewArg = EntryBB->createFunctionArgument(SpecArg->getType(),
SpecArg->getDecl()); SpecArg->getDecl());
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(SpecArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(SpecArg)->getLifetimeAnnotation());
Arguments.push_back(NewArg); Arguments.push_back(NewArg);
} }
FullApplySite ApplySite = createReabstractionThunkApply(Builder); FullApplySite ApplySite = createReabstractionThunkApply(Builder);
@@ -2642,8 +2646,12 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
auto cloneSpecializedArgument = [&]() { auto cloneSpecializedArgument = [&]() {
// No change to the argument. // No change to the argument.
SILArgument *SpecArg = *SpecArgIter++; SILArgument *SpecArg = *SpecArgIter++;
SILArgument *NewArg = auto *NewArg =
EntryBB->createFunctionArgument(SpecArg->getType(), SpecArg->getDecl()); EntryBB->createFunctionArgument(SpecArg->getType(), SpecArg->getDecl());
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(SpecArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(SpecArg)->getLifetimeAnnotation());
Arguments.push_back(NewArg); Arguments.push_back(NewArg);
}; };
// ReInfo.NumIndirectResults corresponds to SubstTy's formal indirect // ReInfo.NumIndirectResults corresponds to SubstTy's formal indirect
@@ -2685,6 +2693,10 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
SILArgument *SpecArg = *SpecArgIter++; SILArgument *SpecArg = *SpecArgIter++;
SILFunctionArgument *NewArg = SILFunctionArgument *NewArg =
EntryBB->createFunctionArgument(ParamTy, SpecArg->getDecl()); EntryBB->createFunctionArgument(ParamTy, SpecArg->getDecl());
NewArg->setNoImplicitCopy(
cast<SILFunctionArgument>(SpecArg)->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(SpecArg)->getLifetimeAnnotation());
if (!NewArg->getArgumentConvention().isGuaranteedConvention()) { if (!NewArg->getArgumentConvention().isGuaranteedConvention()) {
SILValue argVal = Builder.emitLoadValueOperation( SILValue argVal = Builder.emitLoadValueOperation(
Loc, NewArg, LoadOwnershipQualifier::Take); Loc, NewArg, LoadOwnershipQualifier::Take);

View File

@@ -46,6 +46,22 @@ public struct ResilientContainer {
let x = computedProperty let x = computedProperty
print(x) print(x)
} }
@inlinable
@_eagerMove
@_specialize(where T == Int)
public func genericEagerMoveInlineableContext<T>(_ t: T) {
let x = computedProperty
print(x)
print(t)
}
@inlinable
@_eagerMove
public func eagerMoveInlineableContext() {
let x = computedProperty
print(x)
}
} }
public struct WrapperP2<Wrapped: ExternalP2>: ExternalP2 { public struct WrapperP2<Wrapped: ExternalP2>: ExternalP2 {

View File

@@ -0,0 +1,49 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -allocbox-to-stack -enable-copy-propagation=requested-passes-only -enable-lexical-borrow-scopes=false | %FileCheck %s
sil_stage raw
protocol P {}
sil [ossa] @callWithAutoclosure_3 : $@convention(thin) <T where T : P> (@in T) -> () {
bb0(%0 : $*T):
debug_value %0 : $*T, expr op_deref
%2 = function_ref @mightApply : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
%3 = function_ref @closure_to_specialize : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
%4c = mark_uninitialized [var] %4 : $<τ_0_0> { var τ_0_0 } <T>
%4a = project_box %4c : $<τ_0_0> { var τ_0_0 } <T>, 0
%4copy = copy_value %4c : $<τ_0_0> { var τ_0_0 } <T>
copy_addr %0 to [initialization] %4a : $*T
%6 = partial_apply %3<T>(%4copy) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
%7 = apply %2<T>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
destroy_addr %0 : $*T
destroy_value %4c : $<τ_0_0> { var τ_0_0 } <T>
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: sil {{.*}}@$s21closure_to_specializeTf0ns_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $*T, {{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s21closure_to_specializeTf0ns_n'
sil shared [ossa] @closure_to_specialize : $@convention(thin) <T where T : P> (@owned <τ_0_0> { var τ_0_0 } <T>) -> @out T {
bb0(%0 : @_eagerMove $*T, %1 : @_eagerMove @owned $<τ_0_0> { var τ_0_0 } <T>):
%2 = project_box %1 : $<τ_0_0> { var τ_0_0 } <T>, 0
copy_addr %2 to [initialization] %0 : $*T
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <T>
%5 = tuple ()
return %5 : $()
}
sil [transparent] [serialized] [ossa] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> () {
bb0(%0 : @owned $@callee_owned () -> @out U):
debug_value %0 : $@callee_owned () -> @out U
%1 = copy_value %0 : $@callee_owned () -> @out U
%3 = alloc_stack $U
%4 = apply %1(%3) : $@callee_owned () -> @out U
destroy_addr %3 : $*U
dealloc_stack %3 : $*U
destroy_value %0 : $@callee_owned () -> @out U
%8 = tuple ()
return %8 : $()
}

View File

@@ -0,0 +1,62 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -capture-prop | %FileCheck %s
sil_stage raw
import Builtin
import Swift
class C {}
sil [ossa] @getC : $@convention(thin) () -> @owned C
sil [ossa] @test_capture_propagation : $@convention(thin) () -> () {
bb0:
%addr = alloc_stack $C
%getC = function_ref @getC : $@convention(thin) () -> @owned C
%c1 = apply %getC() : $@convention(thin) () -> @owned C
store %c1 to [init] %addr : $*C
%closure = function_ref @closure : $@convention(thin) (@owned C) -> ()
%thick_closure = thin_to_thick_function %closure : $@convention(thin) (@owned C) -> () to $@callee_owned (@owned C) -> ()
%thunk = function_ref @thunk : $@convention(thin) (@in C, @owned @callee_owned (@owned C) -> ()) -> ()
%thunked_closure = partial_apply %thunk(%thick_closure) : $@convention(thin) (@in C, @owned @callee_owned (@owned C) -> ()) -> ()
%apply_closure = function_ref @apply_closure : $@convention(thin) (@in C, @owned @callee_owned (@in C) -> ()) -> ()
apply %apply_closure(%addr, %thunked_closure) : $@convention(thin) (@in C, @owned @callee_owned (@in C) -> ()) -> ()
dealloc_stack %addr : $*C
%retval = tuple ()
return %retval : $()
}
sil [ossa] @closure : $@convention(thin) (@owned C) -> () {
bb0(%0 : @owned $C):
destroy_value %0 : $C
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil {{.*}}@$s5thunk7closureTf3npf_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s5thunk7closureTf3npf_n'
sil [ossa] [transparent] @thunk : $@convention(thin) (@in C, @owned @callee_owned (@owned C) -> ()) -> () {
bb0(%addr : @_eagerMove $*C, %closure : @owned $@callee_owned (@owned C) -> ()):
%instance = load [take] %addr : $*C
apply %closure(%instance) : $@callee_owned (@owned C) -> ()
%retval = tuple ()
return %retval : $()
}
sil [ossa] [noinline] @apply_closure : $@convention(thin) (@in C, @owned @callee_owned (@in C) -> ()) -> () {
bb0(%addr : $*C, %closure : @owned $@callee_owned (@in C) -> ()):
%stack_addr = alloc_stack $C
%instance = load [take] %addr : $*C
store %instance to [init] %stack_addr : $*C
apply %closure(%stack_addr) : $@callee_owned (@in C) -> ()
dealloc_stack %stack_addr : $*C
%retval = tuple ()
return %retval : $()
}

View File

@@ -0,0 +1,54 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -capture-prop | %FileCheck %s
sil_stage raw
import Builtin
import Swift
class C {}
struct Str {
@_hasStorage var a: C { get set }
}
sil @calleeWithKeypath : $@convention(thin) (@noescape @callee_guaranteed (@owned Str) -> @owned C) -> ()
sil @swift_getAtKeyPath : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
// CHECK-LABEL: sil [ossa] @testKeypathNoescapeOSSA
// CHECK: [[K:%[0-9]+]] = keypath
// CHECK: [[C:%[0-9]+]] = function_ref @$s22closureWithKeypathOSSA{{.*}}main3StrVAC1CCTf3npk_n
// CHECK: [[T:%[0-9]+]] = thin_to_thick_function [[C]]
// CHECK: [[F:%[0-9]+]] = function_ref @calleeWithKeypath
// CHECK: apply [[F]]([[T]])
// CHECK: destroy_value [[K]]
// CHECK: } // end sil function 'testKeypathNoescapeOSSA'
sil [ossa] @testKeypathNoescapeOSSA : $@convention(thin) () -> () {
bb0:
%0 = keypath $KeyPath<Str, C>, (root $Str; stored_property #Str.a : $C)
%1 = function_ref @closureWithKeypathOSSA : $@convention(thin) (@owned Str, @guaranteed KeyPath<Str, C>) -> @owned C
%2 = partial_apply [callee_guaranteed] [on_stack] %1(%0) : $@convention(thin) (@owned Str, @guaranteed KeyPath<Str, C>) -> @owned C
%4 = function_ref @calleeWithKeypath : $@convention(thin) (@noescape @callee_guaranteed (@owned Str) -> @owned C) -> ()
%5 = apply %4(%2) : $@convention(thin) (@noescape @callee_guaranteed (@owned Str) -> @owned C) -> ()
dealloc_stack %2 : $@noescape @callee_guaranteed (@owned Str) -> @owned C
destroy_value %0 : $KeyPath<Str, C>
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil {{.*}}@$s22closureWithKeypathOSSA{{.*}}main3StrVAC1CCTf3npk_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove @owned $
// CHECK: } // end sil function '$s22closureWithKeypathOSSA{{.*}}main3StrVAC1CCTf3npk_n'
sil [ossa] @closureWithKeypathOSSA : $@convention(thin) (@owned Str, @guaranteed KeyPath<Str, C>) -> @owned C {
bb0(%0 : @_eagerMove @owned $Str, %1 : @guaranteed $KeyPath<Str, C>):
%4 = alloc_stack $Str
store %0 to [init] %4 : $*Str
%6 = function_ref @swift_getAtKeyPath : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
%7 = alloc_stack $C
%8 = apply %6<Str, C>(%7, %4, %1) : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
%9 = load [take] %7 : $*C
dealloc_stack %7 : $*C
destroy_addr %4 : $*Str
dealloc_stack %4 : $*Str
return %9 : $C
}

View File

@@ -0,0 +1,46 @@
// RUN: %target-sil-opt -enable-sil-verify-all -closure-specialize %s | %FileCheck %s
import Builtin
class C {}
sil [ossa] @getC : $@convention(thin) () -> @owned C
// Verify that the argument to the specialized take_closure is still @_eagerMove.
// CHECK-LABEL: sil {{.*}}@$s12take_closure0B04main1CCTf1nc_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove @owned $C, {{%[^,]+}} :
// CHECK-LABEL: } // end sil function '$s12take_closure0B04main1CCTf1nc_n'
sil [ossa] [noinline] @take_closure : $@convention(thin) (@owned C, @noescape @callee_guaranteed (@owned C, @owned C) -> ()) -> () {
bb0(%c : @_eagerMove @owned $C, %0 : $@noescape @callee_guaranteed (@owned C, @owned C) -> ()):
%getC = function_ref @getC : $@convention(thin) () -> @owned C
%c1 = apply %getC() : $@convention(thin) () -> @owned C
%c2 = apply %getC() : $@convention(thin) () -> @owned C
%3 = apply %0(%c1, %c2) : $@noescape @callee_guaranteed (@owned C, @owned C) -> ()
destroy_value %c : $C
%retval = tuple()
return %retval : $()
}
sil shared [ossa] @closure : $@convention(thin) (@owned C, @owned C, @owned C) -> () {
bb0(%0 : @owned $C, %1 : @owned $C, %2 : @owned $C):
destroy_value %0 : $C
destroy_value %1 : $C
destroy_value %2 : $C
%15 = tuple ()
return %15 : $()
}
sil @caller : $@convention(thin) (@owned C) -> () {
bb0(%0 : $C):
%3 = function_ref @closure : $@convention(thin) (@owned C, @owned C, @owned C) -> ()
%4 = partial_apply [callee_guaranteed] [on_stack] %3(%0) : $@convention(thin) (@owned C, @owned C, @owned C) -> ()
%take_closure = function_ref @take_closure : $@convention(thin) (@owned C, @noescape @callee_guaranteed (@owned C, @owned C) -> ()) -> ()
strong_retain %0 : $C
%5 = apply %take_closure(%0, %4) : $@convention(thin) (@owned C, @noescape @callee_guaranteed (@owned C, @owned C) -> ()) -> ()
strong_release %0 : $C
dealloc_stack %4 : $@noescape @callee_guaranteed (@owned C, @owned C) -> ()
%retval = tuple()
return %retval : $()
}

View File

@@ -0,0 +1,68 @@
// RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer %s | %FileCheck %s
import Swift
public protocol AnElt {
}
public protocol HasElt {
associatedtype Elt
init(e: Elt)
}
struct X : AnElt {
@_hasStorage var i: Int { get set }
init(i: Int)
}
struct S : HasElt {
typealias Elt = X
@_hasStorage var e: X { get set }
init(e: Elt)
}
class Klass {}
class EltTrivialKlass : AnElt {
var i: Int { get set }
init(i: Int) {}
}
class ContainerKlass : HasElt {
typealias Elt = EltTrivialKlass
var e: Elt { get set }
required init(e: Elt)
}
public struct G<Container : HasElt> {
var container: Container? = nil
public func getContainer(e: Container.Elt) -> Container
init()
}
public struct GTrivial<Container : HasElt> {
public func getContainer(e: Container.Elt) -> Container
init()
}
sil [ossa] @callee : $@convention(method) <Container where Container : HasElt> (@in Container.Elt, @in_guaranteed G<Container>) -> @out Container {
bb0(%0 : $*Container, %1 : $*Container.Elt, %2 : $*G<Container>):
%4 = witness_method $Container, #HasElt.init!allocator : $@convention(witness_method: HasElt) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @thick τ_0_0.Type) -> @out τ_0_0
%5 = metatype $@thick Container.Type
%6 = apply %4<Container>(%0, %1, %5) : $@convention(witness_method: HasElt) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @thick τ_0_0.Type) -> @out τ_0_0
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil {{.*}}@$s6caller4main1SV_Tg5 : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $G<S>, {{%[^,]+}} :
// CHECK-LABEL: } // end sil function '$s6caller4main1SV_Tg5'
sil [_specialize where T == S] [ossa] @caller : $@convention(thin) <T where T : HasElt, T.Elt : AnElt> (@in_guaranteed G<T>, @in T.Elt) -> @out T {
bb0(%0 : $*T, %1 : @_eagerMove $*G<T>, %2 : $*T.Elt):
%5 = function_ref @callee : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @in_guaranteed G<τ_0_0>) -> @out τ_0_0
%6 = apply %5<T>(%0, %2, %1) : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @in_guaranteed G<τ_0_0>) -> @out τ_0_0
%7 = tuple ()
return %7 : $()
}

View File

@@ -0,0 +1,58 @@
// RUN: %target-swift-frontend -module-name main -O -emit-sil -primary-file %s | %FileCheck %s
protocol P {
func foo()
}
class C {}
public struct Inner {
var x: C
var y: Int
}
public struct S : P {
var i: Inner
func foo() {
print(i.x)
}
}
@_silgen_name("barrier")
func barrier()
// The specializations should be @_eagerMove.
// CHECK-LABEL: sil {{.*}}@$s4main27callee_guaranteed_eagerMoveyyAA1P_pFTf4e_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s4main27callee_guaranteed_eagerMoveyyAA1P_pFTf4e_n'
// CHECK-LABEL: sil {{.*}}@$s4main27callee_guaranteed_eagerMoveyyAA1P_pFTf4e_nAA1SV_Tg5Tf4x_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove
// CHECK-LABEL: } // end sil function '$s4main27callee_guaranteed_eagerMoveyyAA1P_pFTf4e_nAA1SV_Tg5Tf4x_n'
@inline(never)
func callee_guaranteed_eagerMove(@_eagerMove _ p: P) {
p.foo()
barrier()
}
public func caller_guaranteed_eagerMove(s: S) {
callee_guaranteed_eagerMove(s)
}
// CHECK-LABEL: sil {{.*}}@$s4main22callee_owned_eagerMoveyyAA1P_pnFTf4e_nTf4g_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s4main22callee_owned_eagerMoveyyAA1P_pnFTf4e_nTf4g_n'
// CHECK-LABEL: sil {{.*}}@$s4main22callee_owned_eagerMoveyyAA1P_pnFTf4e_nAA1SV_Tg5Tf4gX_n : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s4main22callee_owned_eagerMoveyyAA1P_pnFTf4e_nAA1SV_Tg5Tf4gX_n'
@inline(never)
func callee_owned_eagerMove(@_eagerMove _ p: __owned P) {
p.foo()
barrier()
}
public func caller_owned_eagerMove(s: S) {
callee_owned_eagerMove(s)
}

View File

@@ -372,12 +372,23 @@ public func testResilientInlinablePropertyCallsResilientInlinable() {
useP(r.inlineablePropertyCallsResilientInlineable.myValue3()) useP(r.inlineablePropertyCallsResilientInlineable.myValue3())
} }
// RESILIENT-LABEL: sil {{.*}}@$s9External218ResilientContainerV33genericEagerMoveInlineableContextyyxlFSi_Tgq5 : {{.*}}{
// RESILIENT: {{bb[0-9]+}}({{%[^,]+}} : $Int, {{%[^,]+}} : @_eagerMove $
// RESILIENT-LABEL: } // end sil function '$s9External218ResilientContainerV33genericEagerMoveInlineableContextyyxlFSi_Tgq5'
// RESILIENT-LABEL: sil [serialized] [canonical] @$s9External218ResilientContainerV33genericEagerMoveInlineableContextyyxlF : {{.*}} {
// RESILIENT: {{bb[0-9]+}}({{%[^,]+}} : $*T, {{%[^,]+}} : @_eagerMove $
// RESILIENT-LABEL: } // end sil function '$s9External218ResilientContainerV33genericEagerMoveInlineableContextyyxlF'
// RESILIENT-LABEL: sil [serialized] [canonical] @$s9External218ResilientContainerV26eagerMoveInlineableContextyyF : $@convention(method) (@in_guaranteed ResilientContainer) -> () {
// RESILIENT: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// RESILIENT-LABEL: } // end sil function '$s9External218ResilientContainerV26eagerMoveInlineableContextyyF'
// RESILIENT-LABEL: sil [serialized] [canonical] @$s9External218ResilientContainerV17inlineableContextyyF // RESILIENT-LABEL: sil [serialized] [canonical] @$s9External218ResilientContainerV17inlineableContextyyF
// RESILIENT: [[RES:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s9External218ResilientContainerV16computedPropertyQrvp", 0) // RESILIENT: [[RES:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s9External218ResilientContainerV16computedPropertyQrvp", 0)
// RESILIENT: [[FUN:%.*]] = function_ref @$s9External218ResilientContainerV16computedPropertyQrvg // RESILIENT: [[FUN:%.*]] = function_ref @$s9External218ResilientContainerV16computedPropertyQrvg
// RESILIENT: apply [[FUN]]([[RES]], %0) // RESILIENT: apply [[FUN]]([[RES]], %0)
public protocol P4 { public protocol P4 {
associatedtype AT associatedtype AT
func foo(_ x: Int64) -> AT func foo(_ x: Int64) -> AT
@@ -390,6 +401,19 @@ struct PA : P4 {
} }
} }
public class K {}
public protocol P4EM {
associatedtype AT
func foo(@_eagerMove _ x: K) -> AT
}
struct PAEM : P4EM {
func foo(@_eagerMove _ x: K) -> some P {
return 5 as Int64
}
}
// CHECK-LABEL: sil private [transparent] [thunk] @$s1A2PAVAA2P4A2aDP4testyyFTW // CHECK-LABEL: sil private [transparent] [thunk] @$s1A2PAVAA2P4A2aDP4testyyFTW
// CHECK: [[V:%.*]] = load %0 : $*PA // CHECK: [[V:%.*]] = load %0 : $*PA
// CHECK: [[F:%.*]] = function_ref @$s1A2PAV4testyyF // CHECK: [[F:%.*]] = function_ref @$s1A2PAV4testyyF
@@ -426,6 +450,28 @@ public func testPartialApply() {
testPartialApply(PA()) testPartialApply(PA())
} }
// CHECK-LABEL: sil shared [noinline] @$s1A25testPartialApplyEagerMoveyyxAA4P4EMRzlFAA4PAEMV_Tg5 : {{.*}}{
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @_eagerMove $
// CHECK-LABEL: } // end sil function '$s1A25testPartialApplyEagerMoveyyxAA4P4EMRzlFAA4PAEMV_Tg5'
@inline(never)
func testItEagerMove<T>(cl: (K) throws -> T) {
do {
print(try cl(K()))
} catch (_) {}
}
@inline(never)
func testPartialApplyEagerMove<T: P4EM>(@_eagerMove _ t: T) {
let fun = t.foo
testItEagerMove(cl: fun)
print(fun(K()))
}
public func testPartialApplyEagerMove() {
testPartialApplyEagerMove(PAEM())
}
struct Trivial<T> { struct Trivial<T> {
var x : Int64 var x : Int64
} }