forked from OSchip/llvm-project
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). llvm-svn: 214752
This commit is contained in:
parent
1193b5e272
commit
ee02499a8f
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -408,6 +408,9 @@ def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>;
|
|||
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">;
|
||||
|
|
|
@ -88,6 +88,8 @@ VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified
|
|||
|
||||
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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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::CreateASTConsumer(CompilerInstance &CI,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -829,6 +829,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
|||
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);
|
||||
|
|
|
@ -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(CodeGenModule &CGM) {
|
|||
|
||||
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 &C, const CodeGenOptions &CGO,
|
|||
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(Decl *D) {
|
|||
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(Decl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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 CodeGenTypeCache {
|
|||
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);
|
||||
|
||||
|
|
|
@ -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::Function *Fn) {
|
|||
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::Function *Fn) {
|
|||
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::buildDataVar() {
|
|||
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"));
|
||||
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);
|
||||
// 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(CodeGenModule &CGM) {
|
|||
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(const Decl *D, llvm::Function *Fn) {
|
|||
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 Decl *D) {
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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(DiagnosticsEngine &Diags,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -3230,6 +3230,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
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()) {
|
||||
|
|
|
@ -403,6 +403,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue