Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -428,6 +428,22 @@ let Documentation = [Undocumented]; } +def XRayInstrument : InheritableAttr { + let Spellings = [GNU<"xray_always_instrument">, + CXX11<"clang", "xray_always_instrument">, + GNU<"xray_never_instrument">, + CXX11<"clang", "xray_never_instrument">]; + let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag, + "ExpectedFunctionOrMethod">; + let Accessors = [Accessor<"alwaysXRayInstrument", + [GNU<"xray_always_instrument">, + CXX11<"clang", "xray_always_instrument">]>, + Accessor<"neverXRayInstrument", + [GNU<"xray_never_instrument">, + CXX11<"clang", "xray_never_instrument">]>]; + let Documentation = [XRayDocs]; +} + def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2450,3 +2450,14 @@ .. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html }]; } + +def XRayDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +``__attribute__((xray_always_instrument))`` or ``[[clang:xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang:xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + }]; +} Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -781,6 +781,21 @@ def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; + +def fxray_instrument : Flag<["-"], "fxray-instrument">, Group, + Flags<[CC1Option]>, + HelpText<"Generate XRay instrumentation sleds on function entry and exit">; +def fnoxray_instrument : Flag<["-"], "fno-xray-instrument">, Group, + Flags<[CC1Option]>; + +def fxray_instruction_threshold_EQ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold=">, + Group, Flags<[CC1Option]>, + HelpText<"Sets the minimum function size to instrument with XRay">; +def fxray_instruction_threshold_ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold">, + Group, Flags<[CC1Option]>; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -74,6 +74,14 @@ CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. + +CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is + ///< enabled. + +///< Set the minimum number of instructions in a function to determine selective +///< XRay instrumentation. +VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) + CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to ///< be generated. Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1521,6 +1521,10 @@ /// instrumented with __cyg_profile_func_* calls bool ShouldInstrumentFunction(); + /// ShouldXRayInstrument - Return true if the current function should be + /// instrumented with XRay nop sleds. + bool ShouldXRayInstrumentFunction() const; + /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -397,6 +397,12 @@ return true; } +/// ShouldXRayInstrument - Return true if the current function should be +/// instrumented with XRay nop sleds. +bool CodeGenFunction::ShouldXRayInstrumentFunction() const { + return CGM.getCodeGenOpts().XRayInstrumentFunctions; +} + /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. @@ -684,6 +690,20 @@ if (SanOpts.has(SanitizerKind::SafeStack)) Fn->addFnAttr(llvm::Attribute::SafeStack); + // Apply xray attributes to the function (as a string, for now) + if (D && ShouldXRayInstrumentFunction()) { + if (const auto *XRayAttr = D->getAttr()) { + if (XRayAttr->alwaysXRayInstrument()) + Fn->addFnAttr("function-instrument", "xray-always"); + if (XRayAttr->neverXRayInstrument()) + Fn->addFnAttr("function-instrument", "xray-never"); + } else { + Fn->addFnAttr( + "xray-instruction-threshold", + llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); + } + } + // Pass inline keyword to optimizer if it appears explicitly on any // declaration. Also, in the case of -fno-inline attach NoInline // attribute to all functions that are not marked AlwaysInline, or Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3181,6 +3181,28 @@ return !StaticRuntimes.empty(); } +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + return false; +} + +static void linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-latomic"); + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + CmdArgs.push_back("-ldl"); +} + static bool areOptimizationsEnabled(const ArgList &Args) { // Find the last -O arg and see if it is non-zero. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) @@ -4582,6 +4604,16 @@ Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasArg(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-fxray-instrument"); + if (Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, + options::OPT_fxray_instruction_threshold_EQ)) { + CmdArgs.push_back("-fxray-instruction-threshold"); + CmdArgs.push_back(A->getValue()); + } + } + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); // Add runtime flag for PS4 when PGO or Coverage are enabled. @@ -9390,6 +9422,7 @@ CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9416,6 +9449,9 @@ if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, CmdArgs); + bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -687,6 +687,9 @@ } Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + Opts.XRayInstructionThreshold = + getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5909,10 +5909,13 @@ case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute(S, D, Attr); break; + // XRay attributes. + case AttributeList::AT_XRayInstrument: + handleSimpleAttribute(S, D, Attr); + break; } } Index: test/CodeGen/xray-attributes-supported.cpp =================================================================== --- /dev/null +++ test/CodeGen/xray-attributes-supported.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple x86_64-unknown-linux-gnu | FileCheck %s + +// Make sure that the LLVM attribute for XRay-annotated functions do show up. +[[clang::xray_always_instrument]] void foo() { +// CHECK: define void @_Z3foov() #0 +}; + +[[clang::xray_never_instrument]] void bar() { +// CHECK: define void @_Z3barv() #1 +}; + +// CHECK: #0 = {{.*}}"function-instrument"="xray-always" +// CHECK: #1 = {{.*}}"function-instrument"="xray-never" Index: test/Sema/xray-always-instrument-attr.c =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c11 +void foo() __attribute__((xray_always_instrument)); + +struct __attribute__((xray_always_instrument)) a { int x; }; // expected-warning {{'xray_always_instrument' attribute only applies to functions and methods}} + +void bar() __attribute__((xray_always_instrument("not-supported"))); // expected-error {{'xray_always_instrument' attribute takes no arguments}} Index: test/Sema/xray-always-instrument-attr.cpp =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++ +void foo [[clang::xray_always_instrument]] (); + +struct [[clang::xray_always_instrument]] a { int x; }; // expected-warning {{'xray_always_instrument' attribute only applies to functions and methods}} + +class b { + void c [[clang::xray_always_instrument]] (); +}; + +void baz [[clang::xray_always_instrument("not-supported")]] (); // expected-error {{'xray_always_instrument' attribute takes no arguments}}