34
34
using namespace swift ;
35
35
using namespace Lowering ;
36
36
37
+ static std::optional<ConversionPeepholeHint>
38
+ combineConversions (SILGenFunction &SGF, const Conversion &outer,
39
+ const Conversion &inner);
40
+
41
+
37
42
// FIXME: With some changes to their callers, all of the below functions
38
43
// could be re-worked to use emitInjectEnum().
39
44
ManagedValue
@@ -1255,7 +1260,7 @@ bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF, SILLocation loc,
1255
1260
Conversion innerConversion,
1256
1261
ValueProducerRef produceValue) {
1257
1262
const auto &outerConversion = getConversion ();
1258
- auto hint = canPeepholeConversions (SGF, outerConversion, innerConversion);
1263
+ auto hint = combineConversions (SGF, outerConversion, innerConversion);
1259
1264
if (!hint)
1260
1265
return false ;
1261
1266
@@ -1663,58 +1668,168 @@ static bool isPeepholeableConversion(CanType innerSrcType, CanType innerDestType
1663
1668
return isPeepholeableConversionImpl (innerSrcType, innerDestType, outerDestType);
1664
1669
}
1665
1670
1671
+ static std::optional<ConversionPeepholeHint>
1672
+ combineReabstract (SILGenFunction &SGF,
1673
+ const Conversion &outer,
1674
+ const Conversion &inner) {
1675
+ // We can never combine conversions in a way that would lose information
1676
+ // about the intermediate types.
1677
+ if (!isPeepholeableConversion (inner.getReabstractionInputSubstType (),
1678
+ inner.getReabstractionOutputSubstType (),
1679
+ outer.getReabstractionInputSubstType (),
1680
+ outer.getReabstractionOutputSubstType ()))
1681
+ return std::nullopt;
1682
+
1683
+ // Recognize when the whole conversion is an identity.
1684
+ if (inner.getReabstractionInputLoweredType ().getObjectType () ==
1685
+ outer.getReabstractionOutputLoweredType ().getObjectType ())
1686
+ return ConversionPeepholeHint (ConversionPeepholeHint::Identity, false );
1687
+
1688
+ return ConversionPeepholeHint (ConversionPeepholeHint::Reabstract, false );
1689
+ }
1690
+
1691
+ static std::optional<ConversionPeepholeHint>
1692
+ combineSubtypeIntoReabstract (SILGenFunction &SGF,
1693
+ const Conversion &outer,
1694
+ const Conversion &inner) {
1695
+ // We can never combine conversions in a way that would lose information
1696
+ // about the intermediate types.
1697
+ if (!isPeepholeableConversion (inner.getBridgingSourceType (),
1698
+ inner.getBridgingResultType (),
1699
+ outer.getReabstractionInputSubstType (),
1700
+ outer.getReabstractionOutputSubstType ()))
1701
+ return std::nullopt;
1702
+
1703
+ return ConversionPeepholeHint (
1704
+ ConversionPeepholeHint::SubtypeIntoReabstract, false );
1705
+ }
1706
+
1707
+ static std::optional<ConversionPeepholeHint>
1708
+ combineSubtype (SILGenFunction &SGF,
1709
+ const Conversion &outer, const Conversion &inner) {
1710
+ if (!isPeepholeableConversion (inner.getBridgingSourceType (),
1711
+ inner.getBridgingResultType (),
1712
+ outer.getBridgingSourceType (),
1713
+ outer.getBridgingResultType ()))
1714
+ return std::nullopt;
1715
+
1716
+ return ConversionPeepholeHint (ConversionPeepholeHint::Subtype, false );
1717
+ }
1718
+
1719
+ static std::optional<ConversionPeepholeHint>
1720
+ combineBridging (SILGenFunction &SGF,
1721
+ const Conversion &outer, const Conversion &inner) {
1722
+ bool outerExplicit = outer.isBridgingExplicit ();
1723
+ bool innerExplicit = inner.isBridgingExplicit ();
1724
+
1725
+ // Never peephole if both conversions are explicit; there might be
1726
+ // something the user's trying to do which we don't understand.
1727
+ if (outerExplicit && innerExplicit)
1728
+ return std::nullopt;
1729
+
1730
+ // Otherwise, we can peephole if we understand the resulting conversion
1731
+ // and applying the peephole doesn't change semantics.
1732
+
1733
+ CanType sourceType = inner.getBridgingSourceType ();
1734
+ CanType intermediateType = inner.getBridgingResultType ();
1735
+ assert (intermediateType == outer.getBridgingSourceType ());
1736
+
1737
+ // If we're doing a peephole involving a force, we want to propagate
1738
+ // the force to the source value. If it's not in fact optional, that
1739
+ // won't work.
1740
+ bool forced = outer.getKind () == Conversion::ForceAndBridgeToObjC;
1741
+ if (forced) {
1742
+ sourceType = sourceType.getOptionalObjectType ();
1743
+ if (!sourceType)
1744
+ return std::nullopt;
1745
+ intermediateType = intermediateType.getOptionalObjectType ();
1746
+ assert (intermediateType);
1747
+ }
1748
+
1749
+ CanType resultType = outer.getBridgingResultType ();
1750
+ SILType loweredSourceTy = SGF.getLoweredType (sourceType);
1751
+ SILType loweredResultTy = outer.getBridgingLoweredResultType ();
1752
+
1753
+ auto applyPeephole = [&](ConversionPeepholeHint::Kind kind) {
1754
+ return ConversionPeepholeHint (kind, forced);
1755
+ };
1756
+
1757
+ // Converting to Any doesn't do anything semantically special, so we
1758
+ // can apply the peephole unconditionally.
1759
+ if (isMatchedAnyToAnyObjectConversion (intermediateType, resultType)) {
1760
+ if (loweredSourceTy == loweredResultTy) {
1761
+ return applyPeephole (ConversionPeepholeHint::Identity);
1762
+ } else if (isValueToAnyConversion (sourceType, intermediateType)) {
1763
+ return applyPeephole (ConversionPeepholeHint::BridgeToAnyObject);
1764
+ } else {
1765
+ return applyPeephole (ConversionPeepholeHint::Subtype);
1766
+ }
1767
+ }
1768
+
1769
+ // Otherwise, undoing a bridging conversions can change semantics by
1770
+ // e.g. removing a copy, so we shouldn't do it unless the special
1771
+ // syntactic bridging peephole applies. That requires one of the
1772
+ // conversions to be explicit.
1773
+ // TODO: use special SILGen to preserve semantics in this case,
1774
+ // e.g. by making a copy.
1775
+ if (!outerExplicit && !innerExplicit) {
1776
+ return std::nullopt;
1777
+ }
1778
+
1779
+ // Okay, now we're in the domain of the bridging peephole: an
1780
+ // explicit bridging conversion can cancel out an implicit bridge
1781
+ // between related types.
1782
+
1783
+ // If the source and destination types have exactly the same
1784
+ // representation, then (1) they're related and (2) we can directly
1785
+ // emit into the context.
1786
+ if (loweredSourceTy.getObjectType () == loweredResultTy.getObjectType ()) {
1787
+ return applyPeephole (ConversionPeepholeHint::Identity);
1788
+ }
1789
+
1790
+ // Look for a subtype relationship between the source and destination.
1791
+ if (areRelatedTypesForBridgingPeephole (sourceType, resultType)) {
1792
+ return applyPeephole (ConversionPeepholeHint::Subtype);
1793
+ }
1794
+
1795
+ // If the inner conversion is a result conversion that removes
1796
+ // optionality, and the non-optional source type is a subtype of the
1797
+ // value type, this is just an implicit force.
1798
+ if (!forced &&
1799
+ inner.getKind () == Conversion::BridgeResultFromObjC) {
1800
+ if (auto sourceValueType = sourceType.getOptionalObjectType ()) {
1801
+ if (!intermediateType.getOptionalObjectType () &&
1802
+ areRelatedTypesForBridgingPeephole (sourceValueType, resultType)) {
1803
+ forced = true ;
1804
+ return applyPeephole (ConversionPeepholeHint::Subtype);
1805
+ }
1806
+ }
1807
+ }
1808
+
1809
+ return std::nullopt;
1810
+ }
1811
+
1666
1812
// / TODO: this would really be a lot cleaner if it just returned a
1667
1813
// / std::optional<Conversion>.
1668
- std::optional<ConversionPeepholeHint>
1669
- Lowering::canPeepholeConversions (SILGenFunction &SGF,
1670
- const Conversion &outerConversion,
1671
- const Conversion &innerConversion) {
1672
- switch (outerConversion.getKind ()) {
1814
+ static std::optional<ConversionPeepholeHint>
1815
+ combineConversions (SILGenFunction &SGF, const Conversion &outer,
1816
+ const Conversion &inner) {
1817
+ switch (outer.getKind ()) {
1673
1818
case Conversion::Reabstract:
1674
- switch (innerConversion .getKind ()) {
1819
+ switch (inner .getKind ()) {
1675
1820
case Conversion::Reabstract:
1676
- // We can never combine conversions in a way that would lose information
1677
- // about the intermediate types.
1678
- if (!isPeepholeableConversion (
1679
- innerConversion.getReabstractionInputSubstType (),
1680
- innerConversion.getReabstractionOutputSubstType (),
1681
- outerConversion.getReabstractionInputSubstType (),
1682
- outerConversion.getReabstractionOutputSubstType ()))
1683
- return std::nullopt;
1684
-
1685
- // Recognize when the whole conversion is an identity.
1686
- if (innerConversion.getReabstractionInputLoweredType ().getObjectType () ==
1687
- outerConversion.getReabstractionOutputLoweredType ().getObjectType ())
1688
- return ConversionPeepholeHint (ConversionPeepholeHint::Identity, false );
1689
-
1690
- return ConversionPeepholeHint (ConversionPeepholeHint::Reabstract, false );
1821
+ return combineReabstract (SGF, outer, inner);
1691
1822
1692
1823
case Conversion::Subtype:
1693
- // We can never combine conversions in a way that would lose information
1694
- // about the intermediate types.
1695
- if (!isPeepholeableConversion (
1696
- innerConversion.getBridgingSourceType (),
1697
- innerConversion.getBridgingResultType (),
1698
- outerConversion.getReabstractionInputSubstType (),
1699
- outerConversion.getReabstractionOutputSubstType ()))
1700
- return std::nullopt;
1701
-
1702
- return ConversionPeepholeHint (
1703
- ConversionPeepholeHint::SubtypeIntoReabstract, false );
1824
+ return combineSubtypeIntoReabstract (SGF, outer, inner);
1704
1825
1705
1826
default :
1706
- break ;
1827
+ return std::nullopt ;
1707
1828
}
1708
1829
1709
- return std::nullopt;
1710
-
1711
1830
case Conversion::Subtype:
1712
- if (innerConversion.getKind () == Conversion::Subtype &&
1713
- isPeepholeableConversion (innerConversion.getBridgingSourceType (),
1714
- innerConversion.getBridgingResultType (),
1715
- outerConversion.getBridgingSourceType (),
1716
- outerConversion.getBridgingResultType ()))
1717
- return ConversionPeepholeHint (ConversionPeepholeHint::Subtype, false );
1831
+ if (inner.getKind () == Conversion::Subtype)
1832
+ return combineSubtype (SGF, outer, inner);
1718
1833
return std::nullopt;
1719
1834
1720
1835
case Conversion::AnyErasure:
@@ -1726,104 +1841,21 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
1726
1841
1727
1842
case Conversion::ForceAndBridgeToObjC:
1728
1843
case Conversion::BridgeToObjC:
1729
- switch (innerConversion .getKind ()) {
1844
+ switch (inner .getKind ()) {
1730
1845
case Conversion::AnyErasure:
1731
1846
case Conversion::BridgeFromObjC:
1732
- case Conversion::BridgeResultFromObjC: {
1733
- bool outerExplicit = outerConversion.isBridgingExplicit ();
1734
- bool innerExplicit = innerConversion.isBridgingExplicit ();
1735
-
1736
- // Never peephole if both conversions are explicit; there might be
1737
- // something the user's trying to do which we don't understand.
1738
- if (outerExplicit && innerExplicit)
1739
- return std::nullopt;
1740
-
1741
- // Otherwise, we can peephole if we understand the resulting conversion
1742
- // and applying the peephole doesn't change semantics.
1743
-
1744
- CanType sourceType = innerConversion.getBridgingSourceType ();
1745
- CanType intermediateType = innerConversion.getBridgingResultType ();
1746
- assert (intermediateType == outerConversion.getBridgingSourceType ());
1747
-
1748
- // If we're doing a peephole involving a force, we want to propagate
1749
- // the force to the source value. If it's not in fact optional, that
1750
- // won't work.
1751
- bool forced =
1752
- outerConversion.getKind () == Conversion::ForceAndBridgeToObjC;
1753
- if (forced) {
1754
- sourceType = sourceType.getOptionalObjectType ();
1755
- if (!sourceType)
1756
- return std::nullopt;
1757
- intermediateType = intermediateType.getOptionalObjectType ();
1758
- assert (intermediateType);
1759
- }
1760
-
1761
- CanType resultType = outerConversion.getBridgingResultType ();
1762
- SILType loweredSourceTy = SGF.getLoweredType (sourceType);
1763
- SILType loweredResultTy = outerConversion.getBridgingLoweredResultType ();
1764
-
1765
- auto applyPeephole = [&](ConversionPeepholeHint::Kind kind) {
1766
- return ConversionPeepholeHint (kind, forced);
1767
- };
1768
-
1769
- // Converting to Any doesn't do anything semantically special, so we
1770
- // can apply the peephole unconditionally.
1771
- if (isMatchedAnyToAnyObjectConversion (intermediateType, resultType)) {
1772
- if (loweredSourceTy == loweredResultTy) {
1773
- return applyPeephole (ConversionPeepholeHint::Identity);
1774
- } else if (isValueToAnyConversion (sourceType, intermediateType)) {
1775
- return applyPeephole (ConversionPeepholeHint::BridgeToAnyObject);
1776
- } else {
1777
- return applyPeephole (ConversionPeepholeHint::Subtype);
1778
- }
1779
- }
1780
-
1781
- // Otherwise, undoing a bridging conversions can change semantics by
1782
- // e.g. removing a copy, so we shouldn't do it unless the special
1783
- // syntactic bridging peephole applies. That requires one of the
1784
- // conversions to be explicit.
1785
- // TODO: use special SILGen to preserve semantics in this case,
1786
- // e.g. by making a copy.
1787
- if (!outerExplicit && !innerExplicit) {
1788
- return std::nullopt;
1789
- }
1790
-
1791
- // Okay, now we're in the domain of the bridging peephole: an
1792
- // explicit bridging conversion can cancel out an implicit bridge
1793
- // between related types.
1794
-
1795
- // If the source and destination types have exactly the same
1796
- // representation, then (1) they're related and (2) we can directly
1797
- // emit into the context.
1798
- if (loweredSourceTy.getObjectType () == loweredResultTy.getObjectType ()) {
1799
- return applyPeephole (ConversionPeepholeHint::Identity);
1800
- }
1801
-
1802
- // Look for a subtype relationship between the source and destination.
1803
- if (areRelatedTypesForBridgingPeephole (sourceType, resultType)) {
1804
- return applyPeephole (ConversionPeepholeHint::Subtype);
1805
- }
1806
-
1807
- // If the inner conversion is a result conversion that removes
1808
- // optionality, and the non-optional source type is a subtype of the
1809
- // value type, this is just an implicit force.
1810
- if (!forced &&
1811
- innerConversion.getKind () == Conversion::BridgeResultFromObjC) {
1812
- if (auto sourceValueType = sourceType.getOptionalObjectType ()) {
1813
- if (!intermediateType.getOptionalObjectType () &&
1814
- areRelatedTypesForBridgingPeephole (sourceValueType, resultType)) {
1815
- forced = true ;
1816
- return applyPeephole (ConversionPeepholeHint::Subtype);
1817
- }
1818
- }
1819
- }
1820
-
1821
- return std::nullopt;
1822
- }
1847
+ case Conversion::BridgeResultFromObjC:
1848
+ return combineBridging (SGF, outer, inner);
1823
1849
1824
1850
default :
1825
1851
return std::nullopt;
1826
1852
}
1827
1853
}
1828
1854
llvm_unreachable (" bad kind" );
1829
1855
}
1856
+
1857
+ bool Lowering::canPeepholeConversions (SILGenFunction &SGF,
1858
+ const Conversion &outer,
1859
+ const Conversion &inner) {
1860
+ return combineConversions (SGF, outer, inner).has_value ();
1861
+ }
0 commit comments