Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -428,6 +428,16 @@ let Documentation = [Undocumented]; } +def XRayInstrument : InheritableAttr { + let Spellings = [GNU<"xray_always_instrument">, + CXX11<"clang", "xray_always_instrument">, + GNU<"xray_never_instrument">, + CXX11<"clang", "xray_never_instrument">]; + let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag, + "ExpectedFunctionOrMethod">; + let Documentation = [XRayDocs]; +} + def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2448,3 +2448,14 @@ .. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html }]; } + +def XRayDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +``__attribute__((xray_always_instrument))`` or ``[[clang:xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang:xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + }]; +} Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -755,6 +755,21 @@ def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; + +def fxray_instrument : Flag<["-"], "fxray-instrument">, Group, + Flags<[CC1Option]>, + HelpText<"Generate XRay instrumentation sleds on function entry and exit">; +def fnoxray_instrument : Flag<["-"], "fno-xray-instrument">, Group, + Flags<[CC1Option]>; + +def fxray_instruction_threshold_EQ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold=">, + Group, Flags<[CC1Option]>, + HelpText<"Sets the minimum function size to instrument with XRay">; +def fxray_instruction_threshold_ : + JoinedOrSeparate<["-"], "fxray-instruction-threshold">, + Group, Flags<[CC1Option]>; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -74,6 +74,14 @@ CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. + +CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is + ///< enabled. + +///< Set the minimum number of instructions in a function to determine selective +///< XRay instrumentation. +VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) + CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to ///< be generated. Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1447,6 +1447,10 @@ /// instrumented with __cyg_profile_func_* calls bool ShouldInstrumentFunction(); + /// ShouldXRayInstrument - Return true if the current function should be + /// instrumented with XRay nop sleds. + bool ShouldXRayInstrumentFunction(); + /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -13,9 +13,9 @@ #include "CodeGenFunction.h" #include "CGBlocks.h" -#include "CGCleanup.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" +#include "CGCleanup.h" #include "CGDebugInfo.h" #include "CGOpenMPRuntime.h" #include "CodeGenModule.h" @@ -42,15 +42,13 @@ Builder(cgm, cgm.getModule().getContext(), llvm::ConstantFolder(), CGBuilderInserterTy(this)), CurFn(nullptr), ReturnValue(Address::invalid()), - CapturedStmtInfo(nullptr), - SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false), - CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false), - IsOutlinedSEHHelper(false), - BlockInfo(nullptr), BlockPointer(nullptr), - LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), - NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), - ExceptionSlot(nullptr), EHSelectorSlot(nullptr), - DebugInfo(CGM.getModuleDebugInfo()), + CapturedStmtInfo(nullptr), SanOpts(CGM.getLangOpts().Sanitize), + IsSanitizerScope(false), CurFuncIsThunk(false), AutoreleaseResult(false), + SawAsmBlock(false), IsOutlinedSEHHelper(false), BlockInfo(nullptr), + BlockPointer(nullptr), LambdaThisCaptureField(nullptr), + NormalCleanupDest(nullptr), NextCleanupDestIndex(1), + FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), + EHSelectorSlot(nullptr), DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0), @@ -96,8 +94,9 @@ } } -CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, - AlignmentSource *Source) { +CharUnits +CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, + AlignmentSource *Source) { return getNaturalTypeAlignment(T->getPointeeType(), Source, /*forPointee*/ true); } @@ -110,12 +109,14 @@ // there's an expressivity gap here. if (auto TT = T->getAs()) { if (auto Align = TT->getDecl()->getMaxAlignment()) { - if (Source) *Source = AlignmentSource::AttributedType; + if (Source) + *Source = AlignmentSource::AttributedType; return getContext().toCharUnitsFromBits(Align); } } - if (Source) *Source = AlignmentSource::Type; + if (Source) + *Source = AlignmentSource::Type; CharUnits Alignment; if (T->isIncompleteType()) { @@ -151,14 +152,13 @@ /// Given a value of type T* that may not be to a complete object, /// construct an l-value with the natural pointee alignment of T. -LValue -CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) { +LValue CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, + QualType T) { AlignmentSource AlignSource; CharUnits Align = getNaturalTypeAlignment(T, &AlignSource, /*pointee*/ true); return MakeAddrLValue(Address(V, Align), T, AlignSource); } - llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); } @@ -243,7 +243,7 @@ // cleans up functions which started with a unified return block. if (ReturnBlock.getBlock()->hasOneUse()) { llvm::BranchInst *BI = - dyn_cast(*ReturnBlock.getBlock()->user_begin()); + dyn_cast(*ReturnBlock.getBlock()->user_begin()); if (BI && BI->isUnconditional() && BI->getSuccessor(0) == ReturnBlock.getBlock()) { // Record/return the DebugLoc of the simple 'return' expression to be used @@ -265,7 +265,8 @@ } static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) { - if (!BB) return; + if (!BB) + return; if (!BB->use_empty()) return CGF.CurFn->getBasicBlockList().push_back(BB); delete BB; @@ -275,9 +276,9 @@ assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); - bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 - && NumSimpleReturnExprs == NumReturnExprs - && ReturnBlock.getBlock()->use_empty(); + bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 && + NumSimpleReturnExprs == NumReturnExprs && + ReturnBlock.getBlock()->use_empty(); // Usually the return expression is evaluated before the cleanup // code. If the function contains only a simple return statement, // such as a constant, the location before the cleanup code becomes @@ -331,8 +332,7 @@ EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc, EndLoc); EmitEndEHSpec(CurCodeDecl); - assert(EHStack.empty() && - "did not remove all scopes from cleanup stack!"); + assert(EHStack.empty() && "did not remove all scopes from cleanup stack!"); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -378,7 +378,7 @@ if (CGM.getCodeGenOpts().EmitDeclMetadata) EmitDeclMetadata(); - for (SmallVectorImpl >::iterator + for (SmallVectorImpl>::iterator I = DeferredReplacements.begin(), E = DeferredReplacements.end(); I != E; ++I) { @@ -397,6 +397,12 @@ return true; } +/// ShouldXRayInstrument - Return true if the current function should be +/// instrumented with XRay nop sleds. +bool CodeGenFunction::ShouldXRayInstrumentFunction() { + return CGM.getCodeGenOpts().XRayInstrumentFunctions; +} + /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. @@ -404,20 +410,17 @@ auto NL = ApplyDebugLocation::CreateArtificial(*this); // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); llvm::PointerType *PointerTy = Int8PtrTy; - llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; + llvm::Type *ProfileFuncArgs[] = {PointerTy, PointerTy}; llvm::FunctionType *FunctionTy = - llvm::FunctionType::get(VoidTy, ProfileFuncArgs, false); + llvm::FunctionType::get(VoidTy, ProfileFuncArgs, false); llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn); - llvm::CallInst *CallSite = Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::returnaddress), - llvm::ConstantInt::get(Int32Ty, 0), - "callsite"); + llvm::CallInst *CallSite = + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::returnaddress), + llvm::ConstantInt::get(Int32Ty, 0), "callsite"); - llvm::Value *args[] = { - llvm::ConstantExpr::getBitCast(CurFn, PointerTy), - CallSite - }; + llvm::Value *args[] = {llvm::ConstantExpr::getBitCast(CurFn, PointerTy), + CallSite}; EmitNounwindRuntimeCall(F, args); } @@ -426,7 +429,7 @@ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); llvm::Constant *MCountFn = - CGM.CreateRuntimeFunction(FTy, getTarget().getMCountName()); + CGM.CreateRuntimeFunction(FTy, getTarget().getMCountName()); EmitNounwindRuntimeCall(MCountFn); } @@ -479,7 +482,7 @@ // Turn "unsigned type" to "utype" std::string::size_type pos = typeName.find("unsigned"); if (pointeeTy.isCanonical() && pos != std::string::npos) - typeName.erase(pos+1, 8); + typeName.erase(pos + 1, 8); argTypeNames.push_back(llvm::MDString::get(Context, typeName)); @@ -491,7 +494,7 @@ // Turn "unsigned type" to "utype" pos = baseTypeName.find("unsigned"); if (pos != std::string::npos) - baseTypeName.erase(pos+1, 8); + baseTypeName.erase(pos + 1, 8); argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName)); @@ -507,8 +510,7 @@ uint32_t AddrSpc = 0; bool isPipe = ty->isPipeType(); if (ty->isImageType() || isPipe) - AddrSpc = - CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + AddrSpc = CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); addressQuals.push_back( llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc))); @@ -523,22 +525,23 @@ // Turn "unsigned type" to "utype" std::string::size_type pos = typeName.find("unsigned"); if (ty.isCanonical() && pos != std::string::npos) - typeName.erase(pos+1, 8); + typeName.erase(pos + 1, 8); argTypeNames.push_back(llvm::MDString::get(Context, typeName)); std::string baseTypeName; if (isPipe) baseTypeName = - cast(ty)->getElementType().getCanonicalType().getAsString(Policy); + cast(ty)->getElementType().getCanonicalType().getAsString( + Policy); else baseTypeName = - ty.getUnqualifiedType().getCanonicalType().getAsString(Policy); + ty.getUnqualifiedType().getCanonicalType().getAsString(Policy); // Turn "unsigned type" to "utype" pos = baseTypeName.find("unsigned"); if (pos != std::string::npos) - baseTypeName.erase(pos+1, 8); + baseTypeName.erase(pos + 1, 8); argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName)); @@ -554,7 +557,7 @@ argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals)); // Get image and pipe access qualifier: - if (ty->isImageType()|| ty->isPipeType()) { + if (ty->isImageType() || ty->isPipeType()) { const OpenCLAccessAttr *A = parm->getAttr(); if (A && A->isWriteOnly()) accessQuals.push_back(llvm::MDString::get(Context, "write_only")); @@ -573,20 +576,17 @@ llvm::MDNode::get(Context, addressQuals)); Fn->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(Context, accessQuals)); - Fn->setMetadata("kernel_arg_type", - llvm::MDNode::get(Context, argTypeNames)); + Fn->setMetadata("kernel_arg_type", llvm::MDNode::get(Context, argTypeNames)); Fn->setMetadata("kernel_arg_base_type", llvm::MDNode::get(Context, argBaseTypeNames)); Fn->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(Context, argTypeQuals)); if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata) - Fn->setMetadata("kernel_arg_name", - llvm::MDNode::get(Context, argNames)); + Fn->setMetadata("kernel_arg_name", llvm::MDNode::get(Context, argNames)); } void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, - llvm::Function *Fn) -{ + llvm::Function *Fn) { if (!FD->hasAttr()) return; @@ -614,7 +614,8 @@ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))}; - Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, attrMDArgs)); + Fn->setMetadata("work_group_size_hint", + llvm::MDNode::get(Context, attrMDArgs)); } if (const ReqdWorkGroupSizeAttr *A = FD->getAttr()) { @@ -622,12 +623,13 @@ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))}; - Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, attrMDArgs)); + Fn->setMetadata("reqd_work_group_size", + llvm::MDNode::get(Context, attrMDArgs)); } } /// Determine whether the function F ends with a return stmt. -static bool endsWithReturn(const Decl* F) { +static bool endsWithReturn(const Decl *F) { const Stmt *Body = nullptr; if (auto *FD = dyn_cast_or_null(F)) Body = FD->getBody(); @@ -642,8 +644,7 @@ return false; } -void CodeGenFunction::StartFunction(GlobalDecl GD, - QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -684,13 +685,35 @@ if (SanOpts.has(SanitizerKind::SafeStack)) Fn->addFnAttr(llvm::Attribute::SafeStack); + // Apply xray attributes to the function. + if (ShouldXRayInstrumentFunction()) { + if (D->hasAttr()) { + switch (D->getAttr()->getSpellingListIndex()) { + case 0: + case 1: + Fn->addFnAttr("function-instrument", "xray-always"); + break; + case 2: + case 3: + Fn->addFnAttr("function-instrument", "xray-never"); + break; + default: + llvm_unreachable("Unknown attribute index for XRay instrumentation"); + } + } else { + Fn->addFnAttr( + "xray-instruction-threshold", + llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); + } + } + // Pass inline keyword to optimizer if it appears explicitly on any // declaration. Also, in the case of -fno-inline attach NoInline // attribute to all functions that are not marked AlwaysInline, or // to all functions that are not marked inline or implicitly inline // in the case of -finline-hint-functions. if (const FunctionDecl *FD = dyn_cast_or_null(D)) { - const CodeGenOptions& CodeGenOpts = CGM.getCodeGenOpts(); + const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts(); if (!CodeGenOpts.NoInline) { for (auto RI : FD->redecls()) if (RI->isInlineSpecified()) { @@ -724,7 +747,7 @@ CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) { llvm::Constant *FTRTTIConst = CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true); - llvm::Constant *PrologueStructElems[] = { PrologueSig, FTRTTIConst }; + llvm::Constant *PrologueStructElems[] = {PrologueSig, FTRTTIConst}; llvm::Constant *PrologueStructConst = llvm::ConstantStruct::getAnon(PrologueStructElems, /*Packed=*/true); Fn->setPrologueData(PrologueStructConst); @@ -739,7 +762,7 @@ if (const FunctionDecl *FD = dyn_cast_or_null(D)) if (FD->isMain()) Fn->addFnAttr(llvm::Attribute::NoRecurse); - + llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn); // Create a marker to make it easy to insert allocas into the entryblock @@ -805,8 +828,7 @@ // Tell the epilog emitter to autorelease the result. We do this // now so that various specialized functions can suppress it // during their IR-generation. - if (getLangOpts().ObjCAutoRefCount && - !CurFnInfo->isReturnsRetained() && + if (getLangOpts().ObjCAutoRefCount && !CurFnInfo->isReturnsRetained() && RetTy->isObjCRetainableType()) AutoreleaseResult = true; } @@ -819,8 +841,7 @@ if (D && isa(D) && cast(D)->isInstance()) { CGM.getCXXABI().EmitInstanceFunctionProlog(*this); const CXXMethodDecl *MD = cast(D); - if (MD->getParent()->isLambda() && - MD->getOverloadedOperator() == OO_Call) { + if (MD->getParent()->isLambda() && MD->getOverloadedOperator() == OO_Call) { // We're in a lambda; figure out the captures. MD->getParent()->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); @@ -831,21 +852,24 @@ // Get the lvalue for the field (which is a copy of the enclosing object // or contains the address of the enclosing object). - LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); + LValue ThisFieldLValue = + EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { - // If the enclosing object was captured by value, just use its address. + // If the enclosing object was captured by value, just use its + // address. CXXThisValue = ThisFieldLValue.getAddress().getPointer(); } else { // Load the lvalue pointed to by the field, since '*this' was captured // by reference. - CXXThisValue = - EmitLoadOfLValue(ThisFieldLValue, SourceLocation()).getScalarVal(); + CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation()) + .getScalarVal(); } } for (auto *FD : MD->getParent()->fields()) { if (FD->hasCapturedVLAType()) { - auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD), - SourceLocation()).getScalarVal(); + auto *ExprArg = + EmitLoadOfLValue(EmitLValueForLambdaField(FD), SourceLocation()) + .getScalarVal(); auto VAT = FD->getCapturedVLAType(); VLASizeMap[VAT->getSizeExpr()] = ExprArg; } @@ -860,8 +884,8 @@ // If any of the arguments have a variably modified type, make sure to // emit the type size. - for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); - i != e; ++i) { + for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; + ++i) { const VarDecl *VD = *i; // Dig out the type as written from ParmVarDecls; it's unclear whether @@ -918,7 +942,8 @@ static void TryMarkNoThrow(llvm::Function *F) { // LLVM treats 'nounwind' on a function as part of the type, so we // can't do this on functions that can be overwritten. - if (F->isInterposable()) return; + if (F->isInterposable()) + return; for (llvm::BasicBlock &BB : *F) for (llvm::Instruction &I : BB) @@ -966,7 +991,8 @@ CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args); SourceRange BodyRange; - if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); + if (Stmt *Body = FD->getBody()) + BodyRange = Body->getSourceRange(); CurEHLocation = BodyRange.getEnd(); // Use the location of the start of the function to determine where @@ -991,8 +1017,7 @@ EmitDestructorBody(Args); else if (isa(FD)) EmitConstructorBody(Args); - else if (getLangOpts().CUDA && - !getLangOpts().CUDAIsDevice && + else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && FD->hasAttr()) CGM.getCUDARuntime().emitDeviceStub(*this, Args); else if (isa(FD) && @@ -1051,7 +1076,8 @@ /// that we can just remove the code. bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) { // Null statement, not a label! - if (!S) return false; + if (!S) + return false; // If this is a label, we have to emit the code, consider something like: // if (0) { ... foo: bar(); } goto foo; @@ -1083,7 +1109,8 @@ /// inside of it, this is fine. bool CodeGenFunction::containsBreak(const Stmt *S) { // Null statement, not a label! - if (!S) return false; + if (!S) + return false; // If this is a switch or loop that defines its own break scope, then we can // include it and anything inside of it. @@ -1102,7 +1129,6 @@ return false; } - /// ConstantFoldsToSimpleInteger - If the specified expression does not fold /// to a constant, or if it does but contains a label, return false. If it /// constant folds return true and set the boolean result in Result. @@ -1127,17 +1153,15 @@ // to bool. llvm::APSInt Int; if (!Cond->EvaluateAsInt(Int, getContext())) - return false; // Not foldable, not integer or not fully evaluatable. + return false; // Not foldable, not integer or not fully evaluatable. if (!AllowLabels && CodeGenFunction::ContainsLabel(Cond)) - return false; // Contains a label. + return false; // Contains a label. ResultInt = Int; return true; } - - /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if /// statement) to the specified blocks. Based on the condition, this might try /// to simplify the codegen of the conditional based on the branch. @@ -1305,7 +1329,7 @@ // br(c ? throw x : y, t, f) -> br(c, br(throw x, t, f), br(y, t, f) // Fold this to: // br(c, throw x, br(y, t, f)) - EmitCXXThrowExpr(Throw, /*KeepInsertionPoint*/false); + EmitCXXThrowExpr(Throw, /*KeepInsertionPoint*/ false); return; } @@ -1356,13 +1380,12 @@ CGBuilderTy &Builder = CGF.Builder; CharUnits baseSize = CGF.getContext().getTypeSizeInChars(baseType); - llvm::Value *baseSizeInChars - = llvm::ConstantInt::get(CGF.IntPtrTy, baseSize.getQuantity()); + llvm::Value *baseSizeInChars = + llvm::ConstantInt::get(CGF.IntPtrTy, baseSize.getQuantity()); - Address begin = - Builder.CreateElementBitCast(dest, CGF.Int8Ty, "vla.begin"); + Address begin = Builder.CreateElementBitCast(dest, CGF.Int8Ty, "vla.begin"); llvm::Value *end = - Builder.CreateInBoundsGEP(begin.getPointer(), sizeInChars, "vla.end"); + Builder.CreateInBoundsGEP(begin.getPointer(), sizeInChars, "vla.end"); llvm::BasicBlock *originBB = CGF.Builder.GetInsertBlock(); llvm::BasicBlock *loopBB = CGF.createBasicBlock("vla-init.loop"); @@ -1375,8 +1398,7 @@ llvm::PHINode *cur = Builder.CreatePHI(begin.getType(), 2, "vla.cur"); cur->addIncoming(begin.getPointer(), originBB); - CharUnits curAlign = - dest.getAlignment().alignmentOfArrayElement(baseSize); + CharUnits curAlign = dest.getAlignment().alignmentOfArrayElement(baseSize); // memcpy the individual element bit-pattern. Builder.CreateMemCpy(Address(cur, curAlign), src, baseSizeInChars, @@ -1384,7 +1406,7 @@ // Go to the next element. llvm::Value *next = - Builder.CreateInBoundsGEP(CGF.Int8Ty, cur, baseSizeInChars, "vla.next"); + Builder.CreateInBoundsGEP(CGF.Int8Ty, cur, baseSizeInChars, "vla.next"); // Leave if that's the end of the VLA. llvm::Value *done = Builder.CreateICmpEQ(next, end, "vla-init.isdone"); @@ -1394,8 +1416,7 @@ CGF.EmitBlock(contBB); } -void -CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) { +void CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) { // Ignore empty classes in C++. if (getLangOpts().CPlusPlus) { if (const RecordType *RT = Ty->getAs()) { @@ -1417,9 +1438,8 @@ // Don't bother emitting a zero-byte memset. if (size.isZero()) { // But note that getTypeInfo returns 0 for a VLA. - if (const VariableArrayType *vlaType = - dyn_cast_or_null( - getContext().getAsArrayType(Ty))) { + if (const VariableArrayType *vlaType = dyn_cast_or_null( + getContext().getAsArrayType(Ty))) { QualType eltType; llvm::Value *numElts; std::tie(numElts, eltType) = getVLASize(vlaType); @@ -1443,21 +1463,22 @@ // like -1, which happens to be the pattern used by member-pointers. if (!CGM.getTypes().isZeroInitializable(Ty)) { // For a VLA, emit a single element, then splat that over the VLA. - if (vla) Ty = getContext().getBaseElementType(vla); + if (vla) + Ty = getContext().getBaseElementType(vla); llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); - llvm::GlobalVariable *NullVariable = - new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), - /*isConstant=*/true, - llvm::GlobalVariable::PrivateLinkage, - NullConstant, Twine()); + llvm::GlobalVariable *NullVariable = new llvm::GlobalVariable( + CGM.getModule(), NullConstant->getType(), + /*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, NullConstant, + Twine()); CharUnits NullAlign = DestPtr.getAlignment(); NullVariable->setAlignment(NullAlign.getQuantity()); Address SrcPtr(Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()), NullAlign); - if (vla) return emitNonZeroVLAInit(*this, Ty, DestPtr, SrcPtr, SizeVal); + if (vla) + return emitNonZeroVLAInit(*this, Ty, DestPtr, SrcPtr, SizeVal); // Get and call the appropriate llvm.memcpy overload. Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, false); @@ -1484,13 +1505,14 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { // If we already made the indirect branch for indirect goto, return its block. - if (IndirectBranch) return IndirectBranch->getParent(); + if (IndirectBranch) + return IndirectBranch->getParent(); CGBuilderTy TmpBuilder(*this, createBasicBlock("indirectgoto")); // Create the PHI node that indirect gotos will add entries to. - llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0, - "indirect.goto.dest"); + llvm::Value *DestVal = + TmpBuilder.CreatePHI(Int8PtrTy, 0, "indirect.goto.dest"); // Create the indirect branch instruction. IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal); @@ -1530,7 +1552,7 @@ // We have some number of constant-length arrays, so addr should // have LLVM type [M x [N x [...]]]*. Build a GEP that walks // down to the first element of addr. - SmallVector gepIndices; + SmallVector gepIndices; // GEP down to the array type. llvm::ConstantInt *zero = Builder.getInt32(0); @@ -1540,18 +1562,17 @@ QualType eltType; llvm::ArrayType *llvmArrayType = - dyn_cast(addr.getElementType()); + dyn_cast(addr.getElementType()); while (llvmArrayType) { assert(isa(arrayType)); - assert(cast(arrayType)->getSize().getZExtValue() - == llvmArrayType->getNumElements()); + assert(cast(arrayType)->getSize().getZExtValue() == + llvmArrayType->getNumElements()); gepIndices.push_back(zero); countFromCLAs *= llvmArrayType->getNumElements(); eltType = arrayType->getElementType(); - llvmArrayType = - dyn_cast(llvmArrayType->getElementType()); + llvmArrayType = dyn_cast(llvmArrayType->getElementType()); arrayType = getContext().getAsArrayType(arrayType->getElementType()); assert((!llvmArrayType || arrayType) && "LLVM and Clang types are out-of-synch"); @@ -1572,15 +1593,14 @@ addr = Builder.CreateElementBitCast(addr, baseType, "array.begin"); } else { // Create the actual GEP. - addr = Address(Builder.CreateInBoundsGEP(addr.getPointer(), - gepIndices, "array.begin"), - addr.getAlignment()); + addr = Address( + Builder.CreateInBoundsGEP(addr.getPointer(), gepIndices, "array.begin"), + addr.getAlignment()); } baseType = eltType; - llvm::Value *numElements - = llvm::ConstantInt::get(SizeTy, countFromCLAs); + llvm::Value *numElements = llvm::ConstantInt::get(SizeTy, countFromCLAs); // If we had any VLA dimensions, factor them in. if (numVLAElements) @@ -1589,14 +1609,13 @@ return numElements; } -std::pair -CodeGenFunction::getVLASize(QualType type) { +std::pair CodeGenFunction::getVLASize(QualType type) { const VariableArrayType *vla = getContext().getAsVariableArrayType(type); assert(vla && "type was not a variable array type!"); return getVLASize(vla); } -std::pair +std::pair CodeGenFunction::getVLASize(const VariableArrayType *type) { // The number of elements so far; always size_t. llvm::Value *numElements = nullptr; @@ -1617,7 +1636,7 @@ } } while ((type = getContext().getAsVariableArrayType(elementType))); - return std::pair(numElements, elementType); + return std::pair(numElements, elementType); } void CodeGenFunction::EmitVariablyModifiedType(QualType type) { @@ -1709,9 +1728,8 @@ SanitizerScope SanScope(this); llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType()); llvm::Constant *StaticArgs[] = { - EmitCheckSourceLocation(size->getLocStart()), - EmitCheckTypeDescriptor(size->getType()) - }; + EmitCheckSourceLocation(size->getLocStart()), + EmitCheckTypeDescriptor(size->getType())}; EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero), SanitizerKind::VLABound), "vla_bound_not_positive", StaticArgs, Size); @@ -1763,7 +1781,7 @@ } while (type->isVariablyModifiedType()); } -Address CodeGenFunction::EmitVAListRef(const Expr* E) { +Address CodeGenFunction::EmitVAListRef(const Expr *E) { if (getContext().getBuiltinVaListType()->isArrayType()) return EmitPointerWithAlignment(E); return EmitLValue(E).getAddress(); @@ -1775,7 +1793,7 @@ void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init) { - assert (Init && "Invalid DeclRefExpr initializer!"); + assert(Init && "Invalid DeclRefExpr initializer!"); if (CGDebugInfo *Dbg = getDebugInfo()) if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) Dbg->EmitGlobalVariable(E->getDecl(), Init); @@ -1787,9 +1805,11 @@ // is trunc(zext) folding, but if we add more, we can easily // extend this protection. - if (!rvalue.isScalar()) return PeepholeProtection(); + if (!rvalue.isScalar()) + return PeepholeProtection(); llvm::Value *value = rvalue.getScalarVal(); - if (!isa(value)) return PeepholeProtection(); + if (!isa(value)) + return PeepholeProtection(); // Just make an extra bitcast. assert(HaveInsertPoint()); @@ -1802,7 +1822,8 @@ } void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) { - if (!protection.Inst) return; + if (!protection.Inst) + return; // In theory, we could try to duplicate the peepholes now, but whatever. protection.Inst->eraseFromParent(); @@ -1813,11 +1834,10 @@ StringRef AnnotationStr, SourceLocation Location) { llvm::Value *Args[4] = { - AnnotatedVal, - Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy), - Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy), - CGM.EmitAnnotationLineNo(Location) - }; + AnnotatedVal, + Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy), + Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy), + CGM.EmitAnnotationLineNo(Location)}; return Builder.CreateCall(AnnotationFn, Args); } @@ -1836,8 +1856,8 @@ assert(D->hasAttr() && "no annotate attribute"); llvm::Value *V = Addr.getPointer(); llvm::Type *VTy = V->getType(); - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, - CGM.Int8PtrTy); + llvm::Value *F = + CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, CGM.Int8PtrTy); for (const auto *I : D->specific_attrs()) { // FIXME Always emit the cast inst so we can differentiate between @@ -1852,7 +1872,7 @@ return Address(V, Addr.getAlignment()); } -CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { } +CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() {} CodeGenFunction::SanitizerScope::SanitizerScope(CodeGenFunction *CGF) : CGF(CGF) { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3178,6 +3178,28 @@ return !StaticRuntimes.empty(); } +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + return false; +} + +static void linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-latomic"); + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + CmdArgs.push_back("-ldl"); +} + static bool areOptimizationsEnabled(const ArgList &Args) { // Find the last -O arg and see if it is non-zero. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) @@ -4579,6 +4601,16 @@ Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasArg(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-fxray-instrument"); + if (Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, + options::OPT_fxray_instruction_threshold_EQ)) { + CmdArgs.push_back("-fxray-instruction-threshold"); + CmdArgs.push_back(A->getValue()); + } + } + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); // Add runtime flag for PS4 when PGO or Coverage are enabled. @@ -9344,6 +9376,7 @@ CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9370,6 +9403,9 @@ if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, CmdArgs); + bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -685,6 +685,9 @@ } Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + Opts.XRayInstructionThreshold = + getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5913,10 +5913,13 @@ case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute(S, D, Attr); break; + // XRay attributes. + case AttributeList::AT_XRayInstrument: + handleSimpleAttribute(S, D, Attr); + break; } } Index: test/CodeGen/xray-attributes-supported.cpp =================================================================== --- /dev/null +++ test/CodeGen/xray-attributes-supported.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple x86_64-unknown-linux-gnu | FileCheck %s + +// Make sure that the LLVM attribute for XRay-annotated functions do show up. +[[clang::xray_always_instrument]] void foo() { +// CHECK: define void @_Z3foov() #0 +}; + +[[clang::xray_never_instrument]] void bar() { +// CHECK: define void @_Z3barv() #1 +}; + +// CHECK: #0 = {{.*}}"function-instrument"="xray-always" +// CHECK: #1 = {{.*}}"function-instrument"="xray-never" Index: test/Sema/xray-always-instrument-attr.c =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c11 +void foo() __attribute__((xray_always_instrument)); + +struct __attribute__((xray_always_instrument)) a { int x; }; // expected-warning {{'xray_always_instrument' attribute only applies to functions and methods}} + +void bar() __attribute__((xray_always_instrument("not-supported"))); // expected-error {{'xray_always_instrument' attribute takes no arguments}} Index: test/Sema/xray-always-instrument-attr.cpp =================================================================== --- /dev/null +++ test/Sema/xray-always-instrument-attr.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++ +void foo [[clang::xray_always_instrument]] (); + +struct [[clang::xray_always_instrument]] a { int x; }; // expected-warning {{'xray_always_instrument' attribute only applies to functions and methods}} + +class b { + void c [[clang::xray_always_instrument]] (); +}; + +void baz [[clang::xray_always_instrument("not-supported")]] (); // expected-error {{'xray_always_instrument' attribute takes no arguments}}