X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FIR%2FAttributes.cpp;h=d909f7b880c08239c72795c3b219465ba4a10e1b;hp=59e86f02a0e42422bdadf468255881785c2f85e9;hb=996ace13c0eca0ce1c21df9d7b84966416dd1c21;hpb=c6077eff8b9963b59de21e5d1dfae7a6ea75da36 diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 59e86f02a0e..d909f7b880c 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/Attributes.h" #include "AttributeImpl.h" #include "LLVMContextImpl.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Type.h" #include "llvm/Support/Atomic.h" @@ -30,15 +31,12 @@ using namespace llvm; // Attribute Construction Methods //===----------------------------------------------------------------------===// -Attribute Attribute::get(LLVMContext &Context, AttrKind Kind, - Constant *Val) { - if (Kind == None) return Attribute(); - - // Otherwise, build a key to look up the existing attributes. +Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, + uint64_t Val) { LLVMContextImpl *pImpl = Context.pImpl; FoldingSetNodeID ID; ID.AddInteger(Kind); - ID.AddPointer(Val); + if (Val) ID.AddInteger(Val); void *InsertPoint; AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); @@ -46,144 +44,286 @@ Attribute Attribute::get(LLVMContext &Context, AttrKind Kind, if (!PA) { // If we didn't find any existing attributes of the same shape then create a // new one and insert it. - PA = (!Val) ? - new AttributeImpl(Context, Kind) : - new AttributeImpl(Context, Kind, Val); + if (!Val) + PA = new EnumAttributeImpl(Kind); + else + PA = new IntAttributeImpl(Kind, Val); pImpl->AttrsSet.InsertNode(PA, InsertPoint); } - // Return the AttributesList that we found or created. + // Return the Attribute that we found or created. + return Attribute(PA); +} + +Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) { + LLVMContextImpl *pImpl = Context.pImpl; + FoldingSetNodeID ID; + ID.AddString(Kind); + if (!Val.empty()) ID.AddString(Val); + + void *InsertPoint; + AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); + + if (!PA) { + // If we didn't find any existing attributes of the same shape then create a + // new one and insert it. + PA = new StringAttributeImpl(Kind, Val); + pImpl->AttrsSet.InsertNode(PA, InsertPoint); + } + + // Return the Attribute that we found or created. return Attribute(PA); } Attribute Attribute::getWithAlignment(LLVMContext &Context, uint64_t Align) { - return get(Context, Attribute::Alignment, - ConstantInt::get(Type::getInt64Ty(Context), Align)); + assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); + assert(Align <= 0x40000000 && "Alignment too large."); + return get(Context, Alignment, Align); } Attribute Attribute::getWithStackAlignment(LLVMContext &Context, uint64_t Align) { - return get(Context, Attribute::StackAlignment, - ConstantInt::get(Type::getInt64Ty(Context), Align)); + assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); + assert(Align <= 0x100 && "Alignment too large."); + return get(Context, StackAlignment, Align); +} + +Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, + uint64_t Bytes) { + assert(Bytes && "Bytes must be non-zero."); + return get(Context, Dereferenceable, Bytes); +} + +Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context, + uint64_t Bytes) { + assert(Bytes && "Bytes must be non-zero."); + return get(Context, DereferenceableOrNull, Bytes); } //===----------------------------------------------------------------------===// // Attribute Accessor Methods //===----------------------------------------------------------------------===// -bool Attribute::hasAttribute(AttrKind Val) const { - return pImpl && pImpl->hasAttribute(Val); +bool Attribute::isEnumAttribute() const { + return pImpl && pImpl->isEnumAttribute(); } -bool Attribute::hasAttributes() const { - return pImpl && pImpl->hasAttributes(); +bool Attribute::isIntAttribute() const { + return pImpl && pImpl->isIntAttribute(); } -Constant *Attribute::getAttributeKind() const { - return pImpl ? pImpl->getAttributeKind() : 0; +bool Attribute::isStringAttribute() const { + return pImpl && pImpl->isStringAttribute(); +} + +Attribute::AttrKind Attribute::getKindAsEnum() const { + if (!pImpl) return None; + assert((isEnumAttribute() || isIntAttribute()) && + "Invalid attribute type to get the kind as an enum!"); + return pImpl ? pImpl->getKindAsEnum() : None; +} + +uint64_t Attribute::getValueAsInt() const { + if (!pImpl) return 0; + assert(isIntAttribute() && + "Expected the attribute to be an integer attribute!"); + return pImpl ? pImpl->getValueAsInt() : 0; } -ArrayRef Attribute::getAttributeValues() const { - return pImpl ? pImpl->getAttributeValues() : ArrayRef(); +StringRef Attribute::getKindAsString() const { + if (!pImpl) return StringRef(); + assert(isStringAttribute() && + "Invalid attribute type to get the kind as a string!"); + return pImpl ? pImpl->getKindAsString() : StringRef(); +} + +StringRef Attribute::getValueAsString() const { + if (!pImpl) return StringRef(); + assert(isStringAttribute() && + "Invalid attribute type to get the value as a string!"); + return pImpl ? pImpl->getValueAsString() : StringRef(); +} + +bool Attribute::hasAttribute(AttrKind Kind) const { + return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None); +} + +bool Attribute::hasAttribute(StringRef Kind) const { + if (!isStringAttribute()) return false; + return pImpl && pImpl->hasAttribute(Kind); } /// This returns the alignment field of an attribute as a byte alignment value. unsigned Attribute::getAlignment() const { - if (!hasAttribute(Attribute::Alignment)) - return 0; - return pImpl->getAlignment(); + assert(hasAttribute(Attribute::Alignment) && + "Trying to get alignment from non-alignment attribute!"); + return pImpl->getValueAsInt(); } /// This returns the stack alignment field of an attribute as a byte alignment /// value. unsigned Attribute::getStackAlignment() const { - if (!hasAttribute(Attribute::StackAlignment)) - return 0; - return pImpl->getStackAlignment(); + assert(hasAttribute(Attribute::StackAlignment) && + "Trying to get alignment from non-alignment attribute!"); + return pImpl->getValueAsInt(); } -std::string Attribute::getAsString() const { - if (hasAttribute(Attribute::ZExt)) - return "zeroext"; - if (hasAttribute(Attribute::SExt)) - return "signext"; - if (hasAttribute(Attribute::NoReturn)) - return "noreturn"; - if (hasAttribute(Attribute::NoUnwind)) - return "nounwind"; - if (hasAttribute(Attribute::UWTable)) - return "uwtable"; - if (hasAttribute(Attribute::ReturnsTwice)) - return "returns_twice"; +/// This returns the number of dereferenceable bytes. +uint64_t Attribute::getDereferenceableBytes() const { + assert(hasAttribute(Attribute::Dereferenceable) && + "Trying to get dereferenceable bytes from " + "non-dereferenceable attribute!"); + return pImpl->getValueAsInt(); +} + +uint64_t Attribute::getDereferenceableOrNullBytes() const { + assert(hasAttribute(Attribute::DereferenceableOrNull) && + "Trying to get dereferenceable bytes from " + "non-dereferenceable attribute!"); + return pImpl->getValueAsInt(); +} + +std::string Attribute::getAsString(bool InAttrGrp) const { + if (!pImpl) return ""; + + if (hasAttribute(Attribute::SanitizeAddress)) + return "sanitize_address"; + if (hasAttribute(Attribute::AlwaysInline)) + return "alwaysinline"; + if (hasAttribute(Attribute::ArgMemOnly)) + return "argmemonly"; + if (hasAttribute(Attribute::Builtin)) + return "builtin"; + if (hasAttribute(Attribute::ByVal)) + return "byval"; + if (hasAttribute(Attribute::Convergent)) + return "convergent"; + if (hasAttribute(Attribute::InAlloca)) + return "inalloca"; + if (hasAttribute(Attribute::InlineHint)) + return "inlinehint"; if (hasAttribute(Attribute::InReg)) return "inreg"; + if (hasAttribute(Attribute::JumpTable)) + return "jumptable"; + if (hasAttribute(Attribute::MinSize)) + return "minsize"; + if (hasAttribute(Attribute::Naked)) + return "naked"; + if (hasAttribute(Attribute::Nest)) + return "nest"; if (hasAttribute(Attribute::NoAlias)) return "noalias"; + if (hasAttribute(Attribute::NoBuiltin)) + return "nobuiltin"; if (hasAttribute(Attribute::NoCapture)) return "nocapture"; - if (hasAttribute(Attribute::StructRet)) - return "sret"; - if (hasAttribute(Attribute::ByVal)) - return "byval"; - if (hasAttribute(Attribute::Nest)) - return "nest"; + if (hasAttribute(Attribute::NoDuplicate)) + return "noduplicate"; + if (hasAttribute(Attribute::NoImplicitFloat)) + return "noimplicitfloat"; + if (hasAttribute(Attribute::NoInline)) + return "noinline"; + if (hasAttribute(Attribute::NonLazyBind)) + return "nonlazybind"; + if (hasAttribute(Attribute::NonNull)) + return "nonnull"; + if (hasAttribute(Attribute::NoRedZone)) + return "noredzone"; + if (hasAttribute(Attribute::NoReturn)) + return "noreturn"; + if (hasAttribute(Attribute::NoUnwind)) + return "nounwind"; + if (hasAttribute(Attribute::OptimizeNone)) + return "optnone"; + if (hasAttribute(Attribute::OptimizeForSize)) + return "optsize"; if (hasAttribute(Attribute::ReadNone)) return "readnone"; if (hasAttribute(Attribute::ReadOnly)) return "readonly"; - if (hasAttribute(Attribute::OptimizeForSize)) - return "optsize"; - if (hasAttribute(Attribute::NoInline)) - return "noinline"; - if (hasAttribute(Attribute::InlineHint)) - return "inlinehint"; - if (hasAttribute(Attribute::AlwaysInline)) - return "alwaysinline"; + if (hasAttribute(Attribute::Returned)) + return "returned"; + if (hasAttribute(Attribute::ReturnsTwice)) + return "returns_twice"; + if (hasAttribute(Attribute::SExt)) + return "signext"; if (hasAttribute(Attribute::StackProtect)) return "ssp"; if (hasAttribute(Attribute::StackProtectReq)) return "sspreq"; if (hasAttribute(Attribute::StackProtectStrong)) return "sspstrong"; - if (hasAttribute(Attribute::NoRedZone)) - return "noredzone"; - if (hasAttribute(Attribute::NoImplicitFloat)) - return "noimplicitfloat"; - if (hasAttribute(Attribute::Naked)) - return "naked"; - if (hasAttribute(Attribute::NonLazyBind)) - return "nonlazybind"; - if (hasAttribute(Attribute::AddressSafety)) - return "address_safety"; - if (hasAttribute(Attribute::MinSize)) - return "minsize"; - if (hasAttribute(Attribute::StackAlignment)) { + if (hasAttribute(Attribute::SafeStack)) + return "safestack"; + if (hasAttribute(Attribute::StructRet)) + return "sret"; + if (hasAttribute(Attribute::SanitizeThread)) + return "sanitize_thread"; + if (hasAttribute(Attribute::SanitizeMemory)) + return "sanitize_memory"; + if (hasAttribute(Attribute::UWTable)) + return "uwtable"; + if (hasAttribute(Attribute::ZExt)) + return "zeroext"; + if (hasAttribute(Attribute::Cold)) + return "cold"; + + // FIXME: These should be output like this: + // + // align=4 + // alignstack=8 + // + if (hasAttribute(Attribute::Alignment)) { std::string Result; - Result += "alignstack("; - Result += utostr(getStackAlignment()); - Result += ")"; + Result += "align"; + Result += (InAttrGrp) ? "=" : " "; + Result += utostr(getValueAsInt()); return Result; } - if (hasAttribute(Attribute::Alignment)) { + + auto AttrWithBytesToString = [&](const char *Name) { + std::string Result; + Result += Name; + if (InAttrGrp) { + Result += "="; + Result += utostr(getValueAsInt()); + } else { + Result += "("; + Result += utostr(getValueAsInt()); + Result += ")"; + } + return Result; + }; + + if (hasAttribute(Attribute::StackAlignment)) + return AttrWithBytesToString("alignstack"); + + if (hasAttribute(Attribute::Dereferenceable)) + return AttrWithBytesToString("dereferenceable"); + + if (hasAttribute(Attribute::DereferenceableOrNull)) + return AttrWithBytesToString("dereferenceable_or_null"); + + // Convert target-dependent attributes to strings of the form: + // + // "kind" + // "kind" = "value" + // + if (isStringAttribute()) { std::string Result; - Result += "align "; - Result += utostr(getAlignment()); - Result += ""; + Result += (Twine('"') + getKindAsString() + Twine('"')).str(); + + StringRef Val = pImpl->getValueAsString(); + if (Val.empty()) return Result; + + Result += ("=\"" + Val + Twine('"')).str(); return Result; } - if (hasAttribute(Attribute::NoDuplicate)) - return "noduplicate"; llvm_unreachable("Unknown attribute"); } -bool Attribute::operator==(AttrKind K) const { - return pImpl && *pImpl == K; -} -bool Attribute::operator!=(AttrKind K) const { - return !(*this == K); -} - bool Attribute::operator<(Attribute A) const { if (!pImpl && !A.pImpl) return false; if (!pImpl) return true; @@ -191,102 +331,72 @@ bool Attribute::operator<(Attribute A) const { return *pImpl < *A.pImpl; } -uint64_t Attribute::Raw() const { - return pImpl ? pImpl->Raw() : 0; -} - //===----------------------------------------------------------------------===// // AttributeImpl Definition //===----------------------------------------------------------------------===// -AttributeImpl::AttributeImpl(LLVMContext &C, Attribute::AttrKind kind) - : Context(C) { - Kind = ConstantInt::get(Type::getInt64Ty(C), kind); -} -AttributeImpl::AttributeImpl(LLVMContext &C, Attribute::AttrKind kind, - ArrayRef values) - : Context(C) { - Kind = ConstantInt::get(Type::getInt64Ty(C), kind); - Vals.reserve(values.size()); - Vals.append(values.begin(), values.end()); -} -AttributeImpl::AttributeImpl(LLVMContext &C, StringRef kind) - : Context(C) { - Kind = ConstantDataArray::getString(C, kind); -} +// Pin the vtables to this file. +AttributeImpl::~AttributeImpl() {} +void EnumAttributeImpl::anchor() {} +void IntAttributeImpl::anchor() {} +void StringAttributeImpl::anchor() {} bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const { - return (Raw() & getAttrMask(A)) != 0; -} - -bool AttributeImpl::hasAttributes() const { - return Raw() != 0; + if (isStringAttribute()) return false; + return getKindAsEnum() == A; } -uint64_t AttributeImpl::getAlignment() const { - uint64_t Mask = Raw() & getAttrMask(Attribute::Alignment); - return 1ULL << ((Mask >> 16) - 1); +bool AttributeImpl::hasAttribute(StringRef Kind) const { + if (!isStringAttribute()) return false; + return getKindAsString() == Kind; } -uint64_t AttributeImpl::getStackAlignment() const { - uint64_t Mask = Raw() & getAttrMask(Attribute::StackAlignment); - return 1ULL << ((Mask >> 26) - 1); +Attribute::AttrKind AttributeImpl::getKindAsEnum() const { + assert(isEnumAttribute() || isIntAttribute()); + return static_cast(this)->getEnumKind(); } -bool AttributeImpl::operator==(Attribute::AttrKind kind) const { - if (ConstantInt *CI = dyn_cast(Kind)) - return CI->getZExtValue() == kind; - return false; -} -bool AttributeImpl::operator!=(Attribute::AttrKind kind) const { - return !(*this == kind); +uint64_t AttributeImpl::getValueAsInt() const { + assert(isIntAttribute()); + return static_cast(this)->getValue(); } -bool AttributeImpl::operator==(StringRef kind) const { - if (ConstantDataArray *CDA = dyn_cast(Kind)) - if (CDA->isString()) - return CDA->getAsString() == kind; - return false; +StringRef AttributeImpl::getKindAsString() const { + assert(isStringAttribute()); + return static_cast(this)->getStringKind(); } -bool AttributeImpl::operator!=(StringRef kind) const { - return !(*this == kind); +StringRef AttributeImpl::getValueAsString() const { + assert(isStringAttribute()); + return static_cast(this)->getStringValue(); } bool AttributeImpl::operator<(const AttributeImpl &AI) const { - if (!Kind && !AI.Kind) return false; - if (!Kind && AI.Kind) return true; - if (Kind && !AI.Kind) return false; - - ConstantInt *ThisCI = dyn_cast(Kind); - ConstantInt *ThatCI = dyn_cast(AI.Kind); - - ConstantDataArray *ThisCDA = dyn_cast(Kind); - ConstantDataArray *ThatCDA = dyn_cast(AI.Kind); - - if (ThisCI && ThatCI) - return ThisCI->getZExtValue() < ThatCI->getZExtValue(); - - if (ThisCI && ThatCDA) - return true; - - if (ThisCDA && ThatCI) - return false; + // This sorts the attributes with Attribute::AttrKinds coming first (sorted + // relative to their enum value) and then strings. + if (isEnumAttribute()) { + if (AI.isEnumAttribute()) return getKindAsEnum() < AI.getKindAsEnum(); + if (AI.isIntAttribute()) return true; + if (AI.isStringAttribute()) return true; + } - return ThisCDA->getAsString() < ThatCDA->getAsString(); -} + if (isIntAttribute()) { + if (AI.isEnumAttribute()) return false; + if (AI.isIntAttribute()) return getValueAsInt() < AI.getValueAsInt(); + if (AI.isStringAttribute()) return true; + } -uint64_t AttributeImpl::Raw() const { - // FIXME: Remove this. - return cast(Kind)->getZExtValue(); + if (AI.isEnumAttribute()) return false; + if (AI.isIntAttribute()) return false; + if (getKindAsString() == AI.getKindAsString()) + return getValueAsString() < AI.getValueAsString(); + return getKindAsString() < AI.getKindAsString(); } uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) { // FIXME: Remove this. switch (Val) { case Attribute::EndAttrKinds: - case Attribute::AttrKindEmptyKey: - case Attribute::AttrKindTombstoneKey: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; @@ -316,10 +426,32 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) { case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; - case Attribute::AddressSafety: return 1ULL << 32; + case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; + case Attribute::SanitizeThread: return 1ULL << 36; + case Attribute::SanitizeMemory: return 1ULL << 37; + case Attribute::NoBuiltin: return 1ULL << 38; + case Attribute::Returned: return 1ULL << 39; + case Attribute::Cold: return 1ULL << 40; + case Attribute::Builtin: return 1ULL << 41; + case Attribute::OptimizeNone: return 1ULL << 42; + case Attribute::InAlloca: return 1ULL << 43; + case Attribute::NonNull: return 1ULL << 44; + case Attribute::JumpTable: return 1ULL << 45; + case Attribute::Convergent: return 1ULL << 46; + case Attribute::SafeStack: return 1ULL << 47; + case Attribute::Dereferenceable: + llvm_unreachable("dereferenceable attribute not supported in raw format"); + break; + case Attribute::DereferenceableOrNull: + llvm_unreachable("dereferenceable_or_null attribute not supported in raw " + "format"); + break; + case Attribute::ArgMemOnly: + llvm_unreachable("argmemonly attribute not supported in raw format"); + break; } llvm_unreachable("Unsupported attribute type"); } @@ -331,14 +463,14 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) { AttributeSetNode *AttributeSetNode::get(LLVMContext &C, ArrayRef Attrs) { if (Attrs.empty()) - return 0; + return nullptr; // Otherwise, build a key to look up the existing attributes. LLVMContextImpl *pImpl = C.pImpl; FoldingSetNodeID ID; SmallVector SortedAttrs(Attrs.begin(), Attrs.end()); - std::sort(SortedAttrs.begin(), SortedAttrs.end()); + array_pod_sort(SortedAttrs.begin(), SortedAttrs.end()); for (SmallVectorImpl::iterator I = SortedAttrs.begin(), E = SortedAttrs.end(); I != E; ++I) @@ -351,7 +483,9 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, // If we didn't find any existing attributes of the same shape then create a // new one and insert it. if (!PA) { - PA = new AttributeSetNode(SortedAttrs); + // Coallocate entries after the AttributeSetNode itself. + void *Mem = ::operator new(totalSizeToAlloc(SortedAttrs.size())); + PA = new (Mem) AttributeSetNode(SortedAttrs); pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint); } @@ -360,35 +494,67 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, } bool AttributeSetNode::hasAttribute(Attribute::AttrKind Kind) const { - for (SmallVectorImpl::const_iterator I = AttrList.begin(), - E = AttrList.end(); I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Kind)) + return true; + return false; +} + +bool AttributeSetNode::hasAttribute(StringRef Kind) const { + for (iterator I = begin(), E = end(); I != E; ++I) if (I->hasAttribute(Kind)) return true; return false; } +Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Kind)) + return *I; + return Attribute(); +} + +Attribute AttributeSetNode::getAttribute(StringRef Kind) const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Kind)) + return *I; + return Attribute(); +} + unsigned AttributeSetNode::getAlignment() const { - for (SmallVectorImpl::const_iterator I = AttrList.begin(), - E = AttrList.end(); I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) if (I->hasAttribute(Attribute::Alignment)) return I->getAlignment(); return 0; } unsigned AttributeSetNode::getStackAlignment() const { - for (SmallVectorImpl::const_iterator I = AttrList.begin(), - E = AttrList.end(); I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) if (I->hasAttribute(Attribute::StackAlignment)) return I->getStackAlignment(); return 0; } -std::string AttributeSetNode::getAsString() const { - std::string Str = ""; - for (SmallVectorImpl::const_iterator I = AttrList.begin(), - E = AttrList.end(); I != E; ++I) { - if (I != AttrList.begin()) Str += " "; - Str += I->getAsString(); +uint64_t AttributeSetNode::getDereferenceableBytes() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Attribute::Dereferenceable)) + return I->getDereferenceableBytes(); + return 0; +} + +uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Attribute::DereferenceableOrNull)) + return I->getDereferenceableOrNullBytes(); + return 0; +} + +std::string AttributeSetNode::getAsString(bool InAttrGrp) const { + std::string Str; + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I != begin()) + Str += ' '; + Str += I->getAsString(InAttrGrp); } return Str; } @@ -397,21 +563,41 @@ std::string AttributeSetNode::getAsString() const { // AttributeSetImpl Definition //===----------------------------------------------------------------------===// -uint64_t AttributeSetImpl::Raw(uint64_t Index) const { +uint64_t AttributeSetImpl::Raw(unsigned Index) const { for (unsigned I = 0, E = getNumAttributes(); I != E; ++I) { if (getSlotIndex(I) != Index) continue; - const AttributeSetNode *ASN = AttrNodes[I].second; - AttrBuilder B; + const AttributeSetNode *ASN = getSlotNode(I); + uint64_t Mask = 0; + + for (AttributeSetNode::iterator II = ASN->begin(), + IE = ASN->end(); II != IE; ++II) { + Attribute Attr = *II; + + // This cannot handle string attributes. + if (Attr.isStringAttribute()) continue; + + Attribute::AttrKind Kind = Attr.getKindAsEnum(); + + if (Kind == Attribute::Alignment) + Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16; + else if (Kind == Attribute::StackAlignment) + Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26; + else if (Kind == Attribute::Dereferenceable) + llvm_unreachable("dereferenceable not supported in bit mask"); + else + Mask |= AttributeImpl::getAttrMask(Kind); + } - for (AttributeSetNode::const_iterator II = ASN->begin(), - IE = ASN->end(); II != IE; ++II) - B.addAttributes(*II); - return B.Raw(); + return Mask; } return 0; } +void AttributeSetImpl::dump() const { + AttributeSet(const_cast(this)).dump(); +} + //===----------------------------------------------------------------------===// // AttributeSet Construction and Mutation Methods //===----------------------------------------------------------------------===// @@ -429,7 +615,10 @@ AttributeSet::getImpl(LLVMContext &C, // If we didn't find any existing attributes of the same shape then // create a new one and insert it. if (!PA) { - PA = new AttributeSetImpl(C, Attrs); + // Coallocate entries after the AttributeSetImpl itself. + void *Mem = ::operator new( + AttributeSetImpl::totalSizeToAlloc(Attrs.size())); + PA = new (Mem) AttributeSetImpl(C, Attrs); pImpl->AttrsLists.InsertNode(PA, InsertPoint); } @@ -447,7 +636,7 @@ AttributeSet AttributeSet::get(LLVMContext &C, for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { assert((!i || Attrs[i-1].first <= Attrs[i].first) && "Misordered Attributes list!"); - assert(Attrs[i].second.hasAttributes() && + assert(!Attrs[i].second.hasAttribute(Attribute::None) && "Pointless attribute!"); } #endif @@ -481,54 +670,104 @@ AttributeSet AttributeSet::get(LLVMContext &C, return getImpl(C, Attrs); } -AttributeSet AttributeSet::get(LLVMContext &C, unsigned Idx, AttrBuilder &B) { +AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index, + const AttrBuilder &B) { if (!B.hasAttributes()) return AttributeSet(); + // Add target-independent attributes. SmallVector, 8> Attrs; - for (AttrBuilder::iterator I = B.begin(), E = B.end(); I != E; ++I) { - Attribute::AttrKind Kind = *I; + for (Attribute::AttrKind Kind = Attribute::None; + Kind != Attribute::EndAttrKinds; Kind = Attribute::AttrKind(Kind + 1)) { + if (!B.contains(Kind)) + continue; + if (Kind == Attribute::Alignment) - Attrs.push_back(std::make_pair(Idx, Attribute:: + Attrs.push_back(std::make_pair(Index, Attribute:: getWithAlignment(C, B.getAlignment()))); else if (Kind == Attribute::StackAlignment) - Attrs.push_back(std::make_pair(Idx, Attribute:: + Attrs.push_back(std::make_pair(Index, Attribute:: getWithStackAlignment(C, B.getStackAlignment()))); + else if (Kind == Attribute::Dereferenceable) + Attrs.push_back(std::make_pair(Index, + Attribute::getWithDereferenceableBytes(C, + B.getDereferenceableBytes()))); + else if (Kind == Attribute::DereferenceableOrNull) + Attrs.push_back( + std::make_pair(Index, Attribute::getWithDereferenceableOrNullBytes( + C, B.getDereferenceableOrNullBytes()))); else - Attrs.push_back(std::make_pair(Idx, Attribute::get(C, Kind))); + Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind))); } + // Add target-dependent (string) attributes. + for (const AttrBuilder::td_type &TDA : B.td_attrs()) + Attrs.push_back( + std::make_pair(Index, Attribute::get(C, TDA.first, TDA.second))); + return get(C, Attrs); } -AttributeSet AttributeSet::get(LLVMContext &C, unsigned Idx, +AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index, ArrayRef Kind) { SmallVector, 8> Attrs; for (ArrayRef::iterator I = Kind.begin(), E = Kind.end(); I != E; ++I) - Attrs.push_back(std::make_pair(Idx, Attribute::get(C, *I))); + Attrs.push_back(std::make_pair(Index, Attribute::get(C, *I))); return get(C, Attrs); } AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef Attrs) { if (Attrs.empty()) return AttributeSet(); + if (Attrs.size() == 1) return Attrs[0]; SmallVector, 8> AttrNodeVec; - for (unsigned I = 0, E = Attrs.size(); I != E; ++I) { - AttributeSet AS = Attrs[I]; - if (!AS.pImpl) continue; - AttrNodeVec.append(AS.pImpl->AttrNodes.begin(), AS.pImpl->AttrNodes.end()); + AttributeSetImpl *A0 = Attrs[0].pImpl; + if (A0) + AttrNodeVec.append(A0->getNode(0), A0->getNode(A0->getNumAttributes())); + // Copy all attributes from Attrs into AttrNodeVec while keeping AttrNodeVec + // ordered by index. Because we know that each list in Attrs is ordered by + // index we only need to merge each successive list in rather than doing a + // full sort. + for (unsigned I = 1, E = Attrs.size(); I != E; ++I) { + AttributeSetImpl *AS = Attrs[I].pImpl; + if (!AS) continue; + SmallVector, 8>::iterator + ANVI = AttrNodeVec.begin(), ANVE; + for (const IndexAttrPair *AI = AS->getNode(0), + *AE = AS->getNode(AS->getNumAttributes()); + AI != AE; ++AI) { + ANVE = AttrNodeVec.end(); + while (ANVI != ANVE && ANVI->first <= AI->first) + ++ANVI; + ANVI = AttrNodeVec.insert(ANVI, *AI) + 1; + } } return getImpl(C, AttrNodeVec); } -AttributeSet AttributeSet::addAttribute(LLVMContext &C, unsigned Idx, +AttributeSet AttributeSet::addAttribute(LLVMContext &C, unsigned Index, Attribute::AttrKind Attr) const { - return addAttributes(C, Idx, AttributeSet::get(C, Idx, Attr)); + if (hasAttribute(Index, Attr)) return *this; + return addAttributes(C, Index, AttributeSet::get(C, Index, Attr)); } -AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Idx, +AttributeSet AttributeSet::addAttribute(LLVMContext &C, unsigned Index, + StringRef Kind) const { + llvm::AttrBuilder B; + B.addAttribute(Kind); + return addAttributes(C, Index, AttributeSet::get(C, Index, B)); +} + +AttributeSet AttributeSet::addAttribute(LLVMContext &C, unsigned Index, + StringRef Kind, StringRef Value) const { + llvm::AttrBuilder B; + B.addAttribute(Kind, Value); + return addAttributes(C, Index, AttributeSet::get(C, Index, B)); +} + +AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Index, AttributeSet Attrs) const { if (!pImpl) return Attrs; if (!Attrs.pImpl) return *this; @@ -536,8 +775,8 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Idx, #ifndef NDEBUG // FIXME it is not obvious how this should work for alignment. For now, say // we can't change a known alignment. - unsigned OldAlign = getParamAlignment(Idx); - unsigned NewAlign = Attrs.getParamAlignment(Idx); + unsigned OldAlign = getParamAlignment(Index); + unsigned NewAlign = Attrs.getParamAlignment(Index); assert((!OldAlign || !NewAlign || OldAlign == NewAlign) && "Attempt to change alignment!"); #endif @@ -548,8 +787,8 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Idx, AttributeSet AS; uint64_t LastIndex = 0; for (unsigned I = 0, E = NumAttrs; I != E; ++I) { - if (getSlotIndex(I) >= Idx) { - if (getSlotIndex(I) == Idx) AS = getSlotAttributes(LastIndex++); + if (getSlotIndex(I) >= Index) { + if (getSlotIndex(I) == Index) AS = getSlotAttributes(LastIndex++); break; } LastIndex = I + 1; @@ -558,17 +797,17 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Idx, // Now add the attribute into the correct slot. There may already be an // AttributeSet there. - AttrBuilder B(AS, Idx); + AttrBuilder B(AS, Index); for (unsigned I = 0, E = Attrs.pImpl->getNumAttributes(); I != E; ++I) - if (Attrs.getSlotIndex(I) == Idx) { - for (AttributeSetImpl::const_iterator II = Attrs.pImpl->begin(I), + if (Attrs.getSlotIndex(I) == Index) { + for (AttributeSetImpl::iterator II = Attrs.pImpl->begin(I), IE = Attrs.pImpl->end(I); II != IE; ++II) - B.addAttributes(*II); + B.addAttribute(*II); break; } - AttrSet.push_back(AttributeSet::get(C, Idx, B)); + AttrSet.push_back(AttributeSet::get(C, Index, B)); // Add the remaining attribute slots. for (unsigned I = LastIndex, E = NumAttrs; I < E; ++I) @@ -577,22 +816,21 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C, unsigned Idx, return get(C, AttrSet); } -AttributeSet AttributeSet::removeAttribute(LLVMContext &C, unsigned Idx, +AttributeSet AttributeSet::removeAttribute(LLVMContext &C, unsigned Index, Attribute::AttrKind Attr) const { - return removeAttributes(C, Idx, AttributeSet::get(C, Idx, Attr)); + if (!hasAttribute(Index, Attr)) return *this; + return removeAttributes(C, Index, AttributeSet::get(C, Index, Attr)); } -AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Idx, +AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Index, AttributeSet Attrs) const { if (!pImpl) return AttributeSet(); if (!Attrs.pImpl) return *this; -#ifndef NDEBUG // FIXME it is not obvious how this should work for alignment. // For now, say we can't pass in alignment, which no current use does. - assert(!Attrs.hasAttribute(Idx, Attribute::Alignment) && + assert(!Attrs.hasAttribute(Index, Attribute::Alignment) && "Attempt to change alignment!"); -#endif // Add the attribute slots before the one we're trying to add. SmallVector AttrSet; @@ -600,8 +838,8 @@ AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Idx, AttributeSet AS; uint64_t LastIndex = 0; for (unsigned I = 0, E = NumAttrs; I != E; ++I) { - if (getSlotIndex(I) >= Idx) { - if (getSlotIndex(I) == Idx) AS = getSlotAttributes(LastIndex++); + if (getSlotIndex(I) >= Index) { + if (getSlotIndex(I) == Index) AS = getSlotAttributes(LastIndex++); break; } LastIndex = I + 1; @@ -610,15 +848,51 @@ AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Idx, // Now remove the attribute from the correct slot. There may already be an // AttributeSet there. - AttrBuilder B(AS, Idx); + AttrBuilder B(AS, Index); for (unsigned I = 0, E = Attrs.pImpl->getNumAttributes(); I != E; ++I) - if (Attrs.getSlotIndex(I) == Idx) { - B.removeAttributes(Attrs.pImpl->getSlotAttributes(I), Idx); + if (Attrs.getSlotIndex(I) == Index) { + B.removeAttributes(Attrs.pImpl->getSlotAttributes(I), Index); + break; + } + + AttrSet.push_back(AttributeSet::get(C, Index, B)); + + // Add the remaining attribute slots. + for (unsigned I = LastIndex, E = NumAttrs; I < E; ++I) + AttrSet.push_back(getSlotAttributes(I)); + + return get(C, AttrSet); +} + +AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &Attrs) const { + if (!pImpl) return AttributeSet(); + + // FIXME it is not obvious how this should work for alignment. + // For now, say we can't pass in alignment, which no current use does. + assert(!Attrs.hasAlignmentAttr() && "Attempt to change alignment!"); + + // Add the attribute slots before the one we're trying to add. + SmallVector AttrSet; + uint64_t NumAttrs = pImpl->getNumAttributes(); + AttributeSet AS; + uint64_t LastIndex = 0; + for (unsigned I = 0, E = NumAttrs; I != E; ++I) { + if (getSlotIndex(I) >= Index) { + if (getSlotIndex(I) == Index) AS = getSlotAttributes(LastIndex++); break; } + LastIndex = I + 1; + AttrSet.push_back(getSlotAttributes(I)); + } - AttrSet.push_back(AttributeSet::get(C, Idx, B)); + // Now remove the attribute from the correct slot. There may already be an + // AttributeSet there. + AttrBuilder B(AS, Index); + B.remove(Attrs); + + AttrSet.push_back(AttributeSet::get(C, Index, B)); // Add the remaining attribute slots. for (unsigned I = LastIndex, E = NumAttrs; I < E; ++I) @@ -627,15 +901,34 @@ AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Idx, return get(C, AttrSet); } +AttributeSet AttributeSet::addDereferenceableAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const { + llvm::AttrBuilder B; + B.addDereferenceableAttr(Bytes); + return addAttributes(C, Index, AttributeSet::get(C, Index, B)); +} + +AttributeSet AttributeSet::addDereferenceableOrNullAttr(LLVMContext &C, + unsigned Index, + uint64_t Bytes) const { + llvm::AttrBuilder B; + B.addDereferenceableOrNullAttr(Bytes); + return addAttributes(C, Index, AttributeSet::get(C, Index, B)); +} + //===----------------------------------------------------------------------===// // AttributeSet Accessor Methods //===----------------------------------------------------------------------===// -AttributeSet AttributeSet::getParamAttributes(unsigned Idx) const { - return pImpl && hasAttributes(Idx) ? +LLVMContext &AttributeSet::getContext() const { + return pImpl->getContext(); +} + +AttributeSet AttributeSet::getParamAttributes(unsigned Index) const { + return pImpl && hasAttributes(Index) ? AttributeSet::get(pImpl->getContext(), ArrayRef >( - std::make_pair(Idx, getAttributes(Idx)))) : + std::make_pair(Index, getAttributes(Index)))) : AttributeSet(); } @@ -662,6 +955,11 @@ bool AttributeSet::hasAttribute(unsigned Index, Attribute::AttrKind Kind) const{ return ASN ? ASN->hasAttribute(Kind) : false; } +bool AttributeSet::hasAttribute(unsigned Index, StringRef Kind) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->hasAttribute(Kind) : false; +} + bool AttributeSet::hasAttributes(unsigned Index) const { AttributeSetNode *ASN = getAttributes(Index); return ASN ? ASN->hasAttributes() : false; @@ -670,10 +968,10 @@ bool AttributeSet::hasAttributes(unsigned Index) const { /// \brief Return true if the specified attribute is set for at least one /// parameter or for the return value. bool AttributeSet::hasAttrSomewhere(Attribute::AttrKind Attr) const { - if (pImpl == 0) return false; + if (!pImpl) return false; for (unsigned I = 0, E = pImpl->getNumAttributes(); I != E; ++I) - for (AttributeSetImpl::const_iterator II = pImpl->begin(I), + for (AttributeSetImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I); II != IE; ++II) if (II->hasAttribute(Attr)) return true; @@ -681,6 +979,18 @@ bool AttributeSet::hasAttrSomewhere(Attribute::AttrKind Attr) const { return false; } +Attribute AttributeSet::getAttribute(unsigned Index, + Attribute::AttrKind Kind) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->getAttribute(Kind) : Attribute(); +} + +Attribute AttributeSet::getAttribute(unsigned Index, + StringRef Kind) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->getAttribute(Kind) : Attribute(); +} + unsigned AttributeSet::getParamAlignment(unsigned Index) const { AttributeSetNode *ASN = getAttributes(Index); return ASN ? ASN->getAlignment() : 0; @@ -691,21 +1001,44 @@ unsigned AttributeSet::getStackAlignment(unsigned Index) const { return ASN ? ASN->getStackAlignment() : 0; } -std::string AttributeSet::getAsString(unsigned Index) const { +uint64_t AttributeSet::getDereferenceableBytes(unsigned Index) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->getDereferenceableBytes() : 0; +} + +uint64_t AttributeSet::getDereferenceableOrNullBytes(unsigned Index) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->getDereferenceableOrNullBytes() : 0; +} + +std::string AttributeSet::getAsString(unsigned Index, + bool InAttrGrp) const { AttributeSetNode *ASN = getAttributes(Index); - return ASN ? ASN->getAsString() : std::string(""); + return ASN ? ASN->getAsString(InAttrGrp) : std::string(""); } /// \brief The attributes for the specified index are returned. -AttributeSetNode *AttributeSet::getAttributes(unsigned Idx) const { - if (!pImpl) return 0; +AttributeSetNode *AttributeSet::getAttributes(unsigned Index) const { + if (!pImpl) return nullptr; // Loop through to find the attribute node we want. for (unsigned I = 0, E = pImpl->getNumAttributes(); I != E; ++I) - if (pImpl->getSlotIndex(I) == Idx) + if (pImpl->getSlotIndex(I) == Index) return pImpl->getSlotNode(I); - return 0; + return nullptr; +} + +AttributeSet::iterator AttributeSet::begin(unsigned Slot) const { + if (!pImpl) + return ArrayRef().begin(); + return pImpl->begin(Slot); +} + +AttributeSet::iterator AttributeSet::end(unsigned Slot) const { + if (!pImpl) + return ArrayRef().end(); + return pImpl->end(Slot); } //===----------------------------------------------------------------------===// @@ -719,7 +1052,7 @@ unsigned AttributeSet::getNumSlots() const { return pImpl ? pImpl->getNumAttributes() : 0; } -uint64_t AttributeSet::getSlotIndex(unsigned Slot) const { +unsigned AttributeSet::getSlotIndex(unsigned Slot) const { assert(pImpl && Slot < pImpl->getNumAttributes() && "Slot # out of range!"); return pImpl->getSlotIndex(Slot); @@ -756,82 +1089,128 @@ void AttributeSet::dump() const { // AttrBuilder Method Implementations //===----------------------------------------------------------------------===// -AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Idx) - : Alignment(0), StackAlignment(0) { +AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index) + : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), + DerefOrNullBytes(0) { AttributeSetImpl *pImpl = AS.pImpl; if (!pImpl) return; for (unsigned I = 0, E = pImpl->getNumAttributes(); I != E; ++I) { - if (pImpl->getSlotIndex(I) != Idx) continue; + if (pImpl->getSlotIndex(I) != Index) continue; - for (AttributeSetImpl::const_iterator II = pImpl->begin(I), + for (AttributeSetImpl::iterator II = pImpl->begin(I), IE = pImpl->end(I); II != IE; ++II) - addAttributes(*II); + addAttribute(*II); break; } } void AttrBuilder::clear() { - Attrs.clear(); - Alignment = StackAlignment = 0; + Attrs.reset(); + Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0; } AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { - Attrs.insert(Val); + assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); + assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment && + Val != Attribute::Dereferenceable && + "Adding integer attribute without adding a value!"); + Attrs[Val] = true; return *this; } -AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { - Attrs.erase(Val); - if (Val == Attribute::Alignment) - Alignment = 0; - else if (Val == Attribute::StackAlignment) - StackAlignment = 0; +AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { + if (Attr.isStringAttribute()) { + addAttribute(Attr.getKindAsString(), Attr.getValueAsString()); + return *this; + } + + Attribute::AttrKind Kind = Attr.getKindAsEnum(); + Attrs[Kind] = true; + if (Kind == Attribute::Alignment) + Alignment = Attr.getAlignment(); + else if (Kind == Attribute::StackAlignment) + StackAlignment = Attr.getStackAlignment(); + else if (Kind == Attribute::Dereferenceable) + DerefBytes = Attr.getDereferenceableBytes(); + else if (Kind == Attribute::DereferenceableOrNull) + DerefOrNullBytes = Attr.getDereferenceableOrNullBytes(); return *this; } -AttrBuilder &AttrBuilder::addAttributes(Attribute Attr) { - uint64_t Mask = Attr.Raw(); +AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) { + TargetDepAttrs[A] = V; + return *this; +} - for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; - I = Attribute::AttrKind(I + 1)) - if ((Mask & AttributeImpl::getAttrMask(I)) != 0) - Attrs.insert(I); +AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { + assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); + Attrs[Val] = false; + + if (Val == Attribute::Alignment) + Alignment = 0; + else if (Val == Attribute::StackAlignment) + StackAlignment = 0; + else if (Val == Attribute::Dereferenceable) + DerefBytes = 0; + else if (Val == Attribute::DereferenceableOrNull) + DerefOrNullBytes = 0; - if (Attr.getAlignment()) - Alignment = Attr.getAlignment(); - if (Attr.getStackAlignment()) - StackAlignment = Attr.getStackAlignment(); return *this; } AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) { - uint64_t Mask = A.Raw(Index); + unsigned Slot = ~0U; + for (unsigned I = 0, E = A.getNumSlots(); I != E; ++I) + if (A.getSlotIndex(I) == Index) { + Slot = I; + break; + } - for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; - I = Attribute::AttrKind(I + 1)) { - if (Mask & AttributeImpl::getAttrMask(I)) { - Attrs.erase(I); + assert(Slot != ~0U && "Couldn't find index in AttributeSet!"); - if (I == Attribute::Alignment) + for (AttributeSet::iterator I = A.begin(Slot), E = A.end(Slot); I != E; ++I) { + Attribute Attr = *I; + if (Attr.isEnumAttribute() || Attr.isIntAttribute()) { + Attribute::AttrKind Kind = I->getKindAsEnum(); + Attrs[Kind] = false; + + if (Kind == Attribute::Alignment) Alignment = 0; - else if (I == Attribute::StackAlignment) + else if (Kind == Attribute::StackAlignment) StackAlignment = 0; + else if (Kind == Attribute::Dereferenceable) + DerefBytes = 0; + else if (Kind == Attribute::DereferenceableOrNull) + DerefOrNullBytes = 0; + } else { + assert(Attr.isStringAttribute() && "Invalid attribute type!"); + std::map::iterator + Iter = TargetDepAttrs.find(Attr.getKindAsString()); + if (Iter != TargetDepAttrs.end()) + TargetDepAttrs.erase(Iter); } } return *this; } +AttrBuilder &AttrBuilder::removeAttribute(StringRef A) { + std::map::iterator I = TargetDepAttrs.find(A); + if (I != TargetDepAttrs.end()) + TargetDepAttrs.erase(I); + return *this; +} + AttrBuilder &AttrBuilder::addAlignmentAttr(unsigned Align) { if (Align == 0) return *this; assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); assert(Align <= 0x40000000 && "Alignment too large."); - Attrs.insert(Attribute::Alignment); + Attrs[Attribute::Alignment] = true; Alignment = Align; return *this; } @@ -843,21 +1222,116 @@ AttrBuilder &AttrBuilder::addStackAlignmentAttr(unsigned Align) { assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); assert(Align <= 0x100 && "Alignment too large."); - Attrs.insert(Attribute::StackAlignment); + Attrs[Attribute::StackAlignment] = true; StackAlignment = Align; return *this; } -bool AttrBuilder::contains(Attribute::AttrKind A) const { - return Attrs.count(A); +AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) { + if (Bytes == 0) return *this; + + Attrs[Attribute::Dereferenceable] = true; + DerefBytes = Bytes; + return *this; +} + +AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) { + if (Bytes == 0) + return *this; + + Attrs[Attribute::DereferenceableOrNull] = true; + DerefOrNullBytes = Bytes; + return *this; +} + +AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { + // FIXME: What if both have alignments, but they don't match?! + if (!Alignment) + Alignment = B.Alignment; + + if (!StackAlignment) + StackAlignment = B.StackAlignment; + + if (!DerefBytes) + DerefBytes = B.DerefBytes; + + if (!DerefOrNullBytes) + DerefOrNullBytes = B.DerefOrNullBytes; + + Attrs |= B.Attrs; + + for (auto I : B.td_attrs()) + TargetDepAttrs[I.first] = I.second; + + return *this; +} + +AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) { + // FIXME: What if both have alignments, but they don't match?! + if (B.Alignment) + Alignment = 0; + + if (B.StackAlignment) + StackAlignment = 0; + + if (B.DerefBytes) + DerefBytes = 0; + + if (B.DerefOrNullBytes) + DerefOrNullBytes = 0; + + Attrs &= ~B.Attrs; + + for (auto I : B.td_attrs()) + TargetDepAttrs.erase(I.first); + + 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 (auto I : td_attrs()) + if (B.contains(I.first)) + return true; + + return false; +} + +bool AttrBuilder::contains(StringRef A) const { + return TargetDepAttrs.find(A) != TargetDepAttrs.end(); } bool AttrBuilder::hasAttributes() const { - return !Attrs.empty(); + return !Attrs.none() || !TargetDepAttrs.empty(); } bool AttrBuilder::hasAttributes(AttributeSet A, uint64_t Index) const { - return Raw() & A.Raw(Index); + unsigned Slot = ~0U; + for (unsigned I = 0, E = A.getNumSlots(); I != E; ++I) + if (A.getSlotIndex(I) == Index) { + Slot = I; + break; + } + + assert(Slot != ~0U && "Couldn't find the index!"); + + for (AttributeSet::iterator I = A.begin(Slot), E = A.end(Slot); + I != E; ++I) { + Attribute Attr = *I; + if (Attr.isEnumAttribute() || Attr.isIntAttribute()) { + if (Attrs[I->getKindAsEnum()]) + return true; + } else { + assert(Attr.isStringAttribute() && "Invalid attribute kind!"); + return TargetDepAttrs.find(Attr.getKindAsString())!=TargetDepAttrs.end(); + } + } + + return false; } bool AttrBuilder::hasAlignmentAttr() const { @@ -865,18 +1339,30 @@ bool AttrBuilder::hasAlignmentAttr() const { } bool AttrBuilder::operator==(const AttrBuilder &B) { - SmallVector This(Attrs.begin(), Attrs.end()); - SmallVector That(B.Attrs.begin(), B.Attrs.end()); - return This == That; + if (Attrs != B.Attrs) + return false; + + for (td_const_iterator I = TargetDepAttrs.begin(), + E = TargetDepAttrs.end(); I != E; ++I) + if (B.TargetDepAttrs.find(I->first) == B.TargetDepAttrs.end()) + return false; + + return Alignment == B.Alignment && StackAlignment == B.StackAlignment && + DerefBytes == B.DerefBytes; } AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) { + // FIXME: Remove this in 4.0. if (!Val) return *this; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { + if (I == Attribute::Dereferenceable || + I == Attribute::DereferenceableOrNull || + I == Attribute::ArgMemOnly) + continue; if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) { - Attrs.insert(I); + Attrs[I] = true; if (I == Attribute::Alignment) Alignment = 1ULL << ((A >> 16) - 1); @@ -888,29 +1374,12 @@ AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) { return *this; } -uint64_t AttrBuilder::Raw() const { - uint64_t Mask = 0; - - for (DenseSet::const_iterator I = Attrs.begin(), - E = Attrs.end(); I != E; ++I) { - Attribute::AttrKind Kind = *I; - - if (Kind == Attribute::Alignment) - Mask |= (Log2_32(Alignment) + 1) << 16; - else if (Kind == Attribute::StackAlignment) - Mask |= (Log2_32(StackAlignment) + 1) << 26; - else - Mask |= AttributeImpl::getAttrMask(Kind); - } - - return Mask; -} - //===----------------------------------------------------------------------===// // AttributeFuncs Function Defintions //===----------------------------------------------------------------------===// -AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) { +/// \brief Which attributes cannot be applied to a type. +AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) { AttrBuilder Incompatible; if (!Ty->isIntegerTy()) @@ -924,48 +1393,13 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) { .addAttribute(Attribute::Nest) .addAttribute(Attribute::NoAlias) .addAttribute(Attribute::NoCapture) - .addAttribute(Attribute::StructRet); - - return AttributeSet::get(Ty->getContext(), Index, Incompatible); -} - -/// \brief This returns an integer containing an encoding of all the LLVM -/// attributes found in the given attribute bitset. Any change to this encoding -/// is a breaking change to bitcode compatibility. -/// N.B. This should be used only by the bitcode reader! -uint64_t AttributeFuncs::encodeLLVMAttributesForBitcode(AttributeSet Attrs, - unsigned Index) { - // FIXME: It doesn't make sense to store the alignment information as an - // expanded out value, we should store it as a log2 value. However, we can't - // just change that here without breaking bitcode compatibility. If this ever - // becomes a problem in practice, we should introduce new tag numbers in the - // bitcode file and have those tags use a more efficiently encoded alignment - // field. - - // Store the alignment in the bitcode as a 16-bit raw value instead of a 5-bit - // log2 encoded value. Shift the bits above the alignment up by 11 bits. - uint64_t EncodedAttrs = Attrs.Raw(Index) & 0xffff; - if (Attrs.hasAttribute(Index, Attribute::Alignment)) - EncodedAttrs |= Attrs.getParamAlignment(Index) << 16; - EncodedAttrs |= (Attrs.Raw(Index) & (0xffffULL << 21)) << 11; - return EncodedAttrs; -} - -/// \brief This fills an AttrBuilder object with the LLVM attributes that have -/// been decoded from the given integer. This function must stay in sync with -/// 'encodeLLVMAttributesForBitcode'. -/// N.B. This should be used only by the bitcode reader! -void AttributeFuncs::decodeLLVMAttributesForBitcode(LLVMContext &C, - AttrBuilder &B, - uint64_t EncodedAttrs) { - // The alignment is stored as a 16-bit raw value from bits 31--16. We shift - // the bits above 31 down by 11 bits. - unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; - assert((!Alignment || isPowerOf2_32(Alignment)) && - "Alignment must be a power of two."); - - if (Alignment) - B.addAlignmentAttr(Alignment); - B.addRawValue(((EncodedAttrs & (0xffffULL << 32)) >> 11) | - (EncodedAttrs & 0xffff)); + .addAttribute(Attribute::NonNull) + .addDereferenceableAttr(1) // the int here is ignored + .addDereferenceableOrNullAttr(1) // the int here is ignored + .addAttribute(Attribute::ReadNone) + .addAttribute(Attribute::ReadOnly) + .addAttribute(Attribute::StructRet) + .addAttribute(Attribute::InAlloca); + + return Incompatible; }