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
@@ -1247,7 +1252,7 @@ bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF, SILLocation loc,
12471252 Conversion innerConversion,
12481253 ValueProducerRef produceValue) {
12491254 const auto &outerConversion = getConversion ();
1250- auto hint = canPeepholeConversions (SGF, outerConversion, innerConversion);
1255+ auto hint = combineConversions (SGF, outerConversion, innerConversion);
12511256 if (!hint)
12521257 return false ;
12531258
@@ -1655,58 +1660,168 @@ static bool isPeepholeableConversion(CanType innerSrcType, CanType innerDestType
16551660 return isPeepholeableConversionImpl (innerSrcType, innerDestType, outerDestType);
16561661}
16571662
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+
16581804// / TODO: this would really be a lot cleaner if it just returned a
16591805// / 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 ()) {
16651810 case Conversion::Reabstract:
1666- switch (innerConversion .getKind ()) {
1811+ switch (inner .getKind ()) {
16671812 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);
16831814
16841815 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);
16961817
16971818 default :
1698- break ;
1819+ return std:: nullopt ;
16991820 }
17001821
1701- return std::nullopt ;
1702-
17031822 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);
17101825 return std::nullopt ;
17111826
17121827 case Conversion::AnyErasure:
@@ -1718,104 +1833,21 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
17181833
17191834 case Conversion::ForceAndBridgeToObjC:
17201835 case Conversion::BridgeToObjC:
1721- switch (innerConversion .getKind ()) {
1836+ switch (inner .getKind ()) {
17221837 case Conversion::AnyErasure:
17231838 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);
18151841
18161842 default :
18171843 return std::nullopt ;
18181844 }
18191845 }
18201846 llvm_unreachable (" bad kind" );
18211847}
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