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