[XRay][clang] Add flag to choose instrumentation bundles
authorDean Michael Berris <dberris@google.com>
Fri, 13 Apr 2018 02:31:58 +0000 (02:31 +0000)
committerDean Michael Berris <dberris@google.com>
Fri, 13 Apr 2018 02:31:58 +0000 (02:31 +0000)
Summary:
This change addresses http://llvm.org/PR36926 by allowing users to pick
which instrumentation bundles to use, when instrumenting with XRay. In
particular, the flag `-fxray-instrumentation-bundle=` has four valid
values:

- `all`: the default, emits all instrumentation kinds
- `none`: equivalent to -fnoxray-instrument
- `function`: emits the entry/exit instrumentation
- `custom`: emits the custom event instrumentation

These can be combined either as comma-separated values, or as
repeated flag values.

Reviewers: echristo, kpw, eizan, pelikan

Reviewed By: pelikan

Subscribers: mgorny, cfe-commits

Differential Revision: https://reviews.llvm.org/D44970

llvm-svn: 329985

12 files changed:
clang/include/clang/Basic/XRayInstr.h [new file with mode: 0644]
clang/include/clang/Driver/Options.td
clang/include/clang/Driver/XRayArgs.h
clang/include/clang/Frontend/CodeGenOptions.h
clang/lib/Basic/CMakeLists.txt
clang/lib/Basic/XRayInstr.cpp [new file with mode: 0644]
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/Driver/XRayArgs.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/CodeGen/xray-instrumentation-bundles.cpp [new file with mode: 0644]

diff --git a/clang/include/clang/Basic/XRayInstr.h b/clang/include/clang/Basic/XRayInstr.h
new file mode 100644 (file)
index 0000000..a573ba1
--- /dev/null
@@ -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 <cassert>
+#include <cstdint>
+
+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 bf3f1a6..f239c46 100644 (file)
@@ -1125,6 +1125,11 @@ def fxray_link_deps : Flag<["-"], "fxray-link-deps">, Group<f_Group>,
 def fnoxray_link_deps : Flag<["-"], "fnoxray-link-deps">, Group<f_Group>,
   Flags<[CC1Option]>;
 
+def fxray_instrumentation_bundle :
+  JoinedOrSeparate<["-"], "fxray-instrumentation-bundle=">,
+  Group<f_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<f_clang_Group>, Flags<[CC1Option]>,
   HelpText<"Use separate accesses for bitfields with legal widths and alignments.">;
index e4a573e..fd041d9 100644 (file)
@@ -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 @@ class XRayArgs {
   std::vector<std::string> AttrListFiles;
   std::vector<std::string> ExtraDeps;
   std::vector<std::string> Modes;
+  XRayInstrSet InstrumentationBundle;
   bool XRayInstrument = false;
   int InstructionThreshold = 200;
   bool XRayAlwaysEmitCustomEvents = false;
@@ -37,7 +39,7 @@ public:
 
   bool needsXRayRt() const { return XRayInstrument && XRayRT; }
   llvm::ArrayRef<std::string> modeList() const { return Modes; }
-
+  XRayInstrSet instrumentationBundle() const { return InstrumentationBundle; }
 };
 
 } // namespace driver
index c246a77..6ab64f6 100644 (file)
@@ -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 @@ public:
   /// 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 823b908..2e39491 100644 (file)
@@ -96,6 +96,7 @@ add_clang_library(clangBasic
   VersionTuple.cpp
   VirtualFileSystem.cpp
   Warnings.cpp
+  XRayInstr.cpp
   XRayLists.cpp
   ${version_inc}
   )
diff --git a/clang/lib/Basic/XRayInstr.cpp b/clang/lib/Basic/XRayInstr.cpp
new file mode 100644 (file)
index 0000000..42f9038
--- /dev/null
@@ -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<XRayInstrMask>(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 73b95d9..4baa5af 100644 (file)
@@ -3341,6 +3341,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
   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<XRayInstrumentAttr>())
       if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents())
         return RValue::getIgnored();
index 57b1c4b..5367c2a 100644 (file)
@@ -468,7 +468,10 @@ bool CodeGenFunction::ShouldXRayInstrumentFunction() const {
 /// 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 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
   }
 
   // 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<XRayInstrumentAttr>()) {
       if (XRayAttr->alwaysXRayInstrument())
index c3de870..701412f 100644 (file)
@@ -1846,9 +1846,10 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
                                    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 bfc5053..e25259c 100644 (file)
@@ -58,8 +58,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
       }
     } 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 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
                       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<StringRef, 2> BundleParts;
+        llvm::SplitString(B, BundleParts, ",");
+        for (const auto &P : BundleParts) {
+          // TODO: Automate the generation of the string case table.
+          auto Valid = llvm::StringSwitch<bool>(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 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
     CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt));
   }
 
-  for (const autoAttrFile : AttrListFiles) {
+  for (const auto &AttrFile : AttrListFiles) {
     SmallString<64> AttrListFileOpt("-fxray-attr-list=");
     AttrListFileOpt += AttrFile;
     CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt));
index 5260346..147657f 100644 (file)
@@ -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 <algorithm>
 #include <atomic>
 #include <cassert>
@@ -446,6 +447,25 @@ static void parseSanitizerKinds(StringRef FlagName,
   }
 }
 
+static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle,
+                                           ArgList &Args, DiagnosticsEngine &D,
+                                           XRayInstrSet &S) {
+  llvm::SmallVector<StringRef, 2> 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 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
       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);
diff --git a/clang/test/CodeGen/xray-instrumentation-bundles.cpp b/clang/test/CodeGen/xray-instrumentation-bundles.cpp
new file mode 100644 (file)
index 0000000..3e75183
--- /dev/null
@@ -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" {{.*}}