mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -60,6 +60,9 @@ private:
|
|||||||
// The mangled name of the function covered by this mapping.
|
// The mangled name of the function covered by this mapping.
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
|
|
||||||
|
// Whether or not the covered function may have external linkage.
|
||||||
|
bool External;
|
||||||
|
|
||||||
// The coverage hash of the function covered by this mapping.
|
// The coverage hash of the function covered by this mapping.
|
||||||
uint64_t Hash;
|
uint64_t Hash;
|
||||||
|
|
||||||
@@ -80,14 +83,14 @@ private:
|
|||||||
SILCoverageMap &operator=(const SILCoverageMap &) = delete;
|
SILCoverageMap &operator=(const SILCoverageMap &) = delete;
|
||||||
|
|
||||||
/// Private constructor. Create these using SILCoverageMap::create.
|
/// Private constructor. Create these using SILCoverageMap::create.
|
||||||
SILCoverageMap(uint64_t Hash);
|
SILCoverageMap(uint64_t Hash, bool External);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~SILCoverageMap();
|
~SILCoverageMap();
|
||||||
|
|
||||||
static SILCoverageMap *
|
static SILCoverageMap *
|
||||||
create(SILModule &M, StringRef Filename, StringRef Name, uint64_t Hash,
|
create(SILModule &M, StringRef Filename, StringRef Name, bool External,
|
||||||
ArrayRef<MappedRegion> MappedRegions,
|
uint64_t Hash, ArrayRef<MappedRegion> MappedRegions,
|
||||||
ArrayRef<llvm::coverage::CounterExpression> Expressions);
|
ArrayRef<llvm::coverage::CounterExpression> Expressions);
|
||||||
|
|
||||||
/// Return the name of the source file where this mapping is found.
|
/// 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.
|
/// Return the mangled name of the function this mapping covers.
|
||||||
StringRef getName() const { return Name; }
|
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.
|
/// Return the coverage hash for function this mapping covers.
|
||||||
uint64_t getHash() const { return Hash; }
|
uint64_t getHash() const { return Hash; }
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,10 @@ void IRGenModule::emitCoverageMapping() {
|
|||||||
W.write(OS);
|
W.write(OS);
|
||||||
|
|
||||||
std::string NameValue = llvm::getPGOFuncName(
|
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(
|
llvm::GlobalVariable *NamePtr = llvm::createPGOFuncNameVar(
|
||||||
*getModule(), llvm::GlobalValue::LinkOnceAnyLinkage, NameValue);
|
*getModule(), llvm::GlobalValue::LinkOnceAnyLinkage, NameValue);
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// 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.
|
// Fix the intrinsic call here by pointing it to the correct GV.
|
||||||
if (IID == llvm::Intrinsic::instrprof_increment) {
|
if (IID == llvm::Intrinsic::instrprof_increment) {
|
||||||
// Extract the function name.
|
// Extract the PGO function name.
|
||||||
auto *NameGEP = cast<llvm::User>(args.claimNext());
|
auto *NameGEP = cast<llvm::User>(args.claimNext());
|
||||||
auto *NameGV = cast<llvm::GlobalVariable>(NameGEP->getOperand(0));
|
auto *NameGV = dyn_cast<llvm::GlobalVariable>(NameGEP->stripPointerCasts());
|
||||||
auto *NameC = NameGV->getInitializer();
|
if (NameGV) {
|
||||||
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
|
auto *NameC = NameGV->getInitializer();
|
||||||
|
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
|
||||||
|
StringRef PGOFuncName = Name.rtrim(StringRef("\0", 1));
|
||||||
|
|
||||||
// Find the existing function name pointer.
|
// Point the increment call to the right function name variable.
|
||||||
std::string NameValue = llvm::getInstrProfNameVarPrefix();
|
std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName(
|
||||||
NameValue += Name;
|
PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage);
|
||||||
StringRef ProfName = StringRef(NameValue).rtrim(StringRef("\0", 1));
|
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(PGOFuncNameVar);
|
||||||
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(ProfName);
|
|
||||||
assert(FuncNamePtr && "No function name pointer for counter update");
|
|
||||||
|
|
||||||
// Create a GEP into the function name.
|
if (FuncNamePtr) {
|
||||||
llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
|
llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
|
||||||
auto *FuncName = llvm::GetElementPtrInst::CreateInBounds(
|
NameGEP = llvm::GetElementPtrInst::CreateInBounds(
|
||||||
FuncNamePtr, makeArrayRef(Indices), "", IGF.Builder.GetInsertBlock());
|
FuncNamePtr, makeArrayRef(Indices), "",
|
||||||
|
IGF.Builder.GetInsertBlock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replace the placeholder value with the new GEP.
|
// Replace the placeholder value with the new GEP.
|
||||||
Explosion replacement;
|
Explosion replacement;
|
||||||
replacement.add(FuncName);
|
replacement.add(NameGEP);
|
||||||
replacement.add(args.claimAll());
|
replacement.add(args.claimAll());
|
||||||
args = std::move(replacement);
|
args = std::move(replacement);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4613,8 +4613,9 @@ bool Parser::parseSILCoverageMap() {
|
|||||||
LBraceLoc);
|
LBraceLoc);
|
||||||
|
|
||||||
if (!BodyHasError)
|
if (!BodyHasError)
|
||||||
SILCoverageMap::create(*SIL->M, Filename.str(), FuncName.str(), Hash,
|
SILCoverageMap::create(*SIL->M, Filename.str(), FuncName.str(),
|
||||||
Regions, Builder.getExpressions());
|
Func->isPossiblyUsedExternally(), Hash, Regions,
|
||||||
|
Builder.getExpressions());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ using llvm::coverage::CounterExpression;
|
|||||||
|
|
||||||
SILCoverageMap *
|
SILCoverageMap *
|
||||||
SILCoverageMap::create(SILModule &M, StringRef Filename, StringRef Name,
|
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) {
|
ArrayRef<CounterExpression> Expressions) {
|
||||||
void *Buf = M.allocate(sizeof(SILCoverageMap), alignof(SILCoverageMap));
|
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.
|
// Store a copy of the name so that we own the lifetime.
|
||||||
char *AllocatedName = (char *)M.allocate(Filename.size(), alignof(char));
|
char *AllocatedName = (char *)M.allocate(Filename.size(), alignof(char));
|
||||||
@@ -56,7 +57,8 @@ SILCoverageMap::create(SILModule &M, StringRef Filename, StringRef Name,
|
|||||||
return CM;
|
return CM;
|
||||||
}
|
}
|
||||||
|
|
||||||
SILCoverageMap::SILCoverageMap(uint64_t Hash) : Hash(Hash) {}
|
SILCoverageMap::SILCoverageMap(uint64_t Hash, bool External)
|
||||||
|
: Hash(Hash), External(External) {}
|
||||||
|
|
||||||
SILCoverageMap::~SILCoverageMap() {}
|
SILCoverageMap::~SILCoverageMap() {}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
#include "swift/AST/ASTWalker.h"
|
#include "swift/AST/ASTWalker.h"
|
||||||
#include "swift/Basic/Fallthrough.h"
|
#include "swift/Basic/Fallthrough.h"
|
||||||
#include "swift/Parse/Lexer.h"
|
#include "swift/Parse/Lexer.h"
|
||||||
|
#include "swift/SIL/FormalLinkage.h"
|
||||||
#include "llvm/IR/Intrinsics.h"
|
#include "llvm/IR/Intrinsics.h"
|
||||||
|
#include "llvm/IR/GlobalValue.h"
|
||||||
#include "llvm/ProfileData/CoverageMapping.h"
|
#include "llvm/ProfileData/CoverageMapping.h"
|
||||||
#include "llvm/ProfileData/CoverageMappingWriter.h"
|
#include "llvm/ProfileData/CoverageMappingWriter.h"
|
||||||
|
#include "llvm/ProfileData/InstrProf.h"
|
||||||
|
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
|
|
||||||
@@ -408,12 +411,11 @@ public:
|
|||||||
/// \brief Generate the coverage counter mapping regions from collected
|
/// \brief Generate the coverage counter mapping regions from collected
|
||||||
/// source regions.
|
/// source regions.
|
||||||
SILCoverageMap *
|
SILCoverageMap *
|
||||||
emitSourceRegions(SILModule &M, StringRef Name, uint64_t Hash,
|
emitSourceRegions(SILModule &M, StringRef Name, bool External, uint64_t Hash,
|
||||||
llvm::DenseMap<ASTNode, unsigned> &CounterIndices) {
|
llvm::DenseMap<ASTNode, unsigned> &CounterIndices,
|
||||||
|
StringRef Filename) {
|
||||||
if (SourceRegions.empty())
|
if (SourceRegions.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
StringRef Filename = SM.getIdentifierForBuffer(
|
|
||||||
SM.findBufferContainingLoc(SourceRegions.front().getStartLoc()));
|
|
||||||
|
|
||||||
llvm::coverage::CounterExpressionBuilder Builder;
|
llvm::coverage::CounterExpressionBuilder Builder;
|
||||||
std::vector<SILCoverageMap::MappedRegion> Regions;
|
std::vector<SILCoverageMap::MappedRegion> Regions;
|
||||||
@@ -428,7 +430,7 @@ public:
|
|||||||
Regions.emplace_back(Start.first, Start.second, End.first, End.second,
|
Regions.emplace_back(Start.first, Start.second, End.first, End.second,
|
||||||
Region.getCounter().expand(Builder, CounterIndices));
|
Region.getCounter().expand(Builder, CounterIndices));
|
||||||
}
|
}
|
||||||
return SILCoverageMap::create(M, Filename, Name, Hash, Regions,
|
return SILCoverageMap::create(M, Filename, Name, External, Hash, Regions,
|
||||||
Builder.getExpressions());
|
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) {
|
void SILGenProfiling::assignRegionCounters(AbstractFunctionDecl *Root) {
|
||||||
CurrentFuncName = SILDeclRef(Root).mangle();
|
CurrentFuncName = SILDeclRef(Root).mangle();
|
||||||
|
CurrentFuncLinkage = getDeclLinkage(Root);
|
||||||
|
|
||||||
|
if (auto *ParentFile = Root->getParentSourceFile())
|
||||||
|
CurrentFileName = ParentFile->getFilename();
|
||||||
|
|
||||||
MapRegionCounters Mapper(RegionCounterMap);
|
MapRegionCounters Mapper(RegionCounterMap);
|
||||||
walkForProfiling(Root, Mapper);
|
walkForProfiling(Root, Mapper);
|
||||||
@@ -646,8 +661,10 @@ void SILGenProfiling::assignRegionCounters(AbstractFunctionDecl *Root) {
|
|||||||
if (EmitCoverageMapping) {
|
if (EmitCoverageMapping) {
|
||||||
CoverageMapping Coverage(SGM.M.getASTContext().SourceMgr);
|
CoverageMapping Coverage(SGM.M.getASTContext().SourceMgr);
|
||||||
walkForProfiling(Root, Coverage);
|
walkForProfiling(Root, Coverage);
|
||||||
Coverage.emitSourceRegions(SGM.M, CurrentFuncName, FunctionHash,
|
Coverage.emitSourceRegions(SGM.M, CurrentFuncName,
|
||||||
RegionCounterMap);
|
!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 Int32Ty = SGM.Types.getLoweredType(BuiltinIntegerType::get(32, C));
|
||||||
auto Int64Ty = SGM.Types.getLoweredType(BuiltinIntegerType::get(64, C));
|
auto Int64Ty = SGM.Types.getLoweredType(BuiltinIntegerType::get(64, C));
|
||||||
|
|
||||||
|
std::string PGOFuncName = llvm::getPGOFuncName(
|
||||||
|
CurrentFuncName, getEquivalentPGOLinkage(CurrentFuncLinkage),
|
||||||
|
CurrentFileName);
|
||||||
|
|
||||||
SILLocation Loc = getLocation(Node);
|
SILLocation Loc = getLocation(Node);
|
||||||
SILValue Args[] = {
|
SILValue Args[] = {
|
||||||
// The intrinsic must refer to the function profiling name var, which is
|
// The intrinsic must refer to the function profiling name var, which is
|
||||||
// inaccessible during SILGen. Rely on irgen to rewrite the function name.
|
// inaccessible during SILGen. Rely on irgen to rewrite the function name.
|
||||||
Builder.createStringLiteral(Loc, StringRef(CurrentFuncName),
|
Builder.createStringLiteral(Loc, StringRef(PGOFuncName),
|
||||||
StringLiteralInst::Encoding::UTF8),
|
StringLiteralInst::Encoding::UTF8),
|
||||||
Builder.createIntegerLiteral(Loc, Int64Ty, FunctionHash),
|
Builder.createIntegerLiteral(Loc, Int64Ty, FunctionHash),
|
||||||
Builder.createIntegerLiteral(Loc, Int32Ty, NumRegionCounters),
|
Builder.createIntegerLiteral(Loc, Int32Ty, NumRegionCounters),
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "swift/AST/ASTNode.h"
|
#include "swift/AST/ASTNode.h"
|
||||||
#include "swift/AST/Stmt.h"
|
#include "swift/AST/Stmt.h"
|
||||||
|
#include "swift/SIL/FormalLinkage.h"
|
||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
|
|
||||||
@@ -41,6 +42,8 @@ private:
|
|||||||
|
|
||||||
// The current function's name and counter data.
|
// The current function's name and counter data.
|
||||||
std::string CurrentFuncName;
|
std::string CurrentFuncName;
|
||||||
|
StringRef CurrentFileName;
|
||||||
|
FormalLinkage CurrentFuncLinkage;
|
||||||
unsigned NumRegionCounters;
|
unsigned NumRegionCounters;
|
||||||
uint64_t FunctionHash;
|
uint64_t FunctionHash;
|
||||||
llvm::DenseMap<ASTNode, unsigned> RegionCounterMap;
|
llvm::DenseMap<ASTNode, unsigned> RegionCounterMap;
|
||||||
|
|||||||
20
test/IRGen/coverage.swift
Normal file
20
test/IRGen/coverage.swift
Normal 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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user