//===--- 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() { std::vector Mappings; for (const auto &M : getSILModule().getCoverageMaps()) { // Check whether this coverage mapping can reference its name data within // the profile symbol table. If the name global is gone, this function has // been optimized out. StringRef PGOFuncName = M.second->getPGOFuncName(); std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName( PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage); if (!Module.getNamedGlobal(PGOFuncNameVar)) continue; Mappings.push_back(M.second); } // If there aren't any coverage maps, there's nothing to emit. if (Mappings.empty()) return; std::vector 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 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 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 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); }