Skip to content

Commit

Permalink
[Attributor] Deduce "willreturn" function attribute
Browse files Browse the repository at this point in the history
Summary:
Deduce the "willreturn" attribute for functions.

For now, intrinsics are not willreturn. More annotation will be done in another patch.

Reviewers: jdoerfert

Subscribers: jvesely, nhaehnle, nicholas, hiraditya, llvm-commits

Tags: #llvm

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

llvm-svn: 366335
  • Loading branch information
uenoku committed Jul 17, 2019
1 parent 629273e commit 11d3710
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 9 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Expand Up @@ -94,6 +94,8 @@ class ReadNone<int argNo> : IntrinsicProperty {

def IntrNoReturn : IntrinsicProperty;

def IntrWillReturn : IntrinsicProperty;

// IntrCold - Calls to this intrinsic are cold.
// Parallels the cold attribute on LLVM IR functions.
def IntrCold : IntrinsicProperty;
Expand Down
44 changes: 44 additions & 0 deletions llvm/include/llvm/Transforms/IPO/Attributor.h
Expand Up @@ -740,6 +740,50 @@ struct AANonNull : public AbstractAttribute {
/// The identifier used by the Attributor for this class of attributes.
static constexpr Attribute::AttrKind ID = Attribute::NonNull;
};

/// An abstract attribute for norecurse.
struct AANoRecurse : public AbstractAttribute {

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

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

/// Return true if "norecurse" is known.
virtual bool isKnownNoRecurse() const = 0;

/// Return true if "norecurse" is assumed.
virtual bool isAssumedNoRecurse() const = 0;

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

/// An abstract attribute for willreturn.
struct AAWillReturn : public AbstractAttribute {

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

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

/// Return true if "willreturn" is known.
virtual bool isKnownWillReturn() const = 0;

/// Return true if "willreturn" is assumed.
virtual bool isAssumedWillReturn() const = 0;

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

#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
120 changes: 120 additions & 0 deletions llvm/lib/Transforms/IPO/Attributor.cpp
Expand Up @@ -15,6 +15,7 @@

#include "llvm/Transforms/IPO/Attributor.h"

#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
Expand All @@ -23,6 +24,7 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/CommandLine.h"
Expand Down Expand Up @@ -56,6 +58,7 @@ STATISTIC(NumFnReturnedNonNull,
"Number of function return values marked nonnull");
STATISTIC(NumFnArgumentNonNull, "Number of function arguments marked nonnull");
STATISTIC(NumCSArgumentNonNull, "Number of call site arguments marked nonnull");
STATISTIC(NumFnWillReturn, "Number of functions marked willreturn");

// TODO: Determine a good default value.
//
Expand Down Expand Up @@ -128,6 +131,9 @@ static void bookkeeping(AbstractAttribute::ManifestPosition MP,
break;
}
break;
case Attribute::WillReturn:
NumFnWillReturn++;
break;
default:
return;
}
Expand Down Expand Up @@ -1194,6 +1200,117 @@ ChangeStatus AANonNullCallSiteArgument::updateImpl(Attributor &A) {
return ChangeStatus::UNCHANGED;
}

/// ------------------------ Will-Return Attributes ----------------------------

struct AAWillReturnImpl : public AAWillReturn, BooleanState {

/// See AbstractAttribute::AbstractAttribute(...).
AAWillReturnImpl(Function &F, InformationCache &InfoCache)
: AAWillReturn(F, InfoCache) {}

/// See AAWillReturn::isKnownWillReturn().
bool isKnownWillReturn() const override { return getKnown(); }

/// See AAWillReturn::isAssumedWillReturn().
bool isAssumedWillReturn() const override { return getAssumed(); }

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

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

/// See AbstractAttribute::getAsStr()
const std::string getAsStr() const override {
return getAssumed() ? "willreturn" : "may-noreturn";
}
};

struct AAWillReturnFunction final : AAWillReturnImpl {

/// See AbstractAttribute::AbstractAttribute(...).
AAWillReturnFunction(Function &F, InformationCache &InfoCache)
: AAWillReturnImpl(F, InfoCache) {}

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

/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override;

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

// Helper function that checks whether a function has any cycle.
// TODO: Replace with more efficent code
bool containsCycle(Function &F) {
SmallPtrSet<BasicBlock *, 32> Visited;

// Traverse BB by dfs and check whether successor is already visited.
for (BasicBlock *BB : depth_first(&F)) {
Visited.insert(BB);
for (auto *SuccBB : successors(BB)) {
if (Visited.count(SuccBB))
return true;
}
}
return false;
}

// Helper function that checks the function have a loop which might become an
// endless loop
// FIXME: Any cycle is regarded as endless loop for now.
// We have to allow some patterns.
bool containsPossiblyEndlessLoop(Function &F) { return containsCycle(F); }

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

if (containsPossiblyEndlessLoop(F))
indicatePessimisticFixpoint();
}

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

// The map from instruction opcodes to those instructions in the function.
auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);

for (unsigned Opcode :
{(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
(unsigned)Instruction::Call}) {
for (Instruction *I : OpcodeInstMap[Opcode]) {
auto ICS = ImmutableCallSite(I);

if (ICS.hasFnAttr(Attribute::WillReturn))
continue;

auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, *I);
if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn()) {
indicatePessimisticFixpoint();
return ChangeStatus::CHANGED;
}

auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, *I);

// FIXME: (i) Prohibit any recursion for now.
// (ii) AANoRecurse isn't implemented yet so currently any call is
// regarded as having recursion.
// Code below should be
// if ((!NoRecurseAA || !NoRecurseAA->isAssumedNoRecurse()) &&
if (!NoRecurseAA && !ICS.hasFnAttr(Attribute::NoRecurse)) {
indicatePessimisticFixpoint();
return ChangeStatus::CHANGED;
}
}
}

return ChangeStatus::UNCHANGED;
}

/// ----------------------------------------------------------------------------
/// Attributor
/// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -1403,6 +1520,9 @@ void Attributor::identifyDefaultAbstractAttributes(
registerAA(*new AANonNullArgument(Arg, InfoCache));
}

// Every function might be "will-return".
registerAA(*new AAWillReturnFunction(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/test/Transforms/FunctionAttrs/arg_returned.ll
Expand Up @@ -744,7 +744,7 @@ unreachableblock2:
attributes #0 = { noinline nounwind uwtable }

; BOTH-NOT: attributes #
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline norecurse nosync nounwind readnone uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline norecurse nosync nounwind readnone uwtable willreturn }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readonly uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
Expand Down

0 comments on commit 11d3710

Please sign in to comment.