3434using namespace swift ;
3535using namespace Lowering ;
3636
37+ static std::optional<ConversionPeepholeHint>
38+ combineConversions (SILGenFunction &SGF, const Conversion &outer,
39+ const Conversion &inner);
40+
41+
3742// FIXME: With some changes to their callers, all of the below functions
3843// could be re-worked to use emitInjectEnum().
3944ManagedValue
@@ -1255,7 +1260,7 @@ bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF, SILLocation loc,
12551260 Conversion innerConversion,
12561261 ValueProducerRef produceValue) {
12571262 const auto &outerConversion = getConversion ();
1258- auto hint = canPeepholeConversions (SGF, outerConversion, innerConversion);
1263+ auto hint = combineConversions (SGF, outerConversion, innerConversion);
12591264 if (!hint)
12601265 return false ;
12611266
@@ -1663,58 +1668,168 @@ static bool isPeepholeableConversion(CanType innerSrcType, CanType innerDestType
16631668 return isPeepholeableConversionImpl (innerSrcType, innerDestType, outerDestType);
16641669}
16651670
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+
16661812// / TODO: this would really be a lot cleaner if it just returned a
16671813// / 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 ()) {
16731818 case Conversion::Reabstract:
1674- switch (innerConversion .getKind ()) {
1819+ switch (inner .getKind ()) {
16751820 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);
16911822
16921823 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);
17041825
17051826 default :
1706- break ;
1827+ return std:: nullopt ;
17071828 }
17081829
1709- return std::nullopt ;
1710-
17111830 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);
17181833 return std::nullopt ;
17191834
17201835 case Conversion::AnyErasure:
@@ -1726,104 +1841,21 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
17261841
17271842 case Conversion::ForceAndBridgeToObjC:
17281843 case Conversion::BridgeToObjC:
1729- switch (innerConversion .getKind ()) {
1844+ switch (inner .getKind ()) {
17301845 case Conversion::AnyErasure:
17311846 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);
18231849
18241850 default :
18251851 return std::nullopt ;
18261852 }
18271853 }
18281854 llvm_unreachable (" bad kind" );
18291855}
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