@@ -1687,79 +1687,81 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
1687
1687
// and the inserted conversion function.
1688
1688
bool needRetainBeforeCall = false ;
1689
1689
bool needReleaseAfterCall = false ;
1690
- bool needReleaseInSucc = false ;
1690
+ bool needReleaseInSuccess = false ;
1691
1691
switch (ParamTypes[0 ].getConvention ()) {
1692
1692
case ParameterConvention::Direct_Guaranteed:
1693
- assert (!AddressOnlyType &&
1694
- " AddressOnlyType with Direct_Guaranteed is not supported" );
1693
+ case ParameterConvention::Indirect_In_Guaranteed:
1695
1694
switch (ConsumptionKind) {
1696
- case CastConsumptionKind::TakeAlways:
1697
- needReleaseAfterCall = true ;
1698
- break ;
1699
- case CastConsumptionKind::TakeOnSuccess:
1700
- needReleaseInSucc = true ;
1701
- break ;
1702
- case CastConsumptionKind::CopyOnSuccess:
1703
- // Conservatively insert a retain/release pair around the conversion
1704
- // function because the conversion function could decrement the
1705
- // (global) reference count of the source object.
1706
- //
1707
- // %src = load %global_var
1708
- // apply %conversion_func(@guaranteed %src)
1709
- //
1710
- // sil conversion_func {
1711
- // %old_value = load %global_var
1712
- // store %something_else, %global_var
1713
- // strong_release %old_value
1714
- // }
1715
- needRetainBeforeCall = true ;
1716
- needReleaseAfterCall = true ;
1717
- break ;
1695
+ case CastConsumptionKind::TakeAlways:
1696
+ needReleaseAfterCall = true ;
1697
+ break ;
1698
+ case CastConsumptionKind::TakeOnSuccess:
1699
+ needReleaseInSuccess = true ;
1700
+ break ;
1701
+ case CastConsumptionKind::CopyOnSuccess:
1702
+ // Conservatively insert a retain/release pair around the conversion
1703
+ // function because the conversion function could decrement the
1704
+ // (global) reference count of the source object.
1705
+ //
1706
+ // %src = load %global_var
1707
+ // apply %conversion_func(@guaranteed %src)
1708
+ //
1709
+ // sil conversion_func {
1710
+ // %old_value = load %global_var
1711
+ // store %something_else, %global_var
1712
+ // strong_release %old_value
1713
+ // }
1714
+ needRetainBeforeCall = true ;
1715
+ needReleaseAfterCall = true ;
1716
+ break ;
1718
1717
}
1719
1718
break ;
1720
1719
case ParameterConvention::Direct_Owned:
1721
- // The Direct_Owned case is only handled for completeness. Currently this
1720
+ case ParameterConvention::Indirect_In:
1721
+ case ParameterConvention::Indirect_In_Constant:
1722
+ // Currently this
1722
1723
// cannot appear, because the _bridgeToObjectiveC protocol witness method
1723
1724
// always receives the this pointer (= the source) as guaranteed.
1724
- assert (!AddressOnlyType &&
1725
- " AddressOnlyType with Direct_Owned is not supported" );
1725
+ // If it became possible (perhaps with the advent of ownership and
1726
+ // explicit +1 annotations), the implementation should look something
1727
+ // like this:
1728
+ /*
1726
1729
switch (ConsumptionKind) {
1727
1730
case CastConsumptionKind::TakeAlways:
1728
1731
break;
1729
1732
case CastConsumptionKind::TakeOnSuccess:
1730
1733
needRetainBeforeCall = true;
1731
- needReleaseInSucc = true ;
1734
+ needReleaseInSuccess = true;
1732
1735
break;
1733
1736
case CastConsumptionKind::CopyOnSuccess:
1734
1737
needRetainBeforeCall = true;
1735
1738
break;
1736
1739
}
1737
1740
break;
1741
+ */
1742
+ llvm_unreachable (" this should never happen so is currently untestable" );
1738
1743
case ParameterConvention::Direct_Unowned:
1739
1744
assert (!AddressOnlyType &&
1740
1745
" AddressOnlyType with Direct_Unowned is not supported" );
1741
1746
break ;
1742
- case ParameterConvention::Indirect_In_Guaranteed:
1743
- // Source as-is, we don't need to copy it due to guarantee
1744
- break ;
1745
- case ParameterConvention::Indirect_In_Constant:
1746
- case ParameterConvention::Indirect_In: {
1747
- assert (substConv.isSILIndirect (ParamTypes[0 ])
1748
- && " unsupported convention for bridging conversion" );
1749
- // Need to make a copy of the source, can be changed in ObjC
1750
- auto BridgeStack = Builder.createAllocStack (Loc, Src->getType ());
1751
- Builder.createCopyAddr (Loc, Src, BridgeStack, IsNotTake,
1752
- IsInitialization);
1753
- break ;
1754
- }
1755
1747
case ParameterConvention::Indirect_Inout:
1756
1748
case ParameterConvention::Indirect_InoutAliasable:
1757
1749
// TODO handle remaining indirect argument types
1758
1750
return nullptr ;
1759
1751
}
1760
1752
1761
- if (needRetainBeforeCall)
1762
- Builder.createRetainValue (Loc, Src, Builder.getDefaultAtomicity ());
1753
+ bool needStackAllocatedTemporary = false ;
1754
+ if (needRetainBeforeCall) {
1755
+ if (AddressOnlyType) {
1756
+ needStackAllocatedTemporary = true ;
1757
+ auto NewSrc = Builder.createAllocStack (Loc, Src->getType ());
1758
+ Builder.createCopyAddr (Loc, Src, NewSrc,
1759
+ IsNotTake, IsInitialization);
1760
+ Src = NewSrc;
1761
+ } else {
1762
+ Builder.createRetainValue (Loc, Src, Builder.getDefaultAtomicity ());
1763
+ }
1764
+ }
1763
1765
1764
1766
SmallVector<Substitution, 4 > Subs;
1765
1767
if (auto *Sig = Source->getAnyNominal ()->getGenericSignature ())
@@ -1768,12 +1770,41 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
1768
1770
// Generate a code to invoke the bridging function.
1769
1771
auto *NewAI = Builder.createApply (Loc, FnRef, Subs, Src, false );
1770
1772
1773
+ auto releaseSrc = [&](SILBuilder &Builder) {
1774
+ if (AddressOnlyType) {
1775
+ Builder.createDestroyAddr (Loc, Src);
1776
+ } else {
1777
+ Builder.createReleaseValue (Loc, Src, Builder.getDefaultAtomicity ());
1778
+ }
1779
+ };
1780
+
1781
+ Optional<SILBuilder> SuccBuilder;
1782
+ if (needReleaseInSuccess || needStackAllocatedTemporary)
1783
+ SuccBuilder.emplace (SuccessBB->begin ());
1784
+
1771
1785
if (needReleaseAfterCall) {
1772
- Builder.createReleaseValue (Loc, Src, Builder.getDefaultAtomicity ());
1773
- } else if (needReleaseInSucc) {
1774
- SILBuilder SuccBuilder (SuccessBB->begin ());
1775
- SuccBuilder.createReleaseValue (Loc, Src, SuccBuilder.getDefaultAtomicity ());
1786
+ releaseSrc (Builder);
1787
+ } else if (needReleaseInSuccess) {
1788
+ if (SuccessBB) {
1789
+ releaseSrc (*SuccBuilder);
1790
+ } else {
1791
+ // For an unconditional cast, success is the only defined path
1792
+ releaseSrc (Builder);
1793
+ }
1794
+ }
1795
+
1796
+ // Pop the temporary stack slot for a copied temporary.
1797
+ if (needStackAllocatedTemporary) {
1798
+ assert ((bool )SuccessBB == (bool )FailureBB);
1799
+ if (SuccessBB) {
1800
+ SuccBuilder->createDeallocStack (Loc, Src);
1801
+ SILBuilder FailBuilder (FailureBB->begin ());
1802
+ FailBuilder.createDeallocStack (Loc, Src);
1803
+ } else {
1804
+ Builder.createDeallocStack (Loc, Src);
1805
+ }
1776
1806
}
1807
+
1777
1808
SILInstruction *NewI = NewAI;
1778
1809
1779
1810
if (Dest) {
0 commit comments