-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathGenCoverage.cpp
199 lines (173 loc) · 7.63 KB
/
GenCoverage.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//===--- GenCoverage.cpp - IR Generation for coverage ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for the initialization of
// coverage related variables.
//
//===----------------------------------------------------------------------===//
#include "IRGenModule.h"
#include "SwiftTargetInfo.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/SIL/SILModule.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/FileSystem.h"
// This selects the coverage mapping format defined when `InstrProfData.inc`
// is textually included.
#define COVMAP_V3
using namespace swift;
using namespace irgen;
using llvm::coverage::CounterMappingRegion;
using llvm::coverage::CovMapVersion;
static std::string getInstrProfSection(IRGenModule &IGM,
llvm::InstrProfSectKind SK) {
return llvm::getInstrProfSectionName(SK, IGM.Triple.getObjectFormat());
}
void IRGenModule::emitCoverageMapping() {
SmallVector<llvm::Constant *, 4> UnusedFuncNames;
std::vector<const SILCoverageMap *> Mappings;
for (const auto &M : getSILModule().getCoverageMaps()) {
auto FuncName = M.second->getPGOFuncName();
auto VarLinkage = llvm::GlobalValue::LinkOnceAnyLinkage;
auto FuncNameVarName = llvm::getPGOFuncNameVarName(FuncName, VarLinkage);
// Check whether this coverage mapping can reference its name data within
// the profile symbol table. If the name global isn't there, this function
// has been optimized out. We need to tell LLVM about it by emitting the
// name data separately.
if (!Module.getNamedGlobal(FuncNameVarName)) {
auto *Var = llvm::createPGOFuncNameVar(Module, VarLinkage, FuncName);
UnusedFuncNames.push_back(llvm::ConstantExpr::getBitCast(Var, Int8PtrTy));
}
Mappings.push_back(M.second);
}
// If there aren't any coverage maps, there's nothing to emit.
if (Mappings.empty())
return;
// Emit the name data for any unused functions.
if (!UnusedFuncNames.empty()) {
auto NamePtrsTy = llvm::ArrayType::get(Int8PtrTy, UnusedFuncNames.size());
auto NamePtrs = llvm::ConstantArray::get(NamePtrsTy, UnusedFuncNames);
// Note we don't mark this variable as used, as it doesn't need to be
// present in the object file, it gets picked up by the LLVM instrumentation
// lowering pass.
new llvm::GlobalVariable(Module, NamePtrsTy, /*IsConstant*/ true,
llvm::GlobalValue::InternalLinkage, NamePtrs,
llvm::getCoverageUnusedNamesVarName());
}
std::vector<StringRef> Files;
for (const auto &M : Mappings)
if (std::find(Files.begin(), Files.end(), M->getFile()) == Files.end())
Files.push_back(M->getFile());
auto remapper = getOptions().CoveragePrefixMap;
llvm::SmallVector<std::string, 8> FilenameStrs;
for (StringRef Name : Files) {
llvm::SmallString<256> Path(Name);
llvm::sys::fs::make_absolute(Path);
FilenameStrs.push_back(remapper.remapPath(Path));
}
// Encode the filenames.
std::string Filenames;
llvm::LLVMContext &Ctx = getLLVMContext();
{
llvm::raw_string_ostream OS(Filenames);
llvm::coverage::CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
}
auto *FilenamesVal =
llvm::ConstantDataArray::getString(Ctx, Filenames, false);
const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
const size_t FilenamesSize = Filenames.size();
// Emit the function records.
auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
for (const auto &M : Mappings) {
StringRef NameValue = M->getPGOFuncName();
assert(!NameValue.empty() && "Expected a named record");
uint64_t FuncHash = M->getHash();
const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
std::string FuncRecordName = "__covrec_" + llvm::utohexstr(NameHash);
unsigned FileID =
std::find(Files.begin(), Files.end(), M->getFile()) - Files.begin();
std::vector<CounterMappingRegion> Regions;
for (const auto &MR : M->getMappedRegions())
Regions.emplace_back(CounterMappingRegion::makeRegion(
MR.Counter, /*FileID=*/0, MR.StartLine, MR.StartCol, MR.EndLine,
MR.EndCol));
// Append each function's regions into the encoded buffer.
ArrayRef<unsigned> VirtualFileMapping(FileID);
llvm::coverage::CoverageMappingWriter W(VirtualFileMapping,
M->getExpressions(), Regions);
std::string CoverageMapping;
{
llvm::raw_string_ostream OS(CoverageMapping);
W.write(OS);
}
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
llvm::Type *FunctionRecordTypes[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *FunctionRecordTy =
llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
/*isPacked=*/true);
// Create the function record constant.
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
llvm::Constant *FunctionRecordVals[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *FuncRecordConstant = llvm::ConstantStruct::get(
FunctionRecordTy, makeArrayRef(FunctionRecordVals));
// Create the function record global.
auto *FuncRecord = new llvm::GlobalVariable(
*getModule(), FunctionRecordTy, /*isConstant=*/true,
llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
FuncRecordName);
FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
FuncRecord->setSection(getInstrProfSection(*this, llvm::IPSK_covfun));
FuncRecord->setAlignment(llvm::Align(8));
if (Triple.supportsCOMDAT())
FuncRecord->setComdat(getModule()->getOrInsertComdat(FuncRecordName));
// Make sure the data doesn't get deleted.
addUsedGlobal(FuncRecord);
}
// Create the coverage data header.
const unsigned NRecords = 0;
const unsigned CoverageMappingSize = 0;
llvm::Type *CovDataHeaderTypes[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto CovDataHeaderTy =
llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
llvm::Constant *CovDataHeaderVals[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto CovDataHeaderVal = llvm::ConstantStruct::get(
CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
// Create the coverage data record
llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
auto CovDataVal =
llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
auto CovData = new llvm::GlobalVariable(
*getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
CovDataVal, llvm::getCoverageMappingVarName());
CovData->setSection(getInstrProfSection(*this, llvm::IPSK_covmap));
CovData->setAlignment(llvm::Align(8));
addUsedGlobal(CovData);
}
void IRGenerator::emitCoverageMapping() {
for (auto &IGM : *this)
IGM.second->emitCoverageMapping();
}