// We know that GetCPUAndFeaturesAttributes will always have the
// newest set, since it has the newest possible FunctionDecl, so the
// new ones should replace the old.
- llvm::AttrBuilder RemoveAttrs;
+ llvm::AttributeMask RemoveAttrs;
RemoveAttrs.addAttribute("target-cpu");
RemoveAttrs.addAttribute("target-features");
RemoveAttrs.addAttribute("tune-cpu");
/// Remove attributes from an argument.
void removeAttr(Attribute::AttrKind Kind);
- void removeAttrs(const AttrBuilder &B);
+ void removeAttrs(const AttributeMask &AM);
/// Check if an argument has a given attribute.
bool hasAttribute(Attribute::AttrKind Kind) const;
#include <cassert>
#include <cstdint>
#include <map>
+#include <set>
#include <string>
#include <utility>
namespace llvm {
class AttrBuilder;
+class AttributeMask;
class AttributeImpl;
class AttributeListImpl;
class AttributeSetNode;
/// Remove the specified attributes from this set. Returns a new set because
/// attribute sets are immutable.
LLVM_NODISCARD AttributeSet
- removeAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const;
+ removeAttributes(LLVMContext &C, const AttributeMask &AttrsToRemove) const;
/// Return the number of attributes in this set.
unsigned getNumAttributes() const;
/// Remove the specified attributes at the specified index from this
/// attribute list. Returns a new list because attribute lists are immutable.
LLVM_NODISCARD AttributeList removeAttributesAtIndex(
- LLVMContext &C, unsigned Index, const AttrBuilder &AttrsToRemove) const;
+ LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const;
/// Remove all attributes at the specified index from this
/// attribute list. Returns a new list because attribute lists are immutable.
/// Remove the specified attribute at the function index from this
/// attribute list. Returns a new list because attribute lists are immutable.
LLVM_NODISCARD AttributeList
- removeFnAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const {
+ removeFnAttributes(LLVMContext &C, const AttributeMask &AttrsToRemove) const {
return removeAttributesAtIndex(C, FunctionIndex, AttrsToRemove);
}
/// Remove the specified attribute at the return value index from this
/// attribute list. Returns a new list because attribute lists are immutable.
- LLVM_NODISCARD AttributeList
- removeRetAttributes(LLVMContext &C, const AttrBuilder &AttrsToRemove) const {
+ LLVM_NODISCARD AttributeList removeRetAttributes(
+ LLVMContext &C, const AttributeMask &AttrsToRemove) const {
return removeAttributesAtIndex(C, ReturnIndex, AttrsToRemove);
}
/// Remove the specified attribute at the specified arg index from this
/// attribute list. Returns a new list because attribute lists are immutable.
- LLVM_NODISCARD AttributeList removeParamAttributes(
- LLVMContext &C, unsigned ArgNo, const AttrBuilder &AttrsToRemove) const {
+ LLVM_NODISCARD AttributeList
+ removeParamAttributes(LLVMContext &C, unsigned ArgNo,
+ const AttributeMask &AttrsToRemove) const {
return removeAttributesAtIndex(C, ArgNo + FirstArgIndex, AttrsToRemove);
}
//===----------------------------------------------------------------------===//
/// \class
+/// This class stores enough information to efficiently remove some attributes
+/// from an existing AttrBuilder, AttributeSet or AttributeList.
+class AttributeMask {
+ std::bitset<Attribute::EndAttrKinds> Attrs;
+ std::set<SmallString<32>, std::less<>> TargetDepAttrs;
+
+public:
+ AttributeMask() = default;
+ AttributeMask(const AttributeMask &) = delete;
+ AttributeMask(AttributeMask &&) = default;
+
+ AttributeMask(AttributeSet AS) {
+ for (Attribute A : AS)
+ addAttribute(A);
+ }
+
+ /// Add an attribute to the mask.
+ AttributeMask &addAttribute(Attribute::AttrKind Val) {
+ assert((unsigned)Val < Attribute::EndAttrKinds &&
+ "Attribute out of range!");
+ Attrs[Val] = true;
+ return *this;
+ }
+
+ /// Add the Attribute object to the builder.
+ AttributeMask &addAttribute(Attribute A) {
+ if (A.isStringAttribute())
+ addAttribute(A.getKindAsString());
+ else
+ addAttribute(A.getKindAsEnum());
+ return *this;
+ }
+
+ /// Add the target-dependent attribute to the builder.
+ AttributeMask &addAttribute(StringRef A) {
+ TargetDepAttrs.insert(A);
+ return *this;
+ }
+
+ /// Return true if the builder has the specified attribute.
+ bool contains(Attribute::AttrKind A) const {
+ assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");
+ return Attrs[A];
+ }
+
+ /// Return true if the builder has the specified target-dependent
+ /// attribute.
+ bool contains(StringRef A) const { return TargetDepAttrs.count(A); }
+
+ using td_const_iterator = decltype(TargetDepAttrs)::const_iterator;
+ using td_const_range = iterator_range<td_const_iterator>;
+ td_const_range td_attrs() const {
+ return {TargetDepAttrs.begin(), TargetDepAttrs.end()};
+ }
+ auto const &attrs() const { return Attrs; }
+};
+
+//===----------------------------------------------------------------------===//
+/// \class
/// This class is used in conjunction with the Attribute::get method to
/// create an Attribute object. The object itself is uniquified. The Builder's
/// value, however, is not. So this can be used as a quick way to test for
/// Remove an attribute from the builder.
AttrBuilder &removeAttribute(Attribute::AttrKind Val);
+ /// Remove the target-dependent attribute from the builder.
+ AttrBuilder &removeAttribute(StringRef A);
+
+ /// Remove the target-dependent attribute from the builder.
+ AttrBuilder &removeAttribute(Attribute A) {
+ if (A.isStringAttribute())
+ return removeAttribute(A.getKindAsString());
+ else
+ return removeAttribute(A.getKindAsEnum());
+ }
+
/// Remove the attributes from the builder.
AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex);
- /// Remove the target-dependent attribute to the builder.
- AttrBuilder &removeAttribute(StringRef A);
-
/// Add the attributes from the builder.
AttrBuilder &merge(const AttrBuilder &B);
/// Remove the attributes from the builder.
- AttrBuilder &remove(const AttrBuilder &B);
+ AttrBuilder &remove(const AttributeMask &AM);
/// Return true if the builder has any attribute that's in the
/// specified builder.
- bool overlaps(const AttrBuilder &B) const;
+ bool overlaps(const AttributeMask &AM) const;
/// Return true if the builder has the specified attribute.
bool contains(Attribute::AttrKind A) const {
namespace AttributeFuncs {
/// Which attributes cannot be applied to a type.
-AttrBuilder typeIncompatible(Type *Ty);
+AttributeMask typeIncompatible(Type *Ty);
/// Get param/return attributes which imply immediate undefined behavior if an
/// invalid value is passed. For example, this includes noundef (where undef
/// implies UB), but not nonnull (where null implies poison). It also does not
/// include attributes like nocapture, which constrain the function
/// implementation rather than the passed value.
-AttrBuilder getUBImplyingAttributes();
+AttributeMask getUBImplyingAttributes();
/// \returns Return true if the two functions have compatible target-independent
/// attributes for inlining purposes.
/// Remove function attribute from this function.
void removeFnAttr(StringRef Kind);
- void removeFnAttrs(const AttrBuilder &Attrs);
+ void removeFnAttrs(const AttributeMask &Attrs);
/// removes the attribute from the return value list of attributes.
void removeRetAttr(Attribute::AttrKind Kind);
void removeRetAttr(StringRef Kind);
/// removes the attributes from the return value list of attributes.
- void removeRetAttrs(const AttrBuilder &Attrs);
+ void removeRetAttrs(const AttributeMask &Attrs);
/// removes the attribute from the list of attributes.
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
void removeParamAttr(unsigned ArgNo, StringRef Kind);
/// removes the attribute from the list of attributes.
- void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
+ void removeParamAttrs(unsigned ArgNo, const AttributeMask &Attrs);
/// Return true if the function has the attribute.
bool hasFnAttribute(Attribute::AttrKind Kind) const;
}
/// Removes the attributes from the function
- void removeFnAttrs(const AttrBuilder &AttrsToRemove) {
+ void removeFnAttrs(const AttributeMask &AttrsToRemove) {
Attrs = Attrs.removeFnAttributes(getContext(), AttrsToRemove);
}
}
/// Removes the attributes from the return value
- void removeRetAttrs(const AttrBuilder &AttrsToRemove) {
+ void removeRetAttrs(const AttributeMask &AttrsToRemove) {
Attrs = Attrs.removeRetAttributes(getContext(), AttrsToRemove);
}
}
/// Removes the attributes from the given argument
- void removeParamAttrs(unsigned ArgNo, const AttrBuilder &AttrsToRemove) {
+ void removeParamAttrs(unsigned ArgNo, const AttributeMask &AttrsToRemove) {
Attrs = Attrs.removeParamAttributes(getContext(), ArgNo, AttrsToRemove);
}
}
AttributeSet AttributeSet::removeAttributes(LLVMContext &C,
- const AttrBuilder &Attrs) const {
+ const AttributeMask &Attrs) const {
AttrBuilder B(*this);
// If there is nothing to remove, directly return the original set.
if (!B.overlaps(Attrs))
return getImpl(C, AttrSets);
}
-AttributeList
-AttributeList::removeAttributesAtIndex(LLVMContext &C, unsigned Index,
- const AttrBuilder &AttrsToRemove) const {
+AttributeList AttributeList::removeAttributesAtIndex(
+ LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {
AttributeSet Attrs = getAttributes(Index);
AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
// If nothing was removed, return the original list.
return *this;
}
+AttrBuilder &AttrBuilder::removeAttributes(AttributeList AL, uint64_t Index) {
+ remove(AttributeMask(AL.getAttributes(Index)));
+ return *this;
+}
+
AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
Attrs[Val] = false;
return *this;
}
-AttrBuilder &AttrBuilder::removeAttributes(AttributeList A, uint64_t Index) {
- remove(A.getAttributes(Index));
- return *this;
-}
-
AttrBuilder &AttrBuilder::removeAttribute(StringRef A) {
TargetDepAttrs.erase(A);
return *this;
return *this;
}
-AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) {
+AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) {
// FIXME: What if both have an int/type attribute, but they don't match?!
for (unsigned Index = 0; Index < Attribute::NumIntAttrKinds; ++Index)
- if (B.IntAttrs[Index])
+ if (AM.contains((Attribute::AttrKind)Index))
IntAttrs[Index] = 0;
for (unsigned Index = 0; Index < Attribute::NumTypeAttrKinds; ++Index)
- if (B.TypeAttrs[Index])
+ if (AM.contains((Attribute::AttrKind)Index))
TypeAttrs[Index] = nullptr;
- Attrs &= ~B.Attrs;
+ Attrs &= ~AM.attrs();
- for (const auto &I : B.td_attrs())
- TargetDepAttrs.erase(I.first);
+ for (const auto &I : AM.td_attrs())
+ TargetDepAttrs.erase(I);
return *this;
}
-bool AttrBuilder::overlaps(const AttrBuilder &B) const {
+bool AttrBuilder::overlaps(const AttributeMask &AM) const {
// First check if any of the target independent attributes overlap.
- if ((Attrs & B.Attrs).any())
+ if ((Attrs & AM.attrs()).any())
return true;
// Then check if any target dependent ones do.
for (const auto &I : td_attrs())
- if (B.contains(I.first))
+ if (AM.contains(I.first))
return true;
-
return false;
}
//===----------------------------------------------------------------------===//
/// Which attributes cannot be applied to a type.
-AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
- AttrBuilder Incompatible;
+AttributeMask AttributeFuncs::typeIncompatible(Type *Ty) {
+ AttributeMask Incompatible;
if (!Ty->isIntegerTy())
// Attributes that only apply to integers.
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::SwiftError)
- .addDereferenceableAttr(1) // the int here is ignored
- .addDereferenceableOrNullAttr(1) // the int here is ignored
- .addPreallocatedAttr(Ty)
- .addInAllocaAttr(Ty)
- .addByValAttr(Ty)
- .addStructRetAttr(Ty)
- .addByRefAttr(Ty)
- .addTypeAttr(Attribute::ElementType, Ty);
+ .addAttribute(Attribute::Dereferenceable)
+ .addAttribute(Attribute::DereferenceableOrNull)
+ .addAttribute(Attribute::Preallocated)
+ .addAttribute(Attribute::InAlloca)
+ .addAttribute(Attribute::ByVal)
+ .addAttribute(Attribute::StructRet)
+ .addAttribute(Attribute::ByRef)
+ .addAttribute(Attribute::ElementType);
if (!Ty->isPtrOrPtrVectorTy())
// Attributes that only apply to pointers or vectors of pointers.
- Incompatible.addAlignmentAttr(1); // the int here is ignored
+ Incompatible.addAttribute(Attribute::Alignment);
// Some attributes can apply to all "values" but there are no `void` values.
if (Ty->isVoidTy())
return Incompatible;
}
-AttrBuilder AttributeFuncs::getUBImplyingAttributes() {
- AttrBuilder B;
- B.addAttribute(Attribute::NoUndef);
- B.addDereferenceableAttr(1);
- B.addDereferenceableOrNullAttr(1);
- return B;
+AttributeMask AttributeFuncs::getUBImplyingAttributes() {
+ AttributeMask AM;
+ AM.addAttribute(Attribute::NoUndef);
+ AM.addAttribute(Attribute::Dereferenceable);
+ AM.addAttribute(Attribute::DereferenceableOrNull);
+ return AM;
}
template<typename AttrClass>
// If upgrading the SSP attribute, clear out the old SSP Attributes first.
// Having multiple SSP attributes doesn't actually hurt, but it adds useless
// clutter to the IR.
- AttrBuilder OldSSPAttr;
+ AttributeMask OldSSPAttr;
OldSSPAttr.addAttribute(Attribute::StackProtect)
.addAttribute(Attribute::StackProtectStrong)
.addAttribute(Attribute::StackProtectReq);
getParent()->removeParamAttr(getArgNo(), Kind);
}
-void Argument::removeAttrs(const AttrBuilder &B) {
+void Argument::removeAttrs(const AttributeMask &AM) {
AttributeList AL = getParent()->getAttributes();
- AL = AL.removeParamAttributes(Parent->getContext(), getArgNo(), B);
+ AL = AL.removeParamAttributes(Parent->getContext(), getArgNo(), AM);
getParent()->setAttributes(AL);
}
AttributeSets = AttributeSets.removeFnAttribute(getContext(), Kind);
}
-void Function::removeFnAttrs(const AttrBuilder &Attrs) {
- AttributeSets = AttributeSets.removeFnAttributes(getContext(), Attrs);
+void Function::removeFnAttrs(const AttributeMask &AM) {
+ AttributeSets = AttributeSets.removeFnAttributes(getContext(), AM);
}
void Function::removeRetAttr(Attribute::AttrKind Kind) {
AttributeSets = AttributeSets.removeRetAttribute(getContext(), Kind);
}
-void Function::removeRetAttrs(const AttrBuilder &Attrs) {
+void Function::removeRetAttrs(const AttributeMask &Attrs) {
AttributeSets = AttributeSets.removeRetAttributes(getContext(), Attrs);
}
AttributeSets = AttributeSets.removeParamAttribute(getContext(), ArgNo, Kind);
}
-void Function::removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs) {
+void Function::removeParamAttrs(unsigned ArgNo, const AttributeMask &Attrs) {
AttributeSets =
AttributeSets.removeParamAttributes(getContext(), ArgNo, Attrs);
}
AttributeList AL = CB->getAttributes();
if (AL.isEmpty())
return;
- AttrBuilder UBImplyingAttributes = AttributeFuncs::getUBImplyingAttributes();
+ AttributeMask UBImplyingAttributes =
+ AttributeFuncs::getUBImplyingAttributes();
for (unsigned ArgNo = 0; ArgNo < CB->arg_size(); ArgNo++)
CB->removeParamAttrs(ArgNo, UBImplyingAttributes);
CB->removeRetAttrs(UBImplyingAttributes);
"'noinline and alwaysinline' are incompatible!",
V);
- AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
+ AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
for (Attribute Attr : Attrs) {
if (!Attr.isStringAttribute() &&
IncompatibleAttrs.contains(Attr.getKindAsEnum())) {
// off any return attributes, e.g. zeroext doesn't make sense with a struct.
NewFunc->stealArgumentListFrom(F);
- AttrBuilder RetAttrs;
+ AttributeMask RetAttrs;
RetAttrs.addAttribute(Attribute::SExt);
RetAttrs.addAttribute(Attribute::ZExt);
RetAttrs.addAttribute(Attribute::NoAlias);
SmallVector<unsigned, 8> UnusedArgs;
bool Changed = false;
- AttrBuilder UBImplyingAttributes = AttributeFuncs::getUBImplyingAttributes();
+ AttributeMask UBImplyingAttributes =
+ AttributeFuncs::getUBImplyingAttributes();
for (Argument &Arg : Fn.args()) {
if (!Arg.hasSwiftErrorAttr() && Arg.use_empty() &&
!Arg.hasPassPointeeByValueCopyAttr()) {
Changed.insert(F);
// Clear out any existing attributes.
- AttrBuilder AttrsToRemove;
+ AttributeMask AttrsToRemove;
AttrsToRemove.addAttribute(Attribute::ReadOnly);
AttrsToRemove.addAttribute(Attribute::ReadNone);
AttrsToRemove.addAttribute(Attribute::WriteOnly);
MDNode *OriginStoreWeights;
DFSanABIList ABIList;
DenseMap<Value *, Function *> UnwrappedFnMap;
- AttrBuilder ReadOnlyNoneAttrs;
+ AttributeMask ReadOnlyNoneAttrs;
/// Memory map parameters used in calculation mapping application addresses
/// to shadow addresses and origin addresses.
// will become a non-readonly function after it is instrumented by us. To
// prevent this code from being optimized out, mark that function
// non-readonly in advance.
- AttrBuilder B;
+ AttributeMask B;
B.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::WriteOnly)
MemorySanitizerVisitor Visitor(F, *this, TLI);
// Clear out readonly/readnone attributes.
- AttrBuilder B;
+ AttributeMask B;
B.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::WriteOnly)
for (Attribute A : AL.getFnAttrs()) {
if (isStatepointDirectiveAttr(A))
- FnAttrs.remove(A);
+ FnAttrs.removeAttribute(A);
}
// Just skip parameter and return attributes for now
// List of all parameter and return attributes which must be stripped when
// lowering from the abstract machine model. Note that we list attributes
// here which aren't valid as return attributes, that is okay.
-static AttrBuilder getParamAndReturnAttributesToRemove() {
- AttrBuilder R;
- R.addDereferenceableAttr(1);
- R.addDereferenceableOrNullAttr(1);
+static AttributeMask getParamAndReturnAttributesToRemove() {
+ AttributeMask R;
+ R.addAttribute(Attribute::Dereferenceable);
+ R.addAttribute(Attribute::DereferenceableOrNull);
R.addAttribute(Attribute::ReadNone);
R.addAttribute(Attribute::ReadOnly);
R.addAttribute(Attribute::WriteOnly);
return;
}
- AttrBuilder R = getParamAndReturnAttributesToRemove();
+ AttributeMask R = getParamAndReturnAttributesToRemove();
for (Argument &A : F.args())
if (isa<PointerType>(A.getType()))
F.removeParamAttrs(A.getArgNo(), R);
stripInvalidMetadataFromInstruction(I);
- AttrBuilder R = getParamAndReturnAttributesToRemove();
+ AttributeMask R = getParamAndReturnAttributesToRemove();
if (auto *Call = dyn_cast<CallBase>(&I)) {
for (int i = 0, e = Call->arg_size(); i != e; i++)
if (isa<PointerType>(Call->getArgOperand(i)->getType()))
// inaccessiblemem_or_argmemonly attributes do not hold any longer. Remove
// them from both the function and callsites.
if (ReplacedPointerArg) {
- AttrBuilder AttributesToRemove;
+ AttributeMask AttributesToRemove;
AttributesToRemove.addAttribute(Attribute::ArgMemOnly);
AttributesToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly);
F.removeFnAttrs(AttributesToRemove);
AttrBuilder B_align_readonly;
B_align_readonly.addAttribute(AlignAttr);
B_align_readonly.addAttribute(Attribute::ReadOnly);
- AttrBuilder B_align;
+ AttributeMask B_align;
B_align.addAttribute(AlignAttr);
AttrBuilder B_stackalign_optnone;
B_stackalign_optnone.addAttribute(StackAlignAttr);
B_stackalign_optnone.addAttribute(Attribute::OptimizeNone);
- AttrBuilder B_stackalign;
+ AttributeMask B_stackalign;
B_stackalign.addAttribute(StackAlignAttr);
AttributeSet AS = AttributeSet::get(C, B_align_readonly);