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