]> granicus.if.org Git - clang/commitdiff
[XRay] Add clang builtin for xray typed events.
authorKeith Wyss <wyssman@gmail.com>
Tue, 17 Apr 2018 21:32:43 +0000 (21:32 +0000)
committerKeith Wyss <wyssman@gmail.com>
Tue, 17 Apr 2018 21:32:43 +0000 (21:32 +0000)
Summary:
A clang builtin for xray typed events. Differs from
__xray_customevent(...) by the presence of a type tag that is vended by
compiler-rt in typical usage. This allows xray handlers to expand logged
events with their type description and plugins to process traced events
based on type.

This change depends on D45633 for the intrinsic definition.

Reviewers: dberris, pelikan, rnk, eizan

Subscribers: cfe-commits, llvm-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@330220 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/Basic/Builtins.def
include/clang/Basic/LangOptions.def
include/clang/Basic/XRayInstr.h
include/clang/Driver/Options.td
include/clang/Driver/XRayArgs.h
include/clang/Frontend/CodeGenOptions.def
lib/Basic/XRayInstr.cpp
lib/CodeGen/CGBuiltin.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/Driver/XRayArgs.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGen/xray-always-emit-typedevent.cpp [new file with mode: 0644]
test/CodeGen/xray-instrumentation-bundles.cpp
test/CodeGen/xray-typedevent.cpp [new file with mode: 0644]

index 4b7466277bad86530cb0cbc9b6a7d5b477141e14..189c85573562208e9c752fbf4176f4f53f457df1 100644 (file)
@@ -1455,6 +1455,7 @@ LANGBUILTIN(omp_is_initial_device, "i", "nc", OMP_LANG)
 
 // Builtins for XRay
 BUILTIN(__xray_customevent, "vcC*z", "")
+BUILTIN(__xray_typedevent, "vzcC*z", "")
 
 // Win64-compatible va_list functions
 BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
index c05f0dc545e5c0f8f674dfca0695170464284812..029e6516c0a22cfb7d3cba58ae7071e2722b31f4 100644 (file)
@@ -281,6 +281,9 @@ 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.")
+LANGOPT(XRayAlwaysEmitTypedEvents, 1, 0,
+        "controls whether to always emit intrinsic calls to "
+        "__xray_typedevent(...) builtin.")
 
 BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0,
                "allow editor placeholders in source")
@@ -298,4 +301,3 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest,
 #undef VALUE_LANGOPT
 #undef COMPATIBLE_VALUE_LANGOPT
 #undef BENIGN_VALUE_LANGOPT
-
index a573ba1eca3d308df49658e3f53ad9e340f76122..6a03c7b5e26e3f0c6ce25869837f2c221ebfe1d9 100644 (file)
@@ -31,13 +31,15 @@ namespace XRayInstrKind {
 enum XRayInstrOrdinal : XRayInstrMask {
   XRIO_Function,
   XRIO_Custom,
+  XRIO_Typed,
   XRIO_Count
 };
 
 constexpr XRayInstrMask None = 0;
 constexpr XRayInstrMask Function = 1U << XRIO_Function;
 constexpr XRayInstrMask Custom = 1U << XRIO_Custom;
-constexpr XRayInstrMask All = Function | Custom;
+constexpr XRayInstrMask Typed = 1U << XRIO_Typed;
+constexpr XRayInstrMask All = Function | Custom | Typed;
 
 } // namespace XRayInstrKind
 
index 09f759e99656440bcb60e398ef8b9f53509dae42..55e87287585fba5dfe13907862e1a64879c4fe12 100644 (file)
@@ -1119,6 +1119,12 @@ def fxray_always_emit_customevents : Flag<["-"], "fxray-always-emit-customevents
 def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group<f_Group>,
   Flags<[CC1Option]>;
 
+def fxray_always_emit_typedevents : Flag<["-"], "fxray-always-emit-typedevents">, Group<f_Group>,
+  Flags<[CC1Option]>,
+  HelpText<"Determine whether to always emit __xray_typedevent(...) calls even if the function it appears in is not always instrumented.">;
+def fnoxray_always_emit_typedevents : Flag<["-"], "fno-xray-always-emit-typedevents">, Group<f_Group>,
+  Flags<[CC1Option]>;
+
 def fxray_link_deps : Flag<["-"], "fxray-link-deps">, Group<f_Group>,
   Flags<[CC1Option]>,
   HelpText<"Tells clang to add the link dependencies for XRay.">;
