[llvm] r364521 - [Attributor] Deducing existing nounwind attribute.
Stefan Stipanovic via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 27 04:27:54 PDT 2019
Author: sstefan
Date: Thu Jun 27 04:27:54 2019
New Revision: 364521
URL: http://llvm.org/viewvc/llvm-project?rev=364521&view=rev
Log:
[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
Added:
llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
Modified:
llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
llvm/trunk/lib/Transforms/IPO/Attributor.cpp
Modified: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/Attributor.h?rev=364521&r1=364520&r2=364521&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Thu Jun 27 04:27:54 2019
@@ -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
Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=364521&r1=364520&r2=364521&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Thu Jun 27 04:27:54 2019
@@ -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(AbstractAttribut
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::getAn
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::identifyDefaultAbstract
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::identifyDefaultAbstract
// 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())
Added: llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll?rev=364521&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll (added)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll Thu Jun 27 04:27:54 2019
@@ -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()
More information about the llvm-commits
mailing list