@@ -2058,15 +2058,21 @@ void PatternMatchEmission::emitEnumElementDispatch(
2058
2058
// After this point we now that we must have an address only type.
2059
2059
assert(src.getType().isAddressOnly(SGF.F) &&
2060
2060
"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");
2061
2064
2062
2065
CanType sourceType = rows[0].Pattern->getType()->getCanonicalType();
2063
2066
2064
2067
// Collect the cases and specialized rows.
2065
2068
CaseBlocks blocks{SGF, rows, sourceType, SGF.B.getInsertionBB()};
2066
2069
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
2068
2071
// address-only enum, so we can only do so in place if we're allowed to take
2069
2072
// 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.
2070
2076
switch (src.getFinalConsumption()) {
2071
2077
case CastConsumptionKind::TakeAlways:
2072
2078
case CastConsumptionKind::CopyOnSuccess:
@@ -2086,8 +2092,6 @@ void PatternMatchEmission::emitEnumElementDispatch(
2086
2092
}
2087
2093
2088
2094
// Emit the switch_enum_addr instruction.
2089
- //
2090
- // NOTE: switch_enum_addr does not actually consume the underlying value.
2091
2095
SGF.B.createSwitchEnumAddr(loc, src.getValue(), blocks.getDefaultBlock(),
2092
2096
blocks.getCaseBlocks(), blocks.getCounts(),
2093
2097
defaultCaseCount);
@@ -2171,22 +2175,21 @@ void PatternMatchEmission::emitEnumElementDispatch(
2171
2175
ManagedValue eltValue;
2172
2176
// We can only project destructively from an address-only enum, so
2173
2177
// 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 .
2176
2180
switch (eltConsumption) {
2177
2181
case CastConsumptionKind::TakeAlways: {
2178
2182
auto finalValue = src.getFinalManagedValue();
2179
2183
eltValue = SGF.B.createUncheckedTakeEnumDataAddr(loc, finalValue,
2180
2184
eltDecl, eltTy);
2181
2185
break;
2182
2186
}
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
+ }
2190
2193
case CastConsumptionKind::CopyOnSuccess: {
2191
2194
auto temp = SGF.emitTemporary(loc, SGF.getTypeLowering(src.getType()));
2192
2195
SGF.B.createCopyAddr(loc, src.getValue(), temp->getAddress(), IsNotTake,
@@ -2212,12 +2215,22 @@ void PatternMatchEmission::emitEnumElementDispatch(
2212
2215
if (eltTL->isLoadable()) {
2213
2216
// If we do not have a loadable value, just use getManagedSubobject
2214
2217
// Load a loadable data value.
2215
- if (eltConsumption == CastConsumptionKind::CopyOnSuccess) {
2218
+ switch (eltConsumption) {
2219
+ case CastConsumptionKind::CopyOnSuccess:
2216
2220
eltValue = SGF.B.createLoadBorrow(loc, eltValue);
2217
2221
eltConsumption = CastConsumptionKind::BorrowAlways;
2218
- } else {
2219
- assert(eltConsumption == CastConsumptionKind::TakeAlways);
2222
+ break;
2223
+
2224
+ case CastConsumptionKind::TakeAlways:
2220
2225
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");
2221
2234
}
2222
2235
origCMV = {eltValue, eltConsumption};
2223
2236
} else {
@@ -2847,33 +2860,88 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2847
2860
ManagedValue subjectMV = emitRValueAsSingleValue(
2848
2861
S->getSubjectExpr(), SGFContext::AllowGuaranteedPlusZero);
2849
2862
2863
+ llvm::Optional<ValueOwnership> noncopyableSwitchOwnership;
2864
+
2850
2865
// Inline constructor for subject.
2851
2866
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.
2872
2913
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
+ }
2873
2941
}
2874
2942
}
2875
2943
}
2876
-
2944
+
2877
2945
// If we have a plus one value...
2878
2946
if (subjectMV.isPlusOne(*this)) {
2879
2947
// And we have an address that is loadable, perform a load [take].
0 commit comments