index fd041d9bc582ba8567c452f8c835ea2bd30bebc2..c7ca9452917582f72d7a5275311d19937f55aa44 100644 (file)
@@ -29,6 +29,7 @@ class XRayArgs {
   bool XRayInstrument = false;
   int InstructionThreshold = 200;
   bool XRayAlwaysEmitCustomEvents = false;
+  bool XRayAlwaysEmitTypedEvents = false;
   bool XRayRT = true;
 
 public:
index 8d710b0c6f96738333ef42dfe802f37d3d256fbd..684f99e1de308cd6e25d0cd65476789894a764a8 100644 (file)
@@ -96,6 +96,9 @@ CODEGENOPT(StackSizeSection  , 1, 0) ///< Set when -fstack-size-section is enabl
 ///< Set when -fxray-always-emit-customevents is enabled.
 CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0)
 
+///< Set when -fxray-always-emit-typedevents is enabled.
+CODEGENOPT(XRayAlwaysEmitTypedEvents , 1, 0)
+
 ///< Set the minimum number of instructions in a function to determine selective
 ///< XRay instrumentation.
 VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200)
index 42f9038890ab10b8075d128eeca3f526e62d0818..8cc36df79468e4998e5a8b0861dc52ddcbaf6a2f 100644 (file)
@@ -21,6 +21,7 @@ XRayInstrMask parseXRayInstrValue(StringRef Value) {
                                  .Case("all", XRayInstrKind::All)
                                  .Case("custom", XRayInstrKind::Custom)
                                  .Case("function", XRayInstrKind::Function)
+                                 .Case("typed", XRayInstrKind::Typed)
                                  .Case("none", XRayInstrKind::None)
                                  .Default(XRayInstrKind::None);
   return ParsedKind;
index dd245dd5590ed2f315316d0d3129e862de48ce84..fffc2429fb13476c59ea4b6a947b1ceb7d114393 100644 (file)
@@ -3372,6 +3372,44 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
     return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1}));
   }
 
