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.
|
||||
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; }
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
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