diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 61202eebefb..46d279c1576 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -114,8 +114,9 @@ public: //===--------------------------------------------------------------------===// /// \brief Return a uniquified Attribute object. - static Attribute get(LLVMContext &Context, AttrKind Kind, Constant *Val = 0); - static Attribute get(LLVMContext &Context, Constant *Kind, Constant *Val = 0); + static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val = 0); + static Attribute get(LLVMContext &Context, StringRef Kind, + StringRef Val = StringRef()); /// \brief Return a uniquified Attribute object that has the specific /// alignment set. @@ -126,16 +127,34 @@ public: // Attribute Accessors //===--------------------------------------------------------------------===// + /// \brief Return true if the attribute is an Attribute::AttrKind type. + bool isEnumAttribute() const; + + /// \brief Return true if the attribute is an alignment attribute. + bool isAlignAttribute() const; + + /// \brief Return true if the attribute is a string (target-dependent) + /// attribute. + bool isStringAttribute() const; + /// \brief Return true if the attribute is present. bool hasAttribute(AttrKind Val) const; - /// \brief Return the kind of this attribute: enum or string. - Constant *getAttributeKind() const; + /// \brief Return the attribute's kind as an enum (Attribute::AttrKind). This + /// requires the attribute to be an enum or alignment attribute. + Attribute::AttrKind getKindAsEnum() const; - /// \brief Return the values (if present) of the attribute. This may be a - /// ConstantVector to represent a list of values associated with the - /// attribute. - Constant *getAttributeValues() const; + /// \brief Return the attribute's value as an integer. This requires that the + /// attribute be an alignment attribute. + uint64_t getValueAsInt() const; + + /// \brief Return the attribute's kind as a string. This requires the + /// attribute to be a string attribute. + StringRef getKindAsString() const; + + /// \brief Return the attribute's value as a string. This requires the + /// attribute to be a string attribute. + StringRef getValueAsString() const; /// \brief Returns the alignment field of an attribute as a byte alignment /// value. @@ -149,10 +168,7 @@ public: /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString() const; - /// \brief Equality and non-equality query methods. - bool operator==(AttrKind K) const; - bool operator!=(AttrKind K) const; - + /// \brief Equality and non-equality operators. bool operator==(Attribute A) const { return pImpl == A.pImpl; } bool operator!=(Attribute A) const { return pImpl != A.pImpl; } diff --git a/lib/IR/AttributeImpl.h b/lib/IR/AttributeImpl.h index bf87562dd64..5f9e3e70316 100644 --- a/lib/IR/AttributeImpl.h +++ b/lib/IR/AttributeImpl.h @@ -25,49 +25,129 @@ namespace llvm { class Constant; class LLVMContext; +//===----------------------------------------------------------------------===// +/// \class +/// \brief A set of classes that contain the kind and (optional) value of the +/// attribute object. There are three main categories: enum attribute entries, +/// represented by Attribute::AttrKind; alignment attribute entries; and string +/// attribute enties, which are for target-dependent attributes. +class AttributeEntry { + unsigned char KindID; +protected: + enum AttrEntryKind { + EnumAttrEntry, + AlignAttrEntry, + StringAttrEntry + }; +public: + AttributeEntry(AttrEntryKind Kind) + : KindID(Kind) {} + virtual ~AttributeEntry() {} + + unsigned getKindID() const { return KindID; } + + static inline bool classof(const AttributeEntry *) { return true; } +}; + +class EnumAttributeEntry : public AttributeEntry { + Attribute::AttrKind Kind; +public: + EnumAttributeEntry(Attribute::AttrKind Kind) + : AttributeEntry(EnumAttrEntry), Kind(Kind) {} + + Attribute::AttrKind getEnumKind() const { return Kind; } + + static inline bool classof(const AttributeEntry *AE) { + return AE->getKindID() == EnumAttrEntry; + } + static inline bool classof(const EnumAttributeEntry *) { return true; } +}; + +class AlignAttributeEntry : public AttributeEntry { + Attribute::AttrKind Kind; + unsigned Align; +public: + AlignAttributeEntry(Attribute::AttrKind Kind, unsigned Align) + : AttributeEntry(AlignAttrEntry), Kind(Kind), Align(Align) {} + + Attribute::AttrKind getEnumKind() const { return Kind; } + unsigned getAlignment() const { return Align; } + + static inline bool classof(const AttributeEntry *AE) { + return AE->getKindID() == AlignAttrEntry; + } + static inline bool classof(const AlignAttributeEntry *) { return true; } +}; + +class StringAttributeEntry : public AttributeEntry { + std::string Kind; + std::string Val; +public: + StringAttributeEntry(StringRef Kind, StringRef Val = StringRef()) + : AttributeEntry(StringAttrEntry), Kind(Kind), Val(Val) {} + + StringRef getStringKind() const { return Kind; } + StringRef getStringValue() const { return Val; } + + static inline bool classof(const AttributeEntry *AE) { + return AE->getKindID() == StringAttrEntry; + } + static inline bool classof(const StringAttributeEntry *) { return true; } +}; + //===----------------------------------------------------------------------===// /// \class /// \brief This class represents a single, uniqued attribute. That attribute /// could be a single enum, a tuple, or a string. class AttributeImpl : public FoldingSetNode { - LLVMContext &Context; ///< Global context for uniquing objects - Constant *Kind; ///< Kind of attribute: enum or string - Constant *Values; ///< Values associated with the attribute + LLVMContext &Context; ///< Global context for uniquing objects + Constant *Kind; ///< Kind of attribute: enum or string + + AttributeEntry *Entry; ///< Holds the kind and value of the attribute // AttributesImpl is uniqued, these should not be publicly available. void operator=(const AttributeImpl &) LLVM_DELETED_FUNCTION; AttributeImpl(const AttributeImpl &) LLVM_DELETED_FUNCTION; public: - AttributeImpl(LLVMContext &C, Constant *Kind, Constant *Values = 0) - : Context(C), Kind(Kind), Values(Values) {} + AttributeImpl(LLVMContext &C, Attribute::AttrKind Kind); + AttributeImpl(LLVMContext &C, Attribute::AttrKind Kind, unsigned Align); + AttributeImpl(LLVMContext &C, StringRef Kind, StringRef Val = StringRef()); + ~AttributeImpl(); LLVMContext &getContext() { return Context; } + bool isEnumAttribute() const; + bool isAlignAttribute() const; + bool isStringAttribute() const; + bool hasAttribute(Attribute::AttrKind A) const; + bool hasAttribute(StringRef Kind) const; - Constant *getAttributeKind() const { return Kind; } - Constant *getAttributeValues() const { return Values; } + Attribute::AttrKind getKindAsEnum() const; + uint64_t getValueAsInt() const; - uint64_t getAlignment() const; - uint64_t getStackAlignment() const; - - /// \brief Equality and non-equality comparison operators. - bool operator==(Attribute::AttrKind Kind) const; - bool operator!=(Attribute::AttrKind Kind) const; - - bool operator==(StringRef Kind) const; - bool operator!=(StringRef Kind) const; + StringRef getKindAsString() const; + StringRef getValueAsString() const; /// \brief Used when sorting the attributes. bool operator<(const AttributeImpl &AI) const; void Profile(FoldingSetNodeID &ID) const { - Profile(ID, Kind, Values); + if (isEnumAttribute()) + Profile(ID, getKindAsEnum(), 0); + else if (isAlignAttribute()) + Profile(ID, getKindAsEnum(), getValueAsInt()); + else + Profile(ID, getKindAsString(), getValueAsString()); } - static void Profile(FoldingSetNodeID &ID, Constant *Kind, Constant *Values) { - ID.AddPointer(Kind); - if (Values) - ID.AddPointer(Values); + static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, + uint64_t Val) { + ID.AddInteger(Kind); + if (Val) ID.AddInteger(Val); + } + static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { + ID.AddString(Kind); + ID.AddString(Values); } // FIXME: Remove this! diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 8a0551cbf12..d61bd09e2c9 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -30,11 +30,34 @@ using namespace llvm; // Attribute Construction Methods //===----------------------------------------------------------------------===// -Attribute Attribute::get(LLVMContext &Context, Constant *Kind, Constant *Val) { +Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, + uint64_t Val) { LLVMContextImpl *pImpl = Context.pImpl; FoldingSetNodeID ID; - ID.AddPointer(Kind); - if (Val) ID.AddPointer(Val); + ID.AddInteger(Kind); + if (Val) ID.AddInteger(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 = !Val ? + new AttributeImpl(Context, Kind) : + new AttributeImpl(Context, Kind, Val); + pImpl->AttrsSet.InsertNode(PA, InsertPoint); + } + + // 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); @@ -50,47 +73,68 @@ Attribute Attribute::get(LLVMContext &Context, Constant *Kind, Constant *Val) { return Attribute(PA); } -Attribute Attribute::get(LLVMContext &Context, AttrKind Kind, Constant *Val) { - ConstantInt *KindVal = ConstantInt::get(Type::getInt64Ty(Context), Kind); - return get(Context, KindVal, Val); -} - Attribute Attribute::getWithAlignment(LLVMContext &Context, uint64_t Align) { assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); assert(Align <= 0x40000000 && "Alignment too large."); - return get(Context, Alignment, - ConstantInt::get(Type::getInt64Ty(Context), Align)); + return get(Context, Alignment, Align); } Attribute Attribute::getWithStackAlignment(LLVMContext &Context, uint64_t Align) { assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); assert(Align <= 0x100 && "Alignment too large."); - return get(Context, StackAlignment, - ConstantInt::get(Type::getInt64Ty(Context), Align)); + return get(Context, StackAlignment, Align); } //===----------------------------------------------------------------------===// // Attribute Accessor Methods //===----------------------------------------------------------------------===// +bool Attribute::isEnumAttribute() const { + return pImpl && pImpl->isEnumAttribute(); +} + +bool Attribute::isAlignAttribute() const { + return pImpl && pImpl->isAlignAttribute(); +} + +bool Attribute::isStringAttribute() const { + return pImpl && pImpl->isStringAttribute(); +} + +Attribute::AttrKind Attribute::getKindAsEnum() const { + assert((isEnumAttribute() || isAlignAttribute()) && + "Invalid attribute type to get the kind as an enum!"); + return pImpl ? pImpl->getKindAsEnum() : None; +} + +uint64_t Attribute::getValueAsInt() const { + assert(isAlignAttribute() && + "Expected the attribute to be an alignment attribute!"); + return pImpl ? pImpl->getValueAsInt() : 0; +} + +StringRef Attribute::getKindAsString() const { + assert(isStringAttribute() && + "Invalid attribute type to get the kind as a string!"); + return pImpl ? pImpl->getKindAsString() : StringRef(); +} + +StringRef Attribute::getValueAsString() const { + assert(isStringAttribute() && + "Invalid attribute type to get the value as a string!"); + return pImpl ? pImpl->getValueAsString() : StringRef(); +} + bool Attribute::hasAttribute(AttrKind Val) const { - return pImpl && pImpl->hasAttribute(Val); -} - -Constant *Attribute::getAttributeKind() const { - return pImpl ? pImpl->getAttributeKind() : 0; -} - -Constant *Attribute::getAttributeValues() const { - return pImpl ? pImpl->getAttributeValues() : 0; + return (pImpl && pImpl->hasAttribute(Val)) || (!pImpl && Val == None); } /// This returns the alignment field of an attribute as a byte alignment value. unsigned Attribute::getAlignment() const { assert(hasAttribute(Attribute::Alignment) && "Trying to get alignment from non-alignment attribute!"); - return pImpl->getAlignment(); + return pImpl->getValueAsInt(); } /// This returns the stack alignment field of an attribute as a byte alignment @@ -98,7 +142,7 @@ unsigned Attribute::getAlignment() const { unsigned Attribute::getStackAlignment() const { assert(hasAttribute(Attribute::StackAlignment) && "Trying to get alignment from non-alignment attribute!"); - return pImpl->getStackAlignment(); + return pImpl->getValueAsInt(); } std::string Attribute::getAsString() const { @@ -166,17 +210,17 @@ std::string Attribute::getAsString() const { // align=4 // alignstack=8 // - if (hasAttribute(Attribute::StackAlignment)) { - std::string Result; - Result += "alignstack("; - Result += utostr(getStackAlignment()); - Result += ")"; - return Result; - } if (hasAttribute(Attribute::Alignment)) { std::string Result; Result += "align "; - Result += utostr(getAlignment()); + Result += utostr(getValueAsInt()); + return Result; + } + if (hasAttribute(Attribute::StackAlignment)) { + std::string Result; + Result += "alignstack("; + Result += utostr(getValueAsInt()); + Result += ")"; return Result; } @@ -186,33 +230,21 @@ std::string Attribute::getAsString() const { // "kind" = "value" // "kind" = ( "value1" "value2" "value3" ) // - if (ConstantDataArray *CDA = - dyn_cast(pImpl->getAttributeKind())) { + if (isStringAttribute()) { std::string Result; - Result += '\"' + CDA->getAsString().str() + '"'; + Result += '\"' + getKindAsString().str() + '"'; - Constant *Vals = pImpl->getAttributeValues(); - if (!Vals) return Result; - - // FIXME: This should support more than just ConstantDataArrays. Also, - // support a vector of attribute values. + StringRef Val = pImpl->getValueAsString(); + if (Val.empty()) return Result; Result += " = "; - Result += '\"' + cast(Vals)->getAsString().str() + '"'; - + Result += '\"' + Val.str() + '"'; return Result; } llvm_unreachable("Unknown attribute"); } -bool Attribute::operator==(AttrKind K) const { - return (pImpl && *pImpl == K) || (!pImpl && K == None); -} -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; @@ -224,68 +256,86 @@ bool Attribute::operator<(Attribute A) const { // AttributeImpl Definition //===----------------------------------------------------------------------===// +AttributeImpl::AttributeImpl(LLVMContext &C, Attribute::AttrKind Kind) + : Context(C), Entry(new EnumAttributeEntry(Kind)) {} + +AttributeImpl::AttributeImpl(LLVMContext &C, Attribute::AttrKind Kind, + unsigned Align) + : Context(C) { + assert((Kind == Attribute::Alignment || Kind == Attribute::StackAlignment) && + "Wrong kind for alignment attribute!"); + Entry = new AlignAttributeEntry(Kind, Align); +} + +AttributeImpl::AttributeImpl(LLVMContext &C, StringRef Kind, StringRef Val) + : Context(C), Entry(new StringAttributeEntry(Kind, Val)) {} + +AttributeImpl::~AttributeImpl() { + delete Entry; +} + +bool AttributeImpl::isEnumAttribute() const { + return isa(Entry); +} + +bool AttributeImpl::isAlignAttribute() const { + return isa(Entry); +} + +bool AttributeImpl::isStringAttribute() const { + return isa(Entry); +} + bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const { - if (ConstantInt *CI = dyn_cast(Kind)) - return CI->getZExtValue() == A; - return false; + if (isStringAttribute()) return false; + return getKindAsEnum() == A; } -uint64_t AttributeImpl::getAlignment() const { - assert(hasAttribute(Attribute::Alignment) && - "Trying to retrieve the alignment from a non-alignment attr!"); - return cast(Values)->getZExtValue(); +bool AttributeImpl::hasAttribute(StringRef Kind) const { + if (!isStringAttribute()) return false; + return getKindAsString() == Kind; } -uint64_t AttributeImpl::getStackAlignment() const { - assert(hasAttribute(Attribute::StackAlignment) && - "Trying to retrieve the stack alignment from a non-alignment attr!"); - return cast(Values)->getZExtValue(); +Attribute::AttrKind AttributeImpl::getKindAsEnum() const { + if (EnumAttributeEntry *E = dyn_cast(Entry)) + return E->getEnumKind(); + return cast(Entry)->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 { + return cast(Entry)->getAlignment(); } -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 { + return cast(Entry)->getStringKind(); } -bool AttributeImpl::operator!=(StringRef kind) const { - return !(*this == kind); +StringRef AttributeImpl::getValueAsString() const { + return cast(Entry)->getStringValue(); } bool AttributeImpl::operator<(const AttributeImpl &AI) const { // This sorts the attributes with Attribute::AttrKinds coming first (sorted // relative to their enum value) and then strings. + if (isEnumAttribute()) + if (AI.isAlignAttribute() || AI.isEnumAttribute()) + return getKindAsEnum() < AI.getKindAsEnum(); - if (!Kind && !AI.Kind) return false; - if (!Kind && AI.Kind) return true; - if (Kind && !AI.Kind) return false; + if (isAlignAttribute()) { + if (!AI.isStringAttribute() && getKindAsEnum() < AI.getKindAsEnum()) + return true; + if (AI.isAlignAttribute()) + return getValueAsInt() < AI.getValueAsInt(); + } - ConstantInt *ThisCI = dyn_cast(Kind); - ConstantInt *ThatCI = dyn_cast(AI.Kind); + if (isStringAttribute()) { + if (!AI.isStringAttribute()) return false; + if (getKindAsString() < AI.getKindAsString()) return true; + if (getKindAsString() == AI.getKindAsString()) + return getValueAsString() < AI.getValueAsString(); + } - 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; - - return ThisCDA->getAsString() < ThatCDA->getAsString(); + return false; } uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) { @@ -413,15 +463,14 @@ uint64_t AttributeSetImpl::Raw(uint64_t Index) const { for (AttributeSetNode::const_iterator II = ASN->begin(), IE = ASN->end(); II != IE; ++II) { Attribute Attr = *II; - ConstantInt *Kind = cast(Attr.getAttributeKind()); - Attribute::AttrKind KindVal = Attribute::AttrKind(Kind->getZExtValue()); + Attribute::AttrKind Kind = Attr.getKindAsEnum(); - if (KindVal == Attribute::Alignment) + if (Kind == Attribute::Alignment) Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16; - else if (KindVal == Attribute::StackAlignment) + else if (Kind == Attribute::StackAlignment) Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26; else - Mask |= AttributeImpl::getAttrMask(KindVal); + Mask |= AttributeImpl::getAttrMask(Kind); } return Mask; @@ -465,7 +514,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 != Attribute::None && + assert(!Attrs[i].second.hasAttribute(Attribute::None) && "Pointless attribute!"); } #endif @@ -815,13 +864,13 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { } AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { - ConstantInt *Kind = cast(Attr.getAttributeKind()); - Attribute::AttrKind KindVal = Attribute::AttrKind(Kind->getZExtValue()); - Attrs.insert(KindVal); + // FIXME: Handle string attributes. + Attribute::AttrKind Kind = Attr.getKindAsEnum(); + Attrs.insert(Kind); - if (KindVal == Attribute::Alignment) + if (Kind == Attribute::Alignment) Alignment = Attr.getAlignment(); - else if (KindVal == Attribute::StackAlignment) + else if (Kind == Attribute::StackAlignment) StackAlignment = Attr.getStackAlignment(); return *this; } @@ -853,8 +902,8 @@ AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) { assert(Idx != ~0U && "Couldn't find index in AttributeSet!"); for (AttributeSet::iterator I = A.begin(Idx), E = A.end(Idx); I != E; ++I) { - ConstantInt *CI = cast(I->getAttributeKind()); - Attribute::AttrKind Kind = Attribute::AttrKind(CI->getZExtValue()); + // FIXME: Support string attributes. + Attribute::AttrKind Kind = I->getKindAsEnum(); Attrs.erase(Kind); if (Kind == Attribute::Alignment) @@ -915,15 +964,10 @@ bool AttrBuilder::hasAttributes(AttributeSet A, uint64_t Index) const { assert(Idx != ~0U && "Couldn't find the index!"); for (AttributeSet::iterator I = A.begin(Idx), E = A.end(Idx); - I != E; ++I) { - Attribute Attr = *I; - // FIXME: Support StringRefs. - ConstantInt *Kind = cast(Attr.getAttributeKind()); - Attribute::AttrKind KindVal = Attribute::AttrKind(Kind->getZExtValue()); - - if (Attrs.count(KindVal)) + I != E; ++I) + // FIXME: Support string attributes. + if (Attrs.count(I->getKindAsEnum())) return true; - } return false; }