diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -90,6 +90,10 @@ return Kind >= FirstTypeAttr && Kind <= LastTypeAttr; } + static bool canUseAsFnAttr(AttrKind Kind); + static bool canUseAsParamAttr(AttrKind Kind); + static bool canUseAsRetAttr(AttrKind Kind); + private: AttributeImpl *pImpl = nullptr; diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -10,228 +10,243 @@ // //===----------------------------------------------------------------------===// +/// Attribute property base class. +class AttrProperty; + +/// Can be used as function attribute. +def FnAttr : AttrProperty; + +/// Can be used as parameter attribute. +def ParamAttr : AttrProperty; + +/// Can be used as return attribute. +def RetAttr : AttrProperty; + /// Attribute base class. -class Attr { +class Attr P> { // String representation of this attribute in the IR. string AttrString = S; + list Properties = P; } /// Enum attribute. -class EnumAttr : Attr; +class EnumAttr P> : Attr; /// Int attribute. -class IntAttr : Attr; - -/// StringBool attribute. -class StrBoolAttr : Attr; +class IntAttr P> : Attr; /// Type attribute. -class TypeAttr : Attr; +class TypeAttr P> : Attr; + +/// StringBool attribute. +class StrBoolAttr : Attr; /// Target-independent enum attributes. /// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias. /// 0 means unaligned (different from align(1)). -def Alignment : IntAttr<"align">; +def Alignment : IntAttr<"align", [ParamAttr, RetAttr]>; /// The result of the function is guaranteed to point to a number of bytes that /// we can determine if we know the value of the function's arguments. -def AllocSize : IntAttr<"allocsize">; +def AllocSize : IntAttr<"allocsize", [FnAttr]>; /// inline=always. -def AlwaysInline : EnumAttr<"alwaysinline">; +def AlwaysInline : EnumAttr<"alwaysinline", [FnAttr]>; /// Function can access memory only using pointers based on its arguments. -def ArgMemOnly : EnumAttr<"argmemonly">; +def ArgMemOnly : EnumAttr<"argmemonly", [FnAttr]>; /// Callee is recognized as a builtin, despite nobuiltin attribute on its /// declaration. -def Builtin : EnumAttr<"builtin">; +def Builtin : EnumAttr<"builtin", [FnAttr]>; /// Pass structure by value. -def ByVal : TypeAttr<"byval">; +def ByVal : TypeAttr<"byval", [ParamAttr]>; /// Mark in-memory ABI type. -def ByRef : TypeAttr<"byref">; +def ByRef : TypeAttr<"byref", [ParamAttr]>; /// Parameter or return value may not contain uninitialized or poison bits. -def NoUndef : EnumAttr<"noundef">; +def NoUndef : EnumAttr<"noundef", [ParamAttr, RetAttr]>; /// Marks function as being in a cold path. -def Cold : EnumAttr<"cold">; +def Cold : EnumAttr<"cold", [FnAttr]>; /// Can only be moved to control-equivalent blocks. -def Convergent : EnumAttr<"convergent">; +def Convergent : EnumAttr<"convergent", [FnAttr]>; /// Marks function as being in a hot path and frequently called. -def Hot: EnumAttr<"hot">; +def Hot: EnumAttr<"hot", [FnAttr]>; /// Pointer is known to be dereferenceable. -def Dereferenceable : IntAttr<"dereferenceable">; +def Dereferenceable : IntAttr<"dereferenceable", [ParamAttr, RetAttr]>; /// Pointer is either null or dereferenceable. -def DereferenceableOrNull : IntAttr<"dereferenceable_or_null">; +def DereferenceableOrNull : IntAttr<"dereferenceable_or_null", + [ParamAttr, RetAttr]>; /// Function may only access memory that is inaccessible from IR. -def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly">; +def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly", [FnAttr]>; /// Function may only access memory that is either inaccessible from the IR, /// or pointed to by its pointer arguments. -def InaccessibleMemOrArgMemOnly : EnumAttr<"inaccessiblemem_or_argmemonly">; +def InaccessibleMemOrArgMemOnly : EnumAttr<"inaccessiblemem_or_argmemonly", + [FnAttr]>; /// Pass structure in an alloca. -def InAlloca : TypeAttr<"inalloca">; +def InAlloca : TypeAttr<"inalloca", [ParamAttr]>; /// Source said inlining was desirable. -def InlineHint : EnumAttr<"inlinehint">; +def InlineHint : EnumAttr<"inlinehint", [FnAttr]>; /// Force argument to be passed in register. -def InReg : EnumAttr<"inreg">; +def InReg : EnumAttr<"inreg", [ParamAttr, RetAttr]>; /// Build jump-instruction tables and replace refs. -def JumpTable : EnumAttr<"jumptable">; +def JumpTable : EnumAttr<"jumptable", [FnAttr]>; /// Function must be optimized for size first. -def MinSize : EnumAttr<"minsize">; +def MinSize : EnumAttr<"minsize", [FnAttr]>; /// Naked function. -def Naked : EnumAttr<"naked">; +def Naked : EnumAttr<"naked", [FnAttr]>; /// Nested function static chain. -def Nest : EnumAttr<"nest">; +def Nest : EnumAttr<"nest", [ParamAttr]>; /// Considered to not alias after call. -def NoAlias : EnumAttr<"noalias">; +def NoAlias : EnumAttr<"noalias", [ParamAttr, RetAttr]>; /// Callee isn't recognized as a builtin. -def NoBuiltin : EnumAttr<"nobuiltin">; +def NoBuiltin : EnumAttr<"nobuiltin", [FnAttr]>; /// Function cannot enter into caller's translation unit. -def NoCallback : EnumAttr<"nocallback">; +def NoCallback : EnumAttr<"nocallback", [FnAttr]>; /// Function creates no aliases of pointer. -def NoCapture : EnumAttr<"nocapture">; +def NoCapture : EnumAttr<"nocapture", [ParamAttr]>; /// Call cannot be duplicated. -def NoDuplicate : EnumAttr<"noduplicate">; +def NoDuplicate : EnumAttr<"noduplicate", [FnAttr]>; /// Function does not deallocate memory. -def NoFree : EnumAttr<"nofree">; +def NoFree : EnumAttr<"nofree", [FnAttr, ParamAttr]>; /// Disable implicit floating point insts. -def NoImplicitFloat : EnumAttr<"noimplicitfloat">; +def NoImplicitFloat : EnumAttr<"noimplicitfloat", [FnAttr]>; /// inline=never. -def NoInline : EnumAttr<"noinline">; +def NoInline : EnumAttr<"noinline", [FnAttr]>; /// Function is called early and/or often, so lazy binding isn't worthwhile. -def NonLazyBind : EnumAttr<"nonlazybind">; +def NonLazyBind : EnumAttr<"nonlazybind", [FnAttr]>; /// Disable merging for specified functions or call sites. -def NoMerge : EnumAttr<"nomerge">; +def NoMerge : EnumAttr<"nomerge", [FnAttr]>; /// Pointer is known to be not null. -def NonNull : EnumAttr<"nonnull">; +def NonNull : EnumAttr<"nonnull", [ParamAttr, RetAttr]>; /// The function does not recurse. -def NoRecurse : EnumAttr<"norecurse">; +def NoRecurse : EnumAttr<"norecurse", [FnAttr]>; /// Disable redzone. -def NoRedZone : EnumAttr<"noredzone">; +def NoRedZone : EnumAttr<"noredzone", [FnAttr]>; /// Mark the function as not returning. -def NoReturn : EnumAttr<"noreturn">; +def NoReturn : EnumAttr<"noreturn", [FnAttr]>; /// Function does not synchronize. -def NoSync : EnumAttr<"nosync">; +def NoSync : EnumAttr<"nosync", [FnAttr]>; /// Disable Indirect Branch Tracking. -def NoCfCheck : EnumAttr<"nocf_check">; +def NoCfCheck : EnumAttr<"nocf_check", [FnAttr]>; /// Function should not be instrumented. -def NoProfile : EnumAttr<"noprofile">; +def NoProfile : EnumAttr<"noprofile", [FnAttr]>; /// Function doesn't unwind stack. -def NoUnwind : EnumAttr<"nounwind">; +def NoUnwind : EnumAttr<"nounwind", [FnAttr]>; /// No SanitizeCoverage instrumentation. -def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage">; +def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage", [FnAttr]>; /// Null pointer in address space zero is valid. -def NullPointerIsValid : EnumAttr<"null_pointer_is_valid">; +def NullPointerIsValid : EnumAttr<"null_pointer_is_valid", [FnAttr]>; /// Select optimizations for best fuzzing signal. -def OptForFuzzing : EnumAttr<"optforfuzzing">; +def OptForFuzzing : EnumAttr<"optforfuzzing", [FnAttr]>; /// opt_size. -def OptimizeForSize : EnumAttr<"optsize">; +def OptimizeForSize : EnumAttr<"optsize", [FnAttr]>; /// Function must not be optimized. -def OptimizeNone : EnumAttr<"optnone">; +def OptimizeNone : EnumAttr<"optnone", [FnAttr]>; /// Similar to byval but without a copy. -def Preallocated : TypeAttr<"preallocated">; +def Preallocated : TypeAttr<"preallocated", [FnAttr, ParamAttr]>; /// Function does not access memory. -def ReadNone : EnumAttr<"readnone">; +def ReadNone : EnumAttr<"readnone", [FnAttr, ParamAttr]>; /// Function only reads from memory. -def ReadOnly : EnumAttr<"readonly">; +def ReadOnly : EnumAttr<"readonly", [FnAttr, ParamAttr]>; /// Return value is always equal to this argument. -def Returned : EnumAttr<"returned">; +def Returned : EnumAttr<"returned", [ParamAttr]>; /// Parameter is required to be a trivial constant. -def ImmArg : EnumAttr<"immarg">; +def ImmArg : EnumAttr<"immarg", [ParamAttr]>; /// Function can return twice. -def ReturnsTwice : EnumAttr<"returns_twice">; +def ReturnsTwice : EnumAttr<"returns_twice", [FnAttr]>; /// Safe Stack protection. -def SafeStack : EnumAttr<"safestack">; +def SafeStack : EnumAttr<"safestack", [FnAttr]>; /// Shadow Call Stack protection. -def ShadowCallStack : EnumAttr<"shadowcallstack">; +def ShadowCallStack : EnumAttr<"shadowcallstack", [FnAttr]>; /// Sign extended before/after call. -def SExt : EnumAttr<"signext">; +def SExt : EnumAttr<"signext", [ParamAttr, RetAttr]>; /// Alignment of stack for function (3 bits) stored as log2 of alignment with /// +1 bias 0 means unaligned (different from alignstack=(1)). -def StackAlignment : IntAttr<"alignstack">; +def StackAlignment : IntAttr<"alignstack", [FnAttr, ParamAttr]>; /// Function can be speculated. -def Speculatable : EnumAttr<"speculatable">; +def Speculatable : EnumAttr<"speculatable", [FnAttr]>; /// Stack protection. -def StackProtect : EnumAttr<"ssp">; +def StackProtect : EnumAttr<"ssp", [FnAttr]>; /// Stack protection required. -def StackProtectReq : EnumAttr<"sspreq">; +def StackProtectReq : EnumAttr<"sspreq", [FnAttr]>; /// Strong Stack protection. -def StackProtectStrong : EnumAttr<"sspstrong">; +def StackProtectStrong : EnumAttr<"sspstrong", [FnAttr]>; /// Function was called in a scope requiring strict floating point semantics. -def StrictFP : EnumAttr<"strictfp">; +def StrictFP : EnumAttr<"strictfp", [FnAttr]>; /// Hidden pointer to structure to return. -def StructRet : TypeAttr<"sret">; +def StructRet : TypeAttr<"sret", [ParamAttr]>; /// AddressSanitizer is on. -def SanitizeAddress : EnumAttr<"sanitize_address">; +def SanitizeAddress : EnumAttr<"sanitize_address", [FnAttr]>; /// ThreadSanitizer is on. -def SanitizeThread : EnumAttr<"sanitize_thread">; +def SanitizeThread : EnumAttr<"sanitize_thread", [FnAttr]>; /// MemorySanitizer is on. -def SanitizeMemory : EnumAttr<"sanitize_memory">; +def SanitizeMemory : EnumAttr<"sanitize_memory", [FnAttr]>; /// HWAddressSanitizer is on. -def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress">; +def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress", [FnAttr]>; /// MemTagSanitizer is on. -def SanitizeMemTag : EnumAttr<"sanitize_memtag">; +def SanitizeMemTag : EnumAttr<"sanitize_memtag", [FnAttr]>; /// Speculative Load Hardening is enabled. /// @@ -239,34 +254,35 @@ /// inlining) and a conservative merge strategy where inlining an attributed /// body will add the attribute to the caller. This ensures that code carrying /// this attribute will always be lowered with hardening enabled. -def SpeculativeLoadHardening : EnumAttr<"speculative_load_hardening">; +def SpeculativeLoadHardening : EnumAttr<"speculative_load_hardening", + [FnAttr]>; /// Argument is swift error. -def SwiftError : EnumAttr<"swifterror">; +def SwiftError : EnumAttr<"swifterror", [ParamAttr]>; /// Argument is swift self/context. -def SwiftSelf : EnumAttr<"swiftself">; +def SwiftSelf : EnumAttr<"swiftself", [ParamAttr]>; /// Argument is swift async context. -def SwiftAsync : EnumAttr<"swiftasync">; +def SwiftAsync : EnumAttr<"swiftasync", [ParamAttr]>; /// Function must be in a unwind table. -def UWTable : EnumAttr<"uwtable">; +def UWTable : EnumAttr<"uwtable", [FnAttr]>; /// Minimum/Maximum vscale value for function. -def VScaleRange : IntAttr<"vscale_range">; +def VScaleRange : IntAttr<"vscale_range", [FnAttr]>; /// Function always comes back to callsite. -def WillReturn : EnumAttr<"willreturn">; +def WillReturn : EnumAttr<"willreturn", [FnAttr]>; /// Function only writes to memory. -def WriteOnly : EnumAttr<"writeonly">; +def WriteOnly : EnumAttr<"writeonly", [FnAttr, ParamAttr]>; /// Zero extended before/after call. -def ZExt : EnumAttr<"zeroext">; +def ZExt : EnumAttr<"zeroext", [ParamAttr, RetAttr]>; /// Function is required to make Forward Progress. -def MustProgress : EnumAttr<"mustprogress">; +def MustProgress : EnumAttr<"mustprogress", [FnAttr]>; /// Target-independent string attributes. def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -485,6 +485,35 @@ ID.AddPointer(pImpl); } +enum AttributeProperty { + FnAttr = (1 << 0), + ParamAttr = (1 << 1), + RetAttr = (1 << 2), +}; + +#define GET_ATTR_PROP_TABLE +#include "llvm/IR/Attributes.inc" + +static bool hasAttributeProperty(Attribute::AttrKind Kind, + AttributeProperty Prop) { + unsigned Index = Kind - 1; + assert(Index < sizeof(AttrPropTable) / sizeof(AttrPropTable[0]) && + "Invalid attribute kind"); + return AttrPropTable[Index] & Prop; +} + +bool Attribute::canUseAsFnAttr(AttrKind Kind) { + return hasAttributeProperty(Kind, AttributeProperty::FnAttr); +} + +bool Attribute::canUseAsParamAttr(AttrKind Kind) { + return hasAttributeProperty(Kind, AttributeProperty::ParamAttr); +} + +bool Attribute::canUseAsRetAttr(AttrKind Kind) { + return hasAttributeProperty(Kind, AttributeProperty::RetAttr); +} + //===----------------------------------------------------------------------===// // AttributeImpl Definition //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -540,8 +540,7 @@ void verifyTailCCMustTailAttrs(AttrBuilder Attrs, StringRef Context); void verifyMustTailCall(CallInst &CI); bool verifyAttributeCount(AttributeList Attrs, unsigned Params); - void verifyAttributeTypes(AttributeSet Attrs, bool IsFunction, - const Value *V); + void verifyAttributeTypes(AttributeSet Attrs, const Value *V); void verifyParameterAttrs(AttributeSet Attrs, Type *Ty, const Value *V); void checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr, const Value *V); @@ -1654,76 +1653,7 @@ "expected an integer constant", Node->getOperand(2)); } -/// Return true if this attribute kind only applies to functions. -static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { - switch (Kind) { - case Attribute::NoMerge: - case Attribute::NoReturn: - case Attribute::NoSync: - case Attribute::WillReturn: - case Attribute::NoCallback: - case Attribute::NoCfCheck: - case Attribute::NoUnwind: - case Attribute::NoInline: - case Attribute::NoSanitizeCoverage: - case Attribute::AlwaysInline: - case Attribute::OptimizeForSize: - case Attribute::StackProtect: - case Attribute::StackProtectReq: - case Attribute::StackProtectStrong: - case Attribute::SafeStack: - case Attribute::ShadowCallStack: - case Attribute::NoRedZone: - case Attribute::NoImplicitFloat: - case Attribute::Naked: - case Attribute::InlineHint: - case Attribute::UWTable: - case Attribute::VScaleRange: - case Attribute::NonLazyBind: - case Attribute::ReturnsTwice: - case Attribute::SanitizeAddress: - case Attribute::SanitizeHWAddress: - case Attribute::SanitizeMemTag: - case Attribute::SanitizeThread: - case Attribute::SanitizeMemory: - case Attribute::MinSize: - case Attribute::NoDuplicate: - case Attribute::Builtin: - case Attribute::NoBuiltin: - case Attribute::Cold: - case Attribute::Hot: - case Attribute::OptForFuzzing: - case Attribute::OptimizeNone: - case Attribute::JumpTable: - case Attribute::Convergent: - case Attribute::ArgMemOnly: - case Attribute::NoRecurse: - case Attribute::InaccessibleMemOnly: - case Attribute::InaccessibleMemOrArgMemOnly: - case Attribute::AllocSize: - case Attribute::SpeculativeLoadHardening: - case Attribute::Speculatable: - case Attribute::StrictFP: - case Attribute::NullPointerIsValid: - case Attribute::MustProgress: - case Attribute::NoProfile: - return true; - default: - break; - } - return false; -} - -/// Return true if this is a function attribute that can also appear on -/// arguments. -static bool isFuncOrArgAttr(Attribute::AttrKind Kind) { - return Kind == Attribute::ReadOnly || Kind == Attribute::WriteOnly || - Kind == Attribute::ReadNone || Kind == Attribute::NoFree || - Kind == Attribute::Preallocated || Kind == Attribute::StackAlignment; -} - -void Verifier::verifyAttributeTypes(AttributeSet Attrs, bool IsFunction, - const Value *V) { +void Verifier::verifyAttributeTypes(AttributeSet Attrs, const Value *V) { for (Attribute A : Attrs) { if (A.isStringAttribute()) { @@ -1746,20 +1676,6 @@ V); return; } - - if (isFuncOnlyAttr(A.getKindAsEnum())) { - if (!IsFunction) { - CheckFailed("Attribute '" + A.getAsString() + - "' only applies to functions!", - V); - return; - } - } else if (IsFunction && !isFuncOrArgAttr(A.getKindAsEnum())) { - CheckFailed("Attribute '" + A.getAsString() + - "' does not apply to functions!", - V); - return; - } } } @@ -1770,7 +1686,14 @@ if (!Attrs.hasAttributes()) return; - verifyAttributeTypes(Attrs, /*IsFunction=*/false, V); + verifyAttributeTypes(Attrs, V); + + for (Attribute Attr : Attrs) + Assert(Attr.isStringAttribute() || + Attribute::canUseAsParamAttr(Attr.getKindAsEnum()), + "Attribute '" + Attr.getAsString() + + "' does not apply to parameters", + V); if (Attrs.hasAttribute(Attribute::ImmArg)) { Assert(Attrs.getNumAttributes() == 1, @@ -1941,29 +1864,13 @@ // Verify return value attributes. AttributeSet RetAttrs = Attrs.getRetAttributes(); - Assert((!RetAttrs.hasAttribute(Attribute::ByVal) && - !RetAttrs.hasAttribute(Attribute::Nest) && - !RetAttrs.hasAttribute(Attribute::StructRet) && - !RetAttrs.hasAttribute(Attribute::NoCapture) && - !RetAttrs.hasAttribute(Attribute::NoFree) && - !RetAttrs.hasAttribute(Attribute::Returned) && - !RetAttrs.hasAttribute(Attribute::InAlloca) && - !RetAttrs.hasAttribute(Attribute::Preallocated) && - !RetAttrs.hasAttribute(Attribute::ByRef) && - !RetAttrs.hasAttribute(Attribute::SwiftSelf) && - !RetAttrs.hasAttribute(Attribute::SwiftAsync) && - !RetAttrs.hasAttribute(Attribute::SwiftError)), - "Attributes 'byval', 'inalloca', 'preallocated', 'byref', " - "'nest', 'sret', 'nocapture', 'nofree', " - "'returned', 'swiftself', 'swiftasync', and 'swifterror'" - " do not apply to return values!", - V); - Assert((!RetAttrs.hasAttribute(Attribute::ReadOnly) && - !RetAttrs.hasAttribute(Attribute::WriteOnly) && - !RetAttrs.hasAttribute(Attribute::ReadNone)), - "Attribute '" + RetAttrs.getAsString() + - "' does not apply to function returns", - V); + for (Attribute RetAttr : RetAttrs) + Assert(RetAttr.isStringAttribute() || + Attribute::canUseAsRetAttr(RetAttr.getKindAsEnum()), + "Attribute '" + RetAttr.getAsString() + + "' does not apply to function return values", + V); + verifyParameterAttrs(RetAttrs, FT->getReturnType(), V); // Verify parameter attributes. @@ -2024,7 +1931,13 @@ if (!Attrs.hasAttributes(AttributeList::FunctionIndex)) return; - verifyAttributeTypes(Attrs.getFnAttributes(), /*IsFunction=*/true, V); + verifyAttributeTypes(Attrs.getFnAttributes(), V); + for (Attribute FnAttr : Attrs.getFnAttributes()) + Assert(FnAttr.isStringAttribute() || + Attribute::canUseAsFnAttr(FnAttr.getKindAsEnum()), + "Attribute '" + FnAttr.getAsString() + + "' does not apply to functions!", + V); Assert(!(Attrs.hasFnAttribute(Attribute::ReadNone) && Attrs.hasFnAttribute(Attribute::ReadOnly)), @@ -4705,10 +4618,10 @@ Assert(ArgCount == 2, "this attribute should have 2 arguments"); Assert(isa(Call.getOperand(Elem.Begin + 1)), "the second argument should be a constant integral value"); - } else if (isFuncOnlyAttr(Kind)) { - Assert((ArgCount) == 0, "this attribute has no argument"); - } else if (!isFuncOrArgAttr(Kind)) { + } else if (Attribute::canUseAsParamAttr(Kind)) { Assert((ArgCount) == 1, "this attribute should have one argument"); + } else if (Attribute::canUseAsFnAttr(Kind)) { + Assert((ArgCount) == 0, "this attribute has no argument"); } } break; diff --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/ForceFunctionAttrs.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -33,51 +32,6 @@ "example -force-remove-attribute=foo:noinline. This " "option can be specified multiple times.")); -static Attribute::AttrKind parseAttrKind(StringRef Kind) { - return StringSwitch(Kind) - .Case("alwaysinline", Attribute::AlwaysInline) - .Case("builtin", Attribute::Builtin) - .Case("cold", Attribute::Cold) - .Case("convergent", Attribute::Convergent) - .Case("inlinehint", Attribute::InlineHint) - .Case("jumptable", Attribute::JumpTable) - .Case("minsize", Attribute::MinSize) - .Case("naked", Attribute::Naked) - .Case("nobuiltin", Attribute::NoBuiltin) - .Case("noduplicate", Attribute::NoDuplicate) - .Case("noimplicitfloat", Attribute::NoImplicitFloat) - .Case("noinline", Attribute::NoInline) - .Case("nonlazybind", Attribute::NonLazyBind) - .Case("noredzone", Attribute::NoRedZone) - .Case("noreturn", Attribute::NoReturn) - .Case("nocf_check", Attribute::NoCfCheck) - .Case("norecurse", Attribute::NoRecurse) - .Case("nounwind", Attribute::NoUnwind) - .Case("nosanitize_coverage", Attribute::NoSanitizeCoverage) - .Case("optforfuzzing", Attribute::OptForFuzzing) - .Case("optnone", Attribute::OptimizeNone) - .Case("optsize", Attribute::OptimizeForSize) - .Case("readnone", Attribute::ReadNone) - .Case("readonly", Attribute::ReadOnly) - .Case("argmemonly", Attribute::ArgMemOnly) - .Case("returns_twice", Attribute::ReturnsTwice) - .Case("safestack", Attribute::SafeStack) - .Case("shadowcallstack", Attribute::ShadowCallStack) - .Case("sanitize_address", Attribute::SanitizeAddress) - .Case("sanitize_hwaddress", Attribute::SanitizeHWAddress) - .Case("sanitize_memory", Attribute::SanitizeMemory) - .Case("sanitize_thread", Attribute::SanitizeThread) - .Case("sanitize_memtag", Attribute::SanitizeMemTag) - .Case("speculative_load_hardening", Attribute::SpeculativeLoadHardening) - .Case("ssp", Attribute::StackProtect) - .Case("sspreq", Attribute::StackProtectReq) - .Case("sspstrong", Attribute::StackProtectStrong) - .Case("strictfp", Attribute::StrictFP) - .Case("uwtable", Attribute::UWTable) - .Case("vscale_range", Attribute::VScaleRange) - .Default(Attribute::None); -} - /// If F has any forced attributes given on the command line, add them. /// If F has any forced remove attributes given on the command line, remove /// them. When both force and force-remove are given to a function, the latter @@ -88,10 +42,10 @@ auto KV = StringRef(S).split(':'); if (KV.first != F.getName()) return Kind; - Kind = parseAttrKind(KV.second); - if (Kind == Attribute::None) { + Kind = Attribute::getAttrKindFromName(KV.second); + if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) { LLVM_DEBUG(dbgs() << "ForcedAttribute: " << KV.second - << " unknown or not handled!\n"); + << " unknown or not a function attribute!\n"); } return Kind; }; diff --git a/llvm/unittests/IR/VerifierTest.cpp b/llvm/unittests/IR/VerifierTest.cpp --- a/llvm/unittests/IR/VerifierTest.cpp +++ b/llvm/unittests/IR/VerifierTest.cpp @@ -106,7 +106,7 @@ raw_string_ostream ErrorOS(Error); EXPECT_TRUE(verifyModule(M, &ErrorOS)); EXPECT_TRUE(StringRef(ErrorOS.str()).startswith( - "Attribute 'uwtable' only applies to functions!")); + "Attribute 'uwtable' does not apply to function return values")); } TEST(VerifierTest, CrossModuleRef) { diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp --- a/llvm/utils/TableGen/Attributes.cpp +++ b/llvm/utils/TableGen/Attributes.cpp @@ -25,6 +25,7 @@ private: void emitTargetIndependentNames(raw_ostream &OS); void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); + void emitAttributeProperties(raw_ostream &OF); RecordKeeper &Records; }; @@ -109,9 +110,26 @@ OS << "#endif\n"; } +void Attributes::emitAttributeProperties(raw_ostream &OS) { + OS << "#ifdef GET_ATTR_PROP_TABLE\n"; + OS << "#undef GET_ATTR_PROP_TABLE\n"; + OS << "static const uint8_t AttrPropTable[] = {\n"; + for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) { + for (auto A : Records.getAllDerivedDefinitions(KindName)) { + OS << "0"; + for (Init *P : *A->getValueAsListInit("Properties")) + OS << " | AttributeProperty::" << cast(P)->getDef()->getName(); + OS << ",\n"; + } + } + OS << "};\n"; + OS << "#endif\n"; +} + void Attributes::emit(raw_ostream &OS) { emitTargetIndependentNames(OS); emitFnAttrCompatCheck(OS, false); + emitAttributeProperties(OS); } namespace llvm {