ianlevesque created this revision.
ianlevesque added a reviewer: dberris.
Herald added subscribers: llvm-commits, cfe-commits, hiraditya.
Herald added projects: clang, LLVM.

Extend -fxray-instrumentation-bundle to split function-entry and
function-exit into two separate options, so that it is possible to
instrument only function entry or only function exit.  For use cases
that only care about one or the other this will save significant overhead
and code size.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72890

Files:
  clang/include/clang/Basic/XRayInstr.h
  clang/include/clang/Driver/Options.td
  clang/lib/Basic/XRayInstr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/Driver/XRayArgs.cpp
  clang/test/CodeGen/xray-instrumentation-bundles.cpp
  llvm/lib/CodeGen/XRayInstrumentation.cpp
  llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-entry.ll
  llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-exit.ll

Index: llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-exit.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-exit.ll
@@ -0,0 +1,21 @@
+; RUN: llc -filetype=asm -o - -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
+
+define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" "xray-skip-exit" {
+; CHECK-LABEL: Lxray_sled_0:
+; CHECK-NEXT:  b  #32
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-LABEL: Ltmp0:
+  ret i32 0
+; CHECK-NOT: Lxray_sled_1:
+; CHECK:  ret
+}
+; CHECK-LABEL: xray_instr_map
+; CHECK-LABEL: Lxray_sleds_start0
+; CHECK:       .xword .Lxray_sled_0
+; CHECK-LABEL: Lxray_sleds_end0
Index: llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-entry.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/AArch64/xray-partial-instrumentation-skip-entry.ll
@@ -0,0 +1,21 @@
+; RUN: llc -filetype=asm -o - -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
+
+define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" "xray-skip-entry" {
+; CHECK-NOT: Lxray_sled_0:
+  ret i32 0
+; CHECK-LABEL: Lxray_sled_0:
+; CHECK-NEXT:  b  #32
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-NEXT:  nop
+; CHECK-LABEL: Ltmp0:
+; CHECK-NEXT:  ret
+}
+; CHECK-LABEL: xray_instr_map
+; CHECK-LABEL: Lxray_sleds_start0
+; CHECK:       .xword .Lxray_sled_0
+; CHECK-LABEL: Lxray_sleds_end0
Index: llvm/lib/CodeGen/XRayInstrumentation.cpp
===================================================================
--- llvm/lib/CodeGen/XRayInstrumentation.cpp
+++ llvm/lib/CodeGen/XRayInstrumentation.cpp
@@ -201,43 +201,47 @@
     return false;
   }
 
-  // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
-  // MachineFunction.
-  BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
-          TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
-
-  switch (MF.getTarget().getTargetTriple().getArch()) {
-  case Triple::ArchType::arm:
-  case Triple::ArchType::thumb:
-  case Triple::ArchType::aarch64:
-  case Triple::ArchType::mips:
-  case Triple::ArchType::mipsel:
-  case Triple::ArchType::mips64:
-  case Triple::ArchType::mips64el: {
-    // For the architectures which don't have a single return instruction
-    InstrumentationOptions op;
-    op.HandleTailcall = false;
-    op.HandleAllReturns = true;
-    prependRetWithPatchableExit(MF, TII, op);
-    break;
-  }
-  case Triple::ArchType::ppc64le: {
-    // PPC has conditional returns. Turn them into branch and plain returns.
-    InstrumentationOptions op;
-    op.HandleTailcall = false;
-    op.HandleAllReturns = true;
-    replaceRetWithPatchableRet(MF, TII, op);
-    break;
-  }
-  default: {
-    // For the architectures that have a single return instruction (such as
-    //   RETQ on x86_64).
-    InstrumentationOptions op;
-    op.HandleTailcall = true;
-    op.HandleAllReturns = false;
-    replaceRetWithPatchableRet(MF, TII, op);
-    break;
+  if (!F.hasFnAttribute("xray-skip-entry")) {
+    // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
+    // MachineFunction.
+    BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
+            TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
   }
+
+  if (!F.hasFnAttribute("xray-skip-exit")) {
+    switch (MF.getTarget().getTargetTriple().getArch()) {
+    case Triple::ArchType::arm:
+    case Triple::ArchType::thumb:
+    case Triple::ArchType::aarch64:
+    case Triple::ArchType::mips:
+    case Triple::ArchType::mipsel:
+    case Triple::ArchType::mips64:
+    case Triple::ArchType::mips64el: {
+      // For the architectures which don't have a single return instruction
+      InstrumentationOptions op;
+      op.HandleTailcall = false;
+      op.HandleAllReturns = true;
+      prependRetWithPatchableExit(MF, TII, op);
+      break;
+    }
+    case Triple::ArchType::ppc64le: {
+      // PPC has conditional returns. Turn them into branch and plain returns.
+      InstrumentationOptions op;
+      op.HandleTailcall = false;
+      op.HandleAllReturns = true;
+      replaceRetWithPatchableRet(MF, TII, op);
+      break;
+    }
+    default: {
+      // For the architectures that have a single return instruction (such as
+      //   RETQ on x86_64).
+      InstrumentationOptions op;
+      op.HandleTailcall = true;
+      op.HandleAllReturns = false;
+      replaceRetWithPatchableRet(MF, TII, op);
+      break;
+    }
+    }
   }
   return true;
 }
Index: clang/test/CodeGen/xray-instrumentation-bundles.cpp
===================================================================
--- clang/test/CodeGen/xray-instrumentation-bundles.cpp
+++ clang/test/CodeGen/xray-instrumentation-bundles.cpp
@@ -34,6 +34,18 @@
 // 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,TYPED %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=function-entry -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,NOCUSTOM,NOTYPED,SKIPEXIT %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=function-exit -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,NOCUSTOM,NOTYPED,SKIPENTRY %s
+// RUN: %clang_cc1 -fxray-instrument \
+// RUN:     -fxray-instrumentation-bundle=function-entry,function-exit -x c++ \
+// RUN:     -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
+// RUN:     | FileCheck --check-prefixes CHECK,FUNCTION,NOCUSTOM,NOTYPED %s
 
 // CHECK: define void @_Z16alwaysInstrumentv() #[[ALWAYSATTR:[0-9]+]] {
 [[clang::xray_always_instrument]] void alwaysInstrument() {
@@ -48,3 +60,6 @@
 
 // FUNCTION: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}
 // NOFUNCTION-NOT: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}
+
+// SKIPENTRY: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}} "xray-skip-entry" {{.*}}
+// SKIPEXIT: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}} "xray-skip-exit" {{.*}}
Index: clang/lib/Driver/XRayArgs.cpp
===================================================================
--- clang/lib/Driver/XRayArgs.cpp
+++ clang/lib/Driver/XRayArgs.cpp
@@ -113,7 +113,8 @@
         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)
+                           .Cases("none", "all", "function", "function-entry",
+                                  "function-exit", "custom", true)
                            .Default(false);
 
           if (!Valid) {
@@ -237,8 +238,14 @@
   } else if (InstrumentationBundle.empty()) {
     Bundle += "none";
   } else {
-    if (InstrumentationBundle.has(XRayInstrKind::Function))
+    if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) &&
+        InstrumentationBundle.has(XRayInstrKind::FunctionExit))
       Bundle += "function";
