Skip to content

Commit dd57d4d

Browse files
Merge pull request #81952 from nate-chandler/rdar152431332
[DestroyAddrHoisting] Skip init_enum_data_addrs.
2 parents 782128b + c41fd47 commit dd57d4d

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,7 @@ inline bool isAccessStorageTypeCast(SingleValueInstruction *svi) {
16061606
// Simply pass-thru the incoming address. But change its type!
16071607
case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst:
16081608
case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst:
1609+
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst:
16091610
// Simply pass-thru the incoming address. But change its type!
16101611
case SILInstructionKind::UncheckedAddrCastInst:
16111612
// Casting to RawPointer does not affect the AccessPath. When converting
@@ -1652,7 +1653,6 @@ inline bool isAccessStorageIdentityCast(SingleValueInstruction *svi) {
16521653
case SILInstructionKind::MarkDependenceInst:
16531654
case SILInstructionKind::CopyValueInst:
16541655
case SILInstructionKind::BeginBorrowInst:
1655-
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst:
16561656
return true;
16571657
}
16581658
}
@@ -1688,6 +1688,22 @@ inline bool isAccessStorageCast(SingleValueInstruction *svi) {
16881688
return isAccessStorageTypeCast(svi) || isAccessStorageIdentityCast(svi);
16891689
}
16901690

1691+
// Strip access markers and casts that preserve the access storage.
1692+
//
1693+
// Compare to stripAccessAndIdentityCasts. This function strips cast that
1694+
// change the type.
1695+
inline SILValue stripAccessAndAccessStorageCasts(SILValue v) {
1696+
if (auto *bai = dyn_cast<BeginAccessInst>(v)) {
1697+
return stripAccessAndAccessStorageCasts(bai->getOperand());
1698+
}
1699+
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
1700+
if (isAccessStorageCast(svi)) {
1701+
return stripAccessAndAccessStorageCasts(svi->getAllOperands()[0].get());
1702+
}
1703+
}
1704+
return v;
1705+
}
1706+
16911707
/// Abstract CRTP class for a visiting instructions that are part of the use-def
16921708
/// chain from an accessed address up to the storage base.
16931709
///

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@ class AccessPathVisitor : public FindAccessVisitorImpl<AccessPathVisitor> {
14021402
AccessPath::Index::forSubObjectProjection(projIdx.Index));
14031403
} else {
14041404
// Ignore everything in getAccessProjectionOperand that is an access
1405-
// projection with no affect on the access path.
1405+
// projection with no effect on the access path.
14061406
assert(isa<OpenExistentialAddrInst>(projectedAddr) ||
14071407
isa<InitEnumDataAddrInst>(projectedAddr) ||
14081408
isa<UncheckedTakeEnumDataAddrInst>(projectedAddr)
@@ -1982,7 +1982,7 @@ AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi,
19821982
return IgnoredUse;
19831983

19841984
// open_existential_addr and unchecked_take_enum_data_addr are classified as
1985-
// access projections, but they also modify memory. Both see through them and
1985+
// access projections, but they also modify memory. Both look through them and
19861986
// also report them as uses.
19871987
case SILInstructionKind::OpenExistentialAddrInst:
19881988
case SILInstructionKind::UncheckedTakeEnumDataAddrInst:

lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@ struct KnownStorageUses : UniqueStorageUseVisitor {
164164
bool visitStore(Operand *use) override { return recordUser(use->getUser()); }
165165

166166
bool visitDestroy(Operand *use) override {
167+
// An init_enum_data_addr is viewed as an "identity projection", rather than
168+
// a proper projection like a struct_element_addr. As a result, its
169+
// destroys are passed directly to visitors. But such addresses aren't
170+
// quite equivalent to the original address. Specifically, a destroy of an
171+
// init_enum_data_addr cannot in general be replaced with a destroy of the
172+
// whole enum. The latter destroy is only equivalent to the former if there
173+
// has been an `inject_enum_addr`.
174+
//
175+
// Handle a destroy of such a projection just like we handle the destroy of
176+
// a struct_element_addr: by bailing out.
177+
if (isa<InitEnumDataAddrInst>(
178+
stripAccessAndAccessStorageCasts(use->get()))) {
179+
return false;
180+
}
167181
originalDestroys.insert(use->getUser());
168182
return true;
169183
}

test/SILOptimizer/hoist_destroy_addr.sil

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,3 +1280,39 @@ bb0(%aggregate : $*NCAggregate):
12801280
%retval = tuple ()
12811281
return %retval
12821282
}
1283+
1284+
// CHECK-LABEL: sil [ossa] @nohoist_ieda : {{.*}} {
1285+
// CHECK: [[IEDA:%[^,]+]] = init_enum_data_addr
1286+
// CHECK: tuple
1287+
// CHECK-NEXT: destroy_addr [[IEDA]]
1288+
// CHECK-LABEL: } // end sil function 'nohoist_ieda'
1289+
sil [ossa] @nohoist_ieda : $@convention(thin) () -> @out TwoCases {
1290+
bb0(%out : $*TwoCases):
1291+
%ieda = init_enum_data_addr %out, #TwoCases.A!enumelt
1292+
apply undef(%ieda) : $@convention(thin) () -> @out X
1293+
%retval = tuple ()
1294+
destroy_addr %ieda
1295+
apply undef(%ieda) : $@convention(thin) () -> @out X
1296+
inject_enum_addr %out, #TwoCases.A!enumelt
1297+
return %retval
1298+
}
1299+
1300+
// CHECK-LABEL: sil [ossa] @nohoist_ieda_2 : {{.*}} {
1301+
// CHECK: [[IEDA:%[^,]+]] = init_enum_data_addr
1302+
// CHECK: tuple
1303+
// CHECK: [[CTM:%[^,]+]] = copyable_to_moveonlywrapper_addr [[IEDA]]
1304+
// CHECK: [[MTC:%[^,]+]] = moveonlywrapper_to_copyable_addr [[CTM]]
1305+
// CHECK-NEXT: destroy_addr [[MTC]]
1306+
// CHECK-LABEL: } // end sil function 'nohoist_ieda_2'
1307+
sil [ossa] @nohoist_ieda_2 : $@convention(thin) () -> @out TwoCases {
1308+
bb0(%out : $*TwoCases):
1309+
%ieda = init_enum_data_addr %out, #TwoCases.A!enumelt
1310+
apply undef(%ieda) : $@convention(thin) () -> @out X
1311+
%retval = tuple ()
1312+
%ctm = copyable_to_moveonlywrapper_addr %ieda
1313+
%mtc = moveonlywrapper_to_copyable_addr %ctm
1314+
destroy_addr %mtc
1315+
apply undef(%ieda) : $@convention(thin) () -> @out X
1316+
inject_enum_addr %out, #TwoCases.A!enumelt
1317+
return %retval
1318+
}

0 commit comments

Comments
 (0)