@@ -107,8 +107,13 @@ void ExistentialSpecializerCloner::cloneAndPopulateFunction() {
107107 SILBuilderWithScope Builder (exitBB->getTerminator ());
108108 // A return location can't be used for a non-return instruction.
109109 auto loc = RegularLocation::getAutoGeneratedLocation ();
110- for (SILValue cleanupVal : CleanupValues)
111- Builder.createDestroyAddr (loc, cleanupVal);
110+ for (SILValue cleanupVal : CleanupValues) {
111+ if (cleanupVal.getOwnershipKind () == ValueOwnershipKind::Guaranteed) {
112+ Builder.emitEndBorrowOperation (loc, cleanupVal);
113+ } else {
114+ Builder.emitDestroyOperation (loc, cleanupVal);
115+ }
116+ }
112117
113118 for (auto *ASI : llvm::reverse (AllocStackInsts))
114119 Builder.createDeallocStack (loc, ASI);
@@ -180,10 +185,10 @@ void ExistentialSpecializerCloner::cloneArguments(
180185 NewF.getLoweredType (NewF.mapTypeIntoContext (GenericParam));
181186 GenericSILType = GenericSILType.getCategoryType (
182187 ArgDesc.Arg ->getType ().getCategory ());
183- auto *NewArg =
184- ClonedEntryBB-> createFunctionArgument ( GenericSILType, ArgDesc.Decl );
185- NewArg-> setOwnershipKind ( ValueOwnershipKind (
186- NewF, GenericSILType, ArgDesc.Arg ->getArgumentConvention ()));
188+ auto *NewArg = ClonedEntryBB-> createFunctionArgument (
189+ GenericSILType, ArgDesc.Decl ,
190+ ValueOwnershipKind (NewF, GenericSILType,
191+ ArgDesc.Arg ->getArgumentConvention ()));
187192 // Determine the Conformances.
188193 SILType ExistentialType = ArgDesc.Arg ->getType ().getObjectType ();
189194 CanType OpenedType = NewArg->getType ().getASTType ();
@@ -224,35 +229,54 @@ void ExistentialSpecializerCloner::cloneArguments(
224229 }
225230 case ExistentialRepresentation::Class: {
226231 SILValue NewArgValue = NewArg;
232+ bool origConsumed = EAD.isConsumed ;
233+
234+ // Load our object if needed and if our original value was not consumed,
235+ // make a copy in ossa. Do not perturb code-gen in non-ossa code though.
227236 if (!NewArg->getType ().isObject ()) {
228- NewArgValue = NewFBuilder.createLoad (InsertLoc, NewArg,
229- LoadOwnershipQualifier::Unqualified);
237+ auto qual = LoadOwnershipQualifier::Take;
238+ if (NewFBuilder.hasOwnership () && !origConsumed) {
239+ qual = LoadOwnershipQualifier::Copy;
240+ }
241+ NewArgValue =
242+ NewFBuilder.emitLoadValueOperation (InsertLoc, NewArg, qual);
243+ } else {
244+ if (NewFBuilder.hasOwnership () && !origConsumed) {
245+ NewArgValue = NewFBuilder.emitCopyValueOperation (InsertLoc, NewArg);
246+ }
230247 }
231-
232- // FIXME_ownership: init_existential_ref always takes ownership of the
233- // incoming reference. If the argument convention is borrowed
234- // (!isConsumed), then we should create a copy_value here and add this new
235- // existential to the CleanupValues vector.
236248
237249 // / Simple case: Create an init_existential.
238250 // / %5 = init_existential_ref %0 : $T : $T, $P
239251 SILValue InitRef = NewFBuilder.createInitExistentialRef (
240252 InsertLoc, ArgDesc.Arg ->getType ().getObjectType (),
241253 NewArg->getType ().getASTType (),
242254 NewArgValue, Conformances);
243-
255+
256+ // If we don't have an object and we are in ossa, the store will consume
257+ // the InitRef.
244258 if (!NewArg->getType ().isObject ()) {
245259 auto alloc = NewFBuilder.createAllocStack (InsertLoc,
246260 InitRef->getType ());
247- NewFBuilder.createStore (InsertLoc, InitRef, alloc,
248- StoreOwnershipQualifier::Unqualified );
261+ NewFBuilder.emitStoreValueOperation (InsertLoc, InitRef, alloc,
262+ StoreOwnershipQualifier::Init );
249263 InitRef = alloc;
250264 AllocStackInsts.push_back (alloc);
265+ } else {
266+ // Otherwise in ossa, we need to add init existential ref as something
267+ // to be cleaned up. In non-ossa, we do not insert the copies, so we do
268+ // not need to do it then.
269+ //
270+ // TODO: This would be simpler if we had managed value/cleanup scopes.
271+ if (NewFBuilder.hasOwnership () && !origConsumed) {
272+ CleanupValues.push_back (InitRef);
273+ }
251274 }
252275
253276 entryArgs.push_back (InitRef);
254277 break ;
255278 }
279+
256280 default : {
257281 llvm_unreachable (" Unhandled existential type in ExistentialTransform!" );
258282 break ;
@@ -451,12 +475,13 @@ void ExistentialTransform::populateThunkBody() {
451475 SILValue archetypeValue;
452476 auto ExistentialRepr =
453477 ArgDesc.Arg ->getType ().getPreferredExistentialRepresentation ();
478+ bool OriginallyConsumed = ETAD.isConsumed ;
454479 switch (ExistentialRepr) {
455480 case ExistentialRepresentation::Opaque: {
456481 archetypeValue = Builder.createOpenExistentialAddr (
457482 Loc, OrigOperand, OpenedSILType, it->second .AccessType );
458483 SILValue calleeArg = archetypeValue;
459- if (ETAD. isConsumed ) {
484+ if (OriginallyConsumed ) {
460485 // open_existential_addr projects a borrowed address into the
461486 // existential box. Since the callee consumes the generic value, we
462487 // must pass in a copy.
@@ -474,19 +499,39 @@ void ExistentialTransform::populateThunkBody() {
474499 // If the operand is not object type, we need an explicit load.
475500 SILValue OrigValue = OrigOperand;
476501 if (!OrigOperand->getType ().isObject ()) {
477- OrigValue = Builder.createLoad (Loc, OrigValue,
478- LoadOwnershipQualifier::Unqualified);
502+ auto qual = LoadOwnershipQualifier::Take;
503+ if (Builder.hasOwnership () && !OriginallyConsumed) {
504+ qual = LoadOwnershipQualifier::Copy;
505+ }
506+ OrigValue = Builder.emitLoadValueOperation (Loc, OrigValue, qual);
507+ } else {
508+ if (Builder.hasOwnership () && !OriginallyConsumed) {
509+ OrigValue = Builder.emitCopyValueOperation (Loc, OrigValue);
510+ }
479511 }
512+
480513 // OpenExistentialRef forwards ownership, so it does the right thing
481514 // regardless of whether the argument is borrowed or consumed.
482515 archetypeValue =
483516 Builder.createOpenExistentialRef (Loc, OrigValue, OpenedSILType);
517+
518+ // If we don't have an object and we are in ossa, the store will consume
519+ // the open_existential_ref.
484520 if (!OrigOperand->getType ().isObject ()) {
485521 SILValue ASI = Builder.createAllocStack (Loc, OpenedSILType);
486- Builder.createStore (Loc, archetypeValue, ASI,
487- StoreOwnershipQualifier::Unqualified );
522+ Builder.emitStoreValueOperation (Loc, archetypeValue, ASI,
523+ StoreOwnershipQualifier::Init );
488524 Temps.push_back ({ASI, SILValue ()});
489525 archetypeValue = ASI;
526+ } else {
527+ // Otherwise in ossa, we need to add open_existential_ref as something
528+ // to be cleaned up. In non-ossa, we do not insert the copies, so we
529+ // do not need to do it then.
530+ //
531+ // TODO: This would be simpler if we had managed value/cleanup scopes.
532+ if (Builder.hasOwnership () && !OriginallyConsumed) {
533+ Temps.push_back ({SILValue (), archetypeValue});
534+ }
490535 }
491536 ApplyArgs.push_back (archetypeValue);
492537 break ;
@@ -572,11 +617,14 @@ void ExistentialTransform::populateThunkBody() {
572617 // copy_addr %valAdr to %temp // <== Temp CopyAddr
573618 // apply(%temp) // <== Temp is consumed by the apply
574619 //
575- // Destroy the original argument and deallocation the temporary:
620+ // Destroy the original argument and deallocation the temporary. If we have
621+ // an address this becomes:
576622 // destroy_addr %consumedExistential : $*Protocol
577623 // dealloc_stack %temp : $*T
624+ //
625+ // Otherwise, if we had an object, we just emit a destroy_value.
578626 if (Temp.DestroyValue )
579- Builder.createDestroyAddr (cleanupLoc, Temp.DestroyValue );
627+ Builder.emitDestroyOperation (cleanupLoc, Temp.DestroyValue );
580628 if (Temp.DeallocStackEntry )
581629 Builder.createDeallocStack (cleanupLoc, Temp.DeallocStackEntry );
582630 }
0 commit comments