+  case Builtin::BI__xray_typedevent: {
+    // TODO: There should be a way to always emit events even if the current
+    // function is not instrumented. Losing events in a stream can cripple
+    // a trace.
+    if (!ShouldXRayInstrumentFunction())
+      return RValue::getIgnored();
+
+    if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
+            XRayInstrKind::Typed))
+      return RValue::getIgnored();
+
+    if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>())
+      if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayTypedEvents())
+        return RValue::getIgnored();
+
+    Function *F = CGM.getIntrinsic(Intrinsic::xray_typedevent);
+    auto FTy = F->getFunctionType();
+    auto Arg0 = EmitScalarExpr(E->getArg(0));
+    auto PTy0 = FTy->getParamType(0);
+    if (PTy0 != Arg0->getType())
+      Arg0 = Builder.CreateTruncOrBitCast(Arg0, PTy0);
+    auto Arg1 = E->getArg(1);
+    auto Arg1Val = EmitScalarExpr(Arg1);
+    auto Arg1Ty = Arg1->getType();
+    auto PTy1 = FTy->getParamType(1);
+    if (PTy1 != Arg1Val->getType()) {
+      if (Arg1Ty->isArrayType())
+        Arg1Val = EmitArrayToPointerDecay(Arg1).getPointer();
+      else
+        Arg1Val = Builder.CreatePointerCast(Arg1Val, PTy1);
+    }
+    auto Arg2 = EmitScalarExpr(E->getArg(2));
+    auto PTy2 = FTy->getParamType(2);
+    if (PTy2 != Arg2->getType())
+      Arg2 = Builder.CreateTruncOrBitCast(Arg2, PTy2);
+    return RValue::get(Builder.CreateCall(F, {Arg0, Arg1Val, Arg2}));
+  }
+
   case Builtin::BI__builtin_ms_va_start:
   case Builtin::BI__builtin_ms_va_end:
     return RValue::get(
index 92564043e07e7cd0810e3ae57a6329dcf3694985..bf5312550b79fe5d10799cc68b63107476488fe6 100644 (file)
@@ -466,7 +466,7 @@ bool CodeGenFunction::ShouldXRayInstrumentFunction() const {
 }
 
 /// AlwaysEmitXRayCustomEvents - Return true if we should emit IR for calls to
-/// the __xray_customevent(...) builin calls, when doing XRay instrumentation.
+/// the __xray_customevent(...) builtin calls, when doing XRay instrumentation.
 bool CodeGenFunction::AlwaysEmitXRayCustomEvents() const {
   return CGM.getCodeGenOpts().XRayInstrumentFunctions &&
          (CGM.getCodeGenOpts().XRayAlwaysEmitCustomEvents ||
@@ -474,6 +474,13 @@ bool CodeGenFunction::AlwaysEmitXRayCustomEvents() const {
               XRayInstrKind::Custom);
 }
 
+bool CodeGenFunction::AlwaysEmitXRayTypedEvents() const {
+  return CGM.getCodeGenOpts().XRayInstrumentFunctions &&
+         (CGM.getCodeGenOpts().XRayAlwaysEmitTypedEvents ||
+          CGM.getCodeGenOpts().XRayInstrumentationBundle.Mask ==
+              XRayInstrKind::Typed);
+}
+
 llvm::Constant *
 CodeGenFunction::EncodeAddrForUseInPrologue(llvm::Function *F,
                                             llvm::Constant *Addr) {
index 84118a50c1dcb51a9d482792cbdb057c652a8054..091fdc7ab7aa7e3b5aff368a6ec1ed610c538b4d 100644 (file)
@@ -1804,6 +1804,10 @@ public:
   /// XRay custom event handling calls.
   bool AlwaysEmitXRayCustomEvents() const;
 
+  /// AlwaysEmitXRayTypedEvents - Return true if clang must unconditionally emit
+  /// XRay typed event handling calls.
+  bool AlwaysEmitXRayTypedEvents() const;
+
   /// Encode an address into a form suitable for use in a function prologue.
   llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F,
                                              llvm::Constant *Addr);
index 873693354d18252347dd0df29c81bd41bfb75d97..5caeffc9d6e2cf0130db0e01c8d4665cc6d79699 100644 (file)
@@ -77,6 +77,10 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
                      options::OPT_fnoxray_always_emit_customevents, false))
       XRayAlwaysEmitCustomEvents = true;
 
+    if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents,
+                     options::OPT_fnoxray_always_emit_typedevents, false))
+      XRayAlwaysEmitTypedEvents = true;
+
     if (!Args.hasFlag(options::OPT_fxray_link_deps,
                       options::OPT_fnoxray_link_deps, true))
       XRayRT = false;
@@ -174,6 +178,9 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
   if (XRayAlwaysEmitCustomEvents)
     CmdArgs.push_back("-fxray-always-emit-customevents");
 
+  if (XRayAlwaysEmitTypedEvents)
+    CmdArgs.push_back("-fxray-always-emit-typedevents");
+
   CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) +
                                        Twine(InstructionThreshold)));
 
index 469497c485f1446b83cecf68d3f95d266e8b24d0..9146d2a36dfd18112ae593ff2c3af976f13380cf 100644 (file)
@@ -854,6 +854,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
       Args.hasArg(OPT_fxray_instrument);
   Opts.XRayAlwaysEmitCustomEvents =
       Args.hasArg(OPT_fxray_always_emit_customevents);
+  Opts.XRayAlwaysEmitTypedEvents =
+      Args.hasArg(OPT_fxray_always_emit_typedevents);
   Opts.XRayInstructionThreshold =
       getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags);
 
@@ -2678,6 +2680,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
       Args.hasFlag(OPT_fxray_always_emit_customevents,
                    OPT_fnoxray_always_emit_customevents, false);
 
