Skip to content

Commit 934f34d

Browse files
authored
Merge pull request #25693 from gottesmm/pr-2677daef7169119f14e1aaf6f7117ef39430deb8
[cast-opt] Improve handling of arguments when optimizing Swift -> Obj…
2 parents bcdd46c + 5d96753 commit 934f34d

File tree

5 files changed

+271
-173
lines changed

5 files changed

+271
-173
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,16 @@ class SILBuilder {
20922092
lowering.emitDestroyValue(*this, Loc, v);
20932093
}
20942094

2095+
/// Convenience function for destroying objects and addresses.
2096+
///
2097+
/// Objects are destroyed using emitDestroyValueOperation and addresses by
2098+
/// emitting destroy_addr.
2099+
void emitDestroyOperation(SILLocation loc, SILValue v) {
2100+
if (v->getType().isObject())
2101+
return emitDestroyValueOperation(loc, v);
2102+
createDestroyAddr(loc, v);
2103+
}
2104+
20952105
SILValue emitTupleExtract(SILLocation Loc, SILValue Operand, unsigned FieldNo,
20962106
SILType ResultTy) {
20972107
// Fold tuple_extract(tuple(x,y,z),2)

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 35 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -346,27 +346,27 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
346346
// If we have guaranteed normal arguments, insert the destroy.
347347
//
348348
// TODO: Is it safe to just eliminate the initial retain?
349-
Builder.emitDestroyValueOperation(Loc, srcArg);
349+
Builder.emitDestroyOperation(Loc, srcArg);
350350

351351
// If we have an unconditional_checked_cast_addr, return early. We do not need
352352
// to handle any conditional code.
353353
if (isa<UnconditionalCheckedCastAddrInst>(Inst)) {
354354
// Destroy the source value as unconditional_checked_cast_addr would.
355-
Builder.emitDestroyValueOperation(Loc, srcOp);
355+
Builder.emitDestroyOperation(Loc, srcOp);
356356
eraseInstAction(Inst);
357357
return (newI) ? newI : AI;
358358
}
359359

360360
auto *CCABI = cast<CheckedCastAddrBranchInst>(Inst);
361361
switch (CCABI->getConsumptionKind()) {
362362
case CastConsumptionKind::TakeAlways:
363-
Builder.emitDestroyValueOperation(Loc, srcOp);
363+
Builder.emitDestroyOperation(Loc, srcOp);
364364
break;
365365
case CastConsumptionKind::TakeOnSuccess: {
366366
{
367367
// Insert a release in the success BB.
368368
SILBuilderWithScope successBuilder(SuccessBB->begin());
369-
successBuilder.emitDestroyValueOperation(Loc, srcOp);
369+
successBuilder.emitDestroyOperation(Loc, srcOp);
370370
}
371371
{
372372
// And a store in the failure BB.
@@ -590,7 +590,7 @@ static SILValue computeFinalCastedValue(SILBuilderWithScope &builder,
590590
return failureBB->createPhiArgument(newAI->getType(),
591591
ValueOwnershipKind::Owned);
592592
}());
593-
innerBuilder.emitDestroyValueOperation(loc, valueToDestroy);
593+
innerBuilder.emitDestroyOperation(loc, valueToDestroy);
594594
}
595595

596596
auto *condBrSuccessBB =
@@ -651,23 +651,25 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) {
651651
SILType SubstFnTy = bridgedFunc->getLoweredType().substGenericArgs(M, subMap);
652652
SILFunctionConventions substConv(SubstFnTy.castTo<SILFunctionType>(), M);
653653

654-
// check that we can go through with the optimization
654+
// Check that this is a case that the authors of this code thought it could
655+
// handle.
655656
if (!canOptimizeCast(BridgedTargetTy, M, substConv)) {
656657
return nullptr;
657658
}
658659

659660
SILBuilderWithScope Builder(Inst, builderContext);
660661
auto FnRef = Builder.createFunctionRefFor(Loc, bridgedFunc);
661662
auto ParamTypes = SubstFnTy.castTo<SILFunctionType>()->getParameters();
663+
SILValue oldSrc;
662664
if (Src->getType().isAddress() && !substConv.isSILIndirect(ParamTypes[0])) {
663665
// Create load
666+
oldSrc = Src;
664667
Src =
665668
Builder.emitLoadValueOperation(Loc, Src, LoadOwnershipQualifier::Take);
666669
}
667670

668671
// Compensate different owning conventions of the replaced cast instruction
669672
// and the inserted conversion function.
670-
bool needRetainBeforeCall = false;
671673
bool needReleaseAfterCall = false;
672674
bool needReleaseInSuccess = false;
673675
switch (ParamTypes[0].getConvention()) {
@@ -681,21 +683,10 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) {
681683
needReleaseInSuccess = true;
682684
break;
683685
case CastConsumptionKind::BorrowAlways:
686+
llvm_unreachable("Should never hit this");
684687
case CastConsumptionKind::CopyOnSuccess:
685-
// Conservatively insert a retain/release pair around the conversion
686-
// function because the conversion function could decrement the
687-
// (global) reference count of the source object.
688-
//
689-
// %src = load %global_var
690-
// apply %conversion_func(@guaranteed %src)
691-
//
692-
// sil conversion_func {
693-
// %old_value = load %global_var
694-
// store %something_else, %global_var
695-
// strong_release %old_value
696-
// }
697-
needRetainBeforeCall = true;
698-
needReleaseAfterCall = true;
688+
// We assume that our caller is correct and will treat our argument as
689+
// being immutable, so we do not need to do anything here.
699690
break;
700691
}
701692
break;
@@ -733,53 +724,35 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) {
733724
return nullptr;
734725
}
735726

736-
bool needStackAllocatedTemporary = false;
737-
if (needRetainBeforeCall) {
738-
if (AddressOnlyType) {
739-
needStackAllocatedTemporary = true;
740-
auto NewSrc = Builder.createAllocStack(Loc, Src->getType());
741-
Builder.createCopyAddr(Loc, Src, NewSrc, IsNotTake, IsInitialization);
742-
Src = NewSrc;
743-
} else {
744-
Builder.createRetainValue(Loc, Src, Builder.getDefaultAtomicity());
745-
}
746-
}
747-
748727
// Generate a code to invoke the bridging function.
749728
auto *NewAI = Builder.createApply(Loc, FnRef, subMap, Src);
750729

751-
auto releaseSrc = [&](SILBuilder &Builder) {
752-
if (AddressOnlyType) {
753-
Builder.createDestroyAddr(Loc, Src);
754-
} else {
755-
Builder.emitDestroyValueOperation(Loc, Src);
756-
}
757-
};
758-
759-
Optional<SILBuilder> SuccBuilder;
760-
if (needReleaseInSuccess || needStackAllocatedTemporary)
761-
SuccBuilder.emplace(SuccessBB->begin());
762-
730+
// First if we are going to destroy the value unconditionally, just insert the
731+
// destroy right after the call. This handles some of the conditional cases
732+
// and /all/ of the consuming unconditional cases.
763733
if (needReleaseAfterCall) {
764-
releaseSrc(Builder);
765-
} else if (needReleaseInSuccess) {
766-
if (SuccessBB) {
767-
releaseSrc(*SuccBuilder);
768-
} else {
769-
// For an unconditional cast, success is the only defined path
770-
releaseSrc(Builder);
771-
}
772-
}
773-
774-
// Pop the temporary stack slot for a copied temporary.
775-
if (needStackAllocatedTemporary) {
776-
assert((bool)SuccessBB == (bool)FailureBB);
734+
Builder.emitDestroyOperation(Loc, Src);
735+
} else {
777736
if (SuccessBB) {
778-
SuccBuilder->createDeallocStack(Loc, Src);
779-
SILBuilderWithScope FailBuilder(&*FailureBB->begin(), Builder);
780-
FailBuilder.createDeallocStack(Loc, Src);
737+
SILBuilderWithScope succBuilder(&*SuccessBB->begin(), Builder);
738+
if (needReleaseInSuccess) {
739+
succBuilder.emitDestroyOperation(Loc, Src);
740+
} else {
741+
if (oldSrc) {
742+
succBuilder.emitStoreValueOperation(Loc, Src, oldSrc,
743+
StoreOwnershipQualifier::Init);
744+
}
745+
}
746+
SILBuilderWithScope failBuilder(&*FailureBB->begin(), Builder);
747+
if (oldSrc) {
748+
failBuilder.emitStoreValueOperation(Loc, Src, oldSrc,
749+
StoreOwnershipQualifier::Init);
750+
}
781751
} else {
782-
Builder.createDeallocStack(Loc, Src);
752+
if (oldSrc) {
753+
Builder.emitStoreValueOperation(Loc, Src, oldSrc,
754+
StoreOwnershipQualifier::Init);
755+
}
783756
}
784757
}
785758

test/SILOptimizer/const_fold_objc_bridge.sil

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)