diff options
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 16 | ||||
-rw-r--r-- | clang/include/clang/Basic/AttrDocs.td | 11 | ||||
-rw-r--r-- | clang/include/clang/Driver/Options.td | 15 | ||||
-rw-r--r-- | clang/include/clang/Frontend/CodeGenOptions.def | 8 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 20 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 4 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 37 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 5 | ||||
-rw-r--r-- | clang/test/CodeGen/xray-attributes-supported.cpp | 13 | ||||
-rw-r--r-- | clang/test/Sema/xray-always-instrument-attr.c | 6 | ||||
-rw-r--r-- | clang/test/Sema/xray-always-instrument-attr.cpp | 10 |
12 files changed, 147 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 51903cbf921..7305c746ce7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -428,6 +428,22 @@ def AlwaysInline : InheritableAttr { 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">; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 6ed1f298eb0..cb65a445e8a 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2450,3 +2450,14 @@ See the RenderScript_ documentation for more information. .. _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. + }]; +} diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 06c5739cac9..2bc64c6681c 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -781,6 +781,21 @@ def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>; def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; + +def fxray_instrument : Flag<["-"], "fxray-instrument">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Generate XRay instrumentation sleds on function entry and exit">; +def fnoxray_instrument : Flag<["-"], "fno-xray-instrument">, Group<f_Group>, + Flags<[CC1Option]>; + +def fxray_instruction_threshold_EQ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Sets the minimum function size to instrument with XRay">; +def fxray_instruction_threshold_ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold">, + Group<f_Group>, Flags<[CC1Option]>; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; diff --git a/clang/include/clang/Frontend/CodeGenOptions.def b/clang/include/clang/Frontend/CodeGenOptions.def index 85f7c90dcd9..6a4474cfe75 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.def +++ b/clang/include/clang/Frontend/CodeGenOptions.def @@ -74,6 +74,14 @@ CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables 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. diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 755881fb148..183ee12ea23 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -397,6 +397,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() { 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. @@ -686,6 +692,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, 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<XRayInstrumentAttr>()) { + 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 diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index fff7a05b107..08a3b307a4c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1521,6 +1521,10 @@ public: /// 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. diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index d3844dd912e..e4dd0c6f6c0 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3181,6 +3181,28 @@ static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, 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,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-fxray-instrument"); + if (const 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 +9423,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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 +9450,9 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, CmdArgs); + bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 5910664e6a6..c6948ebfc4b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -687,6 +687,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } 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); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4c36ab05d14..a5780a7d71f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5909,10 +5909,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); break; + // XRay attributes. + case AttributeList::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + break; } } diff --git a/clang/test/CodeGen/xray-attributes-supported.cpp b/clang/test/CodeGen/xray-attributes-supported.cpp new file mode 100644 index 00000000000..d70b3aa2601 --- /dev/null +++ b/clang/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" diff --git a/clang/test/Sema/xray-always-instrument-attr.c b/clang/test/Sema/xray-always-instrument-attr.c new file mode 100644 index 00000000000..3c063e21a68 --- /dev/null +++ b/clang/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}} diff --git a/clang/test/Sema/xray-always-instrument-attr.cpp b/clang/test/Sema/xray-always-instrument-attr.cpp new file mode 100644 index 00000000000..8d42837ec6b --- /dev/null +++ b/clang/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}} |