Index: include/clang/Basic/XRayInstr.h =================================================================== --- include/clang/Basic/XRayInstr.h +++ include/clang/Basic/XRayInstr.h @@ -0,0 +1,68 @@ +//===--- XRayInstr.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// \brief Defines the clang::XRayInstrKind enum. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_XRAYINSTR_H +#define LLVM_CLANG_BASIC_XRAYINSTR_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MathExtras.h" +#include +#include + +namespace clang { + +using XRayInstrMask = uint32_t; + +namespace XRayInstrKind { + +// TODO: Auto-generate these as we add more instrumentation kinds. +enum XRayInstrOrdinal : XRayInstrMask { + XRIO_Function, + XRIO_Custom, + XRIO_Count +}; + +constexpr XRayInstrMask None = 0; +constexpr XRayInstrMask Function = 1U << XRIO_Function; +constexpr XRayInstrMask Custom = 1U << XRIO_Custom; +constexpr XRayInstrMask All = Function | Custom; + +} // namespace XRayInstrKind + +struct XRayInstrSet { + bool has(XRayInstrMask K) const { + assert(llvm::isPowerOf2_32(K)); + return Mask & K; + } + + bool hasOneOf(XRayInstrMask K) const { return Mask & K; } + + void set(XRayInstrMask K, bool Value) { + assert(llvm::isPowerOf2_32(K)); + Mask = Value ? (Mask | K) : (Mask & ~K); + } + + void clear(XRayInstrMask K = XRayInstrKind::All) { Mask &= ~K; } + + bool empty() const { return Mask == 0; } + + XRayInstrMask Mask = 0; +}; + +XRayInstrMask parseXRayInstrValue(StringRef Value); + +} // namespace clang + +#endif // LLVM_CLANG_BASIC_XRAYINSTR_H Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1125,6 +1125,11 @@ def fnoxray_link_deps : Flag<["-"], "fnoxray-link-deps">, Group, Flags<[CC1Option]>; +def fxray_instrumentation_bundle : + JoinedOrSeparate<["-"], "fxray-instrumentation-bundle=">, + Group, Flags<[CC1Option]>, + HelpText<"Select which XRay instrumentation points to emit. Options: all, none, function, custom. Default is 'all'.">; + 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: include/clang/Driver/XRayArgs.h =================================================================== --- include/clang/Driver/XRayArgs.h +++ include/clang/Driver/XRayArgs.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_DRIVER_XRAYARGS_H #define LLVM_CLANG_DRIVER_XRAYARGS_H +#include "clang/Basic/XRayInstr.h" #include "clang/Driver/Types.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -24,6 +25,7 @@ std::vector AttrListFiles; std::vector ExtraDeps; std::vector Modes; + XRayInstrSet InstrumentationBundle; bool XRayInstrument = false; int InstructionThreshold = 200; bool XRayAlwaysEmitCustomEvents = false; @@ -37,7 +39,7 @@ bool needsXRayRt() const { return XRayInstrument && XRayRT; } llvm::ArrayRef modeList() const { return Modes; } - + XRayInstrSet instrumentationBundle() const { return InstrumentationBundle; } }; } // namespace driver Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -16,6 +16,7 @@ #include "clang/Basic/DebugInfoOptions.h" #include "clang/Basic/Sanitizers.h" +#include "clang/Basic/XRayInstr.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetOptions.h" @@ -255,6 +256,9 @@ /// registers. std::string PreferVectorWidth; + /// Set of XRay instrumentation kinds to emit. + XRayInstrSet XRayInstrumentationBundle; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) Index: lib/Basic/CMakeLists.txt =================================================================== --- lib/Basic/CMakeLists.txt +++ lib/Basic/CMakeLists.txt @@ -96,6 +96,7 @@ VersionTuple.cpp VirtualFileSystem.cpp Warnings.cpp + XRayInstr.cpp XRayLists.cpp ${version_inc} ) Index: lib/Basic/XRayInstr.cpp =================================================================== --- lib/Basic/XRayInstr.cpp +++ lib/Basic/XRayInstr.cpp @@ -0,0 +1,29 @@ +//===--- XRayInstr.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is part of XRay, a function call instrumentation system. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/XRayInstr.h" +#include "llvm/ADT/StringSwitch.h" + +namespace clang { + +XRayInstrMask parseXRayInstrValue(StringRef Value) { + XRayInstrMask ParsedKind = llvm::StringSwitch(Value) + .Case("all", XRayInstrKind::All) + .Case("custom", XRayInstrKind::Custom) + .Case("function", XRayInstrKind::Function) + .Case("none", XRayInstrKind::None) + .Default(XRayInstrKind::None); + return ParsedKind; +} + +} // namespace clang Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -3341,6 +3341,11 @@ case Builtin::BI__xray_customevent: { if (!ShouldXRayInstrumentFunction()) return RValue::getIgnored(); + + if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::Custom)) + return RValue::getIgnored(); + if (const auto *XRayAttr = CurFuncDecl->getAttr()) if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) return RValue::getIgnored(); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ 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().XRayInstrumentationBundle.Mask == + XRayInstrKind::Custom); } llvm::Constant * @@ -900,7 +903,9 @@ } // Apply xray attributes to the function (as a string, for now) - bool InstrumentXray = ShouldXRayInstrumentFunction(); + bool InstrumentXray = ShouldXRayInstrumentFunction() && + CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::Function); if (D && InstrumentXray) { if (const auto *XRayAttr = D->getAttr()) { if (XRayAttr->alwaysXRayInstrument()) Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1846,9 +1846,10 @@ StringRef Category) const { if (!LangOpts.XRayInstrument) return false; + 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: lib/Driver/XRayArgs.cpp =================================================================== --- lib/Driver/XRayArgs.cpp +++ lib/Driver/XRayArgs.cpp @@ -58,8 +58,7 @@ } } else { D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + - " on non-supported target OS"); + << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } XRayInstrument = true; if (const Arg *A = @@ -82,6 +81,36 @@ options::OPT_fnoxray_link_deps, true)) XRayRT = false; + auto Bundles = + Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); + if (Bundles.empty()) + InstrumentationBundle.Mask = XRayInstrKind::All; + else + for (const auto &B : Bundles) { + llvm::SmallVector BundleParts; + llvm::SplitString(B, BundleParts, ","); + for (const auto &P : BundleParts) { + // TODO: Automate the generation of the string case table. + auto Valid = llvm::StringSwitch(P) + .Cases("none", "all", "function", "custom", true) + .Default(false); + + if (!Valid) { + D.Diag(clang::diag::err_drv_invalid_value) + << "-fxray-instrumentation-bundle=" << P; + continue; + } + + auto Mask = parseXRayInstrValue(P); + if (Mask == XRayInstrKind::None) { + InstrumentationBundle.clear(); + break; + } + + InstrumentationBundle.Mask |= Mask; + } + } + // Validate the always/never attribute files. We also make sure that they // are treated as actual dependencies. for (const auto &Filename : @@ -165,7 +194,7 @@ CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); } - for (const auto& AttrFile : AttrListFiles) { + for (const auto &AttrFile : AttrListFiles) { SmallString<64> AttrListFileOpt("-fxray-attr-list="); AttrListFileOpt += AttrFile; CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/VersionTuple.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Basic/Visibility.h" +#include "clang/Basic/XRayInstr.h" #include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -75,9 +76,9 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Support/ScopedPrinter.h" #include #include #include @@ -446,6 +447,25 @@ } } +static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle, + ArgList &Args, DiagnosticsEngine &D, + XRayInstrSet &S) { + llvm::SmallVector BundleParts; + llvm::SplitString(Bundle, BundleParts, ","); + for (const auto B : BundleParts) { + auto Mask = parseXRayInstrValue(B); + if (Mask == XRayInstrKind::None) + if (B != "none") + D.Report(diag::err_drv_invalid_value) << FlagName << Bundle; + else + S.Mask = Mask; + else if (Mask == XRayInstrKind::All) + S.Mask = Mask; + else + S.set(Mask, true); + } +} + // Set the profile kind for fprofile-instrument. static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { @@ -820,11 +840,23 @@ 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); + + auto XRayInstrBundles = + Args.getAllArgValues(OPT_fxray_instrumentation_bundle); + if (XRayInstrBundles.empty()) + Opts.XRayInstrumentationBundle.Mask = XRayInstrKind::All; + else + for (const auto &A : XRayInstrBundles) + parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args, + Diags, Opts.XRayInstrumentationBundle); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Index: test/CodeGen/xray-instrumentation-bundles.cpp =================================================================== --- test/CodeGen/xray-instrumentation-bundles.cpp +++ test/CodeGen/xray-instrumentation-bundles.cpp @@ -0,0 +1,31 @@ +// 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 -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 -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,NOFUNCTION,CUSTOM %s +// RUN: %clang_cc1 -fxray-instrument \ +// RUN: -fxray-instrumentation-bundle=function,custom -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,FUNCTION,CUSTOM %s +// RUN: %clang_cc1 -fxray-instrument \ +// RUN: -fxray-instrumentation-bundle=function \ +// RUN: -fxray-instrumentation-bundle=custom -x c++ \ +// RUN: -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK,FUNCTION,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" {{.*}}