[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