Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1455,6 +1455,7 @@ // 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: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -281,6 +281,9 @@ 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 @@ #undef VALUE_LANGOPT #undef COMPATIBLE_VALUE_LANGOPT #undef BENIGN_VALUE_LANGOPT - Index: include/clang/Basic/XRayInstr.h =================================================================== --- include/clang/Basic/XRayInstr.h +++ include/clang/Basic/XRayInstr.h @@ -31,13 +31,15 @@ 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: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1119,6 +1119,12 @@ def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group, Flags<[CC1Option]>; +def fxray_always_emit_typedevents : Flag<["-"], "fxray-always-emit-typedevents">, 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, + Flags<[CC1Option]>; + def fxray_link_deps : Flag<["-"], "fxray-link-deps">, Group, Flags<[CC1Option]>, HelpText<"Tells clang to add the link dependencies for XRay.">; Index: include/clang/Driver/XRayArgs.h =================================================================== --- include/clang/Driver/XRayArgs.h +++ include/clang/Driver/XRayArgs.h @@ -29,6 +29,7 @@ bool XRayInstrument = false; int InstructionThreshold = 200; bool XRayAlwaysEmitCustomEvents = false; + bool XRayAlwaysEmitTypedEvents = false; bool XRayRT = true; public: Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -95,6 +95,9 @@ ///< 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: lib/Basic/XRayInstr.cpp =================================================================== --- lib/Basic/XRayInstr.cpp +++ lib/Basic/XRayInstr.cpp @@ -21,6 +21,7 @@ .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: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -3369,6 +3369,44 @@ 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()) + 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: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1804,6 +1804,10 @@ /// 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: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -466,7 +466,7 @@ } /// 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 @@ 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: lib/Driver/XRayArgs.cpp =================================================================== --- lib/Driver/XRayArgs.cpp +++ lib/Driver/XRayArgs.cpp @@ -77,6 +77,10 @@ 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 @@ 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: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -845,6 +845,8 @@ 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); @@ -2669,6 +2671,11 @@ 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); Index: test/CodeGen/xray-always-emit-typedevent.cpp =================================================================== --- /dev/null +++ test/CodeGen/xray-always-emit-typedevent.cpp @@ -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: test/CodeGen/xray-instrumentation-bundles.cpp =================================================================== --- test/CodeGen/xray-instrumentation-bundles.cpp +++ test/CodeGen/xray-instrumentation-bundles.cpp @@ -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" {{.*}} Index: test/CodeGen/xray-typedevent.cpp =================================================================== --- /dev/null +++ test/CodeGen/xray-typedevent.cpp @@ -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) +}