Skip to content

Commit

Permalink
Fixing build error from commit 95cbc3d
Browse files Browse the repository at this point in the history
[Attributor] Liveness analysis.

Liveness analysis abstract attribute used to indicate which BasicBlocks are dead and can therefore be ignored.
Right now we are only looking at noreturn calls.

Reviewers: jdoerfert, uenoku

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D64162

llvm-svn: 366769
  • Loading branch information
sstefan1 committed Jul 22, 2019
1 parent b2a9cf7 commit 6058b86
Show file tree
Hide file tree
Showing 5 changed files with 468 additions and 1 deletion.
40 changes: 40 additions & 0 deletions llvm/include/llvm/Transforms/IPO/Attributor.h
Expand Up @@ -805,6 +805,46 @@ struct AANoAlias : public AbstractAttribute {
static constexpr Attribute::AttrKind ID = Attribute::NoAlias;
};

/// An AbstractAttribute for noreturn.
struct AANoReturn : public AbstractAttribute {

/// See AbstractAttribute::AbstractAttribute(...).
AANoReturn(Value &V, InformationCache &InfoCache)
: AbstractAttribute(V, InfoCache) {}

/// Return true if the underlying object is known to never return.
virtual bool isKnownNoReturn() const = 0;

/// Return true if the underlying object is assumed to never return.
virtual bool isAssumedNoReturn() const = 0;

/// See AbstractAttribute::getAttrKind()
Attribute::AttrKind getAttrKind() const override { return ID; }

/// The identifier used by the Attributor for this class of attributes.
static constexpr Attribute::AttrKind ID = Attribute::NoReturn;
};

/// An abstract interface for liveness abstract attribute.
struct AAIsDead : public AbstractAttribute {

/// See AbstractAttribute::AbstractAttribute(...).
AAIsDead(Value &V, InformationCache &InfoCache)
: AbstractAttribute(V, InfoCache) {}

/// See AbstractAttribute::getAttrKind()
Attribute::AttrKind getAttrKind() const override { return ID; }

static constexpr Attribute::AttrKind ID =
Attribute::AttrKind(Attribute::EndAttrKinds + 1);

/// Returns true if \p BB is assumed dead.
virtual bool isAssumedDead(BasicBlock *BB) const = 0;

/// Returns true if \p BB is known dead.
virtual bool isKnownDead(BasicBlock *BB) const = 0;
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
3 changes: 3 additions & 0 deletions llvm/include/llvm/Transforms/Utils/Local.h
Expand Up @@ -271,6 +271,9 @@ inline unsigned getKnownAlignment(Value *V, const DataLayout &DL,
return getOrEnforceKnownAlignment(V, 0, DL, CxtI, AC, DT);
}

/// This function converts the specified invoek into a normall call.
void changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr);

///===---------------------------------------------------------------------===//
/// Dbg Intrinsic utilities
///
Expand Down
174 changes: 174 additions & 0 deletions llvm/lib/Transforms/IPO/Attributor.cpp
Expand Up @@ -16,6 +16,7 @@
#include "llvm/Transforms/IPO/Attributor.h"

#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
Expand All @@ -31,6 +32,9 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"

#include <cassert>

using namespace llvm;
Expand Down Expand Up @@ -1411,6 +1415,173 @@ ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) {
return ChangeStatus::UNCHANGED;
}

/// -------------------AAIsDead Function Attribute-----------------------

struct AAIsDeadFunction : AAIsDead, BooleanState {

AAIsDeadFunction(Function &F, InformationCache &InfoCache)
: AAIsDead(F, InfoCache) {}

/// See AbstractAttribute::getState()
/// {
AbstractState &getState() override { return *this; }
const AbstractState &getState() const override { return *this; }
/// }

/// See AbstractAttribute::getManifestPosition().
ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }

void initialize(Attributor &A) override {
Function &F = getAnchorScope();

ToBeExploredPaths.insert(&(F.getEntryBlock().front()));
AssumedLiveBlocks.insert(&(F.getEntryBlock()));
for (size_t i = 0; i < ToBeExploredPaths.size(); ++i)
explorePath(A, ToBeExploredPaths[i]);
}

/// Explores new instructions starting from \p I. If instruction is dead, stop
/// and return true if it discovered a new instruction.
bool explorePath(Attributor &A, Instruction *I);

const std::string getAsStr() const override {
return "LiveBBs(" + std::to_string(AssumedLiveBlocks.size()) + "/" +
std::to_string(getAnchorScope().size()) + ")";
}

