mirror of
https://github.com/apple/swift.git
synced 2025-12-25 12:15:36 +01:00
We previously eagerly emitted such functions to ensure that their name data is emitted through the profiler increment. Now that are able to emit the profile name data separately, this is unnecessary, and we can avoid emitting their definitions.
200 lines
7.6 KiB
C++
200 lines
7.6 KiB
C++
//===--- 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();
|
|
}
|