Skip to content

Commit 2b019d8

Browse files
authored
Merge pull request #65579 from atrick/fix-silgen-consume
Fix SILGen ManagedValue::isPlusOne for addresses
2 parents 5936f83 + 298880d commit 2b019d8

12 files changed

+92
-46
lines changed

lib/SILGen/ManagedValue.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -155,22 +155,22 @@ SILValue ManagedValue::forward(SILGenFunction &SGF) const {
155155

156156
void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
157157
SILValue address) {
158-
assert(isPlusOne(SGF));
158+
assert(isPlusOneOrTrivial(SGF));
159159
auto &addrTL = SGF.getTypeLowering(address->getType());
160160
SGF.emitSemanticStore(loc, forward(SGF), address, addrTL, IsInitialization);
161161
}
162162

163163
void ManagedValue::assignInto(SILGenFunction &SGF, SILLocation loc,
164164
SILValue address) {
165-
assert(isPlusOne(SGF));
165+
assert(isPlusOneOrTrivial(SGF));
166166
auto &addrTL = SGF.getTypeLowering(address->getType());
167167
SGF.emitSemanticStore(loc, forward(SGF), address, addrTL,
168168
IsNotInitialization);
169169
}
170170

171171
void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
172172
Initialization *dest) {
173-
assert(isPlusOne(SGF));
173+
assert(isPlusOneOrTrivial(SGF));
174174
dest->copyOrInitValueInto(SGF, loc, *this, /*isInit*/ true);
175175
dest->finishInitialization(SGF);
176176
}
@@ -281,7 +281,7 @@ ManagedValue ManagedValue::ensurePlusOne(SILGenFunction &SGF,
281281
if (isa<SILUndef>(getValue()))
282282
return *this;
283283

284-
if (!isPlusOne(SGF)) {
284+
if (!isPlusOneOrTrivial(SGF)) {
285285
return copy(SGF, loc);
286286
}
287287
return *this;
@@ -293,19 +293,20 @@ bool ManagedValue::isPlusOne(SILGenFunction &SGF) const {
293293
if (isa<SILUndef>(getValue()))
294294
return true;
295295

296-
// Ignore trivial values since for our purposes they are always at +1 since
297-
// they can always be passed to +1 APIs.
298-
if (getType().isTrivial(SGF.F))
299-
return true;
300-
301-
// If we have an object and the object has any ownership, the same
302-
// property applies.
296+
// A value without ownership can always be passed to +1 APIs.
297+
//
298+
// This is not true for address types because deinitializing an in-memory
299+
// value invalidates the storage.
303300
if (getType().isObject() && getOwnershipKind() == OwnershipKind::None)
304301
return true;
305302

306303
return hasCleanup();
307304
}
308305

306+
bool ManagedValue::isPlusOneOrTrivial(SILGenFunction &SGF) const {
307+
return getType().isTrivial(SGF.F) || isPlusOne(SGF);
308+
}
309+
309310
bool ManagedValue::isPlusZero() const {
310311
// SILUndef can always be passed to +0 APIs.
311312
if (isa<SILUndef>(getValue()))

lib/SILGen/ManagedValue.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,19 +217,24 @@ class ManagedValue {
217217
return !hasCleanup();
218218
}
219219

220-
/// Returns true if this is an managed value that can be used safely as a +1
221-
/// managed value.
220+
/// Returns true if this managed value can be consumed.
222221
///
223-
/// This returns true iff:
222+
/// This is true if either this value has a cleanup or if it is an
223+
/// SSA value without ownership.
224224
///
225-
/// 1. All sub-values are trivially typed.
226-
/// 2. There exists at least one non-trivial typed sub-value and all such
227-
/// sub-values all have cleanups.
228-
///
229-
/// *NOTE* Due to 1. isPlusOne and isPlusZero both return true for managed
230-
/// values consisting of only trivial values.
225+
/// When an SSA value does not have ownership, it can be used by a consuming
226+
/// operation without destroying it. Consuming a value by address, however,
227+
/// deinitializes the memory regardless of whether the value has ownership.
231228
bool isPlusOne(SILGenFunction &SGF) const;
232229

230+
/// Returns true if this managed value can be forwarded without necessarilly
231+
/// destroying the original.
232+
///
233+
/// This is true if either isPlusOne is true or the value is trivial. A
234+
/// trivial value in memory can be forwarded as a +1 value without
235+
/// deinitializing the memory.
236+
bool isPlusOneOrTrivial(SILGenFunction &SGF) const;
237+
233238
/// Returns true if this is an ManagedValue that can be used safely as a +0
234239
/// ManagedValue.
235240
///

lib/SILGen/RValue.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ SILValue RValue::forwardAsSingleStorageValue(SILGenFunction &SGF,
550550
void RValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
551551
Initialization *I) && {
552552
assert(isComplete() && "rvalue is not complete");
553-
assert(isPlusOne(SGF) && "Can not forward borrowed RValues");
553+
assert(isPlusOneOrTrivial(SGF) && "Can not forward borrowed RValues");
554554
ArrayRef<ManagedValue> elts = values;
555555
copyOrInitValuesInto<ImplodeKind::Forward>(I, elts, type, loc, SGF);
556556
}
@@ -588,7 +588,7 @@ static void assignRecursive(SILGenFunction &SGF, SILLocation loc,
588588
void RValue::assignInto(SILGenFunction &SGF, SILLocation loc,
589589
SILValue destAddr) && {
590590
assert(isComplete() && "rvalue is not complete");
591-
assert(isPlusOne(SGF) && "Can not assign borrowed RValues");
591+
assert(isPlusOneOrTrivial(SGF) && "Can not assign borrowed RValues");
592592
ArrayRef<ManagedValue> srcValues = values;
593593
assignRecursive(SGF, loc, type, srcValues, destAddr);
594594
assert(srcValues.empty() && "didn't claim all elements!");
@@ -734,7 +734,7 @@ RValue RValue::copy(SILGenFunction &SGF, SILLocation loc) const & {
734734
}
735735

736736
RValue RValue::ensurePlusOne(SILGenFunction &SGF, SILLocation loc) && {
737-
if (!isPlusOne(SGF))
737+
if (!isPlusOneOrTrivial(SGF))
738738
return copy(SGF, loc);
739739
return std::move(*this);
740740
}
@@ -751,7 +751,8 @@ RValue RValue::borrow(SILGenFunction &SGF, SILLocation loc) const & {
751751
}
752752

753753
ManagedValue RValue::materialize(SILGenFunction &SGF, SILLocation loc) && {
754-
assert(isPlusOne(SGF) && "Can not materialize a non-plus one RValue");
754+
assert(isPlusOneOrTrivial(SGF) &&
755+
"Can not materialize a non-plus one RValue");
755756
auto &paramTL = SGF.getTypeLowering(getType());
756757

757758
// If we're already materialized, we're done.
@@ -823,6 +824,13 @@ bool RValue::isPlusOne(SILGenFunction &SGF) const & {
823824
values, [&SGF](ManagedValue mv) -> bool { return mv.isPlusOne(SGF); });
824825
}
825826

827+
bool RValue::isPlusOneOrTrivial(SILGenFunction &SGF) const & {
828+
return llvm::all_of(
829+
values, [&SGF](ManagedValue mv) -> bool {
830+
return mv.isPlusOneOrTrivial(SGF);
831+
});
832+
}
833+
826834
bool RValue::isPlusZero(SILGenFunction &SGF) const & {
827835
return llvm::none_of(values,
828836
[](ManagedValue mv) -> bool { return mv.isPlusZero(); });

lib/SILGen/RValue.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -242,18 +242,24 @@ class RValue {
242242
return value;
243243
}
244244

245-
/// Returns true if this is an rvalue that can be used safely as a +1 rvalue.
245+
/// Returns true if this rvalue can be consumed.
246246
///
247-
/// This returns true iff:
247+
/// This is true if each element either has a cleanup or is an SSA value
248+
/// without ownership.
248249
///
249-
/// 1. All sub-values are trivially typed.
250-
/// 2. There exists at least one non-trivial typed sub-value and all such
251-
/// sub-values all have cleanups.
252-
///
253-
/// *NOTE* Due to 1. isPlusOne and isPlusZero both return true for rvalues
254-
/// consisting of only trivial values.
250+
/// When an SSA value does not have ownership, it can be used by a consuming
251+
/// operation without destroying it. Consuming a value by address, however,
252+
/// deinitializes the memory regardless of whether the value has ownership.
255253
bool isPlusOne(SILGenFunction &SGF) const &;
256254

255+
/// Returns true if this rvalue can be forwarded without necessarilly
256+
/// destroying the original.
257+
///
258+
/// This is true if either isPlusOne is true or the value is trivial. A
259+
/// trivial value in memory can be forwarded as a +1 value without
260+
/// deinitializing the memory.
261+
bool isPlusOneOrTrivial(SILGenFunction &SGF) const &;
262+
257263
/// Returns true if this is an rvalue that can be used safely as a +0 rvalue.
258264
///
259265
/// Specifically, we return true if:

lib/SILGen/SILGenConvert.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ ManagedValue SILGenFunction::manageOpaqueValue(ManagedValue value,
999999
SGFContext C) {
10001000
// If the opaque value is consumable, we can just return the
10011001
// value with a cleanup. There is no need to retain it separately.
1002-
if (value.isPlusOne(*this))
1002+
if (value.isPlusOneOrTrivial(*this))
10031003
return value;
10041004

10051005
// If the context wants a +0 value, guaranteed or immediate, we can

lib/SILGen/SILGenDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ void TupleInitialization::copyOrInitValueInto(SILGenFunction &SGF,
145145
// In the address case, we forward the underlying value and store it
146146
// into memory and then create a +1 cleanup. since we assume here
147147
// that we have a +1 value since we are forwarding into memory.
148-
assert(value.isPlusOne(SGF) && "Can not store a +0 value into memory?!");
148+
assert(value.isPlusOneOrTrivial(SGF) &&
149+
"Can not store a +0 value into memory?!");
149150
CleanupCloner cloner(SGF, value);
150151
SILValue v = value.forward(SGF);
151152

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4679,7 +4679,7 @@ RValue SILGenFunction::emitLoadOfLValue(SILLocation loc, LValue &&src,
46794679
emitLoad(loc, projection.getValue(), origFormalType,
46804680
substFormalType, rvalueTL, C, IsNotTake, isBaseGuaranteed);
46814681
} else if (isReadAccessResultOwned(src.getAccessKind()) &&
4682-
!projection.isPlusOne(*this)) {
4682+
!projection.isPlusOneOrTrivial(*this)) {
46834683

46844684
// Before we copy, if we have a move only wrapped value, unwrap the
46854685
// value using a guaranteed moveonlywrapper_to_copyable.

lib/SILGen/SILGenPack.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -860,14 +860,14 @@ SILGenFunction::emitPackTransform(SILLocation loc,
860860
CanPackType outputFormalPackType,
861861
unsigned outputComponentIndex,
862862
bool isSimpleProjection,
863-
bool outputIsPlusOne,
863+
bool canForwardOutput,
864864
llvm::function_ref<ManagedValue(ManagedValue input,
865865
SILType outputEltTy,
866866
SGFContext context)> emitBody) {
867867

868868
// This is an inherent limitation of the representation; we need pack
869869
// coroutines to get around it.
870-
assert((isSimpleProjection || outputIsPlusOne) &&
870+
assert((isSimpleProjection || canForwardOutput) &&
871871
"we cannot support complex transformations that yield borrows");
872872

873873
CleanupCloner inputCloner(*this, inputPackMV);
@@ -890,7 +890,7 @@ SILGenFunction::emitPackTransform(SILLocation loc,
890890
{&inputEltTy, &outputEltTy});
891891

892892
auto &outputEltTL = getTypeLowering(outputEltTy);
893-
bool outputNeedsCleanup = (outputIsPlusOne && !outputEltTL.isTrivial());
893+
bool outputNeedsCleanup = (canForwardOutput && !outputEltTL.isTrivial());
894894

895895
// If the transformation is not a simple projection, we need to
896896
// create a tuple to hold the transformed values.
@@ -947,10 +947,10 @@ SILGenFunction::emitPackTransform(SILLocation loc,
947947
// Apply the transform.
948948
ManagedValue outputElt =
949949
emitBody(inputElt, outputEltTy,
950-
outputIsPlusOne ? SGFContext(outputEltInit.get())
950+
canForwardOutput ? SGFContext(outputEltInit.get())
951951
: SGFContext::AllowGuaranteedPlusZero);
952-
assert(outputIsPlusOne == (outputElt.isInContext() ||
953-
outputElt.isPlusOne(*this)) &&
952+
assert(canForwardOutput == (outputElt.isInContext() ||
953+
outputElt.isPlusOneOrTrivial(*this)) &&
954954
"transformation produced a value of the wrong ownership");
955955
assert((outputElt.isInContext() ||
956956
outputElt.getType() == outputEltTy) &&
@@ -991,7 +991,7 @@ SILGenFunction::emitPackTransform(SILLocation loc,
991991
outputComponentIndex,
992992
/*limit*/ SILValue());
993993
return ManagedValue::forOwnedAddressRValue(outputPackAddr, cleanup);
994-
} else if (outputIsPlusOne) {
994+
} else if (canForwardOutput) {
995995
return ManagedValue::forTrivialAddressRValue(outputPackAddr);
996996
} else {
997997
return ManagedValue::forBorrowedAddressRValue(outputPackAddr);

lib/SILGen/SILGenPattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1679,7 +1679,7 @@ emitCastOperand(SILGenFunction &SGF, SILLocation loc,
16791679
finalValue =
16801680
SGF.emitSubstToOrigValue(loc, finalValue, abstraction, sourceType, ctx);
16811681
}
1682-
assert(finalValue.isPlusOne(SGF));
1682+
assert(finalValue.isPlusOneOrTrivial(SGF));
16831683

16841684
// If we at this point do not require an address, return final value. We know
16851685
// that it is a +1 take always value.

lib/SILGen/SILGenProlog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
295295
}
296296

297297
if (emitInto) {
298-
if (mv.isPlusOne(SGF))
298+
if (mv.isPlusOneOrTrivial(SGF))
299299
mv.forwardInto(SGF, loc, emitInto);
300300
else
301301
mv.copyInto(SGF, loc, emitInto);

lib/SILGen/Scope.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ static void lifetimeExtendAddressOnlyRValueSubValues(
7777

7878
RValue Scope::popPreservingValue(RValue &&rv) {
7979
auto &SGF = cleanups.SGF;
80-
assert(rv.isPlusOne(SGF) && "Can only push plus one rvalues through a scope");
80+
assert(rv.isPlusOneOrTrivial(SGF) &&
81+
"Can only push plus one rvalues through a scope");
8182

8283
// Perform a quick check if we have an incontext value. If so, just pop and
8384
// return rv.

test/SILGen/protocol_enum_witness.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2-
// RUN: %target-swift-emit-silgen %s -enable-library-evolution
2+
// RUN: %target-swift-emit-silgen %s -enable-library-evolution | %FileCheck %s --check-prefix=CHECK-LIB
33

44
public protocol Foo {
55
static var button: Self { get }
@@ -55,3 +55,27 @@ enum InternalEnumWithPublicStruct : Foo {
5555

5656
// CHECK-LABEL: sil_witness_table [serialized] AnotherBar: AnotherFoo module protocol_enum_witness {
5757
// CHECK: method #AnotherFoo.bar: <Self where Self : AnotherFoo> (Self.Type) -> (Int) -> Self : @$s21protocol_enum_witness10AnotherBarOAA0D3FooA2aDP3bar3argxSi_tFZTW
58+
59+
// -----------------------------------------------------------------------------
60+
// rdar://108001491 (SIL verification failed: Found mutating or consuming use of
61+
// an in_guaranteed parameter?!:
62+
// !ImmutableAddressUseVerifier().isMutatingOrConsuming(fArg))
63+
64+
public struct EntityIdentifier {
65+
public let value: Swift.UInt64
66+
}
67+
68+
public protocol ObjectProtocol {
69+
static func entityReference(_ id: EntityIdentifier) -> Self
70+
}
71+
72+
public enum Object : ObjectProtocol {
73+
case entityReference(EntityIdentifier)
74+
}
75+
76+
// CHECK-LIB-LABEL: sil private [transparent] [thunk] [ossa] @$s21protocol_enum_witness6ObjectOAA0D8ProtocolA2aDP15entityReferenceyxAA16EntityIdentifierVFZTW : $@convention(witness_method: ObjectProtocol) (@in_guaranteed EntityIdentifier, @thick Object.Type) -> @out Object {
77+
// CHECK-LIB: bb0(%0 : $*Object, %1 : $*EntityIdentifier, %2 : $@thick Object.Type):
78+
// CHECK-LIB: [[TEMP:%.*]] = alloc_stack $EntityIdentifier
79+
// CHECK-LIB: copy_addr %1 to [init] %3 : $*EntityIdentifier
80+
// CHECK-LIB: apply %{{.*}}(%0, [[TEMP]], %{{.*}}) : $@convention(method) (@in EntityIdentifier, @thin Object.Type) -> @out Object
81+
// CHECK-LIB-LABEL: } // end sil function '$s21protocol_enum_witness6ObjectOAA0D8ProtocolA2aDP15entityReferenceyxAA16EntityIdentifierVFZTW'

0 commit comments

Comments
 (0)