@@ -2058,15 +2058,21 @@ void PatternMatchEmission::emitEnumElementDispatch(
20582058 // After this point we now that we must have an address only type.
20592059 assert (src.getType ().isAddressOnly (SGF.F ) &&
20602060 " Should have an address only type here" );
2061+ assert (!UncheckedTakeEnumDataAddrInst::isDestructive (src.getType ().getEnumOrBoundGenericEnum (),
2062+ SGF.getModule ()) &&
2063+ " address only enum projection should never be destructive" );
20612064
20622065 CanType sourceType = rows[0 ].Pattern ->getType ()->getCanonicalType ();
20632066
20642067 // Collect the cases and specialized rows.
20652068 CaseBlocks blocks{SGF, rows, sourceType, SGF.B .getInsertionBB ()};
20662069
2067- // We lack a SIL instruction to nondestructively project data from an
2070+ // We (used to) lack a SIL instruction to nondestructively project data from an
20682071 // address-only enum, so we can only do so in place if we're allowed to take
20692072 // the source always. Copy the source if we can't.
2073+ //
2074+ // TODO: This should no longer be necessary now that we guarantee that
2075+ // potentially address-only enums never use spare bit optimization.
20702076 switch (src.getFinalConsumption ()) {
20712077 case CastConsumptionKind::TakeAlways:
20722078 case CastConsumptionKind::CopyOnSuccess:
@@ -2086,8 +2092,6 @@ void PatternMatchEmission::emitEnumElementDispatch(
20862092 }
20872093
20882094 // Emit the switch_enum_addr instruction.
2089- //
2090- // NOTE: switch_enum_addr does not actually consume the underlying value.
20912095 SGF.B .createSwitchEnumAddr (loc, src.getValue (), blocks.getDefaultBlock (),
20922096 blocks.getCaseBlocks (), blocks.getCounts (),
20932097 defaultCaseCount);
@@ -2171,22 +2175,21 @@ void PatternMatchEmission::emitEnumElementDispatch(
21712175 ManagedValue eltValue;
21722176 // We can only project destructively from an address-only enum, so
21732177 // copy the value if we can't consume it.
2174- // TODO: Should have a more efficient way to copy payload
2175- // nondestructively from an enum .
2178+ // TODO: Copying should be avoidable now that we guarantee that address-
2179+ // only enums never use spare bit optimization .
21762180 switch (eltConsumption) {
21772181 case CastConsumptionKind::TakeAlways: {
21782182 auto finalValue = src.getFinalManagedValue ();
21792183 eltValue = SGF.B .createUncheckedTakeEnumDataAddr (loc, finalValue,
21802184 eltDecl, eltTy);
21812185 break ;
21822186 }
2183- case CastConsumptionKind::BorrowAlways:
2184- // If we reach this point, we know that we have a loadable
2185- // element type from an enum with mixed address
2186- // only/loadable cases. Since we had an address only type,
2187- // we assume that we will not have BorrowAlways since
2188- // address only types do not support BorrowAlways.
2189- llvm_unreachable (" not allowed" );
2187+ case CastConsumptionKind::BorrowAlways: {
2188+ eltValue = ManagedValue::forBorrowedAddressRValue (
2189+ SGF.B .createUncheckedTakeEnumDataAddr (loc, src.getValue (),
2190+ eltDecl, eltTy));
2191+ break ;
2192+ }
21902193 case CastConsumptionKind::CopyOnSuccess: {
21912194 auto temp = SGF.emitTemporary (loc, SGF.getTypeLowering (src.getType ()));
21922195 SGF.B .createCopyAddr (loc, src.getValue (), temp->getAddress (), IsNotTake,
@@ -2212,12 +2215,22 @@ void PatternMatchEmission::emitEnumElementDispatch(
22122215 if (eltTL->isLoadable ()) {
22132216 // If we do not have a loadable value, just use getManagedSubobject
22142217 // Load a loadable data value.
2215- if (eltConsumption == CastConsumptionKind::CopyOnSuccess) {
2218+ switch (eltConsumption) {
2219+ case CastConsumptionKind::CopyOnSuccess:
22162220 eltValue = SGF.B .createLoadBorrow (loc, eltValue);
22172221 eltConsumption = CastConsumptionKind::BorrowAlways;
2218- } else {
2219- assert (eltConsumption == CastConsumptionKind::TakeAlways);
2222+ break ;
2223+
2224+ case CastConsumptionKind::TakeAlways:
22202225 eltValue = SGF.B .createLoadTake (loc, eltValue);
2226+ break ;
2227+
2228+ case CastConsumptionKind::BorrowAlways:
2229+ eltValue = SGF.B .createLoadBorrow (loc, eltValue);
2230+ break ;
2231+
2232+ case CastConsumptionKind::TakeOnSuccess:
2233+ llvm_unreachable (" not possible" );
22212234 }
22222235 origCMV = {eltValue, eltConsumption};
22232236 } else {
@@ -2847,33 +2860,88 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
28472860 ManagedValue subjectMV = emitRValueAsSingleValue (
28482861 S->getSubjectExpr (), SGFContext::AllowGuaranteedPlusZero);
28492862
2863+ llvm::Optional<ValueOwnership> noncopyableSwitchOwnership;
2864+
28502865 // Inline constructor for subject.
28512866 auto subject = ([&]() -> ConsumableManagedValue {
2852- // If we have a noImplicitCopy value, ensure plus one and convert
2853- // it. Switches always consume move only values.
2854- //
2855- // NOTE: We purposely do not do this for pure move only types since for them
2856- // we emit everything at +0 and then run the BorrowToDestructure transform
2857- // upon them. The reason that we do this is that internally to
2858- // SILGenPattern, we always attempt to move from +1 -> +0 meaning that even
2859- // if we start at +1, we will go back to +0 given enough patterns to go
2860- // through. It is simpler to just let SILGenPattern do what it already wants
2861- // to do, rather than fight it or try to resusitate the "fake owned borrow"
2862- // path that we still use for address only types (and that we want to delete
2863- // once we have opaque values).
2864- if (subjectMV.getType ().isMoveOnly () && subjectMV.getType ().isObject ()) {
2865- if (subjectMV.getType ().isMoveOnlyWrapped ()) {
2866- subjectMV = B.createOwnedMoveOnlyWrapperToCopyableValue (
2867- S, subjectMV.ensurePlusOne (*this , S));
2868- } else {
2869- // If we have a pure move only type and it is owned, borrow it so that
2870- // BorrowToDestructure can handle it.
2871- if (subjectMV.getOwnershipKind () == OwnershipKind::Owned) {
2867+ if (subjectMV.getType ().isMoveOnly ()) {
2868+ if (getASTContext ().LangOpts .hasFeature (Feature::BorrowingSwitch)) {
2869+ // Determine the overall ownership behavior of the switch, based on the
2870+ // patterns' ownership behavior.
2871+ auto ownership = ValueOwnership::Shared;
2872+ for (auto caseLabel : S->getCases ()) {
2873+ for (auto item : caseLabel->getCaseLabelItems ()) {
2874+ ownership = std::max (ownership, item.getPattern ()->getOwnership ());
2875+ }
2876+ }
2877+ noncopyableSwitchOwnership = ownership;
2878+
2879+ // Based on the ownership behavior, prepare the subject.
2880+ // The pattern match itself will always be performed on a borrow, to
2881+ // ensure that the order of pattern evaluation doesn't prematurely
2882+ // consume or modify the value until we commit to a match. But if the
2883+ // match consumes the value, then we need a +1 value to go back to in
2884+ // order to consume the parts we match to, so we force a +1 value then
2885+ // borrow that for the pattern match.
2886+ switch (ownership) {
2887+ case ValueOwnership::Default:
2888+ llvm_unreachable (" invalid" );
2889+
2890+ case ValueOwnership::Shared:
2891+ if (subjectMV.getType ().isAddress () &&
2892+ subjectMV.getType ().isLoadable (F)) {
2893+ // Load a borrow if the type is loadable.
2894+ subjectMV = B.createLoadBorrow (S, subjectMV);
2895+ } else if (!subjectMV.isPlusZero ()) {
2896+ subjectMV = subjectMV.borrow (*this , S);
2897+ }
2898+ return {subjectMV, CastConsumptionKind::BorrowAlways};
2899+
2900+ case ValueOwnership::InOut:
2901+ // TODO: mutating switches
2902+ llvm_unreachable (" not implemented" );
2903+
2904+ case ValueOwnership::Owned:
2905+ // Make sure we own the subject value.
2906+ subjectMV = subjectMV.ensurePlusOne (*this , S);
2907+ if (subjectMV.getType ().isAddress () &&
2908+ subjectMV.getType ().isLoadable (F)) {
2909+ // Move the value into memory if it's loadable.
2910+ subjectMV = B.createLoadTake (S, subjectMV);
2911+ }
2912+ // Perform the pattern match on a borrow of the subject.
28722913 subjectMV = subjectMV.borrow (*this , S);
2914+ return {subjectMV, CastConsumptionKind::BorrowAlways};
2915+ }
2916+ llvm_unreachable (" unhandled value ownership" );
2917+ } else {
2918+ // If we have a noImplicitCopy value, ensure plus one and convert
2919+ // it. Switches always consume move only values.
2920+ //
2921+ // NOTE: We purposely do not do this for pure move only types since for them
2922+ // we emit everything at +0 and then run the BorrowToDestructure transform
2923+ // upon them. The reason that we do this is that internally to
2924+ // SILGenPattern, we always attempt to move from +1 -> +0 meaning that even
2925+ // if we start at +1, we will go back to +0 given enough patterns to go
2926+ // through. It is simpler to just let SILGenPattern do what it already wants
2927+ // to do, rather than fight it or try to resusitate the "fake owned borrow"
2928+ // path that we still use for address only types (and that we want to delete
2929+ // once we have opaque values).
2930+ if (subjectMV.getType ().isObject ()) {
2931+ if (subjectMV.getType ().isMoveOnlyWrapped ()) {
2932+ subjectMV = B.createOwnedMoveOnlyWrapperToCopyableValue (
2933+ S, subjectMV.ensurePlusOne (*this , S));
2934+ } else {
2935+ // If we have a pure move only type and it is owned, borrow it so that
2936+ // BorrowToDestructure can handle it.
2937+ if (subjectMV.getOwnershipKind () == OwnershipKind::Owned) {
2938+ subjectMV = subjectMV.borrow (*this , S);
2939+ }
2940+ }
28732941 }
28742942 }
28752943 }
2876-
2944+
28772945 // If we have a plus one value...
28782946 if (subjectMV.isPlusOne (*this )) {
28792947 // And we have an address that is loadable, perform a load [take].
0 commit comments