summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorHideto Ueno <uenoku.tokotoko@gmail.com>2019-10-08 15:25:56 +0000
committerHideto Ueno <uenoku.tokotoko@gmail.com>2019-10-08 15:25:56 +0000
commit96e6ce4cd3613527107ed0fc762c510e9d18a860 (patch)
tree0f7a2c1e5bef513a9c4efff26aa20623427f453c /llvm/lib
parentfb92ef1e55d7371c29d695889d0b4d026627637d (diff)
downloadbcm5719-llvm-96e6ce4cd3613527107ed0fc762c510e9d18a860.tar.gz
bcm5719-llvm-96e6ce4cd3613527107ed0fc762c510e9d18a860.zip
[Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer
Summary: In D65186 and related patches, MustBeExecutedContextExplorer is introduced. This enables us to traverse instructions guaranteed to execute from function entry. If we can know the argument is used as `dereferenceable` or `nonnull` in these instructions, we can mark `dereferenceable` or `nonnull` in the argument definition: 1. Memory instruction (similar to D64258) Trace memory instruction pointer operand. Currently, only inbounds GEPs are traced. ``` define i64* @f(i64* %a) { entry: %add.ptr = getelementptr inbounds i64, i64* %a, i64 1 ; (because of inbounds GEP we can know that %a is at least dereferenceable(16)) store i64 1, i64* %add.ptr, align 8 ret i64* %add.ptr ; dereferenceable 8 (because above instruction stores into it) } ``` 2. Propagation from callsite (similar to D27855) If `deref` or `nonnull` are known in call site parameter attributes we can also say that argument also that attribute. ``` declare void @use3(i8* %x, i8* %y, i8* %z); declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z); define void @parent1(i8* %a, i8* %b, i8* %c) { call void @use3nonnull(i8* %b, i8* %c, i8* %a) ; Above instruction is always executed so we can say that@parent1(i8* nonnnull %a, i8* nonnull %b, i8* nonnull %c) call void @use3(i8* %c, i8* %a, i8* %b) ret void } ``` Reviewers: jdoerfert, sstefan1, spatel, reames Reviewed By: jdoerfert Subscribers: xbolva00, hiraditya, jfb, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D65402 llvm-svn: 374063
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Transforms/IPO/Attributor.cpp233
1 files changed, 209 insertions, 24 deletions
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 3a1562252f5..4943721c469 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -288,6 +288,35 @@ static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
llvm_unreachable("Expected enum or string attribute!");
}
+static const Value *getPointerOperand(const Instruction *I) {
+ if (auto *LI = dyn_cast<LoadInst>(I))
+ if (!LI->isVolatile())
+ return LI->getPointerOperand();
+
+ if (auto *SI = dyn_cast<StoreInst>(I))
+ if (!SI->isVolatile())
+ return SI->getPointerOperand();
+
+ if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(I))
+ if (!CXI->isVolatile())
+ return CXI->getPointerOperand();
+
+ if (auto *RMWI = dyn_cast<AtomicRMWInst>(I))
+ if (!RMWI->isVolatile())
+ return RMWI->getPointerOperand();
+
+ return nullptr;
+}
+static const Value *getBasePointerOfAccessPointerOperand(const Instruction *I,
+ int64_t &BytesOffset,
+ const DataLayout &DL) {
+ const Value *Ptr = getPointerOperand(I);
+ if (!Ptr)
+ return nullptr;
+
+ return GetPointerBaseWithConstantOffset(Ptr, BytesOffset, DL,
+ /*AllowNonInbounds*/ false);
+}
ChangeStatus AbstractAttribute::update(Attributor &A) {
ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
@@ -654,7 +683,8 @@ struct AAArgumentFromCallSiteArguments : public Base {
};
/// Helper class for generic replication: function returned -> cs returned.
-template <typename AAType, typename Base>
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
struct AACallSiteReturnedFromReturned : public Base {
AACallSiteReturnedFromReturned(const IRPosition &IRP) : Base(IRP) {}
@@ -678,6 +708,80 @@ struct AACallSiteReturnedFromReturned : public Base {
}
};
+/// Helper class for generic deduction using must-be-executed-context
+/// Base class is required to have `followUse` method.
+
+/// bool followUse(Attributor &A, const Use *U, const Instruction *I)
+/// \param U Underlying use.
+/// \param I The user of the \p U.
+/// `followUse` returns true if the value should be tracked transitively.
+
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
+struct AAFromMustBeExecutedContext : public Base {
+ AAFromMustBeExecutedContext(const IRPosition &IRP) : Base(IRP) {}
+
+ void initialize(Attributor &A) override {
+ Base::initialize(A);
+ IRPosition &IRP = this->getIRPosition();
+ Instruction *CtxI = IRP.getCtxI();
+
+ if (!CtxI)
+ return;
+
+ for (const Use &U : IRP.getAssociatedValue().uses())
+ Uses.insert(&U);
+ }
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ auto BeforeState = this->getState();
+ auto &S = this->getState();
+ Instruction *CtxI = this->getIRPosition().getCtxI();
+ if (!CtxI)
+ return ChangeStatus::UNCHANGED;
+
+ MustBeExecutedContextExplorer &Explorer =
+ A.getInfoCache().getMustBeExecutedContextExplorer();
+
+ SetVector<const Use *> NextUses;
+
+ for (const Use *U : Uses) {
+ if (const Instruction *UserI = dyn_cast<Instruction>(U->getUser())) {
+ auto EIt = Explorer.begin(CtxI), EEnd = Explorer.end(CtxI);
+ bool Found = EIt.count(UserI);
+ while (!Found && ++EIt != EEnd)
+ Found = EIt.getCurrentInst() == UserI;
+ if (Found && Base::followUse(A, U, UserI))
+ for (const Use &Us : UserI->uses())
+ NextUses.insert(&Us);
+ }
+ }
+ for (const Use *U : NextUses)
+ Uses.insert(U);
+
+ return BeforeState == S ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED;
+ }
+
+private:
+ /// Container for (transitive) uses of the associated value.
+ SetVector<const Use *> Uses;
+};
+
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
+using AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext =
+ AAComposeTwoGenericDeduction<AAType, Base, StateType,
+ AAFromMustBeExecutedContext,
+ AAArgumentFromCallSiteArguments>;
+
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
+using AACallSiteReturnedFromReturnedAndMustBeExecutedContext =
+ AAComposeTwoGenericDeduction<AAType, Base, StateType,
+ AAFromMustBeExecutedContext,
+ AACallSiteReturnedFromReturned>;
+
/// -----------------------NoUnwind Function Attribute--------------------------
struct AANoUnwindImpl : AANoUnwind {
@@ -1434,6 +1538,46 @@ struct AANoFreeCallSite final : AANoFreeImpl {
};
/// ------------------------ NonNull Argument Attribute ------------------------
+static int64_t getKnownNonNullAndDerefBytesForUse(
+ Attributor &A, AbstractAttribute &QueryingAA, Value &AssociatedValue,
+ const Use *U, const Instruction *I, bool &IsNonNull, bool &TrackUse) {
+ // TODO: Add GEP support
+ TrackUse = false;
+
+ const Function *F = I->getFunction();
+ bool NullPointerIsDefined = F ? F->nullPointerIsDefined() : true;
+ const DataLayout &DL = A.getInfoCache().getDL();
+ if (ImmutableCallSite ICS = ImmutableCallSite(I)) {
+ if (ICS.isBundleOperand(U))
+ return 0;
+
+ if (ICS.isCallee(U)) {
+ IsNonNull |= !NullPointerIsDefined;
+ return 0;
+ }
+
+ unsigned ArgNo = ICS.getArgumentNo(U);
+ IRPosition IRP = IRPosition::callsite_argument(ICS, ArgNo);
+ auto &DerefAA = A.getAAFor<AADereferenceable>(QueryingAA, IRP);
+ IsNonNull |= DerefAA.isKnownNonNull();
+ return DerefAA.getKnownDereferenceableBytes();
+ }
+
+ int64_t Offset;
+ if (const Value *Base = getBasePointerOfAccessPointerOperand(I, Offset, DL)) {
+ if (Base == &AssociatedValue) {
+ int64_t DerefBytes =
+ Offset +
+ (int64_t)DL.getTypeStoreSize(
+ getPointerOperand(I)->getType()->getPointerElementType());
+
+ IsNonNull |= !NullPointerIsDefined;
+ return DerefBytes;
+ }
+ }
+
+ return 0;
+}
struct AANonNullImpl : AANonNull {
AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {}
@@ -1445,6 +1589,16 @@ struct AANonNullImpl : AANonNull {
AANonNull::initialize(A);
}
+ /// See AAFromMustBeExecutedContext
+ bool followUse(Attributor &A, const Use *U, const Instruction *I) {
+ bool IsNonNull = false;
+ bool TrackUse = false;
+ getKnownNonNullAndDerefBytesForUse(A, *this, getAssociatedValue(), U, I,
+ IsNonNull, TrackUse);
+ takeKnownMaximum(IsNonNull);
+ return TrackUse;
+ }
+
/// See AbstractAttribute::getAsStr().
const std::string getAsStr() const override {
return getAssumed() ? "nonnull" : "may-null";
@@ -1452,12 +1606,14 @@ struct AANonNullImpl : AANonNull {
};
/// NonNull attribute for a floating value.
-struct AANonNullFloating : AANonNullImpl {
- AANonNullFloating(const IRPosition &IRP) : AANonNullImpl(IRP) {}
+struct AANonNullFloating
+ : AAFromMustBeExecutedContext<AANonNull, AANonNullImpl> {
+ using Base = AAFromMustBeExecutedContext<AANonNull, AANonNullImpl>;
+ AANonNullFloating(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
- AANonNullImpl::initialize(A);
+ Base::initialize(A);
if (isAtFixpoint())
return;
@@ -1475,6 +1631,10 @@ struct AANonNullFloating : AANonNullImpl {
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus Change = Base::updateImpl(A);
+ if (isKnownNonNull())
+ return Change;
+
const DataLayout &DL = A.getDataLayout();
auto VisitValueCB = [&](Value &V, AAAlign::StateType &T,
@@ -1518,9 +1678,12 @@ struct AANonNullReturned final
/// NonNull attribute for function argument.
struct AANonNullArgument final
- : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
+ : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AANonNull,
+ AANonNullImpl> {
AANonNullArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP) {}
+ : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AANonNull,
+ AANonNullImpl>(
+ IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nonnull) }
@@ -1535,9 +1698,12 @@ struct AANonNullCallSiteArgument final : AANonNullFloating {
/// NonNull attribute for a call site return position.
struct AANonNullCallSiteReturned final
- : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl> {
+ : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<AANonNull,
+ AANonNullImpl> {
AANonNullCallSiteReturned(const IRPosition &IRP)
- : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl>(IRP) {}
+ : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<AANonNull,
+ AANonNullImpl>(
+ IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) }
@@ -2290,6 +2456,16 @@ struct AADereferenceableImpl : AADereferenceable {
const StateType &getState() const override { return *this; }
/// }
+ /// See AAFromMustBeExecutedContext
+ bool followUse(Attributor &A, const Use *U, const Instruction *I) {
+ bool IsNonNull = false;
+ bool TrackUse = false;
+ int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
+ A, *this, getAssociatedValue(), U, I, IsNonNull, TrackUse);
+ takeKnownDerefBytesMaximum(DerefBytes);
+ return TrackUse;
+ }
+
void getDeducedAttributes(LLVMContext &Ctx,
SmallVectorImpl<Attribute> &Attrs) const override {
// TODO: Add *_globally support
@@ -2314,12 +2490,16 @@ struct AADereferenceableImpl : AADereferenceable {
};
/// Dereferenceable attribute for a floating value.
-struct AADereferenceableFloating : AADereferenceableImpl {
- AADereferenceableFloating(const IRPosition &IRP)
- : AADereferenceableImpl(IRP) {}
+struct AADereferenceableFloating
+ : AAFromMustBeExecutedContext<AADereferenceable, AADereferenceableImpl> {
+ using Base =
+ AAFromMustBeExecutedContext<AADereferenceable, AADereferenceableImpl>;
+ AADereferenceableFloating(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus Change = Base::updateImpl(A);
+
const DataLayout &DL = A.getDataLayout();
auto VisitValueCB = [&](Value &V, DerefState &T, bool Stripped) -> bool {
@@ -2378,7 +2558,7 @@ struct AADereferenceableFloating : AADereferenceableImpl {
A, getIRPosition(), *this, T, VisitValueCB))
return indicatePessimisticFixpoint();
- return clampStateAndIndicateChange(getState(), T);
+ return Change | clampStateAndIndicateChange(getState(), T);
}
/// See AbstractAttribute::trackStatistics()
@@ -2403,12 +2583,11 @@ struct AADereferenceableReturned final
/// Dereferenceable attribute for an argument
struct AADereferenceableArgument final
- : AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl,
- DerefState> {
- AADereferenceableArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArguments<AADereferenceable,
- AADereferenceableImpl, DerefState>(
- IRP) {}
+ : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<
+ AADereferenceable, AADereferenceableImpl, DerefState> {
+ using Base = AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<
+ AADereferenceable, AADereferenceableImpl, DerefState>;
+ AADereferenceableArgument(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
@@ -2428,13 +2607,16 @@ struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
};
/// Dereferenceable attribute deduction for a call site return value.
-struct AADereferenceableCallSiteReturned final : AADereferenceableImpl {
- AADereferenceableCallSiteReturned(const IRPosition &IRP)
- : AADereferenceableImpl(IRP) {}
+struct AADereferenceableCallSiteReturned final
+ : AACallSiteReturnedFromReturnedAndMustBeExecutedContext<
+ AADereferenceable, AADereferenceableImpl> {
+ using Base = AACallSiteReturnedFromReturnedAndMustBeExecutedContext<
+ AADereferenceable, AADereferenceableImpl>;
+ AADereferenceableCallSiteReturned(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
- AADereferenceableImpl::initialize(A);
+ Base::initialize(A);
Function *F = getAssociatedFunction();
if (!F)
indicatePessimisticFixpoint();
@@ -2446,11 +2628,14 @@ struct AADereferenceableCallSiteReturned final : AADereferenceableImpl {
// call site specific liveness information and then it makes
// sense to specialize attributes for call sites arguments instead of
// redirecting requests to the callee argument.
+
+ ChangeStatus Change = Base::updateImpl(A);
Function *F = getAssociatedFunction();
const IRPosition &FnPos = IRPosition::returned(*F);
auto &FnAA = A.getAAFor<AADereferenceable>(*this, FnPos);
- return clampStateAndIndicateChange(
- getState(), static_cast<const DerefState &>(FnAA.getState()));
+ return Change |
+ clampStateAndIndicateChange(
+ getState(), static_cast<const DerefState &>(FnAA.getState()));
}
/// See AbstractAttribute::trackStatistics()
OpenPOWER on IntegriCloud