[Coverage] Respect function linkage in PGO name variables

Fix a crash in emitBuiltinCall() which occurs because we drop function
linkage information when creating SILCoverageMaps.
This commit is contained in:
Vedant Kumar
2016-03-17 17:57:05 -07:00
parent 43d2cd2908
commit 45c7e4e861
8 changed files with 91 additions and 32 deletions

View File

@@ -60,6 +60,9 @@ private:
// The mangled name of the function covered by this mapping.
StringRef Name;
// Whether or not the covered function may have external linkage.
bool External;
// The coverage hash of the function covered by this mapping.
uint64_t Hash;
@@ -80,14 +83,14 @@ private:
SILCoverageMap &operator=(const SILCoverageMap &) = delete;
/// Private constructor. Create these using SILCoverageMap::create.
SILCoverageMap(uint64_t Hash);
SILCoverageMap(uint64_t Hash, bool External);
public:
~SILCoverageMap();
static SILCoverageMap *
create(SILModule &M, StringRef Filename, StringRef Name, uint64_t Hash,
ArrayRef<MappedRegion> MappedRegions,
create(SILModule &M, StringRef Filename, StringRef Name, bool External,
uint64_t Hash, ArrayRef<MappedRegion> MappedRegions,
ArrayRef<llvm::coverage::CounterExpression> Expressions);
/// Return the name of the source file where this mapping is found.
@@ -96,6 +99,9 @@ public:
/// Return the mangled name of the function this mapping covers.
StringRef getName() const { return Name; }
/// Check whether the covered function may have external linkage.
bool isPossiblyUsedExternally() const { return External; }
/// Return the coverage hash for function this mapping covers.
uint64_t getHash() const { return Hash; }

View File

@@ -104,7 +104,10 @@ void IRGenModule::emitCoverageMapping() {
W.write(OS);
std::string NameValue = llvm::getPGOFuncName(
M.getName(), llvm::GlobalValue::LinkOnceAnyLinkage, M.getFile());
M.getName(),
M.isPossiblyUsedExternally() ? llvm::GlobalValue::ExternalLinkage
: llvm::GlobalValue::PrivateLinkage,
M.getFile());
llvm::GlobalVariable *NamePtr = llvm::createPGOFuncNameVar(
*getModule(), llvm::GlobalValue::LinkOnceAnyLinkage, NameValue);

View File

@@ -1806,27 +1806,30 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, Identifier FnId,
// At that stage, the function name GV used by the profiling pass is hidden.
// Fix the intrinsic call here by pointing it to the correct GV.
if (IID == llvm::Intrinsic::instrprof_increment) {
// Extract the function name.
// Extract the PGO function name.
auto *NameGEP = cast<llvm::User>(args.claimNext());
auto *NameGV = cast<llvm::GlobalVariable>(NameGEP->getOperand(0));
auto *NameC = NameGV->getInitializer();
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
auto *NameGV = dyn_cast<llvm::GlobalVariable>(NameGEP->stripPointerCasts());
if (NameGV) {
auto *NameC = NameGV->getInitializer();
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
StringRef PGOFuncName = Name.rtrim(StringRef("\0", 1));
// Find the existing function name pointer.
std::string NameValue = llvm::getInstrProfNameVarPrefix();
NameValue += Name;
StringRef ProfName = StringRef(NameValue).rtrim(StringRef("\0", 1));
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(ProfName);
assert(FuncNamePtr && "No function name pointer for counter update");
// Point the increment call to the right function name variable.
std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName(
PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage);
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(PGOFuncNameVar);
// Create a GEP into the function name.
llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
auto *FuncName = llvm::GetElementPtrInst::CreateInBounds(
FuncNamePtr, makeArrayRef(Indices), "", IGF.Builder.GetInsertBlock());
if (FuncNamePtr) {
llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
NameGEP = llvm::GetElementPtrInst::CreateInBounds(
FuncNamePtr, makeArrayRef(Indices), "",
IGF.Builder.GetInsertBlock());
}
}
// Replace the placeholder value with the new GEP.
Explosion replacement;
replacement.add(FuncName);
replacement.add(NameGEP);
replacement.add(args.claimAll());
args = std::move(replacement);
}

View File

@@ -4613,8 +4613,9 @@ bool Parser::parseSILCoverageMap() {
LBraceLoc);
if (!BodyHasError)
SILCoverageMap::create(*SIL->M, Filename.str(), FuncName.str(), Hash,
Regions, Builder.getExpressions());
SILCoverageMap::create(*SIL->M, Filename.str(), FuncName.str(),
Func->isPossiblyUsedExternally(), Hash, Regions,
Builder.getExpressions());
return false;
}

