// 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")
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")
#undef VALUE_LANGOPT
#undef COMPATIBLE_VALUE_LANGOPT
#undef BENIGN_VALUE_LANGOPT
-
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
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.">;
bool XRayInstrument = false;
int InstructionThreshold = 200;
bool XRayAlwaysEmitCustomEvents = false;
+ bool XRayAlwaysEmitTypedEvents = false;
bool XRayRT = true;
public:
///< 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)
.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;
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(
}
/// 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 ||
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) {
/// 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);
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;
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)));
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);
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);
--- /dev/null
+// 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)
+}
// 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" {{.*}}
--- /dev/null
+// 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)
+}