Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ 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 = [Clang<"fn_attr">]; + let Args = [StringArgument<"AttrName">]; + let Documentation = [Undocumented]; +} + +def LLVMARG : InheritableAttr { + let Spellings = [Clang<"arg_attr">]; + let Args = [ParamOrParamIdxArgument<"ParamIndex">, StringArgument<"AttrName">]; + let Documentation = [Undocumented]; +} + +def LLVMRET : InheritableAttr { + let Spellings = [Clang<"ret_attr">]; + 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? Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -44,6 +44,8 @@ InGroup; def remark_fe_backend_optimization_remark_analysis : Remark<"%0">, BackendInfo, InGroup; +def remark_fe_backend_optimization_remark_annotation : Remark<"%0">, BackendInfo, + InGroup; def remark_fe_backend_optimization_remark_analysis_fpcommute : Remark<"%0; " "allow reordering by specifying '#pragma clang loop vectorize(enable)' " "before the loop or by providing the compiler option '-ffast-math'.">, Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -1013,6 +1013,7 @@ def BackendFrameLargerThanEQ : DiagGroup<"frame-larger-than=">; def BackendPlugin : DiagGroup<"backend-plugin">; def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">; +def BackendOptimizationRemarkAnnotation : DiagGroup<"annotation">; def BackendOptimizationRemark : DiagGroup<"pass">; def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">; def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; Index: clang/lib/CodeGen/CodeGenAction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenAction.cpp +++ clang/lib/CodeGen/CodeGenAction.cpp @@ -369,6 +369,8 @@ unsigned DiagID); void OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D); + void OptimizationRemarkHandler( + const llvm::OptimizationRemarkAnnotation &D); void OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisFPCommute &D); void OptimizationRemarkHandler( @@ -681,6 +683,27 @@ } } +void BackendConsumer::OptimizationRemarkHandler( + const llvm::OptimizationRemarkAnnotation &D) { + // Optimization analysis remarks are active if the pass name is set to + // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a + // regular expression that matches the name of the pass name in \p D. + + StringRef Filename; + unsigned Line, Column; + bool BadDebugInfo = false; + FullSourceLoc Loc = + getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + + std::string Msg; + raw_string_ostream MsgStream(Msg); + MsgStream << D.getMsg(); + + Diags.Report(Loc, diag::remark_fe_backend_optimization_remark_annotation) + << MsgStream.str() + ; +} + void BackendConsumer::OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisFPCommute &D) { // Optimization analysis remarks are active if the pass name is set to @@ -751,6 +774,11 @@ // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; + case llvm::DK_OptimizationRemarkAnnotation: + // Optimization remarks are always handled completely by this + // handler. There is no generic way of emitting them. + OptimizationRemarkHandler(cast(DI)); + return; case llvm::DK_OptimizationRemarkAnalysisFPCommute: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -730,6 +730,43 @@ SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast; } + if (D) { + for(auto Attr: D->attrs()) { + if (isa(Attr) || isa(Attr) || isa(Attr)) { + std::pair AttributeAndValue; + int Index; + + if (auto RetAttr = dyn_cast(Attr)) { + AttributeAndValue = RetAttr->getAttrName().split('='); + Index = llvm::AttributeList::ReturnIndex; + } else if (auto ArgAttr = dyn_cast(Attr)) { + AttributeAndValue = ArgAttr->getAttrName().split('='); + Index = llvm::AttributeList::FirstArgIndex + ArgAttr->getParamIndex(); + } else if (auto ArgAttr = dyn_cast(Attr)) { + AttributeAndValue = ArgAttr->getAttrName().split('='); + Index = -1; + } else assert(0 && "must be llvm ret or arg attribute"); + + llvm::Attribute::AttrKind AttrKind = llvm::Attribute::parseAttrKind(AttributeAndValue.first); + if (AttrKind != llvm::Attribute::None) { + assert(AttributeAndValue.second.size() == 0 && "Enum Attribute cannot have value"); + if (Index == -1) { + Fn->addFnAttr(llvm::Attribute::get(Fn->getContext(), AttrKind)); + } else { + Fn->addParamAttr(Index, llvm::Attribute::get(Fn->getContext(), AttrKind)); + } + } + else { + if (Index == -1) { + Fn->addFnAttr(llvm::Attribute::get(Fn->getContext(), AttributeAndValue.first, AttributeAndValue.second)); + } 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()) { Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ 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; Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ 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); } Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ 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. Index: llvm/include/llvm/IR/DiagnosticInfo.h =================================================================== --- llvm/include/llvm/IR/DiagnosticInfo.h +++ llvm/include/llvm/IR/DiagnosticInfo.h @@ -64,6 +64,7 @@ DK_OptimizationRemarkAnalysis, DK_OptimizationRemarkAnalysisFPCommute, DK_OptimizationRemarkAnalysisAliasing, + DK_OptimizationRemarkAnnotation, DK_OptimizationFailure, DK_FirstRemark = DK_OptimizationRemark, DK_LastRemark = DK_OptimizationFailure, @@ -688,6 +689,11 @@ OptimizationRemark(const char *PassName, StringRef RemarkName, const Function *Func); + /// Same as above, but the debug location and code region are derived from \p + /// Func with custom enum. + OptimizationRemark(enum DiagnosticKind Kind, const char *PassName, StringRef RemarkName, + const Function *Func); + static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemark; } @@ -819,6 +825,26 @@ PassName, Fn, Loc, Msg) {} }; +/// Diagnostic information for optimization analysis remarks related to +/// annotation emission +class OptimizationRemarkAnnotation : public OptimizationRemark { +public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass-analysis=, then the + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). The front-end will append its own message related to + /// options that address floating-point non-commutativity. + OptimizationRemarkAnnotation(const char *PassName, + StringRef RemarkName, + const Function *Fn) + : OptimizationRemark(DK_OptimizationRemarkAnnotation, PassName, RemarkName, Fn) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_OptimizationRemarkAnnotation; + } +}; /// Diagnostic information for optimization analysis remarks related to /// floating-point non-commutativity. class OptimizationRemarkAnalysisFPCommute : public OptimizationRemarkAnalysis { Index: llvm/include/llvm/InitializePasses.h =================================================================== --- llvm/include/llvm/InitializePasses.h +++ llvm/include/llvm/InitializePasses.h @@ -136,6 +136,7 @@ void initializeEarlyTailDuplicatePass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry&); +void initializeEmitAnnotationsLegacyPassPass(PassRegistry&); void initializeEntryExitInstrumenterPass(PassRegistry&); void initializeExpandMemCmpPassPass(PassRegistry&); void initializeExpandPostRAPass(PassRegistry&); Index: llvm/include/llvm/LinkAllPasses.h =================================================================== --- llvm/include/llvm/LinkAllPasses.h +++ llvm/include/llvm/LinkAllPasses.h @@ -100,6 +100,7 @@ (void) llvm::createDomPrinterPass(); (void) llvm::createDomOnlyViewerPass(); (void) llvm::createDomViewerPass(); + (void) llvm::createEmitAnnotationsPass(); (void) llvm::createGCOVProfilerPass(); (void) llvm::createPGOInstrumentationGenLegacyPass(); (void) llvm::createPGOInstrumentationUseLegacyPass(); Index: llvm/include/llvm/Transforms/Utils.h =================================================================== --- llvm/include/llvm/Transforms/Utils.h +++ llvm/include/llvm/Transforms/Utils.h @@ -98,6 +98,13 @@ // FunctionPass *createPromoteMemoryToRegisterPass(); + +//===----------------------------------------------------------------------===// +// +// EmitAnnotations - This pass is used to create annotations about derived LLVM +// information that can be fed back in through the front end +FunctionPass *createEmitAnnotationsPass(); + //===----------------------------------------------------------------------===// // // LoopSimplify - Insert Pre-header blocks into the CFG for every function in Index: llvm/include/llvm/Transforms/Utils/EmitAnnotations.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Utils/EmitAnnotations.h @@ -0,0 +1,31 @@ +//===-- EmitAnnotations.h - Emit Annotations Pass -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file emits function annotations +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_EMIT_ANNOTATIONS_H +#define LLVM_TRANSFORMS_UTILS_EMIT_ANNOTATIONS_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Simple pass that canonicalizes aliases. +class EmitAnnotationsPass : public PassInfoMixin { +public: + EmitAnnotationsPass() = default; + + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_EMIT_ANNOTATIONS_H Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ 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; Index: llvm/lib/IR/DiagnosticInfo.cpp =================================================================== --- llvm/lib/IR/DiagnosticInfo.cpp +++ llvm/lib/IR/DiagnosticInfo.cpp @@ -257,6 +257,13 @@ RemarkName, *Func, Func->getSubprogram(), &getFirstFunctionBlock(Func)) {} +OptimizationRemark::OptimizationRemark(enum DiagnosticKind kind, const char *PassName, + StringRef RemarkName, + const Function *Func) + : DiagnosticInfoIROptimization(kind, DS_Remark, PassName, + RemarkName, *Func, Func->getSubprogram(), + &getFirstFunctionBlock(Func)) {} + bool OptimizationRemark::isEnabled() const { const Function &Fn = getFunction(); LLVMContext &Ctx = Fn.getContext(); Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -163,6 +163,8 @@ #include "llvm/Transforms/Utils/BreakCriticalEdges.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/EmitAnnotations.h" #include "llvm/Transforms/Utils/LCSSA.h" #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h" #include "llvm/Transforms/Utils/LoopSimplify.h" @@ -997,6 +999,10 @@ // Now add the optimization pipeline. MPM.addPass(buildModuleOptimizationPipeline(Level, DebugLogging, LTOPreLink)); + FunctionPassManager FPM(DebugLogging); + FPM.addPass(EmitAnnotationsPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + return MPM; } Index: llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ 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"); Index: llvm/lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -777,7 +777,7 @@ MPM.add(createCFGSimplificationPass()); addExtensionsToPM(EP_OptimizerLast, MPM); - + MPM.add(createEmitAnnotationsPass()); if (PrepareForLTO) { MPM.add(createCanonicalizeAliasesPass()); // Rename anon globals to be able to handle them in the summary Index: llvm/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Utils/CMakeLists.txt +++ llvm/lib/Transforms/Utils/CMakeLists.txt @@ -12,6 +12,7 @@ CodeExtractor.cpp CtorUtils.cpp DemoteRegToStack.cpp + EmitAnnotations.cpp EntryExitInstrumenter.cpp EscapeEnumerator.cpp Evaluator.cpp Index: llvm/lib/Transforms/Utils/EmitAnnotations.cpp =================================================================== --- /dev/null +++ llvm/lib/Transforms/Utils/EmitAnnotations.cpp @@ -0,0 +1,96 @@ +//===-- UnrollLoop.cpp - Loop unrolling utilities -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements some loop unrolling utilities. It does not define any +// actual pass or policy, but provides a single function to perform loop +// unrolling. +// +// The process of unrolling can produce extraneous basic blocks linked with +// unconditional branches. This will be corrected in the future. +// +//===----------------------------------------------------------------------===// + +#include +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Pass.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/EmitAnnotations.h" + +using namespace llvm; + +#define DEBUG_TYPE "emit-annotations" + +std::string fixQuotes(std::string str) { + str.erase(std::remove(str.begin(), str.end(), '"'), str.end()); + return '"' + str + '"'; +} + +void EmitAnnotations(Function *F, OptimizationRemarkEmitter &ORE) { + OptimizationRemarkAnnotation annotations(DEBUG_TYPE, "annotation ", F); + AttributeList list = F->getAttributes(); + for(auto a : list.getFnAttributes()) { + annotations << "fn_attr(" << fixQuotes(a.getAsString(true)) << ") "; + } + for(auto a : list.getRetAttributes()) { + annotations << "ret_attr(" << fixQuotes(a.getAsString(true)) << ") "; + } + for(unsigned i=0; igetFunctionType()->getNumParams(); i++) + for(auto a : list.getParamAttributes(i)) { + annotations << "arg_attr(" << std::to_string(i) << ", " << fixQuotes(a.getAsString(true)) << ") "; + } + annotations << "\n"; + ORE.emit(annotations); +} + +namespace llvm { + +struct EmitAnnotationsLegacyPass : public FunctionPass { + // Pass identification, replacement for typeid + static char ID; + + EmitAnnotationsLegacyPass() : FunctionPass(ID) { + initializeEmitAnnotationsLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + // runOnFunction - To run this pass, first we calculate the alloca + // instructions that are safe for promotion, then we promote each one. + bool runOnFunction(Function &F) override { + OptimizationRemarkEmitter &ORE = getAnalysis().getORE(); + EmitAnnotations(&F, ORE); + return false; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.setPreservesCFG(); + } +}; + +} // end anonymous namespace + +char EmitAnnotationsLegacyPass::ID = 0; + +PreservedAnalyses EmitAnnotationsPass::run(Function &F, + FunctionAnalysisManager &FM) { + OptimizationRemarkEmitter &ORE = FM.getResult(F); + EmitAnnotations(&F, ORE); + return PreservedAnalyses::all(); +} + +INITIALIZE_PASS_BEGIN(EmitAnnotationsLegacyPass, "emit-annotation", "Emit annotations", + false, false) +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) +INITIALIZE_PASS_END(EmitAnnotationsLegacyPass, "emit-annotation", "Emit annotations", + false, false) + +FunctionPass *llvm::createEmitAnnotationsPass() { + return new EmitAnnotationsLegacyPass(); +} Index: llvm/lib/Transforms/Utils/Utils.cpp =================================================================== --- llvm/lib/Transforms/Utils/Utils.cpp +++ llvm/lib/Transforms/Utils/Utils.cpp @@ -26,6 +26,7 @@ initializeAddDiscriminatorsLegacyPassPass(Registry); initializeBreakCriticalEdgesPass(Registry); initializeCanonicalizeAliasesLegacyPassPass(Registry); + initializeEmitAnnotationsLegacyPassPass(Registry); initializeInstNamerPass(Registry); initializeLCSSAWrapperPassPass(Registry); initializeLibCallsShrinkWrapLegacyPassPass(Registry);