Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -272,6 +272,9 @@ "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") Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1060,6 +1060,12 @@ 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.">; Index: clang/include/clang/Driver/XRayArgs.h =================================================================== --- clang/include/clang/Driver/XRayArgs.h +++ clang/include/clang/Driver/XRayArgs.h @@ -24,6 +24,7 @@ std::vector ExtraDeps; bool XRayInstrument = false; int InstructionThreshold = 200; + bool XRayAlwaysEmitCustomEvents = false; public: /// Parses the XRay arguments from an argument list. Index: clang/include/clang/Frontend/CodeGenOptions.def =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.def +++ clang/include/clang/Frontend/CodeGenOptions.def @@ -84,6 +84,9 @@ 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) Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -3003,10 +3003,10 @@ 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); Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -1771,6 +1771,10 @@ /// 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); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -458,6 +458,12 @@ 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) { Index: clang/lib/Driver/XRayArgs.cpp =================================================================== --- clang/lib/Driver/XRayArgs.cpp +++ clang/lib/Driver/XRayArgs.cpp @@ -27,8 +27,6 @@ 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 @@ 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 @@ 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)); } Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -785,6 +785,8 @@ 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 @@ 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); Index: clang/test/CodeGen/xray-always-emit-customevent.cpp =================================================================== --- /dev/null +++ clang/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) +}