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: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -3369,6 +3369,41 @@ return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1})); } + case Builtin::BI__xray_typedevent: { + if (!ShouldXRayInstrumentFunction()) + return RValue::getIgnored(); + + if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::Custom)) + return RValue::getIgnored(); + + if (const auto *XRayAttr = CurFuncDecl->getAttr()) + if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) + 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: 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) +}