summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Stipanovic <sstipanovic@s-energize.com>2019-06-27 11:27:54 +0000
committerStefan Stipanovic <sstipanovic@s-energize.com>2019-06-27 11:27:54 +0000
commit5360589b7d05745afba23c6ef1cb34b49de4a75b (patch)
tree5b46633d6f320c75de9e86f2ce0a4f298d854436
parentd45b4f861e6482ad928b6c1eabaa6fa3bda031a2 (diff)
downloadbcm5719-llvm-5360589b7d05745afba23c6ef1cb34b49de4a75b.tar.gz
bcm5719-llvm-5360589b7d05745afba23c6ef1cb34b49de4a75b.zip
[Attributor] Deducing existing nounwind attribute.
Adding nounwind deduction in new attributor framework. Reviewers: jdoerfert, uenoku Subscribers: hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D63379 llvm-svn: 364521
-rw-r--r--llvm/include/llvm/Transforms/IPO/Attributor.h17
-rw-r--r--llvm/lib/Transforms/IPO/Attributor.cpp95
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nounwind.ll99
3 files changed, 201 insertions, 10 deletions
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index f2d9c3486c7..8084e38b240 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -642,6 +642,23 @@ Pass *createAttributorLegacyPass();
/// Abstract Attribute Classes
/// ----------------------------------------------------------------------------
+struct AANoUnwind : public AbstractAttribute {
+ /// An abstract interface for all nosync attributes.
+ AANoUnwind(Value &V, InformationCache &InfoCache)
+ : AbstractAttribute(V, InfoCache) {}
+
+ /// See AbstractAttribute::getAttrKind()/
+ virtual Attribute::AttrKind getAttrKind() const override { return ID; }
+
+ static constexpr Attribute::AttrKind ID = Attribute::NoUnwind;
+
+ /// Returns true if nounwind is assumed.
+ virtual bool isAssumedNoUnwind() const = 0;
+
+ /// Returns true if nounwind is known.
+ virtual bool isKnownNoUnwind() const = 0;
+};
+
} // end namespace llvm
#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 0915a990499..48d61078039 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -42,6 +42,7 @@ STATISTIC(NumAttributesValidFixpoint,
"Number of abstract attributes in a valid fixpoint state");
STATISTIC(NumAttributesManifested,
"Number of abstract attributes manifested in IR");
+STATISTIC(NumFnNoUnwind, "Number of functions marked nounwind");
// TODO: Determine a good default value.
//
@@ -86,10 +87,13 @@ static void bookkeeping(AbstractAttribute::ManifestPosition MP,
if (!Attr.isEnumAttribute())
return;
- //switch (Attr.getKindAsEnum()) {
- //default:
- // return;
- //}
+ switch (Attr.getKindAsEnum()) {
+ case Attribute::NoUnwind:
+ NumFnNoUnwind++;
+ return;
+ default:
+ return;
+ }
}
/// Helper to identify the correct offset into an attribute list.
@@ -241,6 +245,64 @@ const Function &AbstractAttribute::getAnchorScope() const {
return const_cast<AbstractAttribute *>(this)->getAnchorScope();
}
+/// -----------------------NoUnwind Function Attribute--------------------------
+
+struct AANoUnwindFunction : AANoUnwind, BooleanState {
+
+ AANoUnwindFunction(Function &F, InformationCache &InfoCache)
+ : AANoUnwind(F, InfoCache) {}
+
+ /// See AbstractAttribute::getState()
+ /// {
+ AbstractState &getState() override { return *this; }
+ const AbstractState &getState() const override { return *this; }
+ /// }
+
+ /// See AbstractAttribute::getManifestPosition().
+ virtual ManifestPosition getManifestPosition() const override {
+ return MP_FUNCTION;
+ }
+
+ virtual const std::string getAsStr() const override {
+ return getAssumed() ? "nounwind" : "may-unwind";
+ }
+
+ /// See AbstractAttribute::updateImpl(...).
+ virtual ChangeStatus updateImpl(Attributor &A) override;
+
+ /// See AANoUnwind::isAssumedNoUnwind().
+ virtual bool isAssumedNoUnwind() const override { return getAssumed(); }
+
+ /// See AANoUnwind::isKnownNoUnwind().
+ virtual bool isKnownNoUnwind() const override { return getKnown(); }
+};
+
+ChangeStatus AANoUnwindFunction::updateImpl(Attributor &A) {
+ Function &F = getAnchorScope();
+
+ // The map from instruction opcodes to those instructions in the function.
+ auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+ auto Opcodes = {
+ (unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
+ (unsigned)Instruction::Call, (unsigned)Instruction::CleanupRet,
+ (unsigned)Instruction::CatchSwitch, (unsigned)Instruction::Resume};
+
+ for (unsigned Opcode : Opcodes) {
+ for (Instruction *I : OpcodeInstMap[Opcode]) {
+ if (!I->mayThrow())
+ continue;
+
+ auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, *I);
+
+ if (!NoUnwindAA || !NoUnwindAA->isAssumedNoUnwind()) {
+ indicatePessimisticFixpoint();
+ return ChangeStatus::CHANGED;
+ }
+ }
+ }
+ return ChangeStatus::UNCHANGED;
+}
+
/// ----------------------------------------------------------------------------
/// Attributor
/// ----------------------------------------------------------------------------
@@ -254,8 +316,8 @@ ChangeStatus Attributor::run() {
<< AllAbstractAttributes.size()
<< " abstract attributes.\n");
- // Now that all abstract attributes are collected and initialized we start the
- // abstract analysis.
+ // Now that all abstract attributes are collected and initialized we start
+ // the abstract analysis.
unsigned IterationCounter = 1;
@@ -383,6 +445,9 @@ void Attributor::identifyDefaultAbstractAttributes(
Function &F, InformationCache &InfoCache,
DenseSet</* Attribute::AttrKind */ unsigned> *Whitelist) {
+ // Every function can be nounwind.
+ registerAA(*new AANoUnwindFunction(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.
@@ -397,10 +462,20 @@ void Attributor::identifyDefaultAbstractAttributes(
// to concrete attributes we only cache the ones that are as identified in
// the following switch.
// Note: There are no concrete attributes now so this is initially empty.
- //switch (I.getOpcode()) {
- //default:
- // break;
- //}
+ switch (I.getOpcode()) {
+ default:
+ assert((!ImmutableCallSite(&I)) && (!isa<CallBase>(&I)) &&
+ "New call site/base instruction type needs to be known int the "
+ "attributor.");
+ break;
+ case Instruction::Call:
+ case Instruction::CallBr:
+ case Instruction::Invoke:
+ case Instruction::CleanupRet:
+ case Instruction::CatchSwitch:
+ case Instruction::Resume:
+ IsInterestingOpcode = true;
+ }
if (IsInterestingOpcode)
InstOpcodeMap[I.getOpcode()].push_back(&I);
if (I.mayReadOrWriteMemory())
diff --git a/llvm/test/Transforms/FunctionAttrs/nounwind.ll b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
new file mode 100644
index 00000000000..219c10dcc6b
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
@@ -0,0 +1,99 @@
+; RUN: opt < %s -functionattrs -S | FileCheck %s
+; RUN: opt < %s -attributor -attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR
+
+; TEST 1
+; CHECK: Function Attrs: norecurse nounwind readnone
+; CHECK-NEXT: define i32 @foo1()
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NEXT: define i32 @foo1()
+define i32 @foo1() {
+ ret i32 1
+}
+
+; TEST 2
+; CHECK: Function Attrs: nounwind readnone
+; CHECK-NEXT: define i32 @scc1_foo()
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
+define i32 @scc1_foo() {
+ %1 = call i32 @scc1_bar()
+ ret i32 1
+}
+
+
+; TEST 3
+; CHECK: Function Attrs: nounwind readnone
+; CHECK-NEXT: define i32 @scc1_bar()
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
+define i32 @scc1_bar() {
+ %1 = call i32 @scc1_foo()
+ ret i32 1
+}
+
+; CHECK: declare i32 @non_nounwind()
+declare i32 @non_nounwind()
+
+; TEST 4
+; CHECK: define void @call_non_nounwind() {
+; ATTRIBUTOR: define void @call_non_nounwind() {
+define void @call_non_nounwind(){
+ tail call i32 @non_nounwind()
+ ret void
+}
+
+; TEST 5 - throw
+; int maybe_throw(bool canThrow) {
+; if (canThrow)
+; throw;
+; else
+; return -1;
+; }
+
+; CHECK: define i32 @maybe_throw(i1 zeroext)
+; ATTRIBUTOR: define i32 @maybe_throw(i1 zeroext)
+define i32 @maybe_throw(i1 zeroext) {
+ br i1 %0, label %2, label %3
+
+2: ; preds = %1
+ tail call void @__cxa_rethrow() #1
+ unreachable
+
+3: ; preds = %1
+ ret i32 -1
+}
+
+declare void @__cxa_rethrow()
+
+; TEST 6 - catch
+; int catch_thing() {
+; try {
+; int a = doThing(true);
+; }
+; catch(...) { return -1; }
+; return 1;
+; }
+
+; CHECK: define i32 @catch_thing()
+; ATTRIBUTOR: define i32 @catch_thing()
+define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+ invoke void @__cxa_rethrow() #1
+ to label %1 unwind label %2
+
+1: ; preds = %0
+ unreachable
+
+2: ; preds = %0
+ %3 = landingpad { i8*, i32 }
+ catch i8* null
+ %4 = extractvalue { i8*, i32 } %3, 0
+ %5 = tail call i8* @__cxa_begin_catch(i8* %4) #2
+ tail call void @__cxa_end_catch()
+ ret i32 -1
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
OpenPOWER on IntegriCloud