[llvm] a198adb - [Attributor] IPO across definition boundary of a function marked alwaysinline

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 12 23:07:11 PDT 2020


Author: Johannes Doerfert
Date: 2020-03-13T01:06:12-05:00
New Revision: a198adb490279cc70b5c60a8989629d92c768231

URL: https://github.com/llvm/llvm-project/commit/a198adb490279cc70b5c60a8989629d92c768231
DIFF: https://github.com/llvm/llvm-project/commit/a198adb490279cc70b5c60a8989629d92c768231.diff

LOG: [Attributor] IPO across definition boundary of a function marked alwaysinline

Reviewed By: jdoerfert

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

Added: 
    llvm/test/Transforms/Attributor/alwaysinline.ll

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Transforms/IPO/Attributor.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 27a879df6674..41d3c2f9ec6d 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -103,6 +103,7 @@
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/CGSCCPassManager.h"
 #include "llvm/Analysis/CallGraph.h"
+#include "llvm/Analysis/InlineCost.h"
 #include "llvm/Analysis/LazyCallGraph.h"
 #include "llvm/Analysis/MustExecute.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -636,6 +637,9 @@ struct InformationCache {
   /// The underlying CGSCC, or null if not available.
   SetVector<Function *> *CGSCC;
 
+  /// Set of inlineable functions
+  SmallPtrSet<const Function *, 8> InlineableFunctions;
+
   /// Give the Attributor access to the members so
   /// Attributor::identifyDefaultAbstractAttributes(...) can initialize them.
   friend struct Attributor;
