Skip to content

Some small optimizer tweaks #42191

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 3 commits into from
Apr 6, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,32 @@ import SIL
public struct CalleeAnalysis {
let bridged: BridgedCalleeAnalysis

public func getCallees(callee: Value) -> FunctionArray {
public func getCallees(callee: Value) -> FunctionArray? {
let bridgedFuncs = CalleeAnalysis_getCallees(bridged, callee.bridged)
if bridgedFuncs.incomplete != 0 {
return nil
}
return FunctionArray(bridged: bridgedFuncs)
}

public func getIncompleteCallees(callee: Value) -> FunctionArray {
return FunctionArray(bridged: CalleeAnalysis_getCallees(bridged, callee.bridged))
}

public func getDestructors(destroyInst: Instruction) -> FunctionArray {
return FunctionArray(bridged:
CalleeAnalysis_getInstCallees(bridged, destroyInst.bridged))
public func getDestructor(ofExactType type: Type) -> Function? {
let destructors = FunctionArray(bridged: CalleeAnalysis_getDestructors(bridged, type.bridged, /*isExactType*/ 1))
if destructors.count == 1 {
return destructors[0]
}
return nil
}

public func getDestructors(of type: Type) -> FunctionArray? {
let bridgedDtors = CalleeAnalysis_getDestructors(bridged, type.bridged, /*isExactType*/ 0)
if bridgedDtors.incomplete != 0 {
return nil
}
return FunctionArray(bridged: bridgedDtors)
}
}

Expand All @@ -35,6 +54,4 @@ public struct FunctionArray : RandomAccessCollection, FormattedLikeArray {
public subscript(_ index: Int) -> Function {
return BridgedFunctionArray_get(bridged, index).function
}

public var allCalleesKnown: Bool { bridged.incomplete == 0 }
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private func tryDevirtualizeReleaseOfObject(

let type = allocRefInstruction.type

guard let dealloc = context.getDestructor(ofClass: type) else {
guard let dealloc = context.calleeAnalysis.getDestructor(ofExactType: type) else {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,20 @@ let simplifyGlobalValuePass = InstructionPass<GlobalValueInst>(
private func checkUsers(of val: Value, users: inout Stack<Instruction>) -> Bool {
for use in val.uses {
let user = use.instruction
if user is RefCountingInst || user is DebugValueInst {
users.push(user)
continue
}
if let upCast = user as? UpcastInst {
if !checkUsers(of: upCast, users: &users) {
switch user {
case is RefCountingInst, is DebugValueInst, is FixLifetimeInst:
users.push(user)
case let upCast as UpcastInst:
if !checkUsers(of: upCast, users: &users) {
return false
}
case is RefElementAddrInst, is RefTailAddrInst:
// Projection instructions don't access the object header, so they don't
// prevent deleting reference counting instructions.
break
default:
return false
}
continue
}
// Projection instructions don't access the object header, so they don't
// prevent deleting reference counting instructions.
if user is RefElementAddrInst || user is RefTailAddrInst {
continue
}
return false
}
return true
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ struct PassContext {
PassContext_fixStackNesting(_bridged, function.bridged)
}

func getDestructor(ofClass type: Type) -> Function? {
PassContext_getDestructor(_bridged, type.bridged).function
}

func getContextSubstitutionMap(for type: Type) -> SubstitutionMap {
SubstitutionMap(PassContext_getContextSubstitutionMap(_bridged, type.bridged))
}
Expand Down
6 changes: 3 additions & 3 deletions include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class CalleeCache {

/// Return the list of callees that can potentially be called at the
/// given instruction. E.g. it could be destructors.
CalleeList getCalleeList(SILInstruction *I) const;
CalleeList getDestructors(SILType type, bool isExactType) const;

CalleeList getCalleeList(SILDeclRef Decl) const;

Expand Down Expand Up @@ -224,9 +224,9 @@ class BasicCalleeAnalysis : public SILAnalysis {
return Cache->getCalleeListOfValue(callee);
}

CalleeList getCalleeList(SILInstruction *I) {
CalleeList getDestructors(SILType type, bool isExactType) {
updateCache();
return Cache->getCalleeList(I);
return Cache->getDestructors(type, isExactType);
}
};

Expand Down
8 changes: 3 additions & 5 deletions include/swift/SILOptimizer/OptimizerBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ BridgedCalleeAnalysis PassContext_getCalleeAnalysis(BridgedPassContext context);

BridgedCalleeList CalleeAnalysis_getCallees(BridgedCalleeAnalysis calleeAnalysis,
BridgedValue callee);
BridgedCalleeList CalleeAnalysis_getInstCallees(BridgedCalleeAnalysis calleeAnalysis,
BridgedInstruction inst);
BridgedCalleeList CalleeAnalysis_getDestructors(BridgedCalleeAnalysis calleeAnalysis,
BridgedType type,
SwiftInt isExactType);
SwiftInt BridgedFunctionArray_size(BridgedCalleeList callees);
BridgedFunction BridgedFunctionArray_get(BridgedCalleeList callees,
SwiftInt index);
Expand Down Expand Up @@ -140,9 +141,6 @@ BridgedFunction BasicBlockSet_getFunction(BridgedBasicBlockSet set);

void AllocRefInstBase_setIsStackAllocatable(BridgedInstruction arb);

OptionalBridgedFunction PassContext_getDestructor(BridgedPassContext context,
BridgedType type);

BridgedSubstitutionMap
PassContext_getContextSubstitutionMap(BridgedPassContext context,
BridgedType bridgedType);
Expand Down
40 changes: 25 additions & 15 deletions lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,19 +287,28 @@ CalleeList CalleeCache::getCalleeList(FullApplySite FAS) const {
return getCalleeListForCalleeKind(FAS.getCalleeOrigin());
}

// Return the list of functions that can be called via the given instruction.
CalleeList CalleeCache::getCalleeList(SILInstruction *I) const {
// We support only deallocation instructions at the moment.
assert((isa<StrongReleaseInst>(I) || isa<ReleaseValueInst>(I)) &&
"A deallocation instruction expected");
auto Ty = I->getOperand(0)->getType();
while (auto payloadTy = Ty.getOptionalObjectType())
Ty = payloadTy;
auto Class = Ty.getClassOrBoundGenericClass();
if (!Class || Class->hasClangNode())
/// Return the list of destructors of the class type \p type.
///
/// If \p type is an optional, look through that optional.
/// If \p exactType is true, then \p type is treated like a final class type.
CalleeList CalleeCache::getDestructors(SILType type, bool isExactType) const {
while (auto payloadTy = type.getOptionalObjectType()) {
type = payloadTy;
}
ClassDecl *classDecl = type.getClassOrBoundGenericClass();
if (!classDecl || classDecl->hasClangNode())
return CalleeList();

if (isExactType || classDecl->isFinal()) {
// In case of a final class, just pick the deinit of the class.
SILDeclRef destructor = SILDeclRef(classDecl->getDestructor());
if (SILFunction *destrImpl = M.lookUpFunction(destructor))
return CalleeList(destrImpl);
return CalleeList();
SILDeclRef Destructor = SILDeclRef(Class->getDestructor());
return getCalleeList(Destructor);
}
// If all that doesn't help get the list of deinits as we do for regular class
// methods.
return getCalleeList(SILDeclRef(classDecl->getDestructor()));
}

void BasicCalleeAnalysis::dump() const {
Expand Down Expand Up @@ -332,10 +341,11 @@ BridgedCalleeList CalleeAnalysis_getCallees(BridgedCalleeAnalysis calleeAnalysis
return {cl.getOpaquePtr(), cl.getOpaqueKind(), cl.isIncomplete()};
}

BridgedCalleeList CalleeAnalysis_getInstCallees(BridgedCalleeAnalysis calleeAnalysis,
BridgedInstruction inst) {
BridgedCalleeList CalleeAnalysis_getDestructors(BridgedCalleeAnalysis calleeAnalysis,
BridgedType type,
SwiftInt isExactType) {
BasicCalleeAnalysis *bca = static_cast<BasicCalleeAnalysis *>(calleeAnalysis.bca);
CalleeList cl = bca->getCalleeList(castToInst(inst));
CalleeList cl = bca->getDestructors(castToSILType(type), isExactType != 0);
return {cl.getOpaquePtr(), cl.getOpaqueKind(), cl.isIncomplete()};
}

Expand Down
7 changes: 5 additions & 2 deletions lib/SILOptimizer/Analysis/FunctionOrder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ void BottomUpFunctionOrder::DFS(SILFunction *Start) {
for (auto &B : *Start) {
for (auto &I : B) {
auto FAS = FullApplySite::isa(&I);
if (!FAS && !isa<StrongReleaseInst>(&I) && !isa<ReleaseValueInst>(&I))
if (!FAS && !isa<StrongReleaseInst>(&I) && !isa<ReleaseValueInst>(&I) &&
!isa<DestroyValueInst>(&I))
continue;

auto Callees = FAS ? BCA->getCalleeList(FAS) : BCA->getCalleeList(&I);
auto Callees = FAS ? BCA->getCalleeList(FAS)
: BCA->getDestructors(I.getOperand(0)->getType(),
/*isExactType*/ false);
for (auto *CalleeFn : Callees) {
// If not yet visited, visit the callee.
if (DFSNum.find(CalleeFn) == DFSNum.end()) {
Expand Down
13 changes: 0 additions & 13 deletions lib/SILOptimizer/PassManager/PassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,19 +1391,6 @@ void AllocRefInstBase_setIsStackAllocatable(BridgedInstruction arb) {
castToInst<AllocRefInstBase>(arb)->setStackAllocatable();
}

OptionalBridgedFunction PassContext_getDestructor(BridgedPassContext context,
BridgedType type) {
auto *cd = castToSILType(type).getClassOrBoundGenericClass();
assert(cd && "no class type allocated with alloc_ref");

auto *pm = castToPassInvocation(context)->getPassManager();
// Find the destructor of the type.
auto *destructor = cd->getDestructor();
SILDeclRef deallocRef(destructor, SILDeclRef::Kind::Deallocator);

return {pm->getModule()->lookUpFunction(deallocRef)};
}

BridgedSubstitutionMap
PassContext_getContextSubstitutionMap(BridgedPassContext context,
BridgedType bridgedType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,26 @@ bb0:
return %t : $(Builtin.Int1, Builtin.BridgeObject)
}

sil_global private @outlined_global : $_ContiguousArrayStorage<Int>

// CHECK-LABEL: sil @remove_arc_of_global_value
// CHECK-NOT: retain
// CHECK-NOT: release
// CHECK-NOT: fix_lifetime
// CHECK-NOT: debug_value
// CHECK: } // end sil function 'remove_arc_of_global_value'
sil @remove_arc_of_global_value : $@convention(thin) () -> Int {
bb0:
%0 = global_value @outlined_global : $_ContiguousArrayStorage<Int>
strong_retain %0 : $_ContiguousArrayStorage<Int>
debug_value %0 : $_ContiguousArrayStorage<Int>, let, name "x"
%2 = upcast %0 : $_ContiguousArrayStorage<Int> to $__ContiguousArrayStorageBase
strong_retain %2 : $__ContiguousArrayStorageBase
%13 = ref_tail_addr [immutable] %2 : $__ContiguousArrayStorageBase, $Int
%16 = load %13 : $*Int
fix_lifetime %0 : $_ContiguousArrayStorage<Int>
strong_release %2 : $__ContiguousArrayStorageBase
strong_release %0 : $_ContiguousArrayStorage<Int>
return %16 : $Int
}