[StackLifetime] More efficient loop for LivenessType::Must

CFG with cycles may requires additional passes of "while (Changed)"
iteration if to propagate data back from latter blocks to earlier blocks,
ordered according to depth_fist.

OR logic, used for ::May, converge to stable state faster then AND logic
use for ::Must.

Though the better solution is to switch to some some form of queue, but
having that this one is good enough, I will consider to do that later.

We can switch ::Must to OR logic if we calculate "may be dead" instead
of direct "must be alive" and then convert values to match existing
interface.

Additionally it fixes correctness in "@cycle" test.

Reviewed By: kstoimenov, fmayer

Differential Revision: https://reviews.llvm.org/D134796
This commit is contained in:
Vitaly Buka 2022-09-27 23:41:32 -07:00
parent 95dabac7a5
commit 01f3e2d619
2 changed files with 36 additions and 21 deletions

View File

@ -174,32 +174,32 @@ void StackLifetime::collectMarkers() {
void StackLifetime::calculateLocalLiveness() {
bool Changed = true;
// LiveIn, LiveOut and BitsIn have a different meaning deppends on type.
// ::Maybe true bits represent "may be alive" allocas, ::Must true bits
// represent "may be dead". After the loop we will convert ::Must bits from
// "may be dead" to "must be alive".
while (Changed) {
// TODO: Consider switching to worklist instead of traversing entire graph.
Changed = false;
for (const BasicBlock *BB : depth_first(&F)) {
BlockLifetimeInfo &BlockInfo = BlockLiveness.find(BB)->getSecond();
// Compute LiveIn by unioning together the LiveOut sets of all preds.
// Compute BitsIn by unioning together the LiveOut sets of all preds.
BitVector BitsIn;
for (const auto *PredBB : predecessors(BB)) {
LivenessMap::const_iterator I = BlockLiveness.find(PredBB);
// If a predecessor is unreachable, ignore it.
if (I == BlockLiveness.end())
continue;
switch (Type) {
case LivenessType::May:
BitsIn |= I->second.LiveOut;
break;
case LivenessType::Must:
if (BitsIn.empty())
BitsIn = I->second.LiveOut;
else
BitsIn &= I->second.LiveOut;
break;
}
BitsIn |= I->second.LiveOut;
}
// Everything is "may be dead" for entry without predecessors.
if (Type == LivenessType::Must && BitsIn.empty())
BitsIn.resize(NumAllocas, true);
// Update block LiveIn set, noting whether it has changed.
if (BitsIn.test(BlockInfo.LiveIn)) {
BlockInfo.LiveIn |= BitsIn;
@ -212,8 +212,18 @@ void StackLifetime::calculateLocalLiveness() {
// because we already handle the case where the BEGIN comes
// before the END when collecting the markers (and building the
// BEGIN/END vectors).
BitsIn.reset(BlockInfo.End);
BitsIn |= BlockInfo.Begin;
switch (Type) {
case LivenessType::May:
BitsIn.reset(BlockInfo.End);
// "may be alive" is set by lifetime start.
BitsIn |= BlockInfo.Begin;
break;
case LivenessType::Must:
BitsIn.reset(BlockInfo.Begin);
// "may be dead" is set by lifetime end.
BitsIn |= BlockInfo.End;
break;
}
// Update block LiveOut set, noting whether it has changed.
if (BitsIn.test(BlockInfo.LiveOut)) {
@ -222,6 +232,14 @@ void StackLifetime::calculateLocalLiveness() {
}
}
} // while changed.
if (Type == LivenessType::Must) {
// Convert from "may be dead" to "must be alive".
for (auto &[BB, BlockInfo] : BlockLiveness) {
BlockInfo.LiveIn.flip();
BlockInfo.LiveOut.flip();
}
}
}
void StackLifetime::calculateLiveIntervals() {

View File

@ -1070,22 +1070,19 @@ entry:
if.then:
; CHECK: if.then:
; MAY-NEXT: Alive: <x y>
; MUST-NEXT: Alive: <>
; MUST-NEXT: Alive: <x>
call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
; CHECK: call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
; MAY-NEXT: Alive: <x y>
; MUST-NEXT: Alive: <y>
; FIXME: Alive: <x y> is expected above.
; CHECK-NEXT: Alive: <x y>
br i1 %a, label %if.then, label %if.end
; CHECK: br i1 %a, label %if.then, label %if.end
; MAY-NEXT: Alive: <x y>
; MUST-NEXT: Alive: <y>
; CHECK-NEXT: Alive: <x y>
if.end:
; CHECK: if.end:
; MAY-NEXT: Alive: <x y>
; MUST-NEXT: Alive: <>
; MUST-NEXT: Alive: <x>
ret void
}