diff options
Diffstat (limited to 'llvm/lib/IR/Attributes.cpp')
-rw-r--r-- | llvm/lib/IR/Attributes.cpp | 346 |
1 files changed, 137 insertions, 209 deletions
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index c899afae6cce..c92bacaee36d 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -607,14 +607,14 @@ AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) { AttributeSet AttributeSet::addAttribute(LLVMContext &C, Attribute::AttrKind Kind) const { if (hasAttribute(Kind)) return *this; - AttrBuilder B; + AttrBuilder B(C); B.addAttribute(Kind); return addAttributes(C, AttributeSet::get(C, B)); } AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind, StringRef Value) const { - AttrBuilder B; + AttrBuilder B(C); B.addAttribute(Kind, Value); return addAttributes(C, AttributeSet::get(C, B)); } @@ -627,17 +627,15 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C, if (!AS.hasAttributes()) return *this; - AttrBuilder B(AS); - for (const auto &I : *this) - B.addAttribute(I); - - return get(C, B); + AttrBuilder B(C, *this); + B.merge(AttrBuilder(C, AS)); + return get(C, B); } AttributeSet AttributeSet::removeAttribute(LLVMContext &C, Attribute::AttrKind Kind) const { if (!hasAttribute(Kind)) return *this; - AttrBuilder B(*this); + AttrBuilder B(C, *this); B.removeAttribute(Kind); return get(C, B); } @@ -645,14 +643,14 @@ AttributeSet AttributeSet::removeAttribute(LLVMContext &C, AttributeSet AttributeSet::removeAttribute(LLVMContext &C, StringRef Kind) const { if (!hasAttribute(Kind)) return *this; - AttrBuilder B(*this); + AttrBuilder B(C, *this); B.removeAttribute(Kind); return get(C, B); } AttributeSet AttributeSet::removeAttributes(LLVMContext &C, - const AttrBuilder &Attrs) const { - AttrBuilder B(*this); + const AttributeMask &Attrs) const { + AttrBuilder B(C, *this); // If there is nothing to remove, directly return the original set. if (!B.overlaps(Attrs)) return *this; @@ -817,28 +815,7 @@ AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C, } AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) { - // Add target-independent attributes. - SmallVector<Attribute, 8> Attrs; - for (Attribute::AttrKind Kind = Attribute::None; - Kind != Attribute::EndAttrKinds; Kind = Attribute::AttrKind(Kind + 1)) { - if (!B.contains(Kind)) - continue; - - Attribute Attr; - if (Attribute::isTypeAttrKind(Kind)) - Attr = Attribute::get(C, Kind, B.getTypeAttr(Kind)); - else if (Attribute::isIntAttrKind(Kind)) - Attr = Attribute::get(C, Kind, B.getRawIntAttr(Kind)); - else - Attr = Attribute::get(C, Kind); - Attrs.push_back(Attr); - } - - // Add target-dependent (string) attributes. - for (const auto &TDA : B.td_attrs()) - Attrs.emplace_back(Attribute::get(C, TDA.first, TDA.second)); - - return getSorted(C, Attrs); + return getSorted(C, B.attrs()); } bool AttributeSetNode::hasAttribute(StringRef Kind) const { @@ -1194,9 +1171,9 @@ AttributeList AttributeList::get(LLVMContext &C, SmallVector<AttributeSet, 8> NewAttrSets(MaxSize); for (unsigned I = 0; I < MaxSize; ++I) { - AttrBuilder CurBuilder; + AttrBuilder CurBuilder(C); for (const auto &List : Attrs) - CurBuilder.merge(List.getAttributes(I - 1)); + CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1))); NewAttrSets[I] = AttributeSet::get(C, CurBuilder); } @@ -1218,14 +1195,14 @@ AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, StringRef Kind, StringRef Value) const { - AttrBuilder B; + AttrBuilder B(C); B.addAttribute(Kind, Value); return addAttributesAtIndex(C, Index, B); } AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, Attribute A) const { - AttrBuilder B; + AttrBuilder B(C); B.addAttribute(A); return addAttributesAtIndex(C, Index, B); } @@ -1250,16 +1227,7 @@ AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C, if (!pImpl) return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}}); -#ifndef NDEBUG - // FIXME it is not obvious how this should work for alignment. For now, say - // we can't change a known alignment. - const MaybeAlign OldAlign = getAttributes(Index).getAlignment(); - const MaybeAlign NewAlign = B.getAlignment(); - assert((!OldAlign || !NewAlign || OldAlign == NewAlign) && - "Attempt to change alignment!"); -#endif - - AttrBuilder Merged(getAttributes(Index)); + AttrBuilder Merged(C, getAttributes(Index)); Merged.merge(B); return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); } @@ -1276,7 +1244,7 @@ AttributeList AttributeList::addParamAttribute(LLVMContext &C, for (unsigned ArgNo : ArgNos) { unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex); - AttrBuilder B(AttrSets[Index]); + AttrBuilder B(C, AttrSets[Index]); B.addAttribute(A); AttrSets[Index] = AttributeSet::get(C, B); } @@ -1314,9 +1282,8 @@ AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C, 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. @@ -1340,7 +1307,7 @@ AttributeList::removeAttributesAtIndex(LLVMContext &C, AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C, uint64_t Bytes) const { - AttrBuilder B; + AttrBuilder B(C); B.addDereferenceableAttr(Bytes); return addRetAttributes(C, B); } @@ -1348,7 +1315,7 @@ AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C, AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C, unsigned Index, uint64_t Bytes) const { - AttrBuilder B; + AttrBuilder B(C); B.addDereferenceableAttr(Bytes); return addParamAttributes(C, Index, B); } @@ -1356,7 +1323,7 @@ AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C, AttributeList AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index, uint64_t Bytes) const { - AttrBuilder B; + AttrBuilder B(C); B.addDereferenceableOrNullAttr(Bytes); return addParamAttributes(C, Index, B); } @@ -1365,7 +1332,7 @@ AttributeList AttributeList::addAllocSizeParamAttr(LLVMContext &C, unsigned Index, unsigned ElemSizeArg, const Optional<unsigned> &NumElemsArg) { - AttrBuilder B; + AttrBuilder B(C); B.addAllocSizeAttr(ElemSizeArg, NumElemsArg); return addParamAttributes(C, Index, B); } @@ -1549,97 +1516,93 @@ LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); } // AttrBuilder Method Implementations //===----------------------------------------------------------------------===// -// FIXME: Remove this ctor, use AttributeSet. -AttrBuilder::AttrBuilder(AttributeList AL, unsigned Index) { - AttributeSet AS = AL.getAttributes(Index); - for (const auto &A : AS) - addAttribute(A); -} - -AttrBuilder::AttrBuilder(AttributeSet AS) { - for (const auto &A : AS) - addAttribute(A); +AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) { + append_range(Attrs, AS); + assert(is_sorted(Attrs) && "AttributeSet should be sorted"); } -void AttrBuilder::clear() { - Attrs.reset(); - TargetDepAttrs.clear(); - IntAttrs = {}; - TypeAttrs = {}; -} +void AttrBuilder::clear() { Attrs.clear(); } -Optional<unsigned> -AttrBuilder::kindToIntIndex(Attribute::AttrKind Kind) const { - if (Attribute::isIntAttrKind(Kind)) - return Kind - Attribute::FirstIntAttr; - return None; -} +/// Attribute comparator that only compares attribute keys. Enum attributes are +/// sorted before string attributes. +struct AttributeComparator { + bool operator()(Attribute A0, Attribute A1) const { + bool A0IsString = A0.isStringAttribute(); + bool A1IsString = A1.isStringAttribute(); + if (A0IsString) { + if (A1IsString) + return A0.getKindAsString() < A1.getKindAsString(); + else + return false; + } + if (A1IsString) + return true; + return A0.getKindAsEnum() < A1.getKindAsEnum(); + } + bool operator()(Attribute A0, Attribute::AttrKind Kind) const { + if (A0.isStringAttribute()) + return false; + return A0.getKindAsEnum() < Kind; + } + bool operator()(Attribute A0, StringRef Kind) const { + if (A0.isStringAttribute()) + return A0.getKindAsString() < Kind; + return true; + } +}; -Optional<unsigned> -AttrBuilder::kindToTypeIndex(Attribute::AttrKind Kind) const { - if (Attribute::isTypeAttrKind(Kind)) - return Kind - Attribute::FirstTypeAttr; - return None; +template <typename K> +static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind, + Attribute Attr) { + auto It = lower_bound(Attrs, Kind, AttributeComparator()); + if (It != Attrs.end() && It->hasAttribute(Kind)) + std::swap(*It, Attr); + else + Attrs.insert(It, Attr); } AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { - if (Attr.isStringAttribute()) { - addAttribute(Attr.getKindAsString(), Attr.getValueAsString()); - return *this; - } - - Attribute::AttrKind Kind = Attr.getKindAsEnum(); - Attrs[Kind] = true; - - if (Optional<unsigned> TypeIndex = kindToTypeIndex(Kind)) - TypeAttrs[*TypeIndex] = Attr.getValueAsType(); - else if (Optional<unsigned> IntIndex = kindToIntIndex(Kind)) - IntAttrs[*IntIndex] = Attr.getValueAsInt(); + if (Attr.isStringAttribute()) + addAttributeImpl(Attrs, Attr.getKindAsString(), Attr); + else + addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr); + return *this; +} +AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) { + addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind)); return *this; } AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) { - TargetDepAttrs[A] = V; + addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V)); return *this; } AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); - Attrs[Val] = false; - - if (Optional<unsigned> TypeIndex = kindToTypeIndex(Val)) - TypeAttrs[*TypeIndex] = nullptr; - else if (Optional<unsigned> IntIndex = kindToIntIndex(Val)) - IntAttrs[*IntIndex] = 0; - - return *this; -} - -AttrBuilder &AttrBuilder::removeAttributes(AttributeList A, uint64_t Index) { - remove(A.getAttributes(Index)); + auto It = lower_bound(Attrs, Val, AttributeComparator()); + if (It != Attrs.end() && It->hasAttribute(Val)) + Attrs.erase(It); return *this; } AttrBuilder &AttrBuilder::removeAttribute(StringRef A) { - TargetDepAttrs.erase(A); + auto It = lower_bound(Attrs, A, AttributeComparator()); + if (It != Attrs.end() && It->hasAttribute(A)) + Attrs.erase(It); return *this; } uint64_t AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const { - Optional<unsigned> IntIndex = kindToIntIndex(Kind); - assert(IntIndex && "Not an int attribute"); - return IntAttrs[*IntIndex]; + assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute"); + Attribute A = getAttribute(Kind); + return A.isValid() ? A.getValueAsInt() : 0; } AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind, uint64_t Value) { - Optional<unsigned> IntIndex = kindToIntIndex(Kind); - assert(IntIndex && "Not an int attribute"); - assert(Value && "Value cannot be zero"); - Attrs[Kind] = true; - IntAttrs[*IntIndex] = Value; - return *this; + return addAttribute(Attribute::get(Ctx, Kind, Value)); } std::pair<unsigned, Optional<unsigned>> AttrBuilder::getAllocSizeArgs() const { @@ -1709,17 +1672,13 @@ AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) { } Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const { - Optional<unsigned> TypeIndex = kindToTypeIndex(Kind); - assert(TypeIndex && "Not a type attribute"); - return TypeAttrs[*TypeIndex]; + assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute"); + Attribute A = getAttribute(Kind); + return A.isValid() ? A.getValueAsType() : nullptr; } AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) { - Optional<unsigned> TypeIndex = kindToTypeIndex(Kind); - assert(TypeIndex && "Not a type attribute"); - Attrs[Kind] = true; - TypeAttrs[*TypeIndex] = Ty; - return *this; + return addAttribute(Attribute::get(Ctx, Kind, Ty)); } AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { @@ -1743,76 +1702,43 @@ AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) { } AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { - // FIXME: What if both have an int/type attribute, but they don't match?! - for (unsigned Index = 0; Index < Attribute::NumIntAttrKinds; ++Index) - if (!IntAttrs[Index]) - IntAttrs[Index] = B.IntAttrs[Index]; - - for (unsigned Index = 0; Index < Attribute::NumTypeAttrKinds; ++Index) - if (!TypeAttrs[Index]) - TypeAttrs[Index] = B.TypeAttrs[Index]; - - Attrs |= B.Attrs; - - for (const auto &I : B.td_attrs()) - TargetDepAttrs[I.first] = I.second; + // TODO: Could make this O(n) as we're merging two sorted lists. + for (const auto &I : B.attrs()) + addAttribute(I); return *this; } -AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) { - // 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]) - IntAttrs[Index] = 0; - - for (unsigned Index = 0; Index < Attribute::NumTypeAttrKinds; ++Index) - if (B.TypeAttrs[Index]) - TypeAttrs[Index] = nullptr; - - Attrs &= ~B.Attrs; - - for (const auto &I : B.td_attrs()) - TargetDepAttrs.erase(I.first); - +AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) { + erase_if(Attrs, [&](Attribute A) { return AM.contains(A); }); return *this; } -bool AttrBuilder::overlaps(const AttrBuilder &B) const { - // First check if any of the target independent attributes overlap. - if ((Attrs & B.Attrs).any()) - return true; - - // Then check if any target dependent ones do. - for (const auto &I : td_attrs()) - if (B.contains(I.first)) - return true; - - return false; +bool AttrBuilder::overlaps(const AttributeMask &AM) const { + return any_of(Attrs, [&](Attribute A) { return AM.contains(A); }); } -bool AttrBuilder::contains(StringRef A) const { - return TargetDepAttrs.find(A) != TargetDepAttrs.end(); +Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const { + assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!"); + auto It = lower_bound(Attrs, A, AttributeComparator()); + if (It != Attrs.end() && It->hasAttribute(A)) + return *It; + return {}; } -bool AttrBuilder::hasAttributes() const { - return !Attrs.none() || !TargetDepAttrs.empty(); +Attribute AttrBuilder::getAttribute(StringRef A) const { + auto It = lower_bound(Attrs, A, AttributeComparator()); + if (It != Attrs.end() && It->hasAttribute(A)) + return *It; + return {}; } -bool AttrBuilder::hasAttributes(AttributeList AL, uint64_t Index) const { - AttributeSet AS = AL.getAttributes(Index); - - for (const auto &Attr : AS) { - if (Attr.isEnumAttribute() || Attr.isIntAttribute()) { - if (contains(Attr.getKindAsEnum())) - return true; - } else { - assert(Attr.isStringAttribute() && "Invalid attribute kind!"); - return contains(Attr.getKindAsString()); - } - } +bool AttrBuilder::contains(Attribute::AttrKind A) const { + return getAttribute(A).isValid(); +} - return false; +bool AttrBuilder::contains(StringRef A) const { + return getAttribute(A).isValid(); } bool AttrBuilder::hasAlignmentAttr() const { @@ -1820,14 +1746,7 @@ bool AttrBuilder::hasAlignmentAttr() const { } bool AttrBuilder::operator==(const AttrBuilder &B) const { - if (Attrs != B.Attrs) - return false; - - for (const auto &TDA : TargetDepAttrs) - if (B.TargetDepAttrs.find(TDA.first) == B.TargetDepAttrs.end()) - return false; - - return IntAttrs == B.IntAttrs && TypeAttrs == B.TypeAttrs; + return Attrs == B.Attrs; } //===----------------------------------------------------------------------===// @@ -1835,16 +1754,16 @@ bool AttrBuilder::operator==(const AttrBuilder &B) const { //===----------------------------------------------------------------------===// /// 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()) - // Attribute that only apply to integers. + // Attributes that only apply to integers. Incompatible.addAttribute(Attribute::SExt) .addAttribute(Attribute::ZExt); if (!Ty->isPointerTy()) - // Attribute that only apply to pointers. + // Attributes that only apply to pointers. Incompatible.addAttribute(Attribute::Nest) .addAttribute(Attribute::NoAlias) .addAttribute(Attribute::NoCapture) @@ -1852,15 +1771,18 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) { .addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::SwiftError) - .addAlignmentAttr(1) // the int here is ignored - .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.addAttribute(Attribute::Alignment); // Some attributes can apply to all "values" but there are no `void` values. if (Ty->isVoidTy()) @@ -1869,12 +1791,12 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) { 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> @@ -1910,10 +1832,16 @@ static void setOR(Function &Caller, const Function &Callee) { /// If the inlined function had a higher stack protection level than the /// calling function, then bump up the caller's stack protection level. static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { + // If the calling function has *no* stack protection level (e.g. it was built + // with Clang's -fno-stack-protector or no_stack_protector attribute), don't + // change it as that could change the program's semantics. + if (!Caller.hasStackProtectorFnAttr()) + return; + // 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); |