Skip to content

Commit 99d86f5

Browse files
committed
[pmo] Eliminate PartialStore and consider Assign to be something that stops
allocations from being removed. PartialStore and Assign in PMO today both are allowed and do not prevent an allocation from being removed. This is incorrect with ownership since in both cases if we have a non-trivial type, we would need to make sure that the value being overwritten is destroyed. Clearly, with ownership given that we do not know how to handle assigns in the aforementioned way, we can not remove allocation with ownership. When I make the optimization more conservative by changing assigns to stop allocations from being removed, I see no difference in the tests/benchmarks/etc. So it makes sense to make the change now. The reason to remove PartialStore is that: 1. It is actually a vestigal remnant of Definite Init code in Predictable Mem Opts. If you look in Definite Init, understanding PartialStores is a very important part of the algorithm for diagnosing partially initialized memory locations. In Predictable Mem Opts it only controlled whether or not we could eliminate an allocation. 2. PartialStore assumes that values are always initialized completely so a partial store must be an assign. Despite that the two places it was used in the code was a place where we assumed that SILGen was always going to always have an init anyways (meaning we produced a partial store without need) or in a case where if we do not have an init, we can just treat it like an assign (the copy_addr) case.
1 parent e145520 commit 99d86f5

File tree

4 files changed

+34
-34
lines changed

4 files changed

+34
-34
lines changed

lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,11 @@ bool ElementUseCollector::collectUses(SILValue Pointer) {
254254

255255
// Coming out of SILGen, we assume that raw stores are initializations,
256256
// unless they have trivial type (which we classify as InitOrAssign).
257-
PMOUseKind Kind;
258-
if (InStructSubElement)
259-
Kind = PMOUseKind::PartialStore;
260-
else if (PointeeType.isTrivial(User->getModule()))
261-
Kind = PMOUseKind::InitOrAssign;
262-
else
263-
Kind = PMOUseKind::Initialization;
264-
257+
auto Kind = ([&]() -> PMOUseKind {
258+
if (PointeeType.isTrivial(User->getModule()))
259+
return PMOUseKind::InitOrAssign;
260+
return PMOUseKind::Initialization;
261+
})();
265262
Uses.emplace_back(User, Kind);
266263
continue;
267264
}
@@ -270,9 +267,7 @@ bool ElementUseCollector::collectUses(SILValue Pointer) {
270267
if (auto *SI = dyn_cast<Store##Name##Inst>(User)) { \
271268
if (UI->getOperandNumber() == 1) { \
272269
PMOUseKind Kind; \
273-
if (InStructSubElement) \
274-
Kind = PMOUseKind::PartialStore; \
275-
else if (SI->isInitializationOfDest()) \
270+
if (SI->isInitializationOfDest()) \
276271
Kind = PMOUseKind::Initialization; \
277272
else \
278273
Kind = PMOUseKind::Assign; \
@@ -294,16 +289,17 @@ bool ElementUseCollector::collectUses(SILValue Pointer) {
294289
// the destination, then this is an unknown assignment. Note that we'll
295290
// revisit this instruction and add it to Uses twice if it is both a load
296291
// and store to the same aggregate.
297-
PMOUseKind Kind;
298-
if (UI->getOperandNumber() == 0)
299-
Kind = PMOUseKind::Load;
300-
else if (InStructSubElement)
301-
Kind = PMOUseKind::PartialStore;
302-
else if (CAI->isInitializationOfDest())
303-
Kind = PMOUseKind::Initialization;
304-
else
305-
Kind = PMOUseKind::Assign;
306-
292+
//
293+
// Inline constructor.
294+
auto Kind = ([&]() -> PMOUseKind {
295+
if (UI->getOperandNumber() == CopyAddrInst::Src)
296+
return PMOUseKind::Load;
297+
if (PointeeType.isTrivial(CAI->getModule()))
298+
return PMOUseKind::InitOrAssign;
299+
if (CAI->isInitializationOfDest())
300+
return PMOUseKind::Initialization;
301+
return PMOUseKind::Assign;
302+
})();
307303
Uses.emplace_back(User, Kind);
308304
continue;
309305
}

lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,6 @@ enum PMOUseKind {
116116
/// value.
117117
Assign,
118118

119-
/// The instruction is a store to a member of a larger struct value.
120-
PartialStore,
121-
122119
/// An indirect 'inout' parameter of an Apply instruction.
123120
InOutUse,
124121

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ void AvailableValueDataflowContext::explodeCopyAddr(CopyAddrInst *CAI) {
911911
assert((LoadUse.isValid() || StoreUse.isValid()) &&
912912
"we should have a load or a store, possibly both");
913913
assert(StoreUse.isInvalid() || StoreUse.Kind == Assign ||
914-
StoreUse.Kind == PartialStore || StoreUse.Kind == Initialization);
914+
StoreUse.Kind == Initialization || StoreUse.Kind == InitOrAssign);
915915

916916
// Now that we've emitted a bunch of instructions, including a load and store
917917
// but also including other stuff, update the internal state of
@@ -1286,7 +1286,7 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {
12861286

12871287
switch (u.Kind) {
12881288
case PMOUseKind::Assign:
1289-
case PMOUseKind::PartialStore:
1289+
return false;
12901290
case PMOUseKind::InitOrAssign:
12911291
break; // These don't prevent removal.
12921292
case PMOUseKind::Initialization:

test/SILOptimizer/predictable_memopt.sil

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ bb0(%0 : $Int):
2424
// Verify that promotion has promoted the tuple load away, and we know that
2525
// %0 is being returned through scalar instructions in SSA form.
2626
//
27-
// CHECK-LABEL: sil @tuple_reg_promotion
27+
// CHECK-LABEL: sil @tuple_reg_promotion :
2828
// CHECK: bb0(%0 : $Int):
2929
// CHECK-NEXT: [[TUPLE:%[0-9]+]] = tuple ({{.*}} : $Int, {{.*}} : $Int)
3030
// CHECK-NEXT: [[TUPLE_ELT:%[0-9]+]] = tuple_extract [[TUPLE]] : $(Int, Int), 0
3131
// CHECK-NEXT: return [[TUPLE_ELT]] : $Int
32+
// CHECK-NEXT: } // end sil function 'tuple_reg_promotion'
3233
sil @tuple_reg_promotion : $@convention(thin) (Int) -> Int {
3334
bb0(%0 : $Int):
3435
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Int)>
@@ -290,10 +291,14 @@ bb0(%0 : $Int32):
290291
// CHECK-NEXT: return [[IL]]
291292
return %25 : $Builtin.Int32
292293
}
294+
// CHECK: } // end sil function 'promote_alloc_stack'
293295

294-
// CHECK-LABEL: sil @copy_addr_to_load
296+
// CHECK-LABEL: sil @copy_addr_to_load : $@convention(thin) (Int) -> Int {
297+
// CHECK: bb0(%0 : $Int):
298+
// CHECK-NEXT: return %0
299+
// CHECK-NEXT: } // end sil function 'copy_addr_to_load'
295300
sil @copy_addr_to_load : $@convention(thin) (Int) -> Int {
296-
bb0(%0 : $Int): // CHECK: bb0(%0 : $Int):
301+
bb0(%0 : $Int):
297302
%1 = alloc_stack $Int
298303
store %0 to %1 : $*Int
299304
%2 = alloc_stack $Int
@@ -304,14 +309,16 @@ bb0(%0 : $Int): // CHECK: bb0(%0 : $Int):
304309

305310
dealloc_stack %2 : $*Int
306311
dealloc_stack %1 : $*Int
307-
// CHECK-NEXT: return %0
308312
return %3 : $Int
309313
}
310314

311315
// rdar://15170149
312-
// CHECK-LABEL: sil @store_to_copyaddr
313-
sil @store_to_copyaddr : $(Bool) -> Bool {
314-
bb0(%0 : $Bool): // CHECK: bb0(%0 :
316+
// CHECK-LABEL: sil @store_to_copyaddr : $@convention(thin) (Bool) -> Bool {
317+
// CHECK: bb0([[ARG:%.*]] :
318+
// CHECK-NEXT: return [[ARG]]
319+
// CHECK-NEXT: } // end sil function 'store_to_copyaddr'
320+
sil @store_to_copyaddr : $@convention(thin) (Bool) -> Bool {
321+
bb0(%0 : $Bool):
315322
%1 = alloc_stack $Bool
316323
store %0 to %1 : $*Bool
317324
%3 = alloc_stack $Bool
@@ -321,7 +328,7 @@ bb0(%0 : $Bool): // CHECK: bb0(%0 :
321328
%12 = load %1 : $*Bool
322329
dealloc_stack %3 : $*Bool
323330
dealloc_stack %1 : $*Bool
324-
return %12 : $Bool // CHECK-NEXT: return %0
331+
return %12 : $Bool
325332
}
326333

327334
// CHECK-LABEL: sil @cross_block_load_promotion

0 commit comments

Comments
 (0)