+  // -fxray-always-emit-typedevents
+  Opts.XRayAlwaysEmitTypedEvents =
+      Args.hasFlag(OPT_fxray_always_emit_typedevents,
+                   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-typedevent.cpp b/test/CodeGen/xray-always-emit-typedevent.cpp
new file mode 100644 (file)
index 0000000..50593dd
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fxray-instrument -fxray-always-emit-typedevents -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_typedevent(1, kPhase, 5);
+  // CHECK: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 5)
+}
index 3e7518344758eee4a3fe0b21553c81b6a770f4ff..79286c2c8aed36369606e1e8dbd4f4a973e5baaa 100644 (file)
@@ -1,30 +1,49 @@
 // 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:     | FileCheck --check-prefixes CHECK,NOFUNCTION,NOCUSTOM,NOTYPED %s
+// RUN: %clang_cc1 -fxray-instrument -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:     | FileCheck --check-prefixes CHECK,FUNCTION,NOCUSTOM,NOTYPED %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:     | FileCheck --check-prefixes CHECK,NOFUNCTION,CUSTOM,NOTYPED %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=typed -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,NOFUNCTION,NOCUSTOM,TYPED %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=custom,typed -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,NOFUNCTION,CUSTOM,TYPED %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:     | FileCheck --check-prefixes CHECK,FUNCTION,CUSTOM,NOTYPED %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=function,typed -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,FUNCTION,NOCUSTOM,TYPED %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=function,custom,typed -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,FUNCTION,CUSTOM,TYPED %s
 // RUN: %clang_cc1 -fxray-instrument \
 // RUN:     -fxray-instrumentation-bundle=function \
-// RUN:     -fxray-instrumentation-bundle=custom -x c++ \
+// RUN:     -fxray-instrumentation-bundle=custom \
+// RUN:     -fxray-instrumentation-bundle=typed -x c++ \
 // RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
-// RUN:     | FileCheck --check-prefixes CHECK,FUNCTION,CUSTOM %s
+// RUN:     | FileCheck --check-prefixes CHECK,FUNCTION,CUSTOM,TYPED %s
 
 // CHECK: define void @_Z16alwaysInstrumentv() #[[ALWAYSATTR:[0-9]+]] {
 [[clang::xray_always_instrument]] void alwaysInstrument() {
   static constexpr char kPhase[] = "always";
   __xray_customevent(kPhase, 6);
+  __xray_typedevent(1, kPhase, 6);
   // CUSTOM: call void @llvm.xray.customevent(i8*{{.*}}, i32 6)
   // NOCUSTOM-NOT: call void @llvm.xray.customevent(i8*{{.*}}, i32 6)
+  // TYPED: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 6)
+  // NOTYPED-NOT: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 6)
 }
 
 // FUNCTION: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}
diff --git a/test/CodeGen/xray-typedevent.cpp b/test/CodeGen/xray-typedevent.cpp
new file mode 100644 (file)
index 0000000..e804b09
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fxray-instrument -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: @_Z16alwaysInstrumentv
+[[clang::xray_always_instrument]] void alwaysInstrument() {
+  // Event types would normally come from calling __xray_register_event_type
+  // from compiler-rt
+  auto EventType = 1;
+  static constexpr char kPhase[] = "instrument";
+  __xray_typedevent(EventType, kPhase, 10);
+  // CHECK: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 10)
+}
+
+// CHECK-LABEL: @_Z15neverInstrumentv
+[[clang::xray_never_instrument]] void neverInstrument() {
+  auto EventType = 2;
+  static constexpr char kPhase[] = "never";
+  __xray_typedevent(EventType, kPhase, 5);
+  // CHECK-NOT: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 5)
+}
+
+// CHECK-LABEL: @_Z21conditionalInstrumenti
+[[clang::xray_always_instrument]] void conditionalInstrument(int v) {
+  auto TrueEventType = 3;
+  auto UntrueEventType = 4;
+  static constexpr char kTrue[] = "true";
+  static constexpr char kUntrue[] = "untrue";
+  if (v % 2)
+    __xray_typedevent(TrueEventType, kTrue, 4);
+  else
+    __xray_typedevent(UntrueEventType, kUntrue, 6);
+
+  // CHECK: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 4)
+  // CHECK: call void @llvm.xray.typedevent(i16 {{.*}}, i8*{{.*}}, i32 6)
+}