View File

@@ -24,10 +24,11 @@ using llvm::coverage::CounterExpression;
SILCoverageMap *
SILCoverageMap::create(SILModule &M, StringRef Filename, StringRef Name,
uint64_t Hash, ArrayRef<MappedRegion> MappedRegions,
bool External, uint64_t Hash,
ArrayRef<MappedRegion> MappedRegions,
ArrayRef<CounterExpression> Expressions) {
void *Buf = M.allocate(sizeof(SILCoverageMap), alignof(SILCoverageMap));
SILCoverageMap *CM = ::new (Buf) SILCoverageMap(Hash);
SILCoverageMap *CM = ::new (Buf) SILCoverageMap(Hash, External);
// Store a copy of the name so that we own the lifetime.
char *AllocatedName = (char *)M.allocate(Filename.size(), alignof(char));
@@ -56,7 +57,8 @@ SILCoverageMap::create(SILModule &M, StringRef Filename, StringRef Name,
return CM;
}
SILCoverageMap::SILCoverageMap(uint64_t Hash) : Hash(Hash) {}
SILCoverageMap::SILCoverageMap(uint64_t Hash, bool External)
: Hash(Hash), External(External) {}
SILCoverageMap::~SILCoverageMap() {}

View File

@@ -17,9 +17,12 @@
#include "swift/AST/ASTWalker.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/Parse/Lexer.h"
#include "swift/SIL/FormalLinkage.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/ProfileData/CoverageMapping.h"
#include "llvm/ProfileData/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include <forward_list>
@@ -408,12 +411,11 @@ public:
/// \brief Generate the coverage counter mapping regions from collected
/// source regions.
SILCoverageMap *
emitSourceRegions(SILModule &M, StringRef Name, uint64_t Hash,
llvm::DenseMap<ASTNode, unsigned> &CounterIndices) {
emitSourceRegions(SILModule &M, StringRef Name, bool External, uint64_t Hash,
llvm::DenseMap<ASTNode, unsigned> &CounterIndices,
StringRef Filename) {
if (SourceRegions.empty())
return nullptr;
StringRef Filename = SM.getIdentifierForBuffer(
SM.findBufferContainingLoc(SourceRegions.front().getStartLoc()));
llvm::coverage::CounterExpressionBuilder Builder;
std::vector<SILCoverageMap::MappedRegion> Regions;
@@ -428,7 +430,7 @@ public:
Regions.emplace_back(Start.first, Start.second, End.first, End.second,
Region.getCounter().expand(Builder, CounterIndices));
}
return SILCoverageMap::create(M, Filename, Name, Hash, Regions,
return SILCoverageMap::create(M, Filename, Name, External, Hash, Regions,
Builder.getExpressions());
}
@@ -633,8 +635,21 @@ static void walkForProfiling(AbstractFunctionDecl *Root, ASTWalker &Walker) {
}
}
static llvm::GlobalValue::LinkageTypes
getEquivalentPGOLinkage(FormalLinkage Linkage) {
return (Linkage == FormalLinkage::HiddenUnique ||
Linkage == FormalLinkage::HiddenNonUnique ||
Linkage == FormalLinkage::Private)
? llvm::GlobalValue::PrivateLinkage
: llvm::GlobalValue::ExternalLinkage;
}
void SILGenProfiling::assignRegionCounters(AbstractFunctionDecl *Root) {
CurrentFuncName = SILDeclRef(Root).mangle();
CurrentFuncLinkage = getDeclLinkage(Root);
if (auto *ParentFile = Root->getParentSourceFile())
CurrentFileName = ParentFile->getFilename();
MapRegionCounters Mapper(RegionCounterMap);
walkForProfiling(Root, Mapper);
@@ -646,8 +661,10 @@ void SILGenProfiling::assignRegionCounters(AbstractFunctionDecl *Root) {
if (EmitCoverageMapping) {
CoverageMapping Coverage(SGM.M.getASTContext().SourceMgr);
walkForProfiling(Root, Coverage);
Coverage.emitSourceRegions(SGM.M, CurrentFuncName, FunctionHash,
RegionCounterMap);
Coverage.emitSourceRegions(SGM.M, CurrentFuncName,
!llvm::GlobalValue::isLocalLinkage(
getEquivalentPGOLinkage(CurrentFuncLinkage)),
FunctionHash, RegionCounterMap, CurrentFileName);
}
}
@@ -672,11 +689,15 @@ void SILGenProfiling::emitCounterIncrement(SILGenBuilder &Builder,ASTNode Node){
auto Int32Ty = SGM.Types.getLoweredType(BuiltinIntegerType::get(32, C));
auto Int64Ty = SGM.Types.getLoweredType(BuiltinIntegerType::get(64, C));
std::string PGOFuncName = llvm::getPGOFuncName(
CurrentFuncName, getEquivalentPGOLinkage(CurrentFuncLinkage),
CurrentFileName);
SILLocation Loc = getLocation(Node);
SILValue Args[] = {
// The intrinsic must refer to the function profiling name var, which is
// inaccessible during SILGen. Rely on irgen to rewrite the function name.
Builder.createStringLiteral(Loc, StringRef(CurrentFuncName),
Builder.createStringLiteral(Loc, StringRef(PGOFuncName),
StringLiteralInst::Encoding::UTF8),
Builder.createIntegerLiteral(Loc, Int64Ty, FunctionHash),
Builder.createIntegerLiteral(Loc, Int32Ty, NumRegionCounters),

View File

@@ -16,6 +16,7 @@
#include "llvm/ADT/DenseMap.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Stmt.h"
#include "swift/SIL/FormalLinkage.h"
namespace swift {
@@ -41,6 +42,8 @@ private:
// The current function's name and counter data.
std::string CurrentFuncName;
StringRef CurrentFileName;
FormalLinkage CurrentFuncLinkage;
unsigned NumRegionCounters;
uint64_t FunctionHash;
llvm::DenseMap<ASTNode, unsigned> RegionCounterMap;

20
test/IRGen/coverage.swift Normal file
View File

@@ -0,0 +1,20 @@
// RUN: %target-swift-frontend %s -profile-generate -profile-coverage-mapping -emit-sil -o - | FileCheck %s --check-prefix=SIL
// RUN: %target-swift-frontend %s -profile-generate -profile-coverage-mapping -emit-ir -o - | FileCheck %s --check-prefix=IR
// SIL-DAG: sil hidden @_TF8coverage2f1FT_T_
// SIL-DAG: string_literal utf8 "_TF8coverage2f1FT_T_"
// IR: @__profn__TF8coverage2f1FT_T_ {{.*}} c"_TF8coverage2f1FT_T_", section "__DATA,__llvm_prf_names"
internal func f1() {}
// SIL-DAG: sil private @_TF8coverageP33_[[F2HASH:[_a-zA-Z0-9]+]]
// SIL-DAG: string_literal utf8 "{{.*}}coverage.swift:_TF8coverageP33_[[F2HASH]]"
// IR: @"__profn_{{.*}}coverage.swift:_TF8coverageP33_[[F2HASH:[_a-zA-Z0-9]+]]" {{.*}} c"{{.*}}coverage.swift:_TF8coverageP33_[[F2HASH]]", section "__DATA,__llvm_prf_names"
private func f2() {}
// SIL-DAG: sil @_TF8coverage2f3FT_T_
// SIL-DAG: string_literal utf8 "_TF8coverage2f3FT_T_"
// IR: @__profn__TF8coverage2f3FT_T_ {{.*}} c"_TF8coverage2f3FT_T_", section "__DATA,__llvm_prf_names"
public func f3() {
f1();
f2();
}