diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -187,6 +187,9 @@ // A list of identifiers matching parameters or ParamIdx indices. class VariadicParamOrParamIdxArgument : Argument; +// Like VariadicParamOrParamIdxArgument but for a single function parameter index. +class ParamOrParamIdxArgument : Argument; + // Like VariadicParamIdxArgument but for a single function parameter index. class ParamIdxArgument : Argument; @@ -1631,6 +1634,24 @@ let Documentation = [AllocAlignDocs]; } +def LLVMFN : InheritableAttr { + let Spellings = [GCC<"LLVMFN">]; + let Args = [StringArgument<"AttrName">]; + let Documentation = [Undocumented]; +} + +def LLVMARG : InheritableAttr { + let Spellings = [GCC<"LLVMARG">]; + let Args = [ParamOrParamIdxArgument<"ParamIndex">, StringArgument<"AttrName">]; + let Documentation = [Undocumented]; +} + +def LLVMRET : InheritableAttr { + let Spellings = [GCC<"LLVMRET">]; + let Args = [StringArgument<"AttrName">]; + let Documentation = [Undocumented]; +} + def NoReturn : InheritableAttr { let Spellings = [GCC<"noreturn">, Declspec<"noreturn">]; // FIXME: Does GCC allow this on the function instead? diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -730,6 +730,36 @@ SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast; } + if (D) { + for(auto a: D->attrs()) { + if (auto atr = dyn_cast(a)) { + Fn->addFnAttr(atr->getAttrName()); + } + if (auto atr = dyn_cast(a)) { + std::pair attributeandvalue = atr->getAttrName().split('='); + unsigned index = llvm::AttributeList::FirstArgIndex + atr->getParamIndex(); //.getLLVMIndex(); + llvm::Attribute::AttrKind attrkind = llvm::Attribute::parseAttrKind(attributeandvalue.first); + if (attrkind != llvm::Attribute::None) { + assert(attributeandvalue.second.size() == 0); + Fn->addParamAttr(index, llvm::Attribute::get(Fn->getContext(), attrkind)); + } + else + Fn->addParamAttr(index, llvm::Attribute::get(Fn->getContext(), attributeandvalue.first, attributeandvalue.second)); + } + if (auto atr = dyn_cast(a)) { + std::pair attributeandvalue = atr->getAttrName().split('='); + unsigned index = llvm::AttributeList::ReturnIndex; + llvm::Attribute::AttrKind attrkind = llvm::Attribute::parseAttrKind(attributeandvalue.first); + if (attrkind != llvm::Attribute::None) { + assert(attributeandvalue.second.size() == 0); + Fn->addParamAttr(index, llvm::Attribute::get(Fn->getContext(), attrkind)); + } + else + Fn->addParamAttr(index, llvm::Attribute::get(Fn->getContext(), attributeandvalue.first, attributeandvalue.second)); + } + } + } + // Apply xray attributes to the function (as a string, for now) if (D) { if (const auto *XRayAttr = D->getAttr()) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3456,20 +3456,9 @@ D->addAttr(NewAttr); } -/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes. -static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // The index that identifies the callback callee is mandatory. - if (AL.getNumArgs() == 0) { - S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) - << AL.getRange(); - return; - } - - bool HasImplicitThisParam = isInstanceMethod(D); - int32_t NumArgs = getFunctionOrMethodNumParams(D); - - FunctionDecl *FD = D->getAsFunction(); - assert(FD && "Expected a function declaration!"); +static int32_t getParamFromNameOrIndex(Sema &S, FunctionDecl *FD, const ParsedAttr &AL, unsigned I) { + bool HasImplicitThisParam = isInstanceMethod(FD); + int32_t NumArgs = getFunctionOrMethodNumParams(FD); llvm::StringMap NameIdxMapping; NameIdxMapping["__"] = -1; @@ -3482,8 +3471,6 @@ auto UnknownName = NameIdxMapping.end(); - SmallVector EncodingIndices; - for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) { SourceRange SR; int32_t ArgIdx; @@ -3493,7 +3480,7 @@ if (It == UnknownName) { S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown) << IdLoc->Ident << IdLoc->Loc; - return; + return -1; } SR = SourceRange(IdLoc->Loc); @@ -3506,14 +3493,14 @@ false)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << (I + 1) << IdxExpr->getSourceRange(); - return; + return -1; } // Check oob, excluding the special values, 0 and -1. if (ArgIdx < -1 || ArgIdx > NumArgs) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << (I + 1) << IdxExpr->getSourceRange(); - return; + return -1; } SR = IdxExpr->getSourceRange(); @@ -3524,7 +3511,7 @@ if (ArgIdx == 0 && !HasImplicitThisParam) { S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available) << (I + 1) << SR; - return; + return -1; } // Adjust for the case we do not have an implicit "this" parameter. In this @@ -3532,9 +3519,31 @@ if (!HasImplicitThisParam && ArgIdx > 0) ArgIdx -= 1; + return ArgIdx; +} + +/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes. +static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The index that identifies the callback callee is mandatory. + if (AL.getNumArgs() == 0) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) + << AL.getRange(); + return; + } + + + FunctionDecl *FD = D->getAsFunction(); + assert(FD && "Expected a function declaration!"); + + + SmallVector EncodingIndices; + for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) { + int32_t ArgIdx = getParamFromNameOrIndex(S, FD, AL, I); + if (ArgIdx == -1) return; EncodingIndices.push_back(ArgIdx); } + bool HasImplicitThisParam = isInstanceMethod(FD); int CalleeIdx = EncodingIndices.front(); // Check if the callee index is proper, thus not "this" and not "unknown". // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam" @@ -3737,6 +3746,42 @@ D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); } +template +static void handleSimpleIntStringAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { + // check the attribute arguments. + if (AL.getNumArgs() != 2) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; + return; + } + + Expr *E = AL.getArgAsExpr(0); + + FunctionDecl *FD = D->getAsFunction(); + assert(FD && "Expected a function declaration!"); + + int32_t ArgIdx = getParamFromNameOrIndex(S, FD, AL, 0); + StringRef Str; + S.checkStringLiteralArgumentAttr(AL, 1, Str); + + D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, ArgIdx, Str, + AL.getAttributeSpellingListIndex())); +} + +template +static void handleSimpleStringAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { + // check the attribute arguments. + if (AL.getNumArgs() != 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; + return; + } + + StringRef Str; + S.checkStringLiteralArgumentAttr(AL, 0, Str); + + D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} + static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the attribute arguments. if (AL.getNumArgs() > 1) { @@ -6618,6 +6663,15 @@ S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) << AL << D->getLocation(); break; + case ParsedAttr::AT_LLVMFN: + handleSimpleStringAttribute(S, D, AL); + break; + case ParsedAttr::AT_LLVMARG: + handleSimpleIntStringAttribute(S, D, AL); + break; + case ParsedAttr::AT_LLVMRET: + handleSimpleStringAttribute(S, D, AL); + break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); break; diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1290,6 +1290,8 @@ Ptr = llvm::make_unique(Arg, Attr); else if (ArgName == "VariadicParamOrParamIdxArgument") Ptr = llvm::make_unique(Arg, Attr); + else if (ArgName == "ParamOrParamIdxArgument") + Ptr = llvm::make_unique(Arg, Attr, "int"); else if (ArgName == "ParamIdxArgument") Ptr = llvm::make_unique(Arg, Attr, "ParamIdx"); else if (ArgName == "VariadicIdentifierArgument") @@ -2184,6 +2186,7 @@ llvm::StringSwitch( Arg->getSuperClasses().back().first->getName()) .Case("VariadicParamOrParamIdxArgument", true) + .Case("ParamOrParamIdxArgument", true) .Default(false); } 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 @@ -192,6 +192,8 @@ static Attribute fromRawPointer(void *RawPtr) { return Attribute(reinterpret_cast(RawPtr)); } + + static Attribute::AttrKind parseAttrKind(StringRef Kind); }; // Specialized opaque value conversions. 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 @@ -479,6 +479,48 @@ llvm_unreachable("Unknown attribute"); } +Attribute::AttrKind Attribute::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("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("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) + .Default(Attribute::None); +} + bool Attribute::operator<(Attribute A) const { if (!pImpl && !A.pImpl) return false; if (!pImpl) return true; 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 @@ -24,48 +24,6 @@ "example -force-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("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("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) - .Default(Attribute::None); -} - /// If F has any forced attributes given on the command line, add them. static void addForcedAttributes(Function &F) { for (auto &S : ForceAttributes) { @@ -73,7 +31,7 @@ if (KV.first != F.getName()) continue; - auto Kind = parseAttrKind(KV.second); + auto Kind = Attribute::parseAttrKind(KV.second); if (Kind == Attribute::None) { LLVM_DEBUG(dbgs() << "ForcedAttribute: " << KV.second << " unknown or not handled!\n");