/// See AbstractAttribute::manifest(...).
ChangeStatus manifest(Attributor &A) override {
assert(getState().isValidState() &&
"Attempted to manifest an invalid state!");

ChangeStatus HasChanged = ChangeStatus::UNCHANGED;

for (Instruction *I : NoReturnCalls) {
BasicBlock *BB = I->getParent();

/// Invoke is replaced with a call and unreachable is placed after it.
if (auto *II = dyn_cast<InvokeInst>(I)) {
changeToCall(II);
changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false);
LLVM_DEBUG(dbgs() << "[AAIsDead] Replaced invoke with call inst\n");
continue;
}

SplitBlock(BB, I->getNextNode());
changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false);
HasChanged = ChangeStatus::CHANGED;
}

return HasChanged;
}

/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override;

/// See AAIsDead::isAssumedDead().
bool isAssumedDead(BasicBlock *BB) const override {
if (!getAssumed())
return false;
return !AssumedLiveBlocks.count(BB);
}

/// See AAIsDead::isKnownDead().
bool isKnownDead(BasicBlock *BB) const override {
if (!getKnown())
return false;
return !AssumedLiveBlocks.count(BB);
}

/// Collection of to be explored paths.
SmallSetVector<Instruction *, 8> ToBeExploredPaths;

/// Collection of all assumed live BasicBlocks.
DenseSet<BasicBlock *> AssumedLiveBlocks;

/// Collection of calls with noreturn attribute, assumed or knwon.
SmallSetVector<Instruction *, 4> NoReturnCalls;
};

bool AAIsDeadFunction::explorePath(Attributor &A, Instruction *I) {
BasicBlock *BB = I->getParent();

while (I) {
ImmutableCallSite ICS(I);

if (ICS) {
auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, *I);

if (NoReturnAA && NoReturnAA->isAssumedNoReturn()) {
if (!NoReturnCalls.insert(I))
// If I is already in the NoReturnCalls set, then it stayed noreturn
// and we didn't discover any new instructions.
return false;

// Discovered new noreturn call, return true to indicate that I is not
// noreturn anymore and should be deleted from NoReturnCalls.
return true;
}

if (ICS.hasFnAttr(Attribute::NoReturn)) {
if(!NoReturnCalls.insert(I))
return false;

return true;
}
}

I = I->getNextNode();
}

// get new paths (reachable blocks).
for (BasicBlock *SuccBB : successors(BB)) {
Instruction *Inst = &(SuccBB->front());
AssumedLiveBlocks.insert(SuccBB);
ToBeExploredPaths.insert(Inst);
}

return true;
}

ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {
Function &F = getAnchorScope();

// Temporary collection to iterate over existing noreturn instructions. This
// will alow easier modification of NoReturnCalls collection
SmallVector<Instruction *, 8> NoReturnChanged;
ChangeStatus Status = ChangeStatus::UNCHANGED;

for (Instruction *I : NoReturnCalls)
NoReturnChanged.push_back(I);

for (Instruction *I : NoReturnChanged) {
size_t Size = ToBeExploredPaths.size();

// Still noreturn.
if (!explorePath(A, I))
continue;

NoReturnCalls.remove(I);

// No new paths.
if (Size == ToBeExploredPaths.size())
continue;

// At least one new path.
Status = ChangeStatus::CHANGED;

// explore new paths.
while (Size != ToBeExploredPaths.size())
explorePath(A, ToBeExploredPaths[Size++]);
}

LLVM_DEBUG(dbgs() << "[AAIsDead] AssumedLiveBlocks: "
<< AssumedLiveBlocks.size()
<< "Total number of blocks: " << F.size() << "\n");

return Status;
}

/// ----------------------------------------------------------------------------
/// Attributor
/// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -1627,6 +1798,9 @@ void Attributor::identifyDefaultAbstractAttributes(
// Every function might be "will-return".
registerAA(*new AAWillReturnFunction(F, InfoCache));

// Check for dead BasicBlocks in every function.
registerAA(*new AAIsDeadFunction(F, InfoCache));

// Walk all instructions to find more attribute opportunities and also
// interesting instructions that might be queried by abstract attributes
// during their initialization or update.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/Local.cpp
Expand Up @@ -1964,7 +1964,7 @@ unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap,
}

/// changeToCall - Convert the specified invoke into a normal call.
static void changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr) {
void llvm::changeToCall(InvokeInst *II, DomTreeUpdater *DTU) {
SmallVector<Value*, 8> Args(II->arg_begin(), II->arg_end());
SmallVector<OperandBundleDef, 1> OpBundles;
II->getOperandBundlesAsDefs(OpBundles);
Expand Down

0 comments on commit 6058b86

Please sign in to comment.