Skip to content

Fix double delete in generic specialization. #1957

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
Mar 30, 2016
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
5 changes: 2 additions & 3 deletions include/swift/SILOptimizer/Utils/Generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ namespace swift {
///
/// This is the top-level entry point for specializing an existing call site.
void trySpecializeApplyOfGeneric(
ApplySite Apply,
llvm::SmallVectorImpl<SILInstruction *> &DeadApplies,
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);
ApplySite Apply, DeadInstructionSet &DeadApplies,
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);

/// Helper class to describe re-abstraction of function parameters done during
/// specialization.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ inline ValueBaseUserRange makeUserRange(
UserTransform(toUser));
}

using DeadInstructionSet = llvm::SmallSetVector<SILInstruction *, 8>;

/// \brief For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/Transforms/GenericSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class GenericSpecializer : public SILFunctionTransform {
} // end anonymous namespace

bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
llvm::SmallVector<SILInstruction *, 8> DeadApplies;
DeadInstructionSet DeadApplies;

for (auto &BB : F) {
for (auto It = BB.begin(), End = BB.end(); It != End;) {
Expand Down
13 changes: 7 additions & 6 deletions lib/SILOptimizer/Utils/Generics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,9 @@ static SILFunction *createReabstractionThunk(const ReabstractionInfo &ReInfo,
return Thunk;
}

void swift::trySpecializeApplyOfGeneric(ApplySite Apply,
llvm::SmallVectorImpl<SILInstruction *> &DeadApplies,
llvm::SmallVectorImpl<SILFunction *> &NewFunctions) {
void swift::trySpecializeApplyOfGeneric(
ApplySite Apply, DeadInstructionSet &DeadApplies,
llvm::SmallVectorImpl<SILFunction *> &NewFunctions) {
assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!");

auto *F = cast<FunctionRefInst>(Apply.getCallee())->getReferencedFunction();
Expand Down Expand Up @@ -450,7 +450,7 @@ void swift::trySpecializeApplyOfGeneric(ApplySite Apply,
NewFunctions.push_back(SpecializedF);
}

DeadApplies.push_back(Apply.getInstruction());
DeadApplies.insert(Apply.getInstruction());

if (replacePartialApplyWithoutReabstraction) {
// There are some unknown users of the partial_apply. Therefore we need a
Expand All @@ -471,6 +471,7 @@ void swift::trySpecializeApplyOfGeneric(ApplySite Apply,
Arguments,
PAI->getType());
PAI->replaceAllUsesWith(NewPAI);
DeadApplies.insert(PAI);
return;
}
// Make the required changes to the call site.
Expand All @@ -486,14 +487,14 @@ void swift::trySpecializeApplyOfGeneric(ApplySite Apply,
if (auto FAS = FullApplySite::isa(User)) {
SILBuilder Builder(User);
replaceWithSpecializedCallee(FAS, NewPAI, Builder, ReInfo);
DeadApplies.push_back(User);
DeadApplies.insert(FAS.getInstruction());
continue;
}
if (auto *PAI = dyn_cast<PartialApplyInst>(User)) {
// This is a partial_apply of a re-abstraction thunk. Just skip this.
assert(PAI->getType() == NewPAI->getType());
PAI->replaceAllUsesWith(NewPAI);
DeadApplies.push_back(PAI);
DeadApplies.insert(PAI);
}
}
}
Expand Down
77 changes: 77 additions & 0 deletions test/SILOptimizer/specialize_reabstraction.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// RUN: %target-sil-opt -enable-sil-verify-all -generic-specializer %s | FileCheck %s
// REQUIRES: rdar://25447450


sil_stage canonical

import Builtin
import Swift

public protocol RefProto {
associatedtype T
var me: Ref<Self.T> { get }
}

public final class Ref<T> : RefProto {
public final var me: Ref<T> { get }
deinit
init()
}

extension RefProto {
public func merge<U>(other: Ref<U>) -> Ref<(Self.T, U)>
}

public protocol ValProto {
associatedtype T
var me: Val<Self.T> { get }
}

extension ValProto {
public func merge<U>(other: Val<U>) -> Val<(Self.T, U)>
}

public struct Val<T> : ValProto {
public var me: Val<T> { get }
init()
}

sil @coerce : $@convention(thin) <T, U, V> (@owned @callee_owned (@owned Ref<T>) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<V>) -> @owned @callee_owned (Val<U>) -> Val<V>

sil @merge : $@convention(method) <Self where Self : RefProto><U> (@owned Ref<U>, @in_guaranteed Self) -> @owned Ref<(Self.T, U)> {

bb0(%0 : $Ref<U>, %1 : $*Self):
%2 = alloc_ref $Ref<(Self.T, U)>
strong_release %0 : $Ref<U>
return %2 : $Ref<(Self.T, U)>
}

sil @merge_curried : $@convention(thin) <Self where Self : RefProto><U> (@in Self) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)> {
bb0(%0 : $*Self):
%1 = function_ref @merge : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)>
%2 = partial_apply %1<Self, Self.T, U>(%0) : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)>
return %2 : $@callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)>
}

sil [reabstraction_thunk] @reabstract : $@convention(thin) <Self where Self : ValProto><U> (@owned Ref<Self.T>, @owned @callee_owned (@in Ref<Self.T>) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)>) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)> {
bb0(%0 : $Ref<Self.T>, %1 : $@callee_owned (@in Ref<Self.T>) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)>):
%2 = alloc_stack $Ref<Self.T>
store %0 to %2 : $*Ref<Self.T>
%4 = apply %1(%2) : $@callee_owned (@in Ref<Self.T>) -> @owned @callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)>
dealloc_stack %2 : $*Ref<Self.T>
return %4 : $@callee_owned (@owned Ref<U>) -> @owned Ref<(Self.T, U)>
}

sil @test : $@convention(thin) (Val<Bool>, Val<Int>) -> Val<(Bool, Int)> {

bb0(%0 : $Val<Bool>, %1 : $Val<Int>):
%4 = function_ref @coerce : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2> (@owned @callee_owned (@owned Ref<τ_0_0>) -> @owned @callee_owned (@owned Ref<τ_0_1>) -> @owned Ref<τ_0_2>) -> @owned @callee_owned (Val<τ_0_1>) -> Val<τ_0_2>
%5 = metatype $@thick Ref<Bool>.Type
%6 = function_ref @merge_curried : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>
%7 = partial_apply %6<Ref<Bool>, Bool, Int>() : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>
%8 = function_ref @reabstract : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>
%9 = partial_apply %8<Val<Bool>, Bool, Int>(%7) : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>
%10 = apply %4<Bool, Int, (Bool, Int)>(%9) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2> (@owned @callee_owned (@owned Ref<τ_0_0>) -> @owned @callee_owned (@owned Ref<τ_0_1>) -> @owned Ref<τ_0_2>) -> @owned @callee_owned (Val<τ_0_1>) -> Val<τ_0_2>
%11 = apply %10(%1) : $@callee_owned (Val<Int>) -> Val<(Bool, Int)>
return %11 : $Val<(Bool, Int)>
}