Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1107,6 +1107,10 @@ def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group, Flags<[CC1Option]>; +def fxray_instrumentation_bundle : Joined<["-"], "fxray-instrumentation-bundle=">, + Group, Flags<[CC1Option]>, + HelpText<"Select which bundle of XRay instrumentation points to emit. Options: all, none, function-extents, custom-only.">; + def ffine_grained_bitfield_accesses : Flag<["-"], "ffine-grained-bitfield-accesses">, Group, Flags<[CC1Option]>, HelpText<"Use separate accesses for bitfields with legal widths and alignments.">; Index: clang/include/clang/Driver/XRayArgs.h =================================================================== --- clang/include/clang/Driver/XRayArgs.h +++ clang/include/clang/Driver/XRayArgs.h @@ -25,6 +25,7 @@ bool XRayInstrument = false; int InstructionThreshold = 200; bool XRayAlwaysEmitCustomEvents = false; + std::string XRayBundle = "all"; public: /// Parses the XRay arguments from an argument list. Index: clang/include/clang/Frontend/CodeGenOptions.h =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.h +++ clang/include/clang/Frontend/CodeGenOptions.h @@ -107,6 +107,14 @@ Embed_Marker // Embed a marker as a placeholder for bitcode. }; + enum XRayInstrumentationPointBundle { + XRay_All, // Always emit all the instrumentation points. + XRay_None, // Emit none of the instrumentation points. + XRay_Function, // Only emit function entry/exit instrumentation + // points. + XRay_CustomOnly, // Only emit custom event instrumentation points. + }; + /// The code model to use (-mcmodel). std::string CodeModel; Index: clang/include/clang/Frontend/CodeGenOptions.def =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.def +++ clang/include/clang/Frontend/CodeGenOptions.def @@ -95,6 +95,10 @@ ///< Set when -fxray-always-emit-customevents is enabled. CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0) +///< Filter the instrumentation points we emit, to predefined groupings. +ENUM_CODEGENOPT(XRayInstrumentationBundle, XRayInstrumentationPointBundle, 4, + XRayInstrumentationPointBundle::XRay_All) + ///< Set the minimum number of instructions in a function to determine selective ///< XRay instrumentation. VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -3241,9 +3241,23 @@ case Builtin::BI__xray_customevent: { if (!ShouldXRayInstrumentFunction()) return RValue::getIgnored(); - if (const auto *XRayAttr = CurFuncDecl->getAttr()) - if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) + + using XRayBundles = CodeGenOptions::XRayInstrumentationPointBundle; + auto Bundle = CGM.getCodeGenOpts().getXRayInstrumentationBundle(); + switch (Bundle) { + case XRayBundles::XRay_None: + case XRayBundles::XRay_Function: return RValue::getIgnored(); + case XRayBundles::XRay_All: + if (const auto *XRayAttr = CurFuncDecl->getAttr()) + if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) + return RValue::getIgnored(); + LLVM_FALLTHROUGH; + case XRayBundles::XRay_CustomOnly: + break; + } + assert(Bundle == XRayBundles::XRay_All || + Bundle == XRayBundles::XRay_CustomOnly); Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent); auto FTy = F->getFunctionType(); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -468,7 +468,10 @@ /// AlwaysEmitXRayCustomEvents - Return true if we should emit IR for calls to /// the __xray_customevent(...) builin calls, when doing XRay instrumentation. bool CodeGenFunction::AlwaysEmitXRayCustomEvents() const { - return CGM.getCodeGenOpts().XRayAlwaysEmitCustomEvents; + return CGM.getCodeGenOpts().XRayInstrumentFunctions && + (CGM.getCodeGenOpts().XRayAlwaysEmitCustomEvents || + CGM.getCodeGenOpts().getXRayInstrumentationBundle() == + CodeGenOptions::XRayInstrumentationPointBundle::XRay_CustomOnly); } llvm::Constant * @@ -894,20 +897,30 @@ // Apply xray attributes to the function (as a string, for now) bool InstrumentXray = ShouldXRayInstrumentFunction(); if (D && InstrumentXray) { - if (const auto *XRayAttr = D->getAttr()) { - if (XRayAttr->alwaysXRayInstrument()) - Fn->addFnAttr("function-instrument", "xray-always"); - if (XRayAttr->neverXRayInstrument()) - Fn->addFnAttr("function-instrument", "xray-never"); - if (const auto *LogArgs = D->getAttr()) { - Fn->addFnAttr("xray-log-args", - llvm::utostr(LogArgs->getArgumentCount())); + using XRayBundles = CodeGenOptions::XRayInstrumentationPointBundle; + auto Bundle = CGM.getCodeGenOpts().getXRayInstrumentationBundle(); + switch (Bundle) { + case XRayBundles::XRay_All: + case XRayBundles::XRay_Function: + if (const auto *XRayAttr = D->getAttr()) { + if (XRayAttr->alwaysXRayInstrument()) + Fn->addFnAttr("function-instrument", "xray-always"); + if (XRayAttr->neverXRayInstrument()) + Fn->addFnAttr("function-instrument", "xray-never"); + if (const auto *LogArgs = D->getAttr()) { + Fn->addFnAttr("xray-log-args", + llvm::utostr(LogArgs->getArgumentCount())); + } + } else { + if (!CGM.imbueXRayAttrs(Fn, Loc)) + Fn->addFnAttr( + "xray-instruction-threshold", + llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); } - } else { - if (!CGM.imbueXRayAttrs(Fn, Loc)) - Fn->addFnAttr( - "xray-instruction-threshold", - llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); + break; + case XRayBundles::XRay_None: + case XRayBundles::XRay_CustomOnly: + break; } } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -1846,9 +1846,23 @@ StringRef Category) const { if (!LangOpts.XRayInstrument) return false; + + // Here, check whether the codegen options say we shouldn't be instrumenting + // functions. + using XRayBundles = CodeGenOptions::XRayInstrumentationPointBundle; + auto Bundle = CodeGenOpts.getXRayInstrumentationBundle(); + switch (Bundle) { + case XRayBundles::XRay_None: + case XRayBundles::XRay_CustomOnly: + return true; + case XRayBundles::XRay_Function: + case XRayBundles::XRay_All: + break; + } + const auto &XRayFilter = getContext().getXRayFilter(); using ImbueAttr = XRayFunctionFilter::ImbueAttribute; - auto Attr = XRayFunctionFilter::ImbueAttribute::NONE; + auto Attr = ImbueAttr::NONE; if (Loc.isValid()) Attr = XRayFilter.shouldImbueLocation(Loc, Category); if (Attr == ImbueAttr::NONE) Index: clang/lib/Driver/XRayArgs.cpp =================================================================== --- clang/lib/Driver/XRayArgs.cpp +++ clang/lib/Driver/XRayArgs.cpp @@ -27,6 +27,8 @@ constexpr char XRayInstrumentOption[] = "-fxray-instrument"; constexpr char XRayInstructionThresholdOption[] = "-fxray-instruction-threshold="; +constexpr char XRayInstrumentationBundleOption[] = + "-fxray-instrumentation-bundle="; } // namespace XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { @@ -50,10 +52,10 @@ << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } } else if (Triple.getOS() == llvm::Triple::FreeBSD) { - if (Triple.getArch() != llvm::Triple::x86_64) { - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); - } + if (Triple.getArch() != llvm::Triple::x86_64) { + D.Diag(diag::err_drv_clang_unsupported) + << (std::string(XRayInstrumentOption) + " on " + Triple.str()); + } } else { D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on non-supported target OS"); @@ -75,6 +77,23 @@ options::OPT_fnoxray_always_emit_customevents, false)) XRayAlwaysEmitCustomEvents = true; + // We check the bundle of instrumentation that we let users choose. This + // coarse grained control is used to determine which instrumentation points + // to actually emit. + if (const Arg *A = + Args.getLastArg(options::OPT_fxray_instrumentation_bundle)) { + StringRef Bundle = A->getValue(); + XRayBundle = llvm::StringSwitch(Bundle) + .Case("all", "all") + .Case("none", "none") + .Case("function-extents", "function-extents") + .Case("custom-only", "custom-only") + .Default("error"); + if (XRayBundle == "error") + D.Diag(clang::diag::err_drv_invalid_value) + << A->getAsString(Args) << Bundle; + } + // Validate the always/never attribute files. We also make sure that they // are treated as actual dependencies. for (const auto &Filename : @@ -109,6 +128,8 @@ CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + Twine(InstructionThreshold))); + CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstrumentationBundleOption) + + Twine(XRayBundle))); for (const auto &Always : AlwaysInstrumentFiles) { SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -446,6 +446,23 @@ } } +static CodeGenOptions::XRayInstrumentationPointBundle +parseXRayInstrumentationBundle(Arg *A, ArgList &Args, DiagnosticsEngine &D) { + StringRef V = A->getValue(); + auto Bundle = llvm::StringSwitch(V) + .Case("all", CodeGenOptions::XRayInstrumentationPointBundle::XRay_All) + .Case("none", CodeGenOptions::XRayInstrumentationPointBundle::XRay_None) + .Case("function-extents", + CodeGenOptions::XRayInstrumentationPointBundle::XRay_Function) + .Case("custom-only", + CodeGenOptions::XRayInstrumentationPointBundle::XRay_CustomOnly) + .Default(CodeGenOptions::XRayInstrumentationPointBundle::XRay_All); + if (Bundle == CodeGenOptions::XRayInstrumentationPointBundle::XRay_All && + !V.empty() && V != "all") + D.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << V; + return Bundle; +} + // Set the profile kind for fprofile-instrument. static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { @@ -821,11 +838,18 @@ Args.hasArg(OPT_finstrument_functions_after_inlining); Opts.InstrumentFunctionEntryBare = Args.hasArg(OPT_finstrument_function_entry_bare); - Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + + Opts.XRayInstrumentFunctions = + Args.hasArg(OPT_fxray_instrument); Opts.XRayAlwaysEmitCustomEvents = Args.hasArg(OPT_fxray_always_emit_customevents); Opts.XRayInstructionThreshold = getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); + + if (auto A = Args.getLastArg(OPT_fxray_instrumentation_bundle)) + Opts.setXRayInstrumentationBundle( + parseXRayInstrumentationBundle(A, Args, Diags)); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Index: clang/test/CodeGen/xray-instrumentation-bundles.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/xray-instrumentation-bundles.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fxray-instrument -fxray-instrumentation-bundle=none -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,NOFUNCTION,NOCUSTOM %s +// RUN: %clang_cc1 -fxray-instrument \ +// RUN: -fxray-instrumentation-bundle=function-extents -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,FUNCTION,NOCUSTOM %s +// RUN: %clang_cc1 -fxray-instrument \ +// RUN: -fxray-instrumentation-bundle=custom-only -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,NOFUNCTION,CUSTOM %s + +// CHECK: define void @_Z16alwaysInstrumentv() #[[ALWAYSATTR:[0-9]+]] { +[[clang::xray_always_instrument]] void alwaysInstrument() { + static constexpr char kPhase[] = "always"; + __xray_customevent(kPhase, 6); + // CUSTOM: call void @llvm.xray.customevent(i8*{{.*}}, i32 6) + // NOCUSTOM-NOT: call void @llvm.xray.customevent(i8*{{.*}}, i32 6) +} + +// FUNCTION: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}} +// NOFUNCTION-NOT: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}