Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -426,6 +426,22 @@ let Documentation = [Undocumented]; } +def XRayAlwaysInstrument : InheritableAttr { + let Spellings = [GNU<"xray_always_instrument">, + CXX11<"clang", "xray_always_instrument">]; + let Subjects = SubjectList<[CXXMethod, Function], WarnDiag, + "ExpectedFunctionOrMethod">; + let Documentation = [Undocumented]; // TODO(dberris): Document this! +} + +def XRayNeverInstrument : InheritableAttr { + let Spellings = [GNU<"xray_never_instrument">, + CXX11<"clang", "xray_never_instrument">]; + let Subjects = SubjectList<[CXXMethod, Function], WarnDiag, + "ExpectedFunctionOrMethod">; + let Documentation = [Undocumented]; // TODO(dberris): Document this! +} + def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -752,6 +752,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<["-"], "fnoxray-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 @@ -1438,6 +1438,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(); + /// 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() { + 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. @@ -698,6 +704,16 @@ if (SanOpts.has(SanitizerKind::SafeStack)) Fn->addFnAttr(llvm::Attribute::SafeStack); + // Apply xray attributes to the function (as a string, for now) + if (ShouldXRayInstrumentFunction()) { + if (D->hasAttr()) + Fn->addFnAttr("function-instrument", "xray-always"); + 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 function that are not marked AlwaysInline. Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3159,6 +3159,28 @@ return !StaticRuntimes.empty(); } +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(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)) @@ -4557,6 +4579,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. @@ -9290,6 +9322,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); @@ -9316,6 +9349,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 @@ -680,6 +680,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 @@ -5913,10 +5913,16 @@ case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute(S, D, Attr); break; + // XRay attributes. + case AttributeList::AT_XRayAlwaysInstrument: + handleSimpleAttribute(S, D, Attr); + break; + case AttributeList::AT_XRayNeverInstrument: + handleSimpleAttribute(S, D, Attr); + break; } } Index: test/Sema/xray-always-instrument-attr.c =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.c @@ -0,0 +1,4 @@ +// 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}} Index: test/Sema/xray-always-instrument-attr.cpp =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.cpp @@ -0,0 +1,8 @@ +// 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]] (); +};