Skip to content

Commit f79c6c8

Browse files
committed
[SIL-opaque] add a test case for phi coalescing
Avoid attempting to coalesce enum payloads.
1 parent ef2bf97 commit f79c6c8

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

lib/SILOptimizer/Mandatory/PhiStorageOptimizer.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ void PhiStorageOptimizer::optimize() {
116116
coalescedPhi.coalescedOperands.push_back(phi.getOperand(predecessor));
117117
return;
118118
}
119-
occupiedBlocks.insert(phi.phiBlock);
120119
for (auto *incomingPred : phi.phiBlock->getPredecessorBlocks()) {
121120
tryCoalesceOperand(incomingPred);
122121
}
@@ -145,14 +144,15 @@ bool PhiStorageOptimizer::canCoalesceValue(SILValue incomingVal) {
145144

146145
auto &incomingStorage = valueStorageMap.getStorage(incomingVal);
147146

148-
// If the incoming use is pre-allocated it can't be coalesced.
149-
// This also handles incoming values that are already coalesced with
150-
// another use.
147+
// If the incoming use directly reuses its def storage, projects out of its
148+
// def storage, or is pre-allocated, then it can't be coalesced. When incoming
149+
// storage is directly reused, isAllocated() is false. isProjection() covers
150+
// the other cases.
151151
//
152152
// Coalescing use projections from incomingVal into its other non-phi uses
153-
// would require by recursively following uses across projections when
154-
// computing liveness.
155-
if (incomingStorage.isProjection())
153+
// could be handled, but would require by recursively following uses across
154+
// projections when computing liveness.
155+
if (!incomingStorage.isAllocated() || incomingStorage.isProjection())
156156
return false;
157157

158158
auto *defInst = incomingVal->getDefiningInstruction();
@@ -163,7 +163,6 @@ bool PhiStorageOptimizer::canCoalesceValue(SILValue incomingVal) {
163163
// analysis of the whole phi web before coalescing phi operands.
164164
return false;
165165
}
166-
assert(incomingStorage.isAllocated() && "nonphi must be allocated");
167166

168167
// Don't coalesce an incoming value unless it's storage is from a stack
169168
// allocation, which can be replaced with another alloc_stack.
@@ -213,7 +212,11 @@ bool PhiStorageOptimizer::recordUseLiveness(SILValue incomingVal,
213212
for (auto *use : incomingVal->getUses()) {
214213
StackList<SILBasicBlock *> liveBBWorklist(getFunction());
215214

215+
// If \p liveBB is already occupied by another value, return
216+
// false. Otherwise, mark \p liveBB live and push it onto liveBBWorklist.
216217
auto visitLiveBlock = [&](SILBasicBlock *liveBB) {
218+
assert(liveBB != phi.phiBlock && "phi operands are consumed");
219+
217220
if (occupiedBlocks.contains(liveBB))
218221
return false;
219222

test/SILOptimizer/address_lowering_phi.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ typealias AnyObject = Builtin.AnyObject
1010
typealias Int = Builtin.Int64
1111
typealias Bool = Builtin.Int1
1212

13+
enum Optional<T> {
14+
case none
15+
case some(T)
16+
}
17+
1318
struct SRef<T> {
1419
@_hasStorage var object: AnyObject { get set }
1520
@_hasStorage var element: T { get set }
@@ -438,3 +443,30 @@ bb6(%phi6 : @owned $InnerStruct<T>):
438443
%outer = struct $OuterStruct<T> (%phi6 : $InnerStruct<T>, %3 : $AnyObject)
439444
return %outer : $OuterStruct<T>
440445
}
446+
447+
// CHECK-LABEL: sil [ossa] @f090_payloadPhiOperand : $@convention(thin) <T> (@in Optional<T>, @in T) -> @out T {
448+
// CHECK: bb0(%0 : $*T, %1 : $*Optional<T>, %2 : $*T):
449+
// CHECK: cond_br undef, bb2, bb1
450+
// CHECK: bb1:
451+
// CHECK: destroy_addr %2 : $*T
452+
// CHECK: [[P:%.*]] = unchecked_take_enum_data_addr %1 : $*Optional<T>, #Optional.some!enumelt
453+
// CHECK: copy_addr [take] [[P]] to [initialization] %0 : $*T
454+
// CHECK: br bb3
455+
// CHECK: bb2:
456+
// CHECK: destroy_addr %1 : $*Optional<T>
457+
// CHECK: copy_addr [take] %2 to [initialization] %0 : $*T
458+
// CHECK: br bb3
459+
// CHECK-LABEL: } // end sil function 'f090_payloadPhiOperand'
460+
sil [ossa] @f090_payloadPhiOperand : $@convention(thin) <T> (@in Optional<T>, @in T) -> @out T {
461+
bb0(%0 : @owned $Optional<T>, %1 : @owned $T):
462+
cond_br undef, bb2, bb1
463+
bb1:
464+
destroy_value %1 : $T
465+
%payload = unchecked_enum_data %0 : $Optional<T>, #Optional.some!enumelt
466+
br bb3(%payload : $T)
467+
bb2:
468+
destroy_value %0 : $Optional<T>
469+
br bb3(%1 : $T)
470+
bb3(%phi : @owned $T):
471+
return %phi : $T
472+
}

0 commit comments

Comments
 (0)