// manifest their result in the IR for passes to come.
//
// Attribute manifestation is not mandatory. If desired, there is support to
-// generate a single LLVM-IR attribute already in the AbstractAttribute base
-// class. In the simplest case, a subclass initializes the IRPosition properly
-// and overloads `AbstractAttribute::getAttrKind()` to return the appropriate
-// value. The Attributor manifestation framework will then create and place a
-// new attribute if it is allowed to do so (based on the abstract state). Other
-// use cases can be achieved by overloading other abstract attribute methods.
+// generate a single or multiple LLVM-IR attributes already in the helper struct
+// IRAttribute. In the simplest case, a subclass inherits from IRAttribute with
+// a proper Attribute::AttrKind as template parameter. The Attributor
+// manifestation framework will then create and place a new attribute if it is
+// allowed to do so (based on the abstract state). Other use cases can be
+// achieved by overloading AbstractAttribute or IRAttribute methods.
//
//
// The "mechanics" of adding a new "abstract attribute":
"Expected a valid argument index!");
}
+#define IRPositionConstructorForward(NAME, BASE) \
+ explicit NAME(Argument &Arg) : BASE(Arg) {} \
+ explicit NAME(Function &Fn, IRPosition::Kind PK) : BASE(Fn, PK) {} \
+ NAME(Value *AssociatedVal, Value &AnchorVal, unsigned ArgumentNo) \
+ : BASE(AssociatedVal, AnchorVal, ArgumentNo) {}
+
IRPosition(const IRPosition &AAP)
: IRPosition(AAP.AssociatedVal, AAP.AnchorVal, AAP.AttributeIdx) {}
int AttributeIdx;
};
+/// Helper class that provides common functionality to manifest IR attributes.
+template <Attribute::AttrKind AK, typename Base>
+struct IRAttribute : public IRPosition, public Base {
+
+ /// Constructors for the IRPosition.
+ ///
+ ///{
+ IRPositionConstructorForward(IRAttribute, IRPosition);
+ ///}
+
+ /// See AbstractAttribute::manifest(...).
+ virtual ChangeStatus manifest(Attributor &A);
+
+ /// Return the kind that identifies the abstract attribute implementation.
+ Attribute::AttrKind getAttrKind() const { return AK; }
+
+ /// Return the deduced attributes in \p Attrs.
+ virtual void getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const {
+ Attrs.emplace_back(Attribute::get(Ctx, getAttrKind()));
+ }
+
+ /// Return an IR position, see struct IRPosition.
+ ///
+ ///{
+ IRPosition &getIRPosition() { return *this; }
+ const IRPosition &getIRPosition() const { return *this; }
+ ///}
+};
+
/// Base struct for all "concrete attribute" deductions.
///
/// The abstract attribute is a minimal interface that allows the Attributor to
/// Return an IR position, see struct IRPosition.
virtual const IRPosition &getIRPosition() const = 0;
- /// Return the kind that identifies the abstract attribute implementation.
- virtual Attribute::AttrKind getAttrKind() const = 0;
-
- /// Return the deduced attributes in \p Attrs.
- virtual void getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const {
- LLVMContext &Ctx = getIRPosition().getAnchorScope().getContext();
- Attrs.emplace_back(Attribute::get(Ctx, getAttrKind()));
- }
-
/// Helper functions, for debug purposes only.
///{
virtual void print(raw_ostream &OS) const;
/// represented by the abstract attribute in the LLVM-IR.
///
/// \Return CHANGED if the IR was altered, otherwise UNCHANGED.
- virtual ChangeStatus manifest(Attributor &A);
+ virtual ChangeStatus manifest(Attributor &A) {
+ return ChangeStatus::UNCHANGED;
+ }
/// Return an IR position, see struct IRPosition.
virtual IRPosition &getIRPosition() = 0;
/// ----------------------------------------------------------------------------
/// An abstract attribute for the returned values of a function.
-struct AAReturnedValues : public AbstractAttribute {
+struct AAReturnedValues
+ : public IRAttribute<Attribute::Returned, AbstractAttribute> {
+ IRPositionConstructorForward(AAReturnedValues, IRAttribute);
/// Check \p Pred on all returned values.
///
std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> &Pred)
const = 0;
- /// See AbstractAttribute::getAttrKind()
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::Returned;
- }
-
/// Unique ID (due to the unique address)
static const char ID;
};
-struct AANoUnwind : public AbstractAttribute {
-
- /// See AbstractAttribute::getAttrKind()/
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::NoUnwind;
- }
+struct AANoUnwind : public IRAttribute<Attribute::NoUnwind, AbstractAttribute> {
+ IRPositionConstructorForward(AANoUnwind, IRAttribute);
/// Returns true if nounwind is assumed.
virtual bool isAssumedNoUnwind() const = 0;
static const char ID;
};
-struct AANoSync : public AbstractAttribute {
-
- /// See AbstractAttribute::getAttrKind().
- Attribute::AttrKind getAttrKind() const override { return Attribute::NoSync; }
+struct AANoSync : public IRAttribute<Attribute::NoSync, AbstractAttribute> {
+ IRPositionConstructorForward(AANoSync, IRAttribute);
/// Returns true if "nosync" is assumed.
virtual bool isAssumedNoSync() const = 0;
};
/// An abstract interface for all nonnull attributes.
-struct AANonNull : public AbstractAttribute {
+struct AANonNull : public IRAttribute<Attribute::NonNull, AbstractAttribute> {
+ IRPositionConstructorForward(AANonNull, IRAttribute);
/// Return true if we assume that the underlying value is nonnull.
virtual bool isAssumedNonNull() const = 0;
/// Return true if we know that underlying value is nonnull.
virtual bool isKnownNonNull() const = 0;
- /// See AbastractState::getAttrKind().
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::NonNull;
- }
-
/// Unique ID (due to the unique address)
static const char ID;
};
/// An abstract attribute for norecurse.
-struct AANoRecurse : public AbstractAttribute {
-
- /// See AbstractAttribute::getAttrKind()
- virtual Attribute::AttrKind getAttrKind() const override {
- return Attribute::NoRecurse;
- }
+struct AANoRecurse
+ : public IRAttribute<Attribute::NoRecurse, AbstractAttribute> {
+ IRPositionConstructorForward(AANoRecurse, IRAttribute);
/// Return true if "norecurse" is known.
virtual bool isKnownNoRecurse() const = 0;
};
/// An abstract attribute for willreturn.
-struct AAWillReturn : public AbstractAttribute {
-
- /// See AbstractAttribute::getAttrKind()
- virtual Attribute::AttrKind getAttrKind() const override {
- return Attribute::WillReturn;
- }
+struct AAWillReturn
+ : public IRAttribute<Attribute::WillReturn, AbstractAttribute> {
+ IRPositionConstructorForward(AAWillReturn, IRAttribute);
/// Return true if "willreturn" is known.
virtual bool isKnownWillReturn() const = 0;
};
/// An abstract interface for all noalias attributes.
-struct AANoAlias : public AbstractAttribute {
+struct AANoAlias : public IRAttribute<Attribute::NoAlias, AbstractAttribute> {
+ IRPositionConstructorForward(AANoAlias, IRAttribute);
/// Return true if we assume that the underlying value is alias.
virtual bool isAssumedNoAlias() const = 0;
/// Return true if we know that underlying value is noalias.
virtual bool isKnownNoAlias() const = 0;
- /// See AbastractState::getAttrKind().
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::NoAlias;
- }
+ /// Unique ID (due to the unique address)
+ static const char ID;
+};
+
+/// An AbstractAttribute for nofree.
+struct AANoFree : public IRAttribute<Attribute::NoFree, AbstractAttribute> {
+ IRPositionConstructorForward(AANoFree, IRAttribute);
+
+ /// Return true if "nofree" is known.
+ virtual bool isKnownNoFree() const = 0;
+
+ /// Return true if "nofree" is assumed.
+ virtual bool isAssumedNoFree() const = 0;
/// Unique ID (due to the unique address)
static const char ID;
};
/// An AbstractAttribute for noreturn.
-struct AANoReturn : public AbstractAttribute {
+struct AANoReturn : public IRAttribute<Attribute::NoReturn, AbstractAttribute> {
+ IRPositionConstructorForward(AANoReturn, IRAttribute);
/// Return true if the underlying object is known to never return.
virtual bool isKnownNoReturn() const = 0;
/// Return true if the underlying object is assumed to never return.
virtual bool isAssumedNoReturn() const = 0;
- /// See AbstractAttribute::getAttrKind()
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::NoReturn;
- }
-
/// Unique ID (due to the unique address)
static const char ID;
};
/// An abstract interface for liveness abstract attribute.
-struct AAIsDead : public AbstractAttribute {
-
- /// See AbstractAttribute::getAttrKind()
- Attribute::AttrKind getAttrKind() const override { return Attribute::None; }
+struct AAIsDead : public AbstractAttribute, public IRPosition {
+ IRPositionConstructorForward(AAIsDead, IRPosition);
/// Returns true if \p BB is assumed dead.
virtual bool isAssumedDead(const BasicBlock *BB) const = 0;
return false;
}
+ /// Return an IR position, see struct IRPosition.
+ ///
+ ///{
+ IRPosition &getIRPosition() { return *this; }
+ const IRPosition &getIRPosition() const { return *this; }
+ ///}
+
/// Unique ID (due to the unique address)
static const char ID;
};
/// An abstract interface for all dereferenceable attribute.
-struct AADereferenceable : public AbstractAttribute {
+struct AADereferenceable
+ : public IRAttribute<Attribute::Dereferenceable, AbstractAttribute> {
+ IRPositionConstructorForward(AADereferenceable, IRAttribute);
/// Return true if we assume that the underlying value is nonnull.
virtual bool isAssumedNonNull() const = 0;
/// Return known dereferenceable bytes.
virtual uint32_t getKnownDereferenceableBytes() const = 0;
- /// See AbastractState::getAttrKind().
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::Dereferenceable;
- }
-
/// Unique ID (due to the unique address)
static const char ID;
};
/// An abstract interface for all align attributes.
-struct AAAlign : public AbstractAttribute {
+struct AAAlign : public IRAttribute<Attribute::Alignment, AbstractAttribute> {
+ IRPositionConstructorForward(AAAlign, IRAttribute);
/// Return assumed alignment.
virtual unsigned getAssumedAlign() const = 0;
/// Return known alignemnt.
virtual unsigned getKnownAlign() const = 0;
- /// See AbastractState::getAttrKind().
- Attribute::AttrKind getAttrKind() const override {
- return Attribute::Alignment;
- }
-
/// Unique ID (due to the unique address)
static const char ID;
};
return HasChanged;
}
-ChangeStatus AbstractAttribute::manifest(Attributor &A) {
- assert(getState().isValidState() &&
+template <Attribute::AttrKind AK, typename Base>
+ChangeStatus IRAttribute<AK, Base>::manifest(Attributor &A) {
+ assert(this->getState().isValidState() &&
"Attempted to manifest an invalid state!");
assert(getIRPosition().getAssociatedValue() &&
"Attempted to manifest an attribute without associated value!");
ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
- IRPosition &Pos = getIRPosition();
- Function &ScopeFn = Pos.getAnchorScope();
+ Function &ScopeFn = getAnchorScope();
LLVMContext &Ctx = ScopeFn.getContext();
- IRPosition::Kind PK = Pos.getPositionKind();
+ IRPosition::Kind PK = getPositionKind();
SmallVector<Attribute, 4> DeducedAttrs;
- getDeducedAttributes(DeducedAttrs);
+ getDeducedAttributes(Ctx, DeducedAttrs);
// In the following some generic code that will manifest attributes in
// DeducedAttrs if they improve the current IR. Due to the different
Attrs = ScopeFn.getAttributes();
break;
case IRPosition::IRP_CALL_SITE_ARGUMENT:
- Attrs = ImmutableCallSite(&Pos.getAnchorValue()).getAttributes();
+ Attrs = ImmutableCallSite(&getAnchorValue()).getAttributes();
break;
}
for (const Attribute &Attr : DeducedAttrs) {
- if (!addIfNotExistent(Ctx, Attr, Attrs, Pos.getAttrIdx()))
+ if (!addIfNotExistent(Ctx, Attr, Attrs, getAttrIdx()))
continue;
HasChanged = ChangeStatus::CHANGED;
ScopeFn.setAttributes(Attrs);
break;
case IRPosition::IRP_CALL_SITE_ARGUMENT:
- CallSite(&Pos.getAnchorValue()).setAttributes(Attrs);
+ CallSite(&getAnchorValue()).setAttributes(Attrs);
}
return HasChanged;
/// -----------------------NoUnwind Function Attribute--------------------------
-#define IRPositionConstructorForward(NAME) \
- NAME(Argument &Arg) : IRPosition(Arg) {} \
- NAME(Function &Fn, IRPosition::Kind PK) : IRPosition(Fn, PK) {} \
- NAME(Value *AssociatedVal, Value &AnchorVal, unsigned ArgumentNo) \
- : IRPosition(AssociatedVal, AnchorVal, ArgumentNo) {}
-#define IRPositionGetter(IRP) \
- IRPosition &getIRPosition() override { return IRP; } \
- const IRPosition &getIRPosition() const override { return IRP; }
-
-struct AANoUnwindImpl : AANoUnwind, BooleanState, IRPosition {
- IRPositionConstructorForward(AANoUnwindImpl);
- IRPositionGetter(*this);
+struct AANoUnwindImpl : AANoUnwind, BooleanState {
+ IRPositionConstructorForward(AANoUnwindImpl, AANoUnwind);
/// See AbstractAttribute::getState()
/// {
///
/// If there is a unique returned value R, the manifest method will:
/// - mark R with the "returned" attribute, if R is an argument.
-class AAReturnedValuesImpl : public AAReturnedValues,
- public AbstractState,
- public IRPosition {
+class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState {
/// Mapping of values potentially returned by the associated function to the
/// return instructions that might return them.
}
public:
- IRPositionConstructorForward(AAReturnedValuesImpl);
- IRPositionGetter(*this);
+ IRPositionConstructorForward(AAReturnedValuesImpl, AAReturnedValues);
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A, InformationCache &InfoCache) override {
if (auto *UniqueRVArg = dyn_cast<Argument>(UniqueRV.getValue())) {
setAssociatedValue(UniqueRVArg);
setAttributeIdx(UniqueRVArg->getArgNo() + AttributeList::FirstArgIndex);
- Changed = AbstractAttribute::manifest(A) | Changed;
+ Changed = IRAttribute::manifest(A) | Changed;
}
return Changed;
/// ------------------------ NoSync Function Attribute -------------------------
-struct AANoSyncImpl : AANoSync, BooleanState, IRPosition {
- IRPositionConstructorForward(AANoSyncImpl);
- IRPositionGetter(*this);
+struct AANoSyncImpl : AANoSync, BooleanState {
+ IRPositionConstructorForward(AANoSyncImpl, AANoSync);
/// See AbstractAttribute::getState()
/// {
/// ------------------------ No-Free Attributes ----------------------------
-struct AANoFreeImpl : AbstractAttribute, BooleanState, IRPosition {
- IRPositionConstructorForward(AANoFreeImpl);
- IRPositionGetter(*this);
+struct AANoFreeImpl : public AANoFree, BooleanState {
+ IRPositionConstructorForward(AANoFreeImpl, AANoFree);
/// See AbstractAttribute::getState()
///{
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A, InformationCache &InfoCache) override;
- /// See AbstractAttribute::getAttrKind().
- Attribute::AttrKind getAttrKind() const override { return Attribute::NoFree; }
-
/// Return true if "nofree" is assumed.
- bool isAssumedNoFree() const { return getAssumed(); }
+ bool isAssumedNoFree() const override { return getAssumed(); }
/// Return true if "nofree" is known.
- bool isKnownNoFree() const { return getKnown(); }
-
- /// Unique ID (due to the unique address)
- static const char ID;
+ bool isKnownNoFree() const override { return getKnown(); }
};
struct AANoFreeFunction final : public AANoFreeImpl {
}
/// ------------------------ NonNull Argument Attribute ------------------------
-struct AANonNullImpl : AANonNull, BooleanState, IRPosition {
- IRPositionConstructorForward(AANonNullImpl);
- IRPositionGetter(*this);
+struct AANonNullImpl : AANonNull, BooleanState {
+ IRPositionConstructorForward(AANonNullImpl, AANonNull);
/// See AbstractAttribute::getState()
/// {
/// ------------------------ Will-Return Attributes ----------------------------
-struct AAWillReturnImpl : public AAWillReturn, BooleanState, IRPosition {
- IRPositionConstructorForward(AAWillReturnImpl);
- IRPositionGetter(*this);
+struct AAWillReturnImpl : public AAWillReturn, BooleanState {
+ IRPositionConstructorForward(AAWillReturnImpl, AAWillReturn);
/// See AAWillReturn::isKnownWillReturn().
bool isKnownWillReturn() const override { return getKnown(); }
/// ------------------------ NoAlias Argument Attribute ------------------------
-struct AANoAliasImpl : AANoAlias, BooleanState, IRPosition {
- IRPositionConstructorForward(AANoAliasImpl);
- IRPositionGetter(*this);
+struct AANoAliasImpl : AANoAlias, BooleanState {
+ IRPositionConstructorForward(AANoAliasImpl, AANoAlias);
/// See AbstractAttribute::getState()
/// {
/// -------------------AAIsDead Function Attribute-----------------------
-struct AAIsDeadImpl : public AAIsDead, BooleanState, IRPosition {
- IRPositionConstructorForward(AAIsDeadImpl);
- IRPositionGetter(*this);
+struct AAIsDeadImpl : public AAIsDead, BooleanState {
+ IRPositionConstructorForward(AAIsDeadImpl, AAIsDead);
void initialize(Attributor &A, InformationCache &InfoCache) override {
Function &F = getAnchorScope();
}
};
-struct AADereferenceableImpl : AADereferenceable, DerefState, IRPosition {
- IRPositionConstructorForward(AADereferenceableImpl);
- IRPositionGetter(*this);
+struct AADereferenceableImpl : AADereferenceable, DerefState {
+ IRPositionConstructorForward(AADereferenceableImpl, AADereferenceable);
/// See AbstractAttribute::getState()
/// {
return NonNullGlobalState.isKnown(DEREF_NONNULL);
}
- void getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
- LLVMContext &Ctx = AnchorVal.getContext();
-
+ void getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const override {
// TODO: Add *_globally support
if (isAssumedNonNull())
Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
// ------------------------ Align Argument Attribute ------------------------
-struct AAAlignImpl : AAAlign, IntegerState, IRPosition {
- IRPositionConstructorForward(AAAlignImpl);
- IRPositionGetter(*this);
+struct AAAlignImpl : AAAlign, IntegerState {
+ IRPositionConstructorForward(AAAlignImpl, AAAlign);
// Max alignemnt value allowed in IR
static const unsigned MAX_ALIGN = 1U << 29;
/// See AbstractAttribute::getDeducedAttributes
virtual void
- getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
- LLVMContext &Ctx = AnchorVal.getContext();
-
+ getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const override {
Attrs.emplace_back(Attribute::getWithAlignment(Ctx, getAssumedAlign()));
}
};
}
/// ------------------ Function No-Return Attribute ----------------------------
-struct AANoReturnImpl : public AANoReturn, BooleanState, IRPosition {
- IRPositionConstructorForward(AANoReturnImpl);
- IRPositionGetter(*this);
+struct AANoReturnImpl : public AANoReturn, BooleanState {
+ IRPositionConstructorForward(AANoReturnImpl, AANoReturn);
/// See AbstractAttribute::getState()
/// {
const char AAReturnedValues::ID = 0;
const char AANoUnwind::ID = 0;
const char AANoSync::ID = 0;
-const char AANoFreeImpl::ID = 0;
+const char AANoFree::ID = 0;
const char AANonNull::ID = 0;
const char AANoRecurse::ID = 0;
const char AAWillReturn::ID = 0;