diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index f26057f81ecb1..42af7bdcbe299 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -153,8 +153,7 @@ class SILBuilder { if (InsertPt == BB->end()) return; // Set the opened archetype context from the instruction. - this->getOpenedArchetypes().addOpenedArchetypeOperands( - InsertPt->getTypeDependentOperands()); + addOpenedArchetypeOperands(&*InsertPt); } /// setInsertionPoint - Set the insertion point to insert before the specified @@ -200,10 +199,7 @@ class SILBuilder { //===--------------------------------------------------------------------===// // Opened archetypes handling //===--------------------------------------------------------------------===// - void addOpenedArchetypeOperands(SILInstruction *I) { - getOpenedArchetypes().addOpenedArchetypeOperands( - I->getTypeDependentOperands()); - } + void addOpenedArchetypeOperands(SILInstruction *I); //===--------------------------------------------------------------------===// // Type remapping diff --git a/include/swift/SIL/SILOpenedArchetypesTracker.h b/include/swift/SIL/SILOpenedArchetypesTracker.h index 92987a7ef2e21..c8c1600d88d69 100644 --- a/include/swift/SIL/SILOpenedArchetypesTracker.h +++ b/include/swift/SIL/SILOpenedArchetypesTracker.h @@ -78,16 +78,19 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler { // Can be used to incrementally populate the mapping, e.g. // if it is done when performing a scan of all instructions // inside a function. - void registerOpenedArchetypes(const SILInstruction *I); + // Returns true if any opened archetypes were registered. + bool registerOpenedArchetypes(const SILInstruction *I); // Register opened archetypes whose definitions are referenced by // the typedef operands of this instruction. - void registerUsedOpenedArchetypes(const SILInstruction *I); + // Returns true if any opened archetypes were registered. + bool registerUsedOpenedArchetypes(const SILInstruction *I); // Register opened archetypes referenced by this type, if they // are not registered yet. Create placeholders representing forward // definitions of these opened archetypes. - void registerUsedOpenedArchetypes(CanType Ty); + // Returns true if any opened archetypes were registered. + bool registerUsedOpenedArchetypes(CanType Ty); // Unregister archetypes opened by a given instruction. // Should be only called when this instruction is to be removed. diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp index ca36bf12f018c..38f4b3df2f5bc 100644 --- a/lib/SIL/SILBuilder.cpp +++ b/lib/SIL/SILBuilder.cpp @@ -344,3 +344,34 @@ SILValue SILBuilder::emitObjCToThickMetatype(SILLocation Loc, SILValue Op, // Just create the objc_to_thick_metatype instruction. return createObjCToThickMetatype(Loc, Op, Ty); } + +/// Add opned archetypes defined or used by the current instruction. +/// If there are no such opened archetypes in the current instruction +/// and it is an instruction with just one operand, try to perform +/// the same action for the instruction defining an operand, because +/// it may have some opened archetypes used or defined. +void SILBuilder::addOpenedArchetypeOperands(SILInstruction *I) { + while (I && I->getNumOperands() == 1 && + I->getNumTypeDependentOperands() == 0) { + I = dyn_cast(I->getOperand(0)); + if (!I) + return; + // If it is a definition of an opened archetype, + // register it and exit. + auto Archetype = getOpenedArchetypeOf(I); + if (!Archetype) + continue; + auto Def = OpenedArchetypes.getOpenedArchetypeDef(Archetype); + // Return if it is a known open archetype. + if (Def) + return; + // Otherwise register it and return. + if (OpenedArchetypesTracker) + OpenedArchetypesTracker->addOpenedArchetypeDef(Archetype, I); + return; + } + + if (I && I->getNumTypeDependentOperands() > 0) { + OpenedArchetypes.addOpenedArchetypeOperands(I->getTypeDependentOperands()); + } +} diff --git a/lib/SIL/SILOpenedArchetypesTracker.cpp b/lib/SIL/SILOpenedArchetypesTracker.cpp index cd298c5d9bee6..d94795ba8820b 100644 --- a/lib/SIL/SILOpenedArchetypesTracker.cpp +++ b/lib/SIL/SILOpenedArchetypesTracker.cpp @@ -39,10 +39,11 @@ bool SILOpenedArchetypesTracker::hasUnresolvedOpenedArchetypeDefinitions() { return false; } -void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(CanType Ty) { +bool SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(CanType Ty) { + bool Registered = false; // Nothing else to be done if the type does not contain an opened archetype. if (!Ty || !Ty->hasOpenedExistential()) - return; + return Registered; // Find all opened existentials used by this type and check if their // definitions are known. @@ -64,33 +65,39 @@ void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(CanType Ty) { // archetype can be constructed. addOpenedArchetypeDef(archetypeTy, Placeholder); }); + return Registered; } // Register archetypes opened by a given instruction. // Can be used to incrementally populate the mapping, e.g. // if it is done when performing a scan of all instructions // inside a function. -void SILOpenedArchetypesTracker::registerOpenedArchetypes( +bool SILOpenedArchetypesTracker::registerOpenedArchetypes( const SILInstruction *I) { assert((!I->getParent() || I->getFunction() == &F) && "Instruction does not belong to a proper SILFunction"); auto Archetype = getOpenedArchetypeOf(I); - if (Archetype) - addOpenedArchetypeDef(Archetype, I); + if (!Archetype) + return false; + addOpenedArchetypeDef(Archetype, I); + return true; } // Register opened archetypes whose definitions are referenced by // the typedef operands of this instruction. -void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes( +bool SILOpenedArchetypesTracker::registerUsedOpenedArchetypes( const SILInstruction *I) { assert((!I->getParent() || I->getFunction() == &F) && "Instruction does not belong to a proper SILFunction"); + bool Registered = false; for (auto &Op : I->getTypeDependentOperands()) { auto OpenedArchetypeDef = Op.get(); if (auto *DefInst = dyn_cast(OpenedArchetypeDef)) { addOpenedArchetypeDef(getOpenedArchetypeOf(DefInst), OpenedArchetypeDef); + Registered = true; } } + return Registered; } // Unregister archetypes opened by a given instruction. diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp index 8cf80e33944ae..47e413772b26b 100644 --- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp @@ -39,8 +39,13 @@ namespace { struct OwnershipModelEliminatorVisitor : SILInstructionVisitor { SILBuilder &B; + SILOpenedArchetypesTracker OpenedArchetypesTracker; + + OwnershipModelEliminatorVisitor(SILBuilder &B) + : B(B), OpenedArchetypesTracker(B.getFunction()) { + B.setOpenedArchetypesTracker(&OpenedArchetypesTracker); + } - OwnershipModelEliminatorVisitor(SILBuilder &B) : B(B) {} void beforeVisit(ValueBase *V) { auto *I = cast(V); B.setInsertionPoint(I); diff --git a/test/SILOptimizer/opened_archetype_operands_tracking.sil b/test/SILOptimizer/opened_archetype_operands_tracking.sil index e215014210b15..6dc748b0a995d 100644 --- a/test/SILOptimizer/opened_archetype_operands_tracking.sil +++ b/test/SILOptimizer/opened_archetype_operands_tracking.sil @@ -130,3 +130,102 @@ bb0(%0 : $*View, %1 : $@thin DynamicItem.Type): dealloc_stack %2 : $*DynamicItem return %9 : $DynamicItem } + +func use(_ t: T) + +final class Foo where T : P { + init(_ x: T) + @sil_stored final var x: T { get set } + @sil_stored final var y: T { get set } + deinit +} + +extension P { + @inline(__always) func foo() +} + +public func bar(_ p: P) + +// Foo.__allocating_init(_:) +sil @Foo_alloc_init : $@convention(method) (@in T, @thick Foo.Type) -> @owned Foo { +bb0(%0 : $*T, %1 : $@thick Foo.Type): + %2 = alloc_ref $Foo + // function_ref Foo.init(_:) + %3 = function_ref @Foo_init : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @owned Foo<τ_0_0>) -> @owned Foo<τ_0_0> + %4 = apply %3(%0, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @owned Foo<τ_0_0>) -> @owned Foo<τ_0_0> + return %4 : $Foo +} // end sil function 'Foo_alloc_init' + +// Foo.init(_:) +sil @Foo_init : $@convention(method) (@in T, @owned Foo) -> @owned Foo { +bb0(%0 : $*T, %1 : $Foo): + %4 = alloc_stack $T + copy_addr %0 to [initialization] %4 : $*T + %6 = ref_element_addr %1 : $Foo, #Foo.x + copy_addr [take] %4 to [initialization] %6 : $*T + dealloc_stack %4 : $*T + %9 = alloc_stack $T + copy_addr %0 to [initialization] %9 : $*T + %11 = ref_element_addr %1 : $Foo, #Foo.y + copy_addr [take] %9 to [initialization] %11 : $*T + dealloc_stack %9 : $*T + destroy_addr %0 : $*T + return %1 : $Foo +} // end sil function 'Foo_init' + +// P.foo() +sil [always_inline] @P_foo : $@convention(method) (@in_guaranteed Self) -> () { +bb0(%0 : $*Self): + // function_ref Foo.__allocating_init(_:) + %2 = function_ref @Foo_alloc_init : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @thick Foo<τ_0_0>.Type) -> @owned Foo<τ_0_0> + %3 = metatype $@thick Foo.Type + %4 = alloc_stack $Self + copy_addr %0 to [initialization] %4 : $*Self + %6 = apply %2(%4, %3) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @thick Foo<τ_0_0>.Type) -> @owned Foo<τ_0_0> + dealloc_stack %4 : $*Self + // function_ref use + %9 = function_ref @use : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + %10 = ref_element_addr %6 : $Foo, #Foo.x + %11 = alloc_stack $Self + copy_addr %10 to [initialization] %11 : $*Self + %13 = apply %9(%11) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + dealloc_stack %11 : $*Self + // function_ref use + %15 = function_ref @use : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + %16 = ref_element_addr %6 : $Foo, #Foo.y + %17 = alloc_stack $Self + copy_addr %16 to [initialization] %17 : $*Self + %19 = apply %15(%17) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + dealloc_stack %17 : $*Self + strong_release %6 : $Foo + %22 = tuple () + return %22 : $() +} // end sil function 'P_foo' + +// use +sil hidden_external @use : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + +// Check that everything besides the external function use is inlined into bar. +// It should contain alloc_ref and alloc_stack instructions using opened archetypes. +// CHECK-LABEL: sil @bar +// CHECK: open_existential{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK: alloc_ref{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK: alloc_stack{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK-NOT: function_ref @use +// CHECK: function_ref @use +// CHECK-NOT: function_ref +// CHECK: dealloc_stack{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK: strong_release{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK: dealloc_ref{{.*}}C08045E0-2779-11E7-970E-A45E60E99281 +// CHECK: end sil function 'bar' +sil @bar : $@convention(thin) (@in P) -> () { +bb0(%0 : $*P): + %2 = open_existential_addr immutable_access %0 : $*P to $*@opened("C08045E0-2779-11E7-970E-A45E60E99281") P + // function_ref P.foo() + %3 = function_ref @P_foo : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () + %4 = apply %3<@opened("C08045E0-2779-11E7-970E-A45E60E99281") P>(%2) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () + destroy_addr %0 : $*P + %6 = tuple () + return %6 : $() +} // end sil function 'bar' +