[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