From: Dean Michael Berris Date: Thu, 30 Nov 2017 00:04:54 +0000 (+0000) Subject: [XRay][clang] Introduce -fxray-always-emit-customevents X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f4f187631c3ca33063ed24b8388c74509c87b019;p=clang [XRay][clang] Introduce -fxray-always-emit-customevents Summary: The -fxray-always-emit-customevents flag instructs clang to always emit the LLVM IR for calls to the `__xray_customevent(...)` built-in function. The default behaviour currently respects whether the function has an `[[clang::xray_never_instrument]]` attribute, and thus not lower the appropriate IR code for the custom event built-in. This change allows users calling through to the `__xray_customevent(...)` built-in to always see those calls lowered to the corresponding LLVM IR to lay down instrumentation points for these custom event calls. Using this flag enables us to emit even just the user-provided custom events even while never instrumenting the start/end of the function where they appear. This is useful in cases where "phase markers" using __xray_customevent(...) can have very few instructions, must never be instrumented when entered/exited. Reviewers: rnk, dblaikie, kpw Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D40601 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319388 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 5388c695fd..f1487d1a18 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -272,6 +272,9 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "aggressive, 2: more aggressive)") LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") +LANGOPT(XRayAlwaysEmitCustomEvents, 1, 0, + "controls whether to always emit intrinsic calls to " + "__xray_customevent(...) builtin.") BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 7082fd2677..d155d703a7 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -1060,6 +1060,12 @@ def fxray_never_instrument : Group, Flags<[CC1Option]>, HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">; +def fxray_always_emit_customevents : Flag<["-"], "fxray-always-emit-customevents">, Group, + Flags<[CC1Option]>, + HelpText<"Determine whether to always emit __xray_customevent(...) calls even if the function it appears in is not always instrumented.">; +def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group, + Flags<[CC1Option]>; + def ffine_grained_bitfield_accesses : Flag<["-"], "ffine-grained-bitfield-accesses">, Group, Flags<[CC1Option]>, HelpText<"Use separate accesses for bitfields with legal widths and alignments.">; diff --git a/include/clang/Driver/XRayArgs.h b/include/clang/Driver/XRayArgs.h index 83210d100a..e5b76162de 100644 --- a/include/clang/Driver/XRayArgs.h +++ b/include/clang/Driver/XRayArgs.h @@ -24,6 +24,7 @@ class XRayArgs { std::vector ExtraDeps; bool XRayInstrument = false; int InstructionThreshold = 200; + bool XRayAlwaysEmitCustomEvents = false; public: /// Parses the XRay arguments from an argument list. diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index e55550554e..9dbdaea001 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -84,6 +84,9 @@ CODEGENOPT(InstrumentFunctionEntryBare , 1, 0) ///< Set when CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. +///< Set when -fxray-always-emit-customevents is enabled. +CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0) + ///< Set the minimum number of instructions in a function to determine selective ///< XRay instrumentation. VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 809f760599..34adc640b4 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -3003,10 +3003,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__xray_customevent: { if (!ShouldXRayInstrumentFunction()) return RValue::getIgnored(); - if (const auto *XRayAttr = CurFuncDecl->getAttr()) { - if (XRayAttr->neverXRayInstrument()) + if (const auto *XRayAttr = CurFuncDecl->getAttr()) + if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) return RValue::getIgnored(); - } + Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent); auto FTy = F->getFunctionType(); auto Arg0 = E->getArg(0); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 6b8359141b..6633320de1 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -458,6 +458,12 @@ bool CodeGenFunction::ShouldXRayInstrumentFunction() const { return CGM.getCodeGenOpts().XRayInstrumentFunctions; } +/// 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; +} + llvm::Constant * CodeGenFunction::EncodeAddrForUseInPrologue(llvm::Function *F, llvm::Constant *Addr) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 8a569fc015..1c8c2a5e36 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1771,6 +1771,10 @@ public: /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; + /// AlwaysEmitXRayCustomEvents - Return true if we must unconditionally emit + /// XRay custom event handling calls. + bool AlwaysEmitXRayCustomEvents() const; + /// Encode an address into a form suitable for use in a function prologue. llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F, llvm::Constant *Addr); diff --git a/lib/Driver/XRayArgs.cpp b/lib/Driver/XRayArgs.cpp index 8d68a8432d..232bacd5f0 100644 --- a/lib/Driver/XRayArgs.cpp +++ b/lib/Driver/XRayArgs.cpp @@ -27,8 +27,6 @@ namespace { constexpr char XRayInstrumentOption[] = "-fxray-instrument"; constexpr char XRayInstructionThresholdOption[] = "-fxray-instruction-threshold="; -constexpr char XRayAlwaysInstrumentOption[] = "-fxray-always-instrument="; -constexpr char XRayNeverInstrumentOption[] = "-fxray-never-instrument="; } // namespace XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { @@ -63,6 +61,14 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } + // By default, the back-end will not emit the lowering for XRay customevent + // calls if the function is not instrumented. In the future we will change + // this default to be the reverse, but in the meantime we're going to + // introduce the new functionality behind a flag. + if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, + options::OPT_fnoxray_always_emit_customevents, false)) + XRayAlwaysEmitCustomEvents = true; + // Validate the always/never attribute files. We also make sure that they // are treated as actual dependencies. for (const auto &Filename : @@ -91,17 +97,21 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, return; CmdArgs.push_back(XRayInstrumentOption); + + if (XRayAlwaysEmitCustomEvents) + CmdArgs.push_back("-fxray-always-emit-customevents"); + CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + Twine(InstructionThreshold))); for (const auto &Always : AlwaysInstrumentFiles) { - SmallString<64> AlwaysInstrumentOpt(XRayAlwaysInstrumentOption); + SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); AlwaysInstrumentOpt += Always; CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); } for (const auto &Never : NeverInstrumentFiles) { - SmallString<64> NeverInstrumentOpt(XRayNeverInstrumentOption); + SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); NeverInstrumentOpt += Never; CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index cdd53608f6..e1555da272 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -785,6 +785,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.InstrumentFunctionEntryBare = Args.hasArg(OPT_finstrument_function_entry_bare); 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); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); @@ -2503,6 +2505,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.XRayInstrument = Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false); + // -fxray-always-emit-customevents + Opts.XRayAlwaysEmitCustomEvents = + Args.hasFlag(OPT_fxray_always_emit_customevents, + OPT_fnoxray_always_emit_customevents, false); + // -fxray-{always,never}-instrument= filenames. Opts.XRayAlwaysInstrumentFiles = Args.getAllArgValues(OPT_fxray_always_instrument); diff --git a/test/CodeGen/xray-always-emit-customevent.cpp b/test/CodeGen/xray-always-emit-customevent.cpp new file mode 100644 index 0000000000..8ac22f2a1b --- /dev/null +++ b/test/CodeGen/xray-always-emit-customevent.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fxray-instrument -fxray-always-emit-customevents -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck %s + +// CHECK-LABEL: @_Z15neverInstrumentv +[[clang::xray_never_instrument]] void neverInstrument() { + static constexpr char kPhase[] = "never"; + __xray_customevent(kPhase, 5); + // CHECK: call void @llvm.xray.customevent(i8*{{.*}}, i32 5) +}