r214752 - Add coverage mapping generation.
David Blaikie
dblaikie at gmail.com
Mon Aug 4 12:08:47 PDT 2014
CMake build fixed in r214758
On Mon, Aug 4, 2014 at 11:41 AM, Alex Lorenz <arphaman at gmail.com> 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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list