Skip to content

SIL optimizer: remove unbalanced retains/releases from immortal objects #38973

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 4 commits into from
Aug 23, 2021
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
2 changes: 2 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ OptionalBridgedInstruction SILInstruction_next(BridgedInstruction inst);
OptionalBridgedInstruction SILInstruction_previous(BridgedInstruction inst);
BridgedBasicBlock SILInstruction_getParent(BridgedInstruction inst);
BridgedArrayRef SILInstruction_getOperands(BridgedInstruction inst);
void SILInstruction_setOperand(BridgedInstruction inst, SwiftInt index,
BridgedValue value);
BridgedLocation SILInstruction_getLocation(BridgedInstruction inst);
BridgedMemoryBehavior SILInstruction_getMemBehavior(BridgedInstruction inst);

Expand Down
16 changes: 8 additions & 8 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -497,11 +497,11 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
ABSTRACT_SINGLE_VALUE_INST(ConversionInst, SingleValueInstruction)
BRIDGED_SINGLE_VALUE_INST(UpcastInst, upcast,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(AddressToPointerInst, address_to_pointer,
BRIDGED_SINGLE_VALUE_INST(AddressToPointerInst, address_to_pointer,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(PointerToAddressInst, pointer_to_address,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(UncheckedRefCastInst, unchecked_ref_cast,
BRIDGED_SINGLE_VALUE_INST(UncheckedRefCastInst, unchecked_ref_cast,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(UncheckedAddrCastInst, unchecked_addr_cast,
ConversionInst, None, DoesNotRelease)
Expand All @@ -513,15 +513,15 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(RefToRawPointerInst, ref_to_raw_pointer,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(RawPointerToRefInst, raw_pointer_to_ref,
BRIDGED_SINGLE_VALUE_INST(RawPointerToRefInst, raw_pointer_to_ref,
ConversionInst, None, DoesNotRelease)
#define LOADABLE_REF_STORAGE(Name, name, ...) \
SINGLE_VALUE_INST(RefTo##Name##Inst, ref_to_##name, \
ConversionInst, None, DoesNotRelease) \
SINGLE_VALUE_INST(Name##ToRefInst, name##_to_ref, \
ConversionInst, None, DoesNotRelease)
#include "swift/AST/ReferenceStorage.def"
SINGLE_VALUE_INST(ConvertFunctionInst, convert_function,
BRIDGED_SINGLE_VALUE_INST(ConvertFunctionInst, convert_function,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ConvertEscapeToNoEscapeInst, convert_escape_to_noescape,
ConversionInst, None, DoesNotRelease)
Expand All @@ -535,15 +535,15 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(BridgeObjectToWordInst, bridge_object_to_word,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ThinToThickFunctionInst, thin_to_thick_function,
BRIDGED_SINGLE_VALUE_INST(ThinToThickFunctionInst, thin_to_thick_function,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ThickToObjCMetatypeInst, thick_to_objc_metatype,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ObjCToThickMetatypeInst, objc_to_thick_metatype,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ObjCMetatypeToObjectInst, objc_metatype_to_object,
BRIDGED_SINGLE_VALUE_INST(ObjCMetatypeToObjectInst, objc_metatype_to_object,
ConversionInst, None, DoesNotRelease)
SINGLE_VALUE_INST(ObjCExistentialMetatypeToObjectInst, objc_existential_metatype_to_object,
BRIDGED_SINGLE_VALUE_INST(ObjCExistentialMetatypeToObjectInst, objc_existential_metatype_to_object,
ConversionInst, None, DoesNotRelease)
// unconditional_checked_cast_value reads the source value and produces
// a new value with a potentially different representation.
Expand All @@ -566,7 +566,7 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)

BRIDGED_SINGLE_VALUE_INST(ClassifyBridgeObjectInst, classify_bridge_object,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(ValueToBridgeObjectInst, value_to_bridge_object,
BRIDGED_SINGLE_VALUE_INST(ValueToBridgeObjectInst, value_to_bridge_object,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(MarkDependenceInst, mark_dependence,
SingleValueInstruction, None, DoesNotRelease)
Expand Down
5 changes: 3 additions & 2 deletions include/swift/SILOptimizer/OptimizerBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ void SILPassManager_registerFunctionPass(BridgedStringRef name,
void SILCombine_registerInstructionPass(BridgedStringRef name,
BridgedInstructionPassRunFn runFn);

BridgedAliasAnalysis PassContext_getAliasAnalysis(BridgedPassContext context,
BridgedFunction function);
SwiftInt PassContext_isSwift51RuntimeAvailable(BridgedPassContext context);

BridgedAliasAnalysis PassContext_getAliasAnalysis(BridgedPassContext context);

BridgedMemoryBehavior AliasAnalysis_getMemBehavior(BridgedAliasAnalysis aa,
BridgedInstruction inst,
Expand Down
20 changes: 16 additions & 4 deletions include/swift/SILOptimizer/PassManager/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,28 @@ void executePassPipelinePlan(SILModule *SM, const SILPassPipelinePlan &plan,
class LibswiftPassInvocation {
/// Backlink to the pass manager.
SILPassManager *passManager;


/// The currently optimized function.
SILFunction *function = nullptr;

/// Non-null if this is an instruction pass, invoked from SILCombine.
SILCombiner *silCombiner;
SILCombiner *silCombiner = nullptr;

/// All slabs, allocated by the pass.
SILModule::SlabList allocatedSlabs;

public:
LibswiftPassInvocation(SILPassManager *passManager, SILCombiner *silCombiner) :
passManager(passManager), silCombiner(silCombiner) {}
LibswiftPassInvocation(SILPassManager *passManager, SILFunction *function,
SILCombiner *silCombiner) :
passManager(passManager), function(function), silCombiner(silCombiner) {}

LibswiftPassInvocation(SILPassManager *passManager) :
passManager(passManager) {}

SILPassManager *getPassManager() const { return passManager; }

SILFunction *getFunction() const { return function; }

FixedSizeSlab *allocSlab(FixedSizeSlab *afterSlab);

FixedSizeSlab *freeSlab(FixedSizeSlab *slab);
Expand All @@ -71,6 +80,9 @@ class LibswiftPassInvocation {
/// Called by the pass when changes are made to the SIL.
void notifyChanges(SILAnalysis::InvalidationKind invalidationKind);

/// Called by the pass manager before the pass starts running.
void startPassRun(SILFunction *function);

/// Called by the pass manager when the pass has finished.
void finishedPassRun();
};
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ PASS(PruneVTables, "prune-vtables",
PASS_RANGE(AllPasses, AADumper, PruneVTables)

SWIFT_INSTRUCTION_PASS_WITH_LEGACY(GlobalValueInst, "simplify-global_value")
SWIFT_INSTRUCTION_PASS_WITH_LEGACY(StrongRetainInst, "simplify-strong_retain")
SWIFT_INSTRUCTION_PASS_WITH_LEGACY(StrongReleaseInst, "simplify-strong_release")

#undef IRGEN_PASS
#undef SWIFT_FUNCTION_PASS
Expand Down
5 changes: 5 additions & 0 deletions lib/SIL/Utils/SILBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,11 @@ BridgedArrayRef SILInstruction_getOperands(BridgedInstruction inst) {
return {(const unsigned char *)operands.data(), operands.size()};
}

void SILInstruction_setOperand(BridgedInstruction inst, SwiftInt index,
BridgedValue value) {
castToInst(inst)->setOperand((unsigned)index, castToSILValue(value));
}

BridgedLocation SILInstruction_getLocation(BridgedInstruction inst) {
SILDebugLocation loc = castToInst(inst)->getDebugLocation();
return *reinterpret_cast<BridgedLocation *>(&loc);
Expand Down
25 changes: 20 additions & 5 deletions lib/SILOptimizer/PassManager/PassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ void swift::executePassPipelinePlan(SILModule *SM,
SILPassManager::SILPassManager(SILModule *M, bool isMandatory,
irgen::IRGenModule *IRMod)
: Mod(M), IRMod(IRMod),
libswiftPassInvocation(this, /*SILCombiner*/ nullptr),
libswiftPassInvocation(this),
isMandatory(isMandatory), deserializationNotificationHandler(nullptr) {
#define ANALYSIS(NAME) \
Analyses.push_back(create##NAME##Analysis(Mod));
Expand Down Expand Up @@ -469,7 +469,9 @@ void SILPassManager::runPassOnFunction(unsigned TransIdx, SILFunction *F) {

assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing
&& "change notifications not cleared");


libswiftPassInvocation.startPassRun(F);

// Run it!
SFT->run();

Expand Down Expand Up @@ -1100,8 +1102,14 @@ FixedSizeSlab *LibswiftPassInvocation::freeSlab(FixedSizeSlab *slab) {
return prev;
}

void LibswiftPassInvocation::startPassRun(SILFunction *function) {
assert(!this->function && "a pass is already running");
this->function = function;
}

void LibswiftPassInvocation::finishedPassRun() {
assert(allocatedSlabs.empty() && "StackList is leaking slabs");
function = nullptr;
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1166,10 +1174,17 @@ void PassContext_eraseInstruction(BridgedPassContext passContext,
castToPassInvocation(passContext)->eraseInstruction(castToInst(inst));
}

BridgedAliasAnalysis PassContext_getAliasAnalysis(BridgedPassContext context,
BridgedFunction function) {
SwiftInt PassContext_isSwift51RuntimeAvailable(BridgedPassContext context) {
SILPassManager *pm = castToPassInvocation(context)->getPassManager();
return {pm->getAnalysis<AliasAnalysis>(castToFunction(function))};
ASTContext &ctxt = pm->getModule()->getASTContext();
return AvailabilityContext::forDeploymentTarget(ctxt).
isContainedIn(ctxt.getSwift51Availability());
}

BridgedAliasAnalysis PassContext_getAliasAnalysis(BridgedPassContext context) {
LibswiftPassInvocation *invocation = castToPassInvocation(context);
SILPassManager *pm = invocation->getPassManager();
return {pm->getAnalysis<AliasAnalysis>(invocation->getFunction())};
}

BridgedCalleeAnalysis PassContext_getCalleeAnalysis(BridgedPassContext context) {
Expand Down
7 changes: 4 additions & 3 deletions lib/SILOptimizer/SILCombiner/SILCombiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ class SILCombiner :
[&](SILInstruction *I) { eraseInstFromFunction(*I); }),
deBlocks(&B.getFunction()),
ownershipFixupContext(getInstModCallbacks(), deBlocks),
libswiftPassInvocation(parentTransform->getPassManager(), this) {}
libswiftPassInvocation(parentTransform->getPassManager(),
parentTransform->getFunction(), this) {}

bool runOnFunction(SILFunction &F);

Expand Down Expand Up @@ -278,7 +279,7 @@ class SILCombiner :
SILInstruction *optimizeStringObject(BuiltinInst *BI);
SILInstruction *visitBuiltinInst(BuiltinInst *BI);
SILInstruction *visitCondFailInst(CondFailInst *CFI);
SILInstruction *visitStrongRetainInst(StrongRetainInst *SRI);
SILInstruction *legacyVisitStrongRetainInst(StrongRetainInst *SRI);
SILInstruction *visitCopyValueInst(CopyValueInst *cvi);
SILInstruction *visitDestroyValueInst(DestroyValueInst *dvi);
SILInstruction *visitRefToRawPointerInst(RefToRawPointerInst *RRPI);
Expand Down Expand Up @@ -308,7 +309,7 @@ class SILCombiner :
SILInstruction *visitRawPointerToRefInst(RawPointerToRefInst *RPTR);
SILInstruction *
visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI);
SILInstruction *visitStrongReleaseInst(StrongReleaseInst *SRI);
SILInstruction *legacyVisitStrongReleaseInst(StrongReleaseInst *SRI);
SILInstruction *visitCondBranchInst(CondBranchInst *CBI);
SILInstruction *
visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *UTBCI);
Expand Down
4 changes: 2 additions & 2 deletions lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,7 @@ SILInstruction *SILCombiner::visitDestroyValueInst(DestroyValueInst *dvi) {
return nullptr;
}

SILInstruction *SILCombiner::visitStrongRetainInst(StrongRetainInst *SRI) {
SILInstruction *SILCombiner::legacyVisitStrongRetainInst(StrongRetainInst *SRI) {
assert(!SRI->getFunction()->hasOwnership());

// Retain of ThinToThickFunction is a no-op.
Expand Down Expand Up @@ -1821,7 +1821,7 @@ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst(
return eraseInstFromFunction(*tedai);
}

SILInstruction *SILCombiner::visitStrongReleaseInst(StrongReleaseInst *SRI) {
SILInstruction *SILCombiner::legacyVisitStrongReleaseInst(StrongReleaseInst *SRI) {
assert(!SRI->getFunction()->hasOwnership());

// Release of ThinToThickFunction is a no-op.
Expand Down
12 changes: 6 additions & 6 deletions libswift/Sources/Optimizer/FunctionPasses/MergeCondFails.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ let mergeCondFailsPass = FunctionPass(name: "merge-cond_fails", runMergeCondFail
/// Return true if the operand of the cond_fail instruction looks like
/// the overflow bit of an arithmetic instruction.
private func hasOverflowConditionOperand(_ cfi: CondFailInst) -> Bool {
if let tei = cfi.condition as? TupleExtractInst {
return tei.tuple is BuiltinInst
if let tei = cfi.operand as? TupleExtractInst {
return tei.operand is BuiltinInst
}
return false
}
Expand All @@ -29,7 +29,7 @@ private func hasOverflowConditionOperand(_ cfi: CondFailInst) -> Bool {
/// write in between them.
/// This pass merges cond_fail instructions by building the disjunction of
/// their operands.
private func runMergeCondFails(function: Function, context: FunctionPassContext) {
private func runMergeCondFails(function: Function, context: PassContext) {

// Merge cond_fail instructions if there is no side-effect or read in
// between them.
Expand Down Expand Up @@ -59,7 +59,7 @@ private func runMergeCondFails(function: Function, context: FunctionPassContext)
/// Try to merge the cond_fail instructions. Returns true if any could
/// be merge.
private func mergeCondFails(_ condFailToMerge: inout StackList<CondFailInst>,
context: FunctionPassContext) {
context: PassContext) {
guard let lastCFI = condFailToMerge.last else {
return
}
Expand All @@ -73,10 +73,10 @@ private func mergeCondFails(_ condFailToMerge: inout StackList<CondFailInst>,
mergedCond = builder.createBuiltinBinaryFunction(name: "or",
operandType: prevCond.type,
resultType: prevCond.type,
arguments: [prevCond, cfi.condition])
arguments: [prevCond, cfi.operand])
didMerge = true
} else {
mergedCond = cfi.condition
mergedCond = cfi.operand
}
}
if !didMerge {
Expand Down
2 changes: 1 addition & 1 deletion libswift/Sources/Optimizer/FunctionPasses/SILPrinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import SIL

let silPrinterPass = FunctionPass(name: "sil-printer", runSILPrinter)

func runSILPrinter(function: Function, context: FunctionPassContext) {
func runSILPrinter(function: Function, context: PassContext) {
print("run SILPrinter on function: \(function.name)")

for (bbIdx, block) in function.blocks.enumerated() {
Expand Down
3 changes: 2 additions & 1 deletion libswift/Sources/Optimizer/InstructionPasses/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

libswift_sources(Optimizer
SimplifyGlobalValue.swift)
SimplifyGlobalValue.swift
SimplifyStrongRetainRelease.swift)
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@

import SIL

// Removes all reference counting instructions of a `global_value` instruction
// if it does not escape.
//
// Note that `simplifyStrongRetainPass` and `simplifyStrongReleasePass` can
// even remove "unbalanced" retains/releases of a `global_value`, but this
// requires a minimum deployment target.
let simplifyGlobalValuePass = InstructionPass<GlobalValueInst>(
name: "simplify-global_value", {
(globalValue: GlobalValueInst, context: InstructionPassContext) in
(globalValue: GlobalValueInst, context: PassContext) in

var users = StackList<Instruction>(context)
if checkUsers(of: globalValue, users: &users) {
Expand Down
Loading