Skip to content

Commit 8eff2e8

Browse files
committed
[LifetimeExtension] Handle use-before-def.
The multi-def algorithm is based off the single-def algorithm. However, it differs from it in needing to handle "liveness holes"--uses before defs. When identifying blocks which are originally live, the algorithm starts from consuming blocks and walks backwards until a condition is met. Previously, that condition was finding blocks which were originally live. That makes sense in the single-def case: if a block is originally live, either it was already walked through or else it was one of the blocks discovered by liveness. In either case, its predecessors have already been visited if appropriate. However, in the multi-def case, this condition is too stringent. It fails to account for the possibility of a block with has a "liveness hole". Only stop the backwards walk if the predecessor not only (1) was in originally live but additionally (2) "kills liveness"--doesn't have a use before a def. rdar://111221183
1 parent 7c1e5ec commit 8eff2e8

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,8 @@ class ExtendUnconsumedLiveness {
14141414

14151415
private:
14161416
bool hasDefAfter(SILInstruction *inst, unsigned element);
1417+
bool isLiveAtBegin(SILBasicBlock *block, unsigned element, bool isLiveAtEnd,
1418+
DestroysCollection const &destroys);
14171419

14181420
bool
14191421
shouldAddDestroyToLiveness(SILInstruction *destroy, unsigned element,
@@ -2967,7 +2969,14 @@ void ExtendUnconsumedLiveness::runOnField(
29672969
// as the other consuming uses).
29682970
BasicBlockWorklist worklist(currentDef->getFunction());
29692971
for (auto *consumingBlock : consumingBlocks) {
2970-
worklist.push(consumingBlock);
2972+
if (!originalLiveBlocks.insert(consumingBlock)
2973+
// Don't walk into the predecessors of blocks which kill liveness.
2974+
&& !isLiveAtBegin(consumingBlock, element, /*isLiveAtEnd=*/true, destroys)) {
2975+
continue;
2976+
}
2977+
for (auto *predecessor : consumingBlock->getPredecessorBlocks()) {
2978+
worklist.pushIfNotVisited(predecessor);
2979+
}
29712980
}
29722981

29732982
// Walk backwards from consuming blocks.
@@ -2976,10 +2985,6 @@ void ExtendUnconsumedLiveness::runOnField(
29762985
continue;
29772986
}
29782987
for (auto *predecessor : block->getPredecessorBlocks()) {
2979-
// If the block was discovered by liveness, we already added it to the
2980-
// set.
2981-
if (originalLiveBlocks.contains(predecessor))
2982-
continue;
29832988
worklist.pushIfNotVisited(predecessor);
29842989
}
29852990
}
@@ -3096,6 +3101,37 @@ bool ExtendUnconsumedLiveness::shouldAddDestroyToLiveness(
30963101
return !consumedAtEntryBlocks.contains(block);
30973102
}
30983103

3104+
/// Compute the block's effect on liveness and apply it to \p isLiveAtEnd.
3105+
bool ExtendUnconsumedLiveness::isLiveAtBegin(SILBasicBlock *block,
3106+
unsigned element, bool isLiveAtEnd,
3107+
DestroysCollection const &destroys) {
3108+
enum class Effect {
3109+
None, // 0
3110+
Kill, // 1
3111+
Gen, // 2
3112+
};
3113+
auto effect = Effect::None;
3114+
for (auto &instruction : llvm::reverse(*block)) {
3115+
// An instruction can be both a destroy and a def. If it is, its
3116+
// behavior is first to destroy and then to init. So when walking
3117+
// backwards, its last action is to destroy, so its effect is that of any
3118+
// destroy.
3119+
if (destroys.find(&instruction) != destroys.end()) {
3120+
effect = Effect::Gen;
3121+
} else if (liveness.isDef(&instruction, element)) {
3122+
effect = Effect::Kill;
3123+
}
3124+
}
3125+
switch (effect) {
3126+
case Effect::None:
3127+
return isLiveAtEnd;
3128+
case Effect::Kill:
3129+
return false;
3130+
case Effect::Gen:
3131+
return true;
3132+
}
3133+
}
3134+
30993135
bool ExtendUnconsumedLiveness::hasDefAfter(SILInstruction *start,
31003136
unsigned element) {
31013137
// NOTE: Start iteration at \p start, not its sequel, because

0 commit comments

Comments
 (0)