+    else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry))
+      Bundle += "function-entry";
+    else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit))
+      Bundle += "function-exit";
+
     if (InstrumentationBundle.has(XRayInstrKind::Custom))
       Bundle += "custom";
     if (InstrumentationBundle.has(XRayInstrKind::Typed))
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -803,7 +803,9 @@
     // Apply xray attributes to the function (as a string, for now)
     if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
       if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
-              XRayInstrKind::Function)) {
+              XRayInstrKind::FunctionEntry) ||
+          CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
+              XRayInstrKind::FunctionExit)) {
         if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction())
           Fn->addFnAttr("function-instrument", "xray-always");
         if (XRayAttr->neverXRayInstrument())
@@ -812,6 +814,14 @@
           if (ShouldXRayInstrumentFunction())
             Fn->addFnAttr("xray-log-args",
                           llvm::utostr(LogArgs->getArgumentCount()));
+        if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
+                XRayInstrKind::FunctionExit)) {
+          Fn->addFnAttr("xray-skip-exit");
+        }
+        if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
+                XRayInstrKind::FunctionEntry)) {
+          Fn->addFnAttr("xray-skip-entry");
+        }
       }
     } else {
       if (ShouldXRayInstrumentFunction() && !CGM.imbueXRayAttrs(Fn, Loc))
Index: clang/lib/Basic/XRayInstr.cpp
===================================================================
--- clang/lib/Basic/XRayInstr.cpp
+++ clang/lib/Basic/XRayInstr.cpp
@@ -16,13 +16,17 @@
 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("typed", XRayInstrKind::Typed)
-                                 .Case("none", XRayInstrKind::None)
-                                 .Default(XRayInstrKind::None);
+  XRayInstrMask ParsedKind =
+      llvm::StringSwitch<XRayInstrMask>(Value)
+          .Case("all", XRayInstrKind::All)
+          .Case("custom", XRayInstrKind::Custom)
+          .Case("function",
+                XRayInstrKind::FunctionEntry | XRayInstrKind::FunctionExit)
+          .Case("function-entry", XRayInstrKind::FunctionEntry)
+          .Case("function-exit", XRayInstrKind::FunctionExit)
+          .Case("typed", XRayInstrKind::Typed)
+          .Case("none", XRayInstrKind::None)
+          .Default(XRayInstrKind::None);
   return ParsedKind;
 }
 
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1301,7 +1301,7 @@
 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'.">;
+  HelpText<"Select which XRay instrumentation points to emit. Options: all, none, function-entry, function-exit, function, custom. Default is 'all'.  'function' includes both 'function-entry' and 'function-exit'.">;
 
 def ffine_grained_bitfield_accesses : Flag<["-"],
   "ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
Index: clang/include/clang/Basic/XRayInstr.h
===================================================================
--- clang/include/clang/Basic/XRayInstr.h
+++ clang/include/clang/Basic/XRayInstr.h
@@ -28,17 +28,19 @@
 
 // TODO: Auto-generate these as we add more instrumentation kinds.
 enum XRayInstrOrdinal : XRayInstrMask {
-  XRIO_Function,
+  XRIO_FunctionEntry,
+  XRIO_FunctionExit,
   XRIO_Custom,
   XRIO_Typed,
   XRIO_Count
 };
 
 constexpr XRayInstrMask None = 0;
-constexpr XRayInstrMask Function = 1U << XRIO_Function;
+constexpr XRayInstrMask FunctionEntry = 1U << XRIO_FunctionEntry;
+constexpr XRayInstrMask FunctionExit = 1U << XRIO_FunctionExit;
 constexpr XRayInstrMask Custom = 1U << XRIO_Custom;
 constexpr XRayInstrMask Typed = 1U << XRIO_Typed;
-constexpr XRayInstrMask All = Function | Custom | Typed;
+constexpr XRayInstrMask All = FunctionEntry | FunctionExit | Custom | Typed;
 
 } // namespace XRayInstrKind
 
@@ -51,7 +53,6 @@
   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);
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to