@@ -789,6 +793,14 @@ struct Attributor {
   /// through the information cache interface *prior* to looking at them.
   void initializeInformationCache(Function &F);
 
+  /// Determine whether the function \p F is IPO amendable
+  ///
+  /// If a function is exactly defined or it has alwaysinline attribute
+  /// and is viable to be inlined, we say it is IPO amendable
+  bool isFunctionIPOAmendable(const Function &F) {
+    return F.hasExactDefinition() || InfoCache.InlineableFunctions.count(&F);
+  }
+
   /// Mark the internal function \p F as live.
   ///
   /// This will trigger the identification and initialization of attributes for
@@ -1719,7 +1731,7 @@ struct IRAttribute : public IRPosition, public Base {
     // TODO: We could always determine abstract attributes and if sufficient
     //       information was found we could duplicate the functions that do not
     //       have an exact definition.
-    if (IsFnInterface && (!FnScope || !FnScope->hasExactDefinition()))
+    if (IsFnInterface && (!FnScope || !A.isFunctionIPOAmendable(*FnScope)))
       this->getState().indicatePessimisticFixpoint();
   }
 
@@ -2762,7 +2774,8 @@ struct AAValueConstantRange : public IntegerRangeState,
   /// Return an assumed constant for the assocaited value a program point \p
   /// CtxI.
   Optional<ConstantInt *>
-  getAssumedConstantInt(Attributor &A, const Instruction *CtxI = nullptr) const {
+  getAssumedConstantInt(Attributor &A,
+                        const Instruction *CtxI = nullptr) const {
     ConstantRange RangeV = getAssumedConstantRange(A, CtxI);
     if (auto *C = RangeV.getSingleElement())
       return cast<ConstantInt>(

diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 0cecfd4461d4..a7ac4cc21d16 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -1232,7 +1232,7 @@ class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState {
       }
     }
 
-    if (!F->hasExactDefinition())
+    if (!A.isFunctionIPOAmendable(*F))
       indicatePessimisticFixpoint();
   }
 
@@ -2512,7 +2512,7 @@ static bool containsCycle(Function &F) {
 // FIXME: Any cycle is regarded as endless loop for now.
 //        We have to allow some patterns.
 static bool containsPossiblyEndlessLoop(Function *F) {
-  return !F || !F->hasExactDefinition() || containsCycle(*F);
+  return containsCycle(*F);
 }
 
 struct AAWillReturnImpl : public AAWillReturn {
@@ -2523,7 +2523,7 @@ struct AAWillReturnImpl : public AAWillReturn {
     AAWillReturn::initialize(A);
 
     Function *F = getAssociatedFunction();
-    if (containsPossiblyEndlessLoop(F))
+    if (!F || !A.isFunctionIPOAmendable(*F) || containsPossiblyEndlessLoop(F))
       indicatePessimisticFixpoint();
   }
 
@@ -3065,7 +3065,7 @@ struct AAIsDeadArgument : public AAIsDeadFloating {
 
   /// See AbstractAttribute::initialize(...).
   void initialize(Attributor &A) override {
-    if (!getAssociatedFunction()->hasExactDefinition())
+    if (!A.isFunctionIPOAmendable(*getAssociatedFunction()))
       indicatePessimisticFixpoint();
   }
 
@@ -3616,8 +3616,8 @@ struct AADereferenceableImpl : AADereferenceable {
 
     const IRPosition &IRP = this->getIRPosition();
     bool IsFnInterface = IRP.isFnInterfaceKind();
-    const Function *FnScope = IRP.getAnchorScope();
-    if (IsFnInterface && (!FnScope || !FnScope->hasExactDefinition()))
+    Function *FnScope = IRP.getAnchorScope();
+    if (IsFnInterface && (!FnScope || !A.isFunctionIPOAmendable(*FnScope)))
       indicatePessimisticFixpoint();
   }
 
@@ -3899,7 +3899,7 @@ struct AAAlignImpl : AAAlign {
 
     if (getIRPosition().isFnInterfaceKind() &&
         (!getAssociatedFunction() ||
-         !getAssociatedFunction()->hasExactDefinition()))
+         !A.isFunctionIPOAmendable(*getAssociatedFunction())))
       indicatePessimisticFixpoint();
   }
 
@@ -4156,7 +4156,7 @@ struct AANoCaptureImpl : public AANoCapture {
     }
     Function *AnchorScope = getAnchorScope();
     if (isFnInterfaceKind() &&
-        (!AnchorScope || !AnchorScope->hasExactDefinition())) {
+        (!AnchorScope || !A.isFunctionIPOAmendable(*AnchorScope))) {
       indicatePessimisticFixpoint();
       return;
     }
@@ -5888,7 +5888,7 @@ struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
 
     // Initialize the use vector with all direct uses of the associated value.
     Argument *Arg = getAssociatedArgument();
-    if (!Arg || !Arg->getParent()->hasExactDefinition()) {
+    if (!Arg || !A.isFunctionIPOAmendable(*(Arg->getParent()))) {
       indicatePessimisticFixpoint();
     } else {
       // Initialize the use vector with all direct uses of the associated value.
@@ -6016,7 +6016,7 @@ struct AAMemoryBehaviorCallSite final : AAMemoryBehaviorImpl {
   void initialize(Attributor &A) override {
     AAMemoryBehaviorImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F || !A.isFunctionIPOAmendable(*F))
       indicatePessimisticFixpoint();
   }
 
@@ -6703,7 +6703,7 @@ struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
   void initialize(Attributor &A) override {
     AAMemoryLocationImpl::initialize(A);
     Function *F = getAssociatedFunction();
-    if (!F || !F->hasExactDefinition())
+    if (!F || !A.isFunctionIPOAmendable(*F))
       indicatePessimisticFixpoint();
   }
 
@@ -8293,6 +8293,10 @@ void Attributor::initializeInformationCache(Function &F) {
     if (I.mayReadOrWriteMemory())
       ReadOrWriteInsts.push_back(&I);
   }
+
+  if (F.hasFnAttribute(Attribute::AlwaysInline) &&
+      isInlineViable(F).isSuccess())
+    InfoCache.InlineableFunctions.insert(&F);
 }
 
 void Attributor::recordDependence(const AbstractAttribute &FromAA,

diff  --git a/llvm/test/Transforms/Attributor/alwaysinline.ll b/llvm/test/Transforms/Attributor/alwaysinline.ll
new file mode 100644
index 000000000000..1be433310457
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/alwaysinline.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -attributor -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=CHECK
+;
+; When a function is marked `alwaysinline` and is able to be inlined,
+; we can IPO its boundaries
+
+; the function is not exactly defined, and marked alwaysinline and can be inlined,
+; so the function can be analyzed
+; CHECK: Function Attrs: alwaysinline nofree nosync nounwind readnone willreturn
+define linkonce void @inner1() alwaysinline {
+; CHECK-LABEL: @inner1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret void
+;
+entry:
+  ret void
+}
+
+; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
+define void @outer1() {
+; CHECK-LABEL: @outer1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret void
+;
+entry:
+  call void @inner1()
+  ret void
+}
+
+; The function is not alwaysinline and is not exactly defined
+; so it will not be analyzed
+; CHECK-NOT: Function Attrs:
+define linkonce i32 @inner2() {
+; CHECK-LABEL: @inner2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i32 1
+;
+entry:
+  ret i32 1
+}
+
+; CHECK-NOT: Function Attrs
+define i32 @outer2() {
+; CHECK-LABEL: @outer2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[R:%.*]] = call i32 @inner2() #2
+; CHECK-NEXT:    ret i32 [[R]]
+;
+entry:
+  %r = call i32 @inner2() alwaysinline
+  ret i32 %r
+}
+
+; This function cannot be inlined although it is marked alwaysinline
+; it is `unexactly defined` and alwaysinline but cannot be inlined.
+; so it will not be analyzed
+; CHECK: Function Attrs:
+; CHECK-NOT: nofree nosync nounwind readnone
+define linkonce i32 @inner3(i8* %addr) alwaysinline {
+; CHECK-LABEL: @inner3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    indirectbr i8* [[ADDR:%.*]], [label [[ONE:%.*]], label %two]
+; CHECK:       one:
+; CHECK-NEXT:    ret i32 42
+; CHECK:       two:
+; CHECK-NEXT:    ret i32 44
+;
+entry:
+  indirectbr i8* %addr, [ label %one, label %two ]
+
+one:
+  ret i32 42
+
+two:
+  ret i32 44
+}
+
+; CHECK-NOT: Function Attrs:
+define i32 @outer3(i32 %x) {
+; CHECK-LABEL: @outer3(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 42
+; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[CMP]], i8* blockaddress(@inner3, [[ONE:%.*]]), i8* blockaddress(@inner3, [[TWO:%.*]])
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @inner3(i8* [[ADDR]])
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %cmp = icmp slt i32 %x, 42
+  %addr = select i1 %cmp, i8* blockaddress(@inner3, %one), i8* blockaddress(@inner3, %two)
+  %call = call i32 @inner3(i8* %addr)
+  ret i32 %call
+}


        


More information about the llvm-commits mailing list