154 changes: 115 additions & 39 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,16 +25,17 @@
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
// naming convention. Do not include that '1' in the PGO profile name.
if (RawFuncName[0] == '\1')
RawFuncName = RawFuncName.substr(1);

if (!Fn->hasLocalLinkage()) {
if (!llvm::GlobalValue::isLocalLinkage(Linkage)) {
PrefixedFuncName.reset(new std::string(RawFuncName));
return;
}
Expand All @@ -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");
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -807,34 +841,37 @@ 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();
if (!InstrumentRegions && !PGOReader)
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();
Expand All @@ -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);
Expand Down
17 changes: 15 additions & 2 deletions clang/lib/CodeGen/CodeGenPGO.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,16 @@ class CodeGenPGO {
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
Expand Down Expand Up @@ -99,6 +104,8 @@ class CodeGenPGO {
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
Expand All @@ -111,9 +118,14 @@ class CodeGenPGO {
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,
Expand All @@ -122,6 +134,7 @@ class CodeGenPGO {
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);
Expand Down
1,166 changes: 1,166 additions & 0 deletions clang/lib/CodeGen/CoverageMappingGen.cpp

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions clang/lib/CodeGen/CoverageMappingGen.h
Original file line number Diff line number Diff line change
@@ -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
17 changes: 13 additions & 4 deletions clang/lib/CodeGen/ModuleBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
8 changes: 8 additions & 0 deletions clang/lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down