1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 11:42:57 +01:00

[Attributor][FIX] Make "known" and "assumed" liveness explicit

We did merge "known" and "assumed" liveness information into a single
set which caused various kinds of problems, especially because we did
not properly record when something was actually known. With this patch
we properly track the "known" bit and distinguish dead ends we know from
the ones we still need to explore in future updates.
This commit is contained in:
Johannes Doerfert 2019-11-01 21:04:54 -05:00
parent ba26cda1ee
commit eb3685d46d
2 changed files with 45 additions and 23 deletions

View File

@ -2309,7 +2309,8 @@ struct AAIsDeadFunction : public AAIsDead {
const std::string getAsStr() const override {
return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" +
std::to_string(getAssociatedFunction()->size()) + "][#TBEP " +
std::to_string(ToBeExploredFrom.size()) + "]";
std::to_string(ToBeExploredFrom.size()) + "][#KDE " +
std::to_string(KnownDeadEnds.size()) + "]";
}
/// See AbstractAttribute::manifest(...).
@ -2330,15 +2331,16 @@ struct AAIsDeadFunction : public AAIsDead {
// function allows to catch asynchronous exceptions.
bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F);
for (const Instruction *ExploreEndI : ToBeExploredFrom) {
auto *CB = dyn_cast<CallBase>(ExploreEndI);
KnownDeadEnds.set_union(ToBeExploredFrom);
for (const Instruction *DeadEndI : KnownDeadEnds) {
auto *CB = dyn_cast<CallBase>(DeadEndI);
if (!CB)
continue;
const auto &NoReturnAA =
A.getAAFor<AANoReturn>(*this, IRPosition::callsite_function(*CB));
if (!NoReturnAA.isAssumedNoReturn())
continue;
Instruction *I = const_cast<Instruction *>(ExploreEndI);
Instruction *I = const_cast<Instruction *>(DeadEndI);
BasicBlock *BB = I->getParent();
Instruction *SplitPos = I->getNextNode();
// TODO: mark stuff before unreachable instructions as dead.
@ -2454,7 +2456,7 @@ struct AAIsDeadFunction : public AAIsDead {
// If it is not after a liveness barrier it is live.
const Instruction *PrevI = I->getPrevNode();
while (PrevI) {
if (ToBeExploredFrom.count(PrevI))
if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
return true;
PrevI = PrevI->getPrevNode();
}
@ -2493,6 +2495,9 @@ struct AAIsDeadFunction : public AAIsDead {
/// did assume they do not transfer control to (one of their) successors.
SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
/// Collection of instructions that are known to not transfer control.
SmallSetVector<const Instruction *, 8> KnownDeadEnds;
/// Collection of all assumed live BasicBlocks.
DenseSet<const BasicBlock *> AssumedLiveBlocks;
};
@ -2505,7 +2510,7 @@ identifyAliveSuccessors(Attributor &A, const CallBase &CB,
const auto &NoReturnAA = A.getAAFor<AANoReturn>(AA, IPos);
if (NoReturnAA.isAssumedNoReturn())
return true;
return !NoReturnAA.isKnownNoReturn();
if (CB.isTerminator())
AliveSuccessors.push_back(&CB.getSuccessor(0)->front());
else
@ -2528,19 +2533,22 @@ identifyAliveSuccessors(Attributor &A, const InvokeInst &II,
} else {
const IRPosition &IPos = IRPosition::callsite_function(II);
const auto &AANoUnw = A.getAAFor<AANoUnwind>(AA, IPos);
if (!AANoUnw.isAssumedNoUnwind()) {
if (AANoUnw.isAssumedNoUnwind()) {
UsedAssumedInformation |= !AANoUnw.isKnownNoUnwind();
} else {
AliveSuccessors.push_back(&II.getUnwindDest()->front());
UsedAssumedInformation = true;
}
}
return UsedAssumedInformation;
}
static Optional<ConstantInt *> getAssumedConstant(Attributor &A, const Value &V,
AbstractAttribute &AA) {
static Optional<ConstantInt *>
getAssumedConstant(Attributor &A, const Value &V, AbstractAttribute &AA,
bool &UsedAssumedInformation) {
const auto &ValueSimplifyAA =
A.getAAFor<AAValueSimplify>(AA, IRPosition::value(V));
Optional<Value *> SimplifiedV = ValueSimplifyAA.getAssumedSimplifiedValue(A);
UsedAssumedInformation |= !ValueSimplifyAA.isKnown();
if (!SimplifiedV.hasValue())
return llvm::None;
if (isa_and_nonnull<UndefValue>(SimplifiedV.getValue()))
@ -2556,17 +2564,18 @@ identifyAliveSuccessors(Attributor &A, const BranchInst &BI,
if (BI.getNumSuccessors() == 1) {
AliveSuccessors.push_back(&BI.getSuccessor(0)->front());
} else {
Optional<ConstantInt *> CI = getAssumedConstant(A, *BI.getCondition(), AA);
Optional<ConstantInt *> CI =
getAssumedConstant(A, *BI.getCondition(), AA, UsedAssumedInformation);
if (!CI.hasValue()) {
// No value yet, assume both edges are dead.
} else if (CI.getValue()) {
const BasicBlock *SuccBB =
BI.getSuccessor(1 - CI.getValue()->getZExtValue());
AliveSuccessors.push_back(&SuccBB->front());
UsedAssumedInformation = true;
} else {
AliveSuccessors.push_back(&BI.getSuccessor(0)->front());
AliveSuccessors.push_back(&BI.getSuccessor(1)->front());
UsedAssumedInformation = false;
}
}
return UsedAssumedInformation;
@ -2576,23 +2585,25 @@ static bool
identifyAliveSuccessors(Attributor &A, const SwitchInst &SI,
AbstractAttribute &AA,
SmallVectorImpl<const Instruction *> &AliveSuccessors) {
Optional<ConstantInt *> CI = getAssumedConstant(A, *SI.getCondition(), AA);
bool UsedAssumedInformation = false;
Optional<ConstantInt *> CI =
getAssumedConstant(A, *SI.getCondition(), AA, UsedAssumedInformation);
if (!CI.hasValue()) {
// No value yet, assume all edges are dead.
} else if (CI.getValue()) {
for (auto &CaseIt : SI.cases()) {
if (CaseIt.getCaseValue() == CI.getValue()) {
AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());
return true;
return UsedAssumedInformation;
}
}
AliveSuccessors.push_back(&SI.getDefaultDest()->front());
return true;
return UsedAssumedInformation;
} else {
for (const BasicBlock *SuccBB : successors(SI.getParent()))
AliveSuccessors.push_back(&SuccBB->front());
}
return false;
return UsedAssumedInformation;
}
ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {
@ -2600,7 +2611,8 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {
LLVM_DEBUG(dbgs() << "[AAIsDead] Live [" << AssumedLiveBlocks.size() << "/"
<< getAssociatedFunction()->size() << "] BBs and "
<< ToBeExploredFrom.size() << " exploration points\n");
<< ToBeExploredFrom.size() << " exploration points and "
<< KnownDeadEnds.size() << " known dead ends\n");
// Copy and clear the list of instructions we need to explore from. It is
// refilled with instructions the next update has to look at.
@ -2644,10 +2656,14 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {
break;
}
if (UsedAssumedInformation)
if (UsedAssumedInformation) {
NewToBeExploredFrom.insert(I);
else
} else {
Change = ChangeStatus::CHANGED;
if (AliveSuccessors.empty() ||
(I->isTerminator() && AliveSuccessors.size() < I->getNumSuccessors()))
KnownDeadEnds.insert(I);
}
LLVM_DEBUG(dbgs() << "[AAIsDead] #AliveSuccessors: "
<< AliveSuccessors.size() << " UsedAssumedInformation: "
@ -2669,9 +2685,15 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {
// If we know everything is live there is no need to query for liveness.
// Instead, indicating a pessimistic fixpoint will cause the state to be
// "invalid" and all queries to be answered conservatively.
// "invalid" and all queries to be answered conservatively without lookups.
// To be in this state we have to (1) finished the exploration and (3) not
// discovered any non-trivial dead end and (2) not ruled unreachable code
// dead.
if (ToBeExploredFrom.empty() &&
getAssociatedFunction()->size() == AssumedLiveBlocks.size())
getAssociatedFunction()->size() == AssumedLiveBlocks.size() &&
llvm::all_of(KnownDeadEnds, [](const Instruction *DeadEndI) {
return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
}))
return indicatePessimisticFixpoint();
return Change;
}

View File

@ -689,12 +689,12 @@ define void @live_with_dead_entry_lp() personality i8* bitcast (i32 (...)* @__gx
; CHECK: define void @live_with_dead_entry_lp(
; CHECK-NEXT: entry:
; CHECK-NEXT: invoke void @blowup()
; CHECK-NEXT: to label %live_with_dead_entry.dead1 unwind label %lp1
; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lp1
; CHECK: lp1: ; preds = %entry
; CHECK-NEXT: %lp = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: invoke void @blowup()
; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lp2
; CHECK-NEXT: to label %live_with_dead_entry.dead1 unwind label %lp2
; CHECK: lp2: ; preds = %lp1
; CHECK-NEXT: %0 = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null