CMake build fixed in r214758
On Mon, Aug 4, 2014 at 11:41 AM, Alex Lorenz <[email protected]> wrote: > Author: arphaman > Date: Mon Aug 4 13:41:51 2014 > New Revision: 214752 > > URL: http://llvm.org/viewvc/llvm-project?rev=214752&view=rev > Log: > Add coverage mapping generation. > > This patch adds the '-fcoverage-mapping' option which > allows clang to generate the coverage mapping information > that can be used to provide code coverage analysis using > the execution counts obtained from the instrumentation > based profiling (-fprofile-instr-generate). > > Added: > cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp > cfe/trunk/lib/CodeGen/CoverageMappingGen.h > Modified: > cfe/trunk/include/clang/CodeGen/CodeGenABITypes.h > cfe/trunk/include/clang/CodeGen/ModuleBuilder.h > cfe/trunk/include/clang/Driver/Options.td > cfe/trunk/include/clang/Frontend/CodeGenOptions.def > cfe/trunk/lib/CodeGen/CodeGenABITypes.cpp > cfe/trunk/lib/CodeGen/CodeGenAction.cpp > cfe/trunk/lib/CodeGen/CodeGenFunction.cpp > cfe/trunk/lib/CodeGen/CodeGenModule.cpp > cfe/trunk/lib/CodeGen/CodeGenModule.h > cfe/trunk/lib/CodeGen/CodeGenPGO.cpp > cfe/trunk/lib/CodeGen/CodeGenPGO.h > cfe/trunk/lib/CodeGen/ModuleBuilder.cpp > cfe/trunk/lib/Driver/Tools.cpp > cfe/trunk/lib/Frontend/CompilerInvocation.cpp > > Modified: cfe/trunk/include/clang/CodeGen/CodeGenABITypes.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/CodeGenABITypes.h?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/include/clang/CodeGen/CodeGenABITypes.h (original) > +++ cfe/trunk/include/clang/CodeGen/CodeGenABITypes.h Mon Aug 4 13:41:51 2014 > @@ -39,6 +39,7 @@ class CXXRecordDecl; > class CodeGenOptions; > class DiagnosticsEngine; > class ObjCMethodDecl; > +class CoverageSourceInfo; > > namespace CodeGen { > class CGFunctionInfo; > @@ -47,7 +48,8 @@ class CodeGenModule; > class CodeGenABITypes > { > public: > - CodeGenABITypes(ASTContext &C, llvm::Module &M, const llvm::DataLayout > &TD); > + CodeGenABITypes(ASTContext &C, llvm::Module &M, const llvm::DataLayout &TD, > + CoverageSourceInfo *CoverageInfo = nullptr); > ~CodeGenABITypes(); > > /// These methods all forward to methods in the private implementation > class > > Modified: cfe/trunk/include/clang/CodeGen/ModuleBuilder.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/ModuleBuilder.h?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/include/clang/CodeGen/ModuleBuilder.h (original) > +++ cfe/trunk/include/clang/CodeGen/ModuleBuilder.h Mon Aug 4 13:41:51 2014 > @@ -24,6 +24,7 @@ namespace llvm { > > namespace clang { > class DiagnosticsEngine; > + class CoverageSourceInfo; > class LangOptions; > class CodeGenOptions; > class TargetOptions; > @@ -44,7 +45,8 @@ namespace clang { > const std::string &ModuleName, > const CodeGenOptions &CGO, > const TargetOptions &TO, > - llvm::LLVMContext& C); > + llvm::LLVMContext& C, > + CoverageSourceInfo *CoverageInfo = > nullptr); > } > > #endif > > Modified: cfe/trunk/include/clang/Driver/Options.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Driver/Options.td (original) > +++ cfe/trunk/include/clang/Driver/Options.td Mon Aug 4 13:41:51 2014 > @@ -408,6 +408,9 @@ def fprofile_instr_use : Flag<["-"], "fp > def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, > Group<f_Group>, Flags<[CC1Option]>, > HelpText<"Use instrumentation data for profile-guided optimization">; > +def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, > + Group<f_Group>, Flags<[CC1Option]>, > + HelpText<"Generate coverage mapping to enable code coverage analysis">; > > def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, > HelpText<"Enable the 'blocks' language feature">; > > Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original) > +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Mon Aug 4 13:41:51 > 2014 > @@ -88,6 +88,8 @@ VALUE_CODEGENOPT(OptimizeSize, 2, 0) /// > > CODEGENOPT(ProfileInstrGenerate , 1, 0) ///< Instrument code to generate > ///< execution counts to use with > PGO. > +CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to > + ///< enable code coverage analysis. > > /// If -fpcc-struct-return or -freg-struct-return is specified. > ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, > SRCK_Default) > > Modified: cfe/trunk/lib/CodeGen/CodeGenABITypes.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenABITypes.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenABITypes.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenABITypes.cpp Mon Aug 4 13:41:51 2014 > @@ -26,9 +26,11 @@ using namespace CodeGen; > > CodeGenABITypes::CodeGenABITypes(ASTContext &C, > llvm::Module &M, > - const llvm::DataLayout &TD) > + const llvm::DataLayout &TD, > + CoverageSourceInfo *CoverageInfo) > : CGO(new CodeGenOptions), > - CGM(new CodeGen::CodeGenModule(C, *CGO, M, TD, C.getDiagnostics())) { > + CGM(new CodeGen::CodeGenModule(C, *CGO, M, TD, C.getDiagnostics(), > + CoverageInfo)) { > } > > CodeGenABITypes::~CodeGenABITypes() > > Modified: cfe/trunk/lib/CodeGen/CodeGenAction.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenAction.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenAction.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenAction.cpp Mon Aug 4 13:41:51 2014 > @@ -7,6 +7,7 @@ > // > > //===----------------------------------------------------------------------===// > > +#include "CoverageMappingGen.h" > #include "clang/CodeGen/CodeGenAction.h" > #include "clang/AST/ASTConsumer.h" > #include "clang/AST/ASTContext.h" > @@ -15,6 +16,7 @@ > #include "clang/Basic/FileManager.h" > #include "clang/Basic/SourceManager.h" > #include "clang/Basic/TargetInfo.h" > +#include "clang/Lex/Preprocessor.h" > #include "clang/CodeGen/BackendUtil.h" > #include "clang/CodeGen/ModuleBuilder.h" > #include "clang/Frontend/CompilerInstance.h" > @@ -59,11 +61,13 @@ namespace clang { > const TargetOptions &targetopts, > const LangOptions &langopts, bool TimePasses, > const std::string &infile, llvm::Module *LinkModule, > - raw_ostream *OS, LLVMContext &C) > + raw_ostream *OS, LLVMContext &C, > + CoverageSourceInfo *CoverageInfo = nullptr) > : Diags(_Diags), Action(action), CodeGenOpts(compopts), > TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS), > Context(), LLVMIRGeneration("LLVM IR Generation Time"), > - Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)), > + Gen(CreateLLVMCodeGen(Diags, infile, compopts, > + targetopts, C, CoverageInfo)), > LinkModule(LinkModule) { > llvm::TimePassesIsEnabled = TimePasses; > } > @@ -636,10 +640,17 @@ ASTConsumer *CodeGenAction::CreateASTCon > LinkModuleToUse = ModuleOrErr.get(); > } > > + CoverageSourceInfo *CoverageInfo = nullptr; > + // Add the preprocessor callback only when the coverage mapping is > generated. > + if (CI.getCodeGenOpts().CoverageMapping) { > + CoverageInfo = new CoverageSourceInfo; > + CI.getPreprocessor().addPPCallbacks(CoverageInfo); > + } > BEConsumer = new BackendConsumer(BA, CI.getDiagnostics(), > CI.getCodeGenOpts(), > CI.getTargetOpts(), CI.getLangOpts(), > CI.getFrontendOpts().ShowTimers, InFile, > - LinkModuleToUse, OS.release(), > *VMContext); > + LinkModuleToUse, OS.release(), *VMContext, > + CoverageInfo); > return BEConsumer; > } > > > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Mon Aug 4 13:41:51 2014 > @@ -829,6 +829,7 @@ void CodeGenFunction::GenerateCode(Globa > StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin()); > > // Generate the body of the function. > + PGO.checkGlobalDecl(GD); > PGO.assignRegionCounters(GD.getDecl(), CurFn); > if (isa<CXXDestructorDecl>(FD)) > EmitDestructorBody(Args); > > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Aug 4 13:41:51 2014 > @@ -21,6 +21,7 @@ > #include "CGOpenMPRuntime.h" > #include "CodeGenFunction.h" > #include "CodeGenPGO.h" > +#include "CoverageMappingGen.h" > #include "CodeGenTBAA.h" > #include "TargetInfo.h" > #include "clang/AST/ASTContext.h" > @@ -74,7 +75,8 @@ static CGCXXABI *createCXXABI(CodeGenMod > > CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, > llvm::Module &M, const llvm::DataLayout &TD, > - DiagnosticsEngine &diags) > + DiagnosticsEngine &diags, > + CoverageSourceInfo *CoverageInfo) > : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M), > Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()), > ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(nullptr), > @@ -146,6 +148,11 @@ CodeGenModule::CodeGenModule(ASTContext > getDiags().Report(DiagID) << EC.message(); > } > } > + > + // If coverage mapping generation is enabled, create the > + // CoverageMappingModuleGen object. > + if (CodeGenOpts.CoverageMapping) > + CoverageMapping.reset(new CoverageMappingModuleGen(*this, > *CoverageInfo)); > } > > CodeGenModule::~CodeGenModule() { > @@ -344,6 +351,9 @@ void CodeGenModule::Release() { > EmitCtorList(GlobalDtors, "llvm.global_dtors"); > EmitGlobalAnnotations(); > EmitStaticExternCAliases(); > + EmitDeferredUnusedCoverageMappings(); > + if (CoverageMapping) > + CoverageMapping->emit(); > emitLLVMUsed(); > > if (CodeGenOpts.Autolink && > @@ -2989,6 +2999,9 @@ void CodeGenModule::EmitTopLevelDecl(Dec > return; > > EmitGlobal(cast<FunctionDecl>(D)); > + // Always provide some coverage mapping > + // even for the functions that aren't emitted. > + AddDeferredUnusedCoverageMapping(D); > break; > > case Decl::Var: > @@ -3138,6 +3151,80 @@ void CodeGenModule::EmitTopLevelDecl(Dec > } > } > > +void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) { > + // Do we need to generate coverage mapping? > + if (!CodeGenOpts.CoverageMapping) > + return; > + switch (D->getKind()) { > + case Decl::CXXConversion: > + case Decl::CXXMethod: > + case Decl::Function: > + case Decl::ObjCMethod: > + case Decl::CXXConstructor: > + case Decl::CXXDestructor: { > + if (!cast<FunctionDecl>(D)->hasBody()) > + return; > + auto I = DeferredEmptyCoverageMappingDecls.find(D); > + if (I == DeferredEmptyCoverageMappingDecls.end()) > + DeferredEmptyCoverageMappingDecls[D] = true; > + break; > + } > + default: > + break; > + }; > +} > + > +void CodeGenModule::ClearUnusedCoverageMapping(const Decl *D) { > + // Do we need to generate coverage mapping? > + if (!CodeGenOpts.CoverageMapping) > + return; > + if (const auto *Fn = dyn_cast<FunctionDecl>(D)) { > + if (Fn->isTemplateInstantiation()) > + ClearUnusedCoverageMapping(Fn->getTemplateInstantiationPattern()); > + } > + auto I = DeferredEmptyCoverageMappingDecls.find(D); > + if (I == DeferredEmptyCoverageMappingDecls.end()) > + DeferredEmptyCoverageMappingDecls[D] = false; > + else > + I->second = false; > +} > + > +void CodeGenModule::EmitDeferredUnusedCoverageMappings() { > + for (const auto I : DeferredEmptyCoverageMappingDecls) { > + if (!I.second) > + continue; > + const auto *D = I.first; > + switch (D->getKind()) { > + case Decl::CXXConversion: > + case Decl::CXXMethod: > + case Decl::Function: > + case Decl::ObjCMethod: { > + CodeGenPGO PGO(*this); > + GlobalDecl GD(cast<FunctionDecl>(D)); > + PGO.emitEmptyCounterMapping(D, getMangledName(GD), > + getFunctionLinkage(GD)); > + break; > + } > + case Decl::CXXConstructor: { > + CodeGenPGO PGO(*this); > + GlobalDecl GD(cast<CXXConstructorDecl>(D), Ctor_Base); > + PGO.emitEmptyCounterMapping(D, getMangledName(GD), > + getFunctionLinkage(GD)); > + break; > + } > + case Decl::CXXDestructor: { > + CodeGenPGO PGO(*this); > + GlobalDecl GD(cast<CXXDestructorDecl>(D), Dtor_Base); > + PGO.emitEmptyCounterMapping(D, getMangledName(GD), > + getFunctionLinkage(GD)); > + break; > + } > + default: > + break; > + }; > + } > +} > + > /// Turns the given pointer into a constant. > static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, > const void *Ptr) { > > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Mon Aug 4 13:41:51 2014 > @@ -73,6 +73,7 @@ class DiagnosticsEngine; > class AnnotateAttr; > class CXXDestructorDecl; > class Module; > +class CoverageSourceInfo; > > namespace CodeGen { > > @@ -87,6 +88,7 @@ class CGOpenMPRuntime; > class CGCUDARuntime; > class BlockFieldFlags; > class FunctionArgList; > +class CoverageMappingModuleGen; > > struct OrderGlobalInits { > unsigned int priority; > @@ -477,10 +479,15 @@ class CodeGenModule : public CodeGenType > std::unique_ptr<SanitizerMetadata> SanitizerMD; > > /// @} > + > + llvm::DenseMap<const Decl *, bool> DeferredEmptyCoverageMappingDecls; > + > + std::unique_ptr<CoverageMappingModuleGen> CoverageMapping; > public: > CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, > llvm::Module &M, const llvm::DataLayout &TD, > - DiagnosticsEngine &Diags); > + DiagnosticsEngine &Diags, > + CoverageSourceInfo *CoverageInfo = nullptr); > > ~CodeGenModule(); > > @@ -529,6 +536,10 @@ public: > InstrProfStats &getPGOStats() { return PGOStats; } > llvm::IndexedInstrProfReader *getPGOReader() const { return > PGOReader.get(); } > > + CoverageMappingModuleGen *getCoverageMapping() const { > + return CoverageMapping.get(); > + } > + > llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) { > return StaticLocalDeclMap[D]; > } > @@ -815,6 +826,18 @@ public: > /// Emit code for a single top level declaration. > void EmitTopLevelDecl(Decl *D); > > + /// \brief Stored a deferred empty coverage mapping for an unused > + /// and thus uninstrumented top level declaration. > + void AddDeferredUnusedCoverageMapping(Decl *D); > + > + /// \brief Remove the deferred empty coverage mapping as this > + /// declaration is actually instrumented. > + void ClearUnusedCoverageMapping(const Decl *D); > + > + /// \brief Emit all the deferred coverage mappings > + /// for the uninstrumented functions. > + void EmitDeferredUnusedCoverageMappings(); > + > /// Tell the consumer that this variable has been instantiated. > void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); > > > Modified: cfe/trunk/lib/CodeGen/CodeGenPGO.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenPGO.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenPGO.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenPGO.cpp Mon Aug 4 13:41:51 2014 > @@ -13,6 +13,7 @@ > > #include "CodeGenPGO.h" > #include "CodeGenFunction.h" > +#include "CoverageMappingGen.h" > #include "clang/AST/RecursiveASTVisitor.h" > #include "clang/AST/StmtVisitor.h" > #include "llvm/IR/MDBuilder.h" > @@ -24,8 +25,9 @@ > using namespace clang; > using namespace CodeGen; > > -void CodeGenPGO::setFuncName(llvm::Function *Fn) { > - RawFuncName = Fn->getName(); > +void CodeGenPGO::setFuncName(StringRef Name, > + llvm::GlobalValue::LinkageTypes Linkage) { > + RawFuncName = Name; > > // Function names may be prefixed with a binary '1' to indicate > // that the backend should not modify the symbols due to any platform > @@ -33,7 +35,7 @@ void CodeGenPGO::setFuncName(llvm::Funct > if (RawFuncName[0] == '\1') > RawFuncName = RawFuncName.substr(1); > > - if (!Fn->hasLocalLinkage()) { > + if (!llvm::GlobalValue::isLocalLinkage(Linkage)) { > PrefixedFuncName.reset(new std::string(RawFuncName)); > return; > } > @@ -49,6 +51,27 @@ void CodeGenPGO::setFuncName(llvm::Funct > PrefixedFuncName->append(RawFuncName); > } > > +void CodeGenPGO::setFuncName(llvm::Function *Fn) { > + setFuncName(Fn->getName(), Fn->getLinkage()); > +} > + > +void CodeGenPGO::setVarLinkage(llvm::GlobalValue::LinkageTypes Linkage) { > + // Set the linkage for variables based on the function linkage. Usually, > we > + // want to match it, but available_externally and extern_weak both have the > + // wrong semantics. > + VarLinkage = Linkage; > + switch (VarLinkage) { > + case llvm::GlobalValue::ExternalWeakLinkage: > + VarLinkage = llvm::GlobalValue::LinkOnceAnyLinkage; > + break; > + case llvm::GlobalValue::AvailableExternallyLinkage: > + VarLinkage = llvm::GlobalValue::LinkOnceODRLinkage; > + break; > + default: > + break; > + } > +} > + > static llvm::Function *getRegisterFunc(CodeGenModule &CGM) { > return CGM.getModule().getFunction("__llvm_profile_register_functions"); > } > @@ -120,37 +143,48 @@ llvm::GlobalVariable *CodeGenPGO::buildD > auto *Int64Ty = llvm::Type::getInt64Ty(Ctx); > auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx); > auto *Int64PtrTy = llvm::Type::getInt64PtrTy(Ctx); > - llvm::Type *DataTypes[] = { > - Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy > - }; > - auto *DataTy = llvm::StructType::get(Ctx, makeArrayRef(DataTypes)); > - llvm::Constant *DataVals[] = { > - llvm::ConstantInt::get(Int32Ty, getFuncName().size()), > - llvm::ConstantInt::get(Int32Ty, NumRegionCounters), > - llvm::ConstantInt::get(Int64Ty, FunctionHash), > - llvm::ConstantExpr::getBitCast(Name, Int8PtrTy), > - llvm::ConstantExpr::getBitCast(RegionCounters, Int64PtrTy) > - }; > - auto *Data = > - new llvm::GlobalVariable(CGM.getModule(), DataTy, true, VarLinkage, > - llvm::ConstantStruct::get(DataTy, DataVals), > - getFuncVarName("data")); > - > - // All the data should be packed into an array in its own section. > - Data->setSection(getDataSection(CGM)); > - Data->setAlignment(8); > + llvm::GlobalVariable *Data = nullptr; > + if (RegionCounters) { > + llvm::Type *DataTypes[] = { > + Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy > + }; > + auto *DataTy = llvm::StructType::get(Ctx, makeArrayRef(DataTypes)); > + llvm::Constant *DataVals[] = { > + llvm::ConstantInt::get(Int32Ty, getFuncName().size()), > + llvm::ConstantInt::get(Int32Ty, NumRegionCounters), > + llvm::ConstantInt::get(Int64Ty, FunctionHash), > + llvm::ConstantExpr::getBitCast(Name, Int8PtrTy), > + llvm::ConstantExpr::getBitCast(RegionCounters, Int64PtrTy) > + }; > + Data = > + new llvm::GlobalVariable(CGM.getModule(), DataTy, true, VarLinkage, > + llvm::ConstantStruct::get(DataTy, DataVals), > + getFuncVarName("data")); > + > + // All the data should be packed into an array in its own section. > + Data->setSection(getDataSection(CGM)); > + Data->setAlignment(8); > + } > + > + // Create coverage mapping data variable. > + if (!CoverageMapping.empty()) > + CGM.getCoverageMapping()->addFunctionMappingRecord(Name, > + getFuncName().size(), > + CoverageMapping); > > // Hide all these symbols so that we correctly get a copy for each > // executable. The profile format expects names and counters to be > // contiguous, so references into shared objects would be invalid. > if (!llvm::GlobalValue::isLocalLinkage(VarLinkage)) { > Name->setVisibility(llvm::GlobalValue::HiddenVisibility); > - Data->setVisibility(llvm::GlobalValue::HiddenVisibility); > - RegionCounters->setVisibility(llvm::GlobalValue::HiddenVisibility); > + if (Data) { > + Data->setVisibility(llvm::GlobalValue::HiddenVisibility); > + RegionCounters->setVisibility(llvm::GlobalValue::HiddenVisibility); > + } > } > > // Make sure the data doesn't get deleted. > - CGM.addUsedGlobal(Data); > + if (Data) CGM.addUsedGlobal(Data); > return Data; > } > > @@ -807,6 +841,20 @@ static void emitRuntimeHook(CodeGenModul > CGM.addUsedGlobal(User); > } > > +void CodeGenPGO::checkGlobalDecl(GlobalDecl GD) { > + // Make sure we only emit coverage mapping for one constructor/destructor. > + // Clang emits several functions for the constructor and the destructor of > + // a class. Every function is instrumented, but we only want to provide > + // coverage for one of them. Because of that we only emit the coverage > mapping > + // for the base constructor/destructor. > + if ((isa<CXXConstructorDecl>(GD.getDecl()) && > + GD.getCtorType() != Ctor_Base) || > + (isa<CXXDestructorDecl>(GD.getDecl()) && > + GD.getDtorType() != Dtor_Base)) { > + SkipCoverageMapping = true; > + } > +} > + > void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) { > bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate; > llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); > @@ -814,27 +862,16 @@ void CodeGenPGO::assignRegionCounters(co > return; > if (D->isImplicit()) > return; > + CGM.ClearUnusedCoverageMapping(D); > setFuncName(Fn); > - > - // Set the linkage for variables based on the function linkage. Usually, > we > - // want to match it, but available_externally and extern_weak both have the > - // wrong semantics. > - VarLinkage = Fn->getLinkage(); > - switch (VarLinkage) { > - case llvm::GlobalValue::ExternalWeakLinkage: > - VarLinkage = llvm::GlobalValue::LinkOnceAnyLinkage; > - break; > - case llvm::GlobalValue::AvailableExternallyLinkage: > - VarLinkage = llvm::GlobalValue::LinkOnceODRLinkage; > - break; > - default: > - break; > - } > + setVarLinkage(Fn->getLinkage()); > > mapRegionCounters(D); > if (InstrumentRegions) { > emitRuntimeHook(CGM); > emitCounterVariables(); > + if (CGM.getCodeGenOpts().CoverageMapping) > + emitCounterRegionMapping(D); > } > if (PGOReader) { > SourceManager &SM = CGM.getContext().getSourceManager(); > @@ -860,6 +897,45 @@ void CodeGenPGO::mapRegionCounters(const > FunctionHash = Walker.Hash.finalize(); > } > > +void CodeGenPGO::emitCounterRegionMapping(const Decl *D) { > + if (SkipCoverageMapping) > + return; > + // Don't map the functions inside the system headers > + auto Loc = D->getBody()->getLocStart(); > + if (CGM.getContext().getSourceManager().isInSystemHeader(Loc)) > + return; > + > + llvm::raw_string_ostream OS(CoverageMapping); > + CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), > + CGM.getContext().getSourceManager(), > + CGM.getLangOpts(), RegionCounterMap.get(), > + NumRegionCounters); > + MappingGen.emitCounterMapping(D, OS); > + OS.flush(); > +} > + > +void > +CodeGenPGO::emitEmptyCounterMapping(const Decl *D, StringRef FuncName, > + llvm::GlobalValue::LinkageTypes Linkage) > { > + if (SkipCoverageMapping) > + return; > + setFuncName(FuncName, Linkage); > + setVarLinkage(Linkage); > + > + // Don't map the functions inside the system headers > + auto Loc = D->getBody()->getLocStart(); > + if (CGM.getContext().getSourceManager().isInSystemHeader(Loc)) > + return; > + > + llvm::raw_string_ostream OS(CoverageMapping); > + CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), > + CGM.getContext().getSourceManager(), > + CGM.getLangOpts()); > + MappingGen.emitEmptyMapping(D, OS); > + OS.flush(); > + buildDataVar(); > +} > + > void CodeGenPGO::computeRegionCounts(const Decl *D) { > StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>); > ComputeRegionCounts Walker(*StmtCountMap, *this); > > Modified: cfe/trunk/lib/CodeGen/CodeGenPGO.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenPGO.h?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenPGO.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenPGO.h Mon Aug 4 13:41:51 2014 > @@ -42,11 +42,16 @@ private: > std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap; > std::unique_ptr<std::vector<uint64_t>> RegionCounts; > uint64_t CurrentRegionCount; > + std::string CoverageMapping; > + /// \brief A flag that is set to true when this function doesn't need > + /// to have coverage mapping data. > + bool SkipCoverageMapping; > > public: > CodeGenPGO(CodeGenModule &CGM) > : CGM(CGM), NumRegionCounters(0), FunctionHash(0), > - RegionCounters(nullptr), CurrentRegionCount(0) {} > + RegionCounters(nullptr), CurrentRegionCount(0), > + SkipCoverageMapping(false) {} > > /// Whether or not we have PGO region data for the current function. This > is > /// false both when we have no data at all and when our data has been > @@ -99,6 +104,8 @@ public: > llvm::MDNode *createBranchWeights(ArrayRef<uint64_t> Weights); > llvm::MDNode *createLoopWeights(const Stmt *Cond, RegionCounter &Cnt); > > + /// Check if we need to emit coverage mapping for a given declaration > + void checkGlobalDecl(GlobalDecl GD); > /// Assign counters to regions and configure them for PGO of a given > /// function. Does nothing if instrumentation is not enabled and either > /// generates global variables or associates PGO data with each of the > @@ -111,9 +118,14 @@ public: > void destroyRegionCounters(); > /// Emit static initialization code, if any. > static llvm::Function *emitInitialization(CodeGenModule &CGM); > - > + /// Emit a coverage mapping range with a counter zero > + /// for an unused declaration. > + void emitEmptyCounterMapping(const Decl *D, StringRef FuncName, > + llvm::GlobalValue::LinkageTypes Linkage); > private: > void setFuncName(llvm::Function *Fn); > + void setFuncName(StringRef Name, llvm::GlobalValue::LinkageTypes Linkage); > + void setVarLinkage(llvm::GlobalValue::LinkageTypes Linkage); > void mapRegionCounters(const Decl *D); > void computeRegionCounts(const Decl *D); > void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader, > @@ -122,6 +134,7 @@ private: > bool IsInMainFile); > void emitCounterVariables(); > llvm::GlobalVariable *buildDataVar(); > + void emitCounterRegionMapping(const Decl *D); > > /// Emit code to increment the counter at the given index > void emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter); > > Added: cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp?rev=214752&view=auto > ============================================================================== > --- cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp (added) > +++ cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp Mon Aug 4 13:41:51 2014 > @@ -0,0 +1,1166 @@ > +//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// Instrumentation-based code coverage mapping generator > +// > +//===----------------------------------------------------------------------===// > + > +#include "CoverageMappingGen.h" > +#include "CodeGenFunction.h" > +#include "clang/AST/StmtVisitor.h" > +#include "clang/Lex/Lexer.h" > +#include "llvm/ProfileData/InstrProfReader.h" > +#include "llvm/ProfileData/CoverageMapping.h" > +#include "llvm/ProfileData/CoverageMappingWriter.h" > +#include "llvm/Support/FileSystem.h" > + > +using namespace clang; > +using namespace CodeGen; > +using namespace llvm::coverage; > + > +void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range) { > + SkippedRanges.push_back(Range); > +} > + > +namespace { > + > +/// \brief A region of source code that can be mapped to a counter. > +struct SourceMappingRegion { > + enum RegionFlags { > + /// \brief This region won't be emitted if it wasn't extended. > + /// This is useful so that we won't emit source ranges for single tokens > + /// that we don't really care that much about, like: > + /// the '(' token in #define MACRO ( > + IgnoreIfNotExtended = 0x0001, > + }; > + > + FileID File, MacroArgumentFile; > + > + Counter Count; > + > + /// \brief A statement that initiated the count of Zero. > + /// > + /// This initiator statement is useful to prevent merging of unreachable > + /// regions with different statements that caused the counter to become > + /// unreachable. > + const Stmt *UnreachableInitiator; > + > + /// \brief A statement that separates certain mapping regions into groups. > + /// > + /// The group statement is sometimes useful when we are emitting the source > + /// regions not in their correct lexical order, e.g. the regions for the > + /// incrementation expression in the 'for' construct. By marking the > regions > + /// in the incrementation expression with the group statement, we avoid the > + /// merging of the regions from the incrementation expression and the > loop's > + /// body. > + const Stmt *Group; > + > + /// \brief The region's starting location. > + SourceLocation LocStart; > + > + /// \brief The region's ending location. > + SourceLocation LocEnd, AlternativeLocEnd; > + unsigned Flags; > + CounterMappingRegion::RegionKind Kind; > + > + SourceMappingRegion(FileID File, FileID MacroArgumentFile, Counter Count, > + const Stmt *UnreachableInitiator, const Stmt *Group, > + SourceLocation LocStart, SourceLocation LocEnd, > + unsigned Flags = 0, > + CounterMappingRegion::RegionKind Kind = > + CounterMappingRegion::CodeRegion) > + : File(File), MacroArgumentFile(MacroArgumentFile), Count(Count), > + UnreachableInitiator(UnreachableInitiator), Group(Group), > + LocStart(LocStart), LocEnd(LocEnd), AlternativeLocEnd(LocStart), > + Flags(Flags), Kind(Kind) {} > + > + bool hasFlag(RegionFlags Flag) const { return (Flags & Flag) != 0; } > + > + void setFlag(RegionFlags Flag) { Flags |= Flag; } > + > + void clearFlag(RegionFlags Flag) { Flags &= ~Flag; } > + > + /// \brief Return true if two regions can be merged together. > + bool isMergeable(SourceMappingRegion &R) { > + return File == R.File && MacroArgumentFile == R.MacroArgumentFile && > + Count == R.Count && UnreachableInitiator == > R.UnreachableInitiator && > + Group == R.Group && Kind == R.Kind; > + } > + > + /// \brief Merge two regions by extending the 'this' region to cover the > + /// given region. > + void mergeByExtendingTo(SourceMappingRegion &R) { > + LocEnd = R.LocEnd; > + AlternativeLocEnd = R.LocStart; > + if (hasFlag(IgnoreIfNotExtended)) > + clearFlag(IgnoreIfNotExtended); > + } > +}; > + > +/// \brief The state of the coverage mapping builder. > +struct SourceMappingState { > + Counter CurrentRegionCount; > + const Stmt *CurrentSourceGroup; > + const Stmt *CurrentUnreachableRegionInitiator; > + > + SourceMappingState(Counter CurrentRegionCount, const Stmt > *CurrentSourceGroup, > + const Stmt *CurrentUnreachableRegionInitiator) > + : CurrentRegionCount(CurrentRegionCount), > + CurrentSourceGroup(CurrentSourceGroup), > + CurrentUnreachableRegionInitiator(CurrentUnreachableRegionInitiator) > {} > +}; > + > +/// \brief Provides the common functionality for the different > +/// coverage mapping region builders. > +class CoverageMappingBuilder { > +public: > + CoverageMappingModuleGen &CVM; > + SourceManager &SM; > + const LangOptions &LangOpts; > + > +private: > + struct FileInfo { > + /// \brief The file id that will be used by the coverage mapping system. > + unsigned CovMappingFileID; > + const FileEntry *Entry; > + > + FileInfo(unsigned CovMappingFileID, const FileEntry *Entry) > + : CovMappingFileID(CovMappingFileID), Entry(Entry) {} > + }; > + > + /// \brief This mapping maps clang's FileIDs to file ids used > + /// by the coverage mapping system and clang's file entries. > + llvm::SmallDenseMap<FileID, FileInfo, 8> FileIDMapping; > + > +public: > + /// \brief The statement that corresponds to the current source group. > + const Stmt *CurrentSourceGroup; > + > + /// \brief The statement the initiated the current unreachable region. > + const Stmt *CurrentUnreachableRegionInitiator; > + > + /// \brief The coverage mapping regions for this function > + llvm::SmallVector<CounterMappingRegion, 32> MappingRegions; > + /// \brief The source mapping regions for this function. > + llvm::SmallVector<SourceMappingRegion, 32> SourceRegions; > + > + CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, > + const LangOptions &LangOpts) > + : CVM(CVM), SM(SM), LangOpts(LangOpts), > + CurrentSourceGroup(nullptr), > + CurrentUnreachableRegionInitiator(nullptr) {} > + > + /// \brief Return the precise end location for the given token. > + SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { > + return Lexer::getLocForEndOfToken(SM.getSpellingLoc(Loc), 0, SM, > LangOpts); > + } > + > + /// \brief Create the mapping that maps from the function's file ids to > + /// the indices for the translation unit's filenames. > + void createFileIDMapping(SmallVectorImpl<unsigned> &Mapping) { > + Mapping.resize(FileIDMapping.size(), 0); > + for (const auto &I : FileIDMapping) > + Mapping[I.second.CovMappingFileID] = CVM.getFileID(I.second.Entry); > + } > + > + /// \brief Get the coverage mapping file id that corresponds to the given > + /// clang file id. If such file id doesn't exist, it gets added to the > + /// mapping that maps from clang's file ids to coverage mapping file ids. > + /// Return true if there was an error getting the coverage mapping file id. > + /// An example of an when this function fails is when the region tries > + /// to get a coverage file id for a location in a built-in macro. > + bool getCoverageFileID(SourceLocation LocStart, FileID File, > + FileID SpellingFile, unsigned &Result) { > + auto Mapping = FileIDMapping.find(File); > + if (Mapping != FileIDMapping.end()) { > + Result = Mapping->second.CovMappingFileID; > + return false; > + } > + > + auto Entry = SM.getFileEntryForID(SpellingFile); > + if (!Entry) > + return true; > + > + Result = FileIDMapping.size(); > + FileIDMapping.insert(std::make_pair(File, FileInfo(Result, Entry))); > + createFileExpansionRegion(LocStart, File); > + return false; > + } > + > + /// \brief Get the coverage mapping file id that corresponds to the given > + /// clang file id. > + /// Return true if there was an error getting the coverage mapping file id. > + bool getExistingCoverageFileID(FileID File, unsigned &Result) { > + // Make sure that the file is valid. > + if (File.isInvalid()) > + return true; > + auto Mapping = FileIDMapping.find(File); > + if (Mapping != FileIDMapping.end()) { > + Result = Mapping->second.CovMappingFileID; > + return false; > + } > + return true; > + } > + > + /// \brief Return true if the given clang's file id has a corresponding > + /// coverage file id. > + bool hasExistingCoverageFileID(FileID File) const { > + return FileIDMapping.count(File); > + } > + > + /// \brief Gather all the regions that were skipped by the preprocessor > + /// using the constructs like #if. > + void gatherSkippedRegions() { > + /// An array of the minimum lineStarts and the maximum lineEnds > + /// for mapping regions from the appropriate source files. > + llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges; > + FileLineRanges.resize( > + FileIDMapping.size(), > + std::make_pair(std::numeric_limits<unsigned>::max(), 0)); > + for (const auto &R : MappingRegions) { > + FileLineRanges[R.FileID].first = > + std::min(FileLineRanges[R.FileID].first, R.LineStart); > + FileLineRanges[R.FileID].second = > + std::max(FileLineRanges[R.FileID].second, R.LineEnd); > + } > + > + auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges(); > + for (const auto &I : SkippedRanges) { > + auto LocStart = I.getBegin(); > + auto LocEnd = I.getEnd(); > + auto FileStart = SM.getFileID(LocStart); > + if (!hasExistingCoverageFileID(FileStart)) > + continue; > + auto ActualFileStart = SM.getDecomposedSpellingLoc(LocStart).first; > + if (ActualFileStart != SM.getDecomposedSpellingLoc(LocEnd).first) > + // Ignore regions that span across multiple files. > + continue; > + > + unsigned CovFileID; > + if (getCoverageFileID(LocStart, FileStart, ActualFileStart, CovFileID)) > + continue; > + unsigned LineStart = SM.getSpellingLineNumber(LocStart); > + unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); > + unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); > + unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); > + CounterMappingRegion Region(Counter(), CovFileID, LineStart, > ColumnStart, > + LineEnd, ColumnEnd, false, > + CounterMappingRegion::SkippedRegion); > + // Make sure that we only collect the regions that are inside > + // the souce code of this function. > + if (Region.LineStart >= FileLineRanges[CovFileID].first && > + Region.LineEnd <= FileLineRanges[CovFileID].second) > + MappingRegions.push_back(Region); > + } > + } > + > + /// \brief Create a mapping region that correponds to an expansion of > + /// a macro or an embedded include. > + void createFileExpansionRegion(SourceLocation Loc, FileID ExpandedFile) { > + SourceLocation LocStart; > + if (Loc.isMacroID()) > + LocStart = SM.getImmediateExpansionRange(Loc).first; > + else { > + LocStart = SM.getIncludeLoc(ExpandedFile); > + if (LocStart.isInvalid()) > + return; // This file has no expansion region. > + } > + > + auto File = SM.getFileID(LocStart); > + auto SpellingFile = SM.getDecomposedSpellingLoc(LocStart).first; > + unsigned CovFileID, ExpandedFileID; > + if (getExistingCoverageFileID(ExpandedFile, ExpandedFileID)) > + return; > + if (getCoverageFileID(LocStart, File, SpellingFile, CovFileID)) > + return; > + unsigned LineStart = SM.getSpellingLineNumber(LocStart); > + unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); > + unsigned LineEnd = LineStart; > + // Compute the end column manually as Lexer::getLocForEndOfToken doesn't > + // give the correct result in all cases. > + unsigned ColumnEnd = > + ColumnStart + > + Lexer::MeasureTokenLength(SM.getSpellingLoc(LocStart), SM, LangOpts); > + > + MappingRegions.push_back(CounterMappingRegion( > + Counter(), CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd, > + false, CounterMappingRegion::ExpansionRegion)); > + MappingRegions.back().ExpandedFileID = ExpandedFileID; > + } > + > + /// \brief Enter a source region group that is identified by the given > + /// statement. > + /// It's not possible to enter a group when there is already > + /// another group present. > + void beginSourceRegionGroup(const Stmt *Group) { > + assert(!CurrentSourceGroup); > + CurrentSourceGroup = Group; > + } > + > + /// \brief Exit the current source region group. > + void endSourceRegionGroup() { CurrentSourceGroup = nullptr; } > + > + /// \brief Brings a region that has the same counter and file to the back > + /// of the source regions array. > + void bringSimilarRegionBack(Counter Count, FileID File, > + FileID MacroArgumentFile, > + const Stmt *UnreachableInitiator, > + const Stmt *SourceGroup) { > + for (size_t I = SourceRegions.size(); I != 0;) { > + --I; > + if (SourceRegions[I].Count == Count && SourceRegions[I].File == File && > + SourceRegions[I].MacroArgumentFile == MacroArgumentFile && > + SourceRegions[I].UnreachableInitiator == UnreachableInitiator && > + SourceRegions[I].Group == SourceGroup) { > + if (I != SourceRegions.size() - 1) > + std::swap(SourceRegions[I], SourceRegions.back()); > + return; > + } > + } > + } > + > + /// \brief Associate a counter with a given source code range. > + void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, > + Counter Count, const Stmt *UnreachableInitiator, > + const Stmt *SourceGroup, unsigned Flags = 0, > + FileID MacroArgumentFile = FileID()) { > + if (SM.isMacroArgExpansion(LocStart)) { > + // Map the code range with the macro argument's value. > + mapSourceCodeRange(SM.getImmediateSpellingLoc(LocStart), > + SM.getImmediateSpellingLoc(LocEnd), Count, > + UnreachableInitiator, SourceGroup, Flags, > + SM.getFileID(LocStart)); > + // Map the code range where the macro argument is referenced. > + SourceLocation > RefLocStart(SM.getImmediateExpansionRange(LocStart).first); > + SourceLocation RefLocEnd(RefLocStart); > + if (SM.isMacroArgExpansion(RefLocStart)) > + mapSourceCodeRange(RefLocStart, RefLocEnd, Count, > UnreachableInitiator, > + SourceGroup, 0, SM.getFileID(RefLocStart)); > + else > + mapSourceCodeRange(RefLocStart, RefLocEnd, Count, > UnreachableInitiator, > + SourceGroup); > + return; > + } > + auto File = SM.getFileID(LocStart); > + // Make sure that the file id is valid. > + if (File.isInvalid()) > + return; > + bringSimilarRegionBack(Count, File, MacroArgumentFile, > UnreachableInitiator, > + SourceGroup); > + SourceMappingRegion R(File, MacroArgumentFile, Count, > UnreachableInitiator, > + SourceGroup, LocStart, LocEnd, Flags); > + if (SourceRegions.empty() || !SourceRegions.back().isMergeable(R)) { > + SourceRegions.push_back(R); > + return; > + } > + SourceRegions.back().mergeByExtendingTo(R); > + } > + > + void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, > + Counter Count, unsigned Flags = 0) { > + mapSourceCodeRange(LocStart, LocEnd, Count, > + CurrentUnreachableRegionInitiator, CurrentSourceGroup, > + Flags); > + } > + > + void mapSourceCodeRange(const SourceMappingState &State, > + SourceLocation LocStart, SourceLocation LocEnd, > + unsigned Flags = 0) { > + mapSourceCodeRange(LocStart, LocEnd, State.CurrentRegionCount, > + State.CurrentUnreachableRegionInitiator, > + State.CurrentSourceGroup, Flags); > + } > + > + /// \brief Generate the coverage counter mapping regions from collected > + /// source regions. > + void emitSourceRegions() { > + for (const auto &R : SourceRegions) { > + SourceLocation LocStart = R.LocStart; > + SourceLocation LocEnd = R.LocEnd; > + if (SM.getFileID(LocEnd) != R.File) > + LocEnd = R.AlternativeLocEnd; > + > + if (R.hasFlag(SourceMappingRegion::IgnoreIfNotExtended) && > + LocStart == LocEnd) > + continue; > + > + LocEnd = getPreciseTokenLocEnd(LocEnd); > + unsigned LineStart = SM.getSpellingLineNumber(LocStart); > + unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); > + unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); > + unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); > + > + auto SpellingFile = SM.getDecomposedSpellingLoc(R.LocStart).first; > + unsigned CovFileID; > + if (getCoverageFileID(R.LocStart, R.File, SpellingFile, CovFileID)) > + continue; > + > + assert(LineStart <= LineEnd); > + MappingRegions.push_back(CounterMappingRegion( > + R.Count, CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd, > + false, CounterMappingRegion::CodeRegion)); > + } > + } > +}; > + > +/// \brief Creates unreachable coverage regions for the functions that > +/// are not emitted. > +struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { > + EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager > &SM, > + const LangOptions &LangOpts) > + : CoverageMappingBuilder(CVM, SM, LangOpts) {} > + > + void VisitDecl(const Decl *D) { > + if (!D->hasBody()) > + return; > + auto Body = D->getBody(); > + mapSourceCodeRange(Body->getLocStart(), Body->getLocEnd(), Counter()); > + } > + > + /// \brief Write the mapping data to the output stream > + void write(llvm::raw_ostream &OS) { > + emitSourceRegions(); > + SmallVector<unsigned, 16> FileIDMapping; > + createFileIDMapping(FileIDMapping); > + > + CoverageMappingWriter Writer( > + FileIDMapping, ArrayRef<CounterExpression>(), MappingRegions); > + Writer.write(OS); > + } > +}; > + > +/// \brief A StmtVisitor that creates coverage mapping regions which map > +/// from the source code locations to the PGO counters. > +struct CounterCoverageMappingBuilder > + : public CoverageMappingBuilder, > + public ConstStmtVisitor<CounterCoverageMappingBuilder> { > + /// \brief The map of statements to count values. > + llvm::DenseMap<const Stmt *, unsigned> &CounterMap; > + > + Counter CurrentRegionCount; > + > + CounterExpressionBuilder Builder; > + > + /// \brief Return a counter that represents the > + /// expression that subracts rhs from lhs. > + Counter subtractCounters(Counter LHS, Counter RHS) { > + return Builder.subtract(LHS, RHS); > + } > + > + /// \brief Return a counter that represents the > + /// the exression that adds lhs and rhs. > + Counter addCounters(Counter LHS, Counter RHS) { > + return Builder.add(LHS, RHS); > + } > + > + /// \brief Return the region counter for the given statement. > + /// This should only be called on statements that have a dedicated counter. > + unsigned getRegionCounter(const Stmt *S) { return CounterMap[S]; } > + > + /// \brief Return the region count for the counter at the given index. > + Counter getRegionCount(unsigned CounterId) { > + return Counter::getCounter(CounterId); > + } > + > + /// \brief Return the counter value of the current region. > + Counter getCurrentRegionCount() { return CurrentRegionCount; } > + > + /// \brief Set the counter value for the current region. > + /// This is used to keep track of changes to the most recent counter > + /// from control flow and non-local exits. > + void setCurrentRegionCount(Counter Count) { > + CurrentRegionCount = Count; > + CurrentUnreachableRegionInitiator = nullptr; > + } > + > + /// \brief Indicate that the current region is never reached, > + /// and thus should have a counter value of zero. > + /// This is important so that subsequent regions can correctly track > + /// their parent counts. > + void setCurrentRegionUnreachable(const Stmt *Initiator) { > + CurrentRegionCount = Counter::getZero(); > + CurrentUnreachableRegionInitiator = Initiator; > + } > + > + /// \brief A counter for a particular region. > + /// This is the primary interface through > + /// which the coverage mapping builder manages counters and their values. > + class RegionMapper { > + CounterCoverageMappingBuilder &Mapping; > + Counter Count; > + Counter ParentCount; > + Counter RegionCount; > + Counter Adjust; > + > + public: > + RegionMapper(CounterCoverageMappingBuilder *Mapper, const Stmt *S) > + : Mapping(*Mapper), > + Count(Mapper->getRegionCount(Mapper->getRegionCounter(S))), > + ParentCount(Mapper->getCurrentRegionCount()) {} > + > + /// Get the value of the counter. In most cases this is the number of > times > + /// the region of the counter was entered, but for switch labels it's the > + /// number of direct jumps to that label. > + Counter getCount() const { return Count; } > + > + /// Get the value of the counter with adjustments applied. Adjustments > occur > + /// when control enters or leaves the region abnormally; i.e., if there > is a > + /// jump to a label within the region, or if the function can return from > + /// within the region. The adjusted count, then, is the value of the > counter > + /// at the end of the region. > + Counter getAdjustedCount() const { > + return Mapping.addCounters(Count, Adjust); > + } > + > + /// Get the value of the counter in this region's parent, i.e., the > region > + /// that was active when this region began. This is useful for deriving > + /// counts in implicitly counted regions, like the false case of a > condition > + /// or the normal exits of a loop. > + Counter getParentCount() const { return ParentCount; } > + > + /// Activate the counter by emitting an increment and starting to track > + /// adjustments. If AddIncomingFallThrough is true, the current region > count > + /// will be added to the counter for the purposes of tracking the region. > + void beginRegion(bool AddIncomingFallThrough = false) { > + RegionCount = Count; > + if (AddIncomingFallThrough) > + RegionCount = > + Mapping.addCounters(RegionCount, > Mapping.getCurrentRegionCount()); > + Mapping.setCurrentRegionCount(RegionCount); > + } > + > + /// For counters on boolean branches, begins tracking adjustments for the > + /// uncounted path. > + void beginElseRegion() { > + RegionCount = Mapping.subtractCounters(ParentCount, Count); > + Mapping.setCurrentRegionCount(RegionCount); > + } > + > + /// Reset the current region count. > + void setCurrentRegionCount(Counter CurrentCount) { > + RegionCount = CurrentCount; > + Mapping.setCurrentRegionCount(RegionCount); > + } > + > + /// Adjust for non-local control flow after emitting a subexpression or > + /// substatement. This must be called to account for constructs such as > + /// gotos, > + /// labels, and returns, so that we can ensure that our region's count is > + /// correct in the code that follows. > + void adjustForControlFlow() { > + Adjust = Mapping.addCounters( > + Adjust, Mapping.subtractCounters(Mapping.getCurrentRegionCount(), > + RegionCount)); > + // Reset the region count in case this is called again later. > + RegionCount = Mapping.getCurrentRegionCount(); > + } > + > + /// Commit all adjustments to the current region. If the region is a > loop, > + /// the LoopAdjust value should be the count of all the breaks and > continues > + /// from the loop, to compensate for those counts being deducted from the > + /// adjustments for the body of the loop. > + void applyAdjustmentsToRegion() { > + Mapping.setCurrentRegionCount(Mapping.addCounters(ParentCount, > Adjust)); > + } > + void applyAdjustmentsToRegion(Counter LoopAdjust) { > + Mapping.setCurrentRegionCount(Mapping.addCounters( > + Mapping.addCounters(ParentCount, Adjust), LoopAdjust)); > + } > + }; > + > + /// \brief Keep counts of breaks and continues inside loops. > + struct BreakContinue { > + Counter BreakCount; > + Counter ContinueCount; > + }; > + SmallVector<BreakContinue, 8> BreakContinueStack; > + > + CounterCoverageMappingBuilder( > + CoverageMappingModuleGen &CVM, > + llvm::DenseMap<const Stmt *, unsigned> &CounterMap, > + unsigned NumRegionCounters, SourceManager &SM, > + const LangOptions &LangOpts) > + : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), > + Builder(NumRegionCounters) {} > + > + /// \brief Write the mapping data to the output stream > + void write(llvm::raw_ostream &OS) { > + emitSourceRegions(); > + llvm::SmallVector<unsigned, 8> VirtualFileMapping; > + createFileIDMapping(VirtualFileMapping); > + gatherSkippedRegions(); > + > + CoverageMappingWriter Writer( > + VirtualFileMapping, Builder.getExpressions(), MappingRegions); > + Writer.write(OS); > + } > + > + /// \brief Return the current source mapping state. > + SourceMappingState getCurrentState() const { > + return SourceMappingState(CurrentRegionCount, CurrentSourceGroup, > + CurrentUnreachableRegionInitiator); > + } > + > + /// \brief Associate the source code range with the current region count. > + void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, > + unsigned Flags = 0) { > + CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocEnd, > + CurrentRegionCount, Flags); > + } > + > + void mapSourceCodeRange(SourceLocation LocStart) { > + CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocStart, > + CurrentRegionCount); > + } > + > + /// \brief Associate the source range of a token with the current region > + /// count. > + /// Ignore the source range for this token if it produces a distinct > + /// mapping region with no other source ranges. > + void mapToken(SourceLocation LocStart) { > + CoverageMappingBuilder::mapSourceCodeRange( > + LocStart, LocStart, CurrentRegionCount, > + SourceMappingRegion::IgnoreIfNotExtended); > + } > + > + void mapToken(const SourceMappingState &State, SourceLocation LocStart) { > + CoverageMappingBuilder::mapSourceCodeRange( > + State, LocStart, LocStart, SourceMappingRegion::IgnoreIfNotExtended); > + } > + > + void VisitStmt(const Stmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + for (Stmt::const_child_range I = S->children(); I; ++I) { > + if (*I) > + this->Visit(*I); > + } > + } > + > + /// \brief If the given statement is a compound statement, > + /// map '}' with the same count as '{'. > + void VisitSubStmtRBraceState(const Stmt *S) { > + if (!isa<CompoundStmt>(S)) > + return Visit(S); > + const auto *CS = cast<CompoundStmt>(S); > + auto State = getCurrentState(); > + mapSourceCodeRange(CS->getLBracLoc()); > + for (Stmt::const_child_range I = S->children(); I; ++I) { > + if (*I) > + this->Visit(*I); > + } > + CoverageMappingBuilder::mapSourceCodeRange(State, CS->getRBracLoc(), > + CS->getRBracLoc()); > + } > + > + void VisitDecl(const Decl *D) { > + if (!D->hasBody()) > + return; > + // Counter tracks entry to the function body. > + auto Body = D->getBody(); > + RegionMapper Cnt(this, Body); > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(Body); > + } > + > + void VisitDeclStmt(const DeclStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + for (Stmt::const_child_range I = static_cast<const Stmt > *>(S)->children(); > + I; ++I) { > + if (*I) > + this->Visit(*I); > + } > + } > + > + void VisitCompoundStmt(const CompoundStmt *S) { > + mapSourceCodeRange(S->getLBracLoc()); > + for (Stmt::const_child_range I = S->children(); I; ++I) { > + if (*I) > + this->Visit(*I); > + } > + mapSourceCodeRange(S->getRBracLoc(), S->getRBracLoc()); > + } > + > + void VisitReturnStmt(const ReturnStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + if (S->getRetValue()) > + Visit(S->getRetValue()); > + setCurrentRegionUnreachable(S); > + } > + > + void VisitGotoStmt(const GotoStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + mapToken(S->getLabelLoc()); > + setCurrentRegionUnreachable(S); > + } > + > + void VisitLabelStmt(const LabelStmt *S) { > + // Counter tracks the block following the label. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(); > + mapSourceCodeRange(S->getLocStart()); > + // Can't map the ':' token as its location isn't known. > + Visit(S->getSubStmt()); > + } > + > + void VisitBreakStmt(const BreakStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); > + BreakContinueStack.back().BreakCount = addCounters( > + BreakContinueStack.back().BreakCount, getCurrentRegionCount()); > + setCurrentRegionUnreachable(S); > + } > + > + void VisitContinueStmt(const ContinueStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); > + BreakContinueStack.back().ContinueCount = addCounters( > + BreakContinueStack.back().ContinueCount, getCurrentRegionCount()); > + setCurrentRegionUnreachable(S); > + } > + > + void VisitWhileStmt(const WhileStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + // Counter tracks the body of the loop. > + RegionMapper Cnt(this, S); > + BreakContinueStack.push_back(BreakContinue()); > + // Visit the body region first so the break/continue adjustments can be > + // included when visiting the condition. > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(S->getBody()); > + Cnt.adjustForControlFlow(); > + > + // ...then go back and propagate counts through the condition. The count > + // at the start of the condition is the sum of the incoming edges, > + // the backedge from the end of the loop body, and the edges from > + // continue statements. > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + Cnt.setCurrentRegionCount( > + addCounters(Cnt.getParentCount(), > + addCounters(Cnt.getAdjustedCount(), BC.ContinueCount))); > + beginSourceRegionGroup(S->getCond()); > + Visit(S->getCond()); > + endSourceRegionGroup(); > + Cnt.adjustForControlFlow(); > + Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, > BC.ContinueCount)); > + } > + > + void VisitDoStmt(const DoStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + // Counter tracks the body of the loop. > + RegionMapper Cnt(this, S); > + BreakContinueStack.push_back(BreakContinue()); > + Cnt.beginRegion(/*AddIncomingFallThrough=*/true); > + VisitSubStmtRBraceState(S->getBody()); > + Cnt.adjustForControlFlow(); > + > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + // The count at the start of the condition is equal to the count at the > + // end of the body. The adjusted count does not include either the > + // fall-through count coming into the loop or the continue count, so add > + // both of those separately. This is coincidentally the same equation as > + // with while loops but for different reasons. > + Cnt.setCurrentRegionCount( > + addCounters(Cnt.getParentCount(), > + addCounters(Cnt.getAdjustedCount(), BC.ContinueCount))); > + Visit(S->getCond()); > + Cnt.adjustForControlFlow(); > + Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, > BC.ContinueCount)); > + } > + > + void VisitForStmt(const ForStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + if (S->getInit()) > + Visit(S->getInit()); > + > + // Counter tracks the body of the loop. > + RegionMapper Cnt(this, S); > + BreakContinueStack.push_back(BreakContinue()); > + // Visit the body region first. (This is basically the same as a while > + // loop; see further comments in VisitWhileStmt.) > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(S->getBody()); > + Cnt.adjustForControlFlow(); > + > + // The increment is essentially part of the body but it needs to include > + // the count for all the continue statements. > + if (S->getInc()) { > + Cnt.setCurrentRegionCount(addCounters( > + getCurrentRegionCount(), BreakContinueStack.back().ContinueCount)); > + beginSourceRegionGroup(S->getInc()); > + Visit(S->getInc()); > + endSourceRegionGroup(); > + Cnt.adjustForControlFlow(); > + } > + > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + > + // ...then go back and propagate counts through the condition. > + if (S->getCond()) { > + Cnt.setCurrentRegionCount( > + addCounters(addCounters(Cnt.getParentCount(), > Cnt.getAdjustedCount()), > + BC.ContinueCount)); > + beginSourceRegionGroup(S->getCond()); > + Visit(S->getCond()); > + endSourceRegionGroup(); > + Cnt.adjustForControlFlow(); > + } > + Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, > BC.ContinueCount)); > + } > + > + void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + Visit(S->getRangeStmt()); > + Visit(S->getBeginEndStmt()); > + // Counter tracks the body of the loop. > + RegionMapper Cnt(this, S); > + BreakContinueStack.push_back(BreakContinue()); > + // Visit the body region first. (This is basically the same as a while > + // loop; see further comments in VisitWhileStmt.) > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(S->getBody()); > + Cnt.adjustForControlFlow(); > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, > BC.ContinueCount)); > + } > + > + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + Visit(S->getElement()); > + // Counter tracks the body of the loop. > + RegionMapper Cnt(this, S); > + BreakContinueStack.push_back(BreakContinue()); > + VisitSubStmtRBraceState(S->getBody()); > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + Cnt.adjustForControlFlow(); > + Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, > BC.ContinueCount)); > + } > + > + void VisitSwitchStmt(const SwitchStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + Visit(S->getCond()); > + BreakContinueStack.push_back(BreakContinue()); > + // Map the '}' for the body to have the same count as the regions after > + // the switch. > + SourceLocation RBracLoc; > + if (const auto *CS = dyn_cast<CompoundStmt>(S->getBody())) { > + mapSourceCodeRange(CS->getLBracLoc()); > + setCurrentRegionUnreachable(S); > + for (Stmt::const_child_range I = CS->children(); I; ++I) { > + if (*I) > + this->Visit(*I); > + } > + RBracLoc = CS->getRBracLoc(); > + } else { > + setCurrentRegionUnreachable(S); > + Visit(S->getBody()); > + } > + // If the switch is inside a loop, add the continue counts. > + BreakContinue BC = BreakContinueStack.pop_back_val(); > + if (!BreakContinueStack.empty()) > + BreakContinueStack.back().ContinueCount = addCounters( > + BreakContinueStack.back().ContinueCount, BC.ContinueCount); > + // Counter tracks the exit block of the switch. > + RegionMapper ExitCnt(this, S); > + ExitCnt.beginRegion(); > + if (RBracLoc.isValid()) > + mapSourceCodeRange(RBracLoc); > + } > + > + void VisitCaseStmt(const CaseStmt *S) { > + // Counter for this particular case. This counts only jumps from the > + // switch header and does not include fallthrough from the case before > + // this one. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(/*AddIncomingFallThrough=*/true); > + mapSourceCodeRange(S->getLocStart()); > + mapToken(S->getColonLoc()); > + Visit(S->getSubStmt()); > + } > + > + void VisitDefaultStmt(const DefaultStmt *S) { > + // Counter for this default case. This does not include fallthrough from > + // the previous case. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(/*AddIncomingFallThrough=*/true); > + mapSourceCodeRange(S->getLocStart()); > + mapToken(S->getColonLoc()); > + Visit(S->getSubStmt()); > + } > + > + void VisitIfStmt(const IfStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + Visit(S->getCond()); > + mapToken(S->getElseLoc()); > + > + // Counter tracks the "then" part of an if statement. The count for > + // the "else" part, if it exists, will be calculated from this counter. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(S->getThen()); > + Cnt.adjustForControlFlow(); > + > + if (S->getElse()) { > + Cnt.beginElseRegion(); > + VisitSubStmtRBraceState(S->getElse()); > + Cnt.adjustForControlFlow(); > + } > + Cnt.applyAdjustmentsToRegion(); > + } > + > + void VisitCXXTryStmt(const CXXTryStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + Visit(S->getTryBlock()); > + for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) > + Visit(S->getHandler(I)); > + // Counter tracks the continuation block of the try statement. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(); > + } > + > + void VisitCXXCatchStmt(const CXXCatchStmt *S) { > + mapSourceCodeRange(S->getLocStart()); > + // Counter tracks the catch statement's handler block. > + RegionMapper Cnt(this, S); > + Cnt.beginRegion(); > + VisitSubStmtRBraceState(S->getHandlerBlock()); > + } > + > + void VisitAbstractConditionalOperator(const AbstractConditionalOperator > *E) { > + Visit(E->getCond()); > + mapToken(E->getQuestionLoc()); > + auto State = getCurrentState(); > + > + // Counter tracks the "true" part of a conditional operator. The > + // count in the "false" part will be calculated from this counter. > + RegionMapper Cnt(this, E); > + Cnt.beginRegion(); > + Visit(E->getTrueExpr()); > + Cnt.adjustForControlFlow(); > + > + mapToken(State, E->getColonLoc()); > + > + Cnt.beginElseRegion(); > + Visit(E->getFalseExpr()); > + Cnt.adjustForControlFlow(); > + > + Cnt.applyAdjustmentsToRegion(); > + } > + > + void VisitBinLAnd(const BinaryOperator *E) { > + Visit(E->getLHS()); > + mapToken(E->getOperatorLoc()); > + // Counter tracks the right hand side of a logical and operator. > + RegionMapper Cnt(this, E); > + Cnt.beginRegion(); > + Visit(E->getRHS()); > + Cnt.adjustForControlFlow(); > + Cnt.applyAdjustmentsToRegion(); > + } > + > + void VisitBinLOr(const BinaryOperator *E) { > + Visit(E->getLHS()); > + mapToken(E->getOperatorLoc()); > + // Counter tracks the right hand side of a logical or operator. > + RegionMapper Cnt(this, E); > + Cnt.beginRegion(); > + Visit(E->getRHS()); > + Cnt.adjustForControlFlow(); > + Cnt.applyAdjustmentsToRegion(); > + } > + > + void VisitParenExpr(const ParenExpr *E) { > + mapToken(E->getLParen()); > + Visit(E->getSubExpr()); > + mapToken(E->getRParen()); > + } > + > + void VisitBinaryOperator(const BinaryOperator *E) { > + Visit(E->getLHS()); > + mapToken(E->getOperatorLoc()); > + Visit(E->getRHS()); > + } > + > + void VisitUnaryOperator(const UnaryOperator *E) { > + bool Postfix = E->isPostfix(); > + if (!Postfix) > + mapToken(E->getOperatorLoc()); > + Visit(E->getSubExpr()); > + if (Postfix) > + mapToken(E->getOperatorLoc()); > + } > + > + void VisitMemberExpr(const MemberExpr *E) { > + Visit(E->getBase()); > + mapToken(E->getMemberLoc()); > + } > + > + void VisitCallExpr(const CallExpr *E) { > + Visit(E->getCallee()); > + for (const auto &Arg : E->arguments()) > + Visit(Arg); > + mapToken(E->getRParenLoc()); > + } > + > + void VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { > + Visit(E->getLHS()); > + Visit(E->getRHS()); > + mapToken(E->getRBracketLoc()); > + } > + > + void VisitCStyleCastExpr(const CStyleCastExpr *E) { > + mapToken(E->getLParenLoc()); > + mapToken(E->getRParenLoc()); > + Visit(E->getSubExpr()); > + } > + > + // Map literals as tokens so that the macros like #define PI 3.14 > + // won't generate coverage mapping regions. > + > + void VisitIntegerLiteral(const IntegerLiteral *E) { > + mapToken(E->getLocStart()); > + } > + > + void VisitFloatingLiteral(const FloatingLiteral *E) { > + mapToken(E->getLocStart()); > + } > + > + void VisitCharacterLiteral(const CharacterLiteral *E) { > + mapToken(E->getLocStart()); > + } > + > + void VisitStringLiteral(const StringLiteral *E) { > + mapToken(E->getLocStart()); > + } > + > + void VisitImaginaryLiteral(const ImaginaryLiteral *E) { > + mapToken(E->getLocStart()); > + } > +}; > +} > + > +static bool isMachO(const CodeGenModule &CGM) { > + return CGM.getTarget().getTriple().isOSBinFormatMachO(); > +} > + > +static StringRef getCoverageSection(const CodeGenModule &CGM) { > + return isMachO(CGM) ? "__DATA,__llvm_covmap" : "__llvm_covmap"; > +} > + > +void CoverageMappingModuleGen::addFunctionMappingRecord( > + llvm::GlobalVariable *FunctionName, unsigned FunctionNameSize, > + const std::string &CoverageMapping) { > + llvm::LLVMContext &Ctx = CGM.getLLVMContext(); > + auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); > + auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx); > + if (!FunctionRecordTy) { > + llvm::Type *FunctionRecordTypes[] = {Int8PtrTy, Int32Ty, Int32Ty}; > + FunctionRecordTy = > + llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes)); > + } > + > + llvm::Constant *FunctionRecordVals[] = { > + llvm::ConstantExpr::getBitCast(FunctionName, Int8PtrTy), > + llvm::ConstantInt::get(Int32Ty, FunctionNameSize), > + llvm::ConstantInt::get(Int32Ty, CoverageMapping.size())}; > + FunctionRecords.push_back(llvm::ConstantStruct::get( > + FunctionRecordTy, makeArrayRef(FunctionRecordVals))); > + CoverageMappings += CoverageMapping; > +} > + > +void CoverageMappingModuleGen::emit() { > + if (FunctionRecords.empty()) > + return; > + llvm::LLVMContext &Ctx = CGM.getLLVMContext(); > + auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); > + > + // Create the filenames and merge them with coverage mappings > + llvm::SmallVector<std::string, 16> FilenameStrs; > + llvm::SmallVector<StringRef, 16> FilenameRefs; > + FilenameStrs.resize(FileEntries.size()); > + FilenameRefs.resize(FileEntries.size()); > + for (const auto &Entry : FileEntries) { > + llvm::SmallString<256> Path(Entry.first->getName()); > + llvm::sys::fs::make_absolute(Path); > + > + auto I = Entry.second; > + FilenameStrs[I] = std::move(std::string(Path.begin(), Path.end())); > + FilenameRefs[I] = FilenameStrs[I]; > + } > + > + std::string FilenamesAndCoverageMappings; > + llvm::raw_string_ostream OS(FilenamesAndCoverageMappings); > + CoverageFilenamesSectionWriter(FilenameRefs).write(OS); > + OS << CoverageMappings; > + size_t CoverageMappingSize = CoverageMappings.size(); > + size_t FilenamesSize = OS.str().size() - CoverageMappingSize; > + // Append extra zeroes if necessary to ensure that the size of the > filenames > + // and coverage mappings is a multiple of 8. > + if (size_t Rem = OS.str().size() % 8) { > + CoverageMappingSize += 8 - Rem; > + for (size_t I = 0, S = 8 - Rem; I < S; ++I) > + OS << '\0'; > + } > + auto *FilenamesAndMappingsVal = > + llvm::ConstantDataArray::getString(Ctx, OS.str(), false); > + > + // Create the deferred function records array > + auto RecordsTy = > + llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size()); > + auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords); > + > + // Create the coverage data record > + llvm::Type *CovDataTypes[] = {Int32Ty, Int32Ty, > + Int32Ty, Int32Ty, > + RecordsTy, > FilenamesAndMappingsVal->getType()}; > + auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes)); > + llvm::Constant *TUDataVals[] = { > + llvm::ConstantInt::get(Int32Ty, FunctionRecords.size()), > + llvm::ConstantInt::get(Int32Ty, FilenamesSize), > + llvm::ConstantInt::get(Int32Ty, CoverageMappingSize), > + llvm::ConstantInt::get(Int32Ty, > + /*Version=*/CoverageMappingVersion1), > + RecordsVal, FilenamesAndMappingsVal}; > + auto CovDataVal = > + llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals)); > + auto CovData = new llvm::GlobalVariable(CGM.getModule(), CovDataTy, true, > + llvm::GlobalValue::InternalLinkage, > + CovDataVal, > + "__llvm_coverage_mapping"); > + > + CovData->setSection(getCoverageSection(CGM)); > + CovData->setAlignment(8); > + > + // Make sure the data doesn't get deleted. > + CGM.addUsedGlobal(CovData); > +} > + > +unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) { > + auto It = FileEntries.find(File); > + if (It != FileEntries.end()) > + return It->second; > + unsigned FileID = FileEntries.size(); > + FileEntries.insert(std::make_pair(File, FileID)); > + return FileID; > +} > + > +void CoverageMappingGen::emitCounterMapping(const Decl *D, > + llvm::raw_ostream &OS) { > + assert(CounterMap); > + CounterCoverageMappingBuilder Walker(CVM, *CounterMap, NumRegionCounters, > SM, > + LangOpts); > + Walker.VisitDecl(D); > + Walker.write(OS); > +} > + > +void CoverageMappingGen::emitEmptyMapping(const Decl *D, > + llvm::raw_ostream &OS) { > + EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); > + Walker.VisitDecl(D); > + Walker.write(OS); > +} > > Added: cfe/trunk/lib/CodeGen/CoverageMappingGen.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CoverageMappingGen.h?rev=214752&view=auto > ============================================================================== > --- cfe/trunk/lib/CodeGen/CoverageMappingGen.h (added) > +++ cfe/trunk/lib/CodeGen/CoverageMappingGen.h Mon Aug 4 13:41:51 2014 > @@ -0,0 +1,117 @@ > +//===---- CoverageMappingGen.h - Coverage mapping generation ----*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// Instrumentation-based code coverage mapping generator > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef CLANG_CODEGEN_COVERAGEMAPPINGGEN_H > +#define CLANG_CODEGEN_COVERAGEMAPPINGGEN_H > + > +#include "clang/Basic/LLVM.h" > +#include "clang/Basic/SourceLocation.h" > +#include "clang/Lex/PPCallbacks.h" > +#include "clang/Frontend/CodeGenOptions.h" > +#include "llvm/ADT/StringMap.h" > +#include "llvm/ADT/DenseMap.h" > +#include "llvm/IR/GlobalValue.h" > +#include "llvm/Support/raw_ostream.h" > + > +namespace clang { > + > +class LangOptions; > +class SourceManager; > +class FileEntry; > +class Preprocessor; > +class Decl; > +class Stmt; > + > +/// \brief Stores additional source code information like skipped ranges > which > +/// is required by the coverage mapping generator and is obtained from > +/// the preprocessor. > +class CoverageSourceInfo : public PPCallbacks { > + std::vector<SourceRange> SkippedRanges; > +public: > + ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; } > + > + void SourceRangeSkipped(SourceRange Range) override; > +}; > + > +namespace CodeGen { > + > +class CodeGenModule; > + > +/// \brief Organizes the cross-function state that is used while generating > +/// code coverage mapping data. > +class CoverageMappingModuleGen { > + CodeGenModule &CGM; > + CoverageSourceInfo &SourceInfo; > + llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries; > + std::vector<llvm::Constant *> FunctionRecords; > + llvm::StructType *FunctionRecordTy; > + std::string CoverageMappings; > + > +public: > + CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo > &SourceInfo) > + : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {} > + > + CoverageSourceInfo &getSourceInfo() const { > + return SourceInfo; > + } > + > + /// \brief Add a function's coverage mapping record to the collection of > the > + /// function mapping records. > + void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName, > + unsigned FunctionNameSize, > + const std::string &CoverageMapping); > + > + /// \brief Emit the coverage mapping data for a translation unit. > + void emit(); > + > + /// \brief Return the coverage mapping translation unit file id > + /// for the given file. > + unsigned getFileID(const FileEntry *File); > +}; > + > +/// \brief Organizes the per-function state that is used while generating > +/// code coverage mapping data. > +class CoverageMappingGen { > + CoverageMappingModuleGen &CVM; > + SourceManager &SM; > + const LangOptions &LangOpts; > + llvm::DenseMap<const Stmt *, unsigned> *CounterMap; > + unsigned NumRegionCounters; > + > +public: > + CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM, > + const LangOptions &LangOpts) > + : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(nullptr), > + NumRegionCounters(0) {} > + > + CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM, > + const LangOptions &LangOpts, > + llvm::DenseMap<const Stmt *, unsigned> *CounterMap, > + unsigned NumRegionCounters) > + : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap), > + NumRegionCounters(NumRegionCounters) {} > + > + /// \brief Emit the coverage mapping data which maps the regions of > + /// code to counters that will be used to find the execution > + /// counts for those regions. > + void emitCounterMapping(const Decl *D, llvm::raw_ostream &OS); > + > + /// \brief Emit the coverage mapping data for an unused function. > + /// It creates mapping regions with the counter of zero. > + void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS); > +}; > + > +} // end namespace CodeGen > +} // end namespace clang > + > +#endif > > Modified: cfe/trunk/lib/CodeGen/ModuleBuilder.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ModuleBuilder.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/ModuleBuilder.cpp (original) > +++ cfe/trunk/lib/CodeGen/ModuleBuilder.cpp Mon Aug 4 13:41:51 2014 > @@ -46,14 +46,18 @@ namespace { > } > }; > > + CoverageSourceInfo *CoverageInfo; > + > protected: > std::unique_ptr<llvm::Module> M; > std::unique_ptr<CodeGen::CodeGenModule> Builder; > > public: > CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& > ModuleName, > - const CodeGenOptions &CGO, llvm::LLVMContext& C) > + const CodeGenOptions &CGO, llvm::LLVMContext& C, > + CoverageSourceInfo *CoverageInfo = nullptr) > : Diags(diags), CodeGenOpts(CGO), HandlingTopLevelDecls(0), > + CoverageInfo(CoverageInfo), > M(new llvm::Module(ModuleName, C)) {} > > virtual ~CodeGeneratorImpl() {} > @@ -86,7 +90,7 @@ namespace { > M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); > TD.reset(new > llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription())); > Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, > - Diags)); > + Diags, CoverageInfo)); > > for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; > ++i) > HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]); > @@ -136,6 +140,10 @@ namespace { > // void foo() { bar(); } > // } A; > DeferredInlineMethodDefinitions.push_back(D); > + > + // Always provide some coverage mapping > + // even for the methods that aren't emitted. > + Builder->AddDeferredUnusedCoverageMapping(D); > } > > /// HandleTagDeclDefinition - This callback is invoked each time a > TagDecl > @@ -221,6 +229,7 @@ CodeGenerator *clang::CreateLLVMCodeGen( > const std::string& ModuleName, > const CodeGenOptions &CGO, > const TargetOptions &/*TO*/, > - llvm::LLVMContext& C) { > - return new CodeGeneratorImpl(Diags, ModuleName, CGO, C); > + llvm::LLVMContext& C, > + CoverageSourceInfo *CoverageInfo) { > + return new CodeGeneratorImpl(Diags, ModuleName, CGO, C, CoverageInfo); > } > > Modified: cfe/trunk/lib/Driver/Tools.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/Driver/Tools.cpp (original) > +++ cfe/trunk/lib/Driver/Tools.cpp Mon Aug 4 13:41:51 2014 > @@ -3230,6 +3230,14 @@ void Clang::ConstructJob(Compilation &C, > Args.hasArg(options::OPT_coverage)) > CmdArgs.push_back("-femit-coverage-data"); > > + if (Args.hasArg(options::OPT_fcoverage_mapping) && > + !Args.hasArg(options::OPT_fprofile_instr_generate)) > + D.Diag(diag::err_drv_argument_only_allowed_with) > + << "-fcoverage-mapping" << "-fprofile-instr-generate"; > + > + if (Args.hasArg(options::OPT_fcoverage_mapping)) > + CmdArgs.push_back("-fcoverage-mapping"); > + > if (C.getArgs().hasArg(options::OPT_c) || > C.getArgs().hasArg(options::OPT_S)) { > if (Output.isFilename()) { > > Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=214752&r1=214751&r2=214752&view=diff > ============================================================================== > --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) > +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Mon Aug 4 13:41:51 2014 > @@ -403,6 +403,7 @@ static bool ParseCodeGenArgs(CodeGenOpti > Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ); > Opts.ProfileInstrGenerate = Args.hasArg(OPT_fprofile_instr_generate); > Opts.InstrProfileInput = Args.getLastArgValue(OPT_fprofile_instr_use_EQ); > + Opts.CoverageMapping = Args.hasArg(OPT_fcoverage_mapping); > Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); > Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); > Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
