Skip to content

[sil-opened-archetype-tracker] Improve tracking of archetypes in SILBuilder #8961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -200,10 +199,7 @@ class SILBuilder {
//===--------------------------------------------------------------------===//
// Opened archetypes handling
//===--------------------------------------------------------------------===//
void addOpenedArchetypeOperands(SILInstruction *I) {
getOpenedArchetypes().addOpenedArchetypeOperands(
I->getTypeDependentOperands());
}
void addOpenedArchetypeOperands(SILInstruction *I);

//===--------------------------------------------------------------------===//
// Type remapping
Expand Down
9 changes: 6 additions & 3 deletions include/swift/SIL/SILOpenedArchetypesTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
37 changes: 37 additions & 0 deletions lib/SIL/SILBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,40 @@ 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) {
// The list of archetypes from the previous instruction needs
// to be replaced, because it may reference a removed instruction.
OpenedArchetypes.addOpenedArchetypeOperands(I->getTypeDependentOperands());
if (I && I->getNumTypeDependentOperands() > 0)
return;

while (I && I->getNumOperands() == 1 &&
I->getNumTypeDependentOperands() == 0) {
I = dyn_cast<SILInstruction>(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());
}
}
19 changes: 13 additions & 6 deletions lib/SIL/SILOpenedArchetypesTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<SILInstruction>(OpenedArchetypeDef)) {
addOpenedArchetypeDef(getOpenedArchetypeOf(DefInst), OpenedArchetypeDef);
Registered = true;
}
}
return Registered;
}

// Unregister archetypes opened by a given instruction.
Expand Down
7 changes: 6 additions & 1 deletion lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ namespace {
struct OwnershipModelEliminatorVisitor
: SILInstructionVisitor<OwnershipModelEliminatorVisitor, bool> {
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<SILInstruction>(V);
B.setInsertionPoint(I);
Expand Down
99 changes: 99 additions & 0 deletions test/SILOptimizer/opened_archetype_operands_tracking.sil
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,102 @@ bb0(%0 : $*View, %1 : $@thin DynamicItem.Type):
dealloc_stack %2 : $*DynamicItem
return %9 : $DynamicItem
}

func use<T>(_ t: T)

final class Foo<T> 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) <T where T : P> (@in T, @thick Foo<T>.Type) -> @owned Foo<T> {
bb0(%0 : $*T, %1 : $@thick Foo<T>.Type):
%2 = alloc_ref $Foo<T>
// 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<T>(%0, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @owned Foo<τ_0_0>) -> @owned Foo<τ_0_0>
return %4 : $Foo<T>
} // end sil function 'Foo_alloc_init'

// Foo.init(_:)
sil @Foo_init : $@convention(method) <T where T : P> (@in T, @owned Foo<T>) -> @owned Foo<T> {
bb0(%0 : $*T, %1 : $Foo<T>):
%4 = alloc_stack $T
copy_addr %0 to [initialization] %4 : $*T
%6 = ref_element_addr %1 : $Foo<T>, #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<T>, #Foo.y
copy_addr [take] %9 to [initialization] %11 : $*T
dealloc_stack %9 : $*T
destroy_addr %0 : $*T
return %1 : $Foo<T>
} // end sil function 'Foo_init'

// P.foo()
sil [always_inline] @P_foo : $@convention(method) <Self where Self : P> (@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<Self>.Type
%4 = alloc_stack $Self
copy_addr %0 to [initialization] %4 : $*Self
%6 = apply %2<Self>(%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<Self>, #Foo.x
%11 = alloc_stack $Self
copy_addr %10 to [initialization] %11 : $*Self
%13 = apply %9<Self>(%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<Self>, #Foo.y
%17 = alloc_stack $Self
copy_addr %16 to [initialization] %17 : $*Self
%19 = apply %15<Self>(%17) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
dealloc_stack %17 : $*Self
strong_release %6 : $Foo<Self>
%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'