TEST(MapVectorTest, insert) { MapVector<int, int> MV; std::pair<MapVector<int, int>::iterator, bool> R; R = MV.insert(std::make_pair(1, 2)); ASSERT_EQ(R.first, MV.begin()); EXPECT_EQ(R.first->first, 1); EXPECT_EQ(R.first->second, 2); EXPECT_TRUE(R.second); R = MV.insert(std::make_pair(1, 3)); ASSERT_EQ(R.first, MV.begin()); EXPECT_EQ(R.first->first, 1); EXPECT_EQ(R.first->second, 2); EXPECT_FALSE(R.second); R = MV.insert(std::make_pair(4, 5)); ASSERT_NE(R.first, MV.end()); EXPECT_EQ(R.first->first, 4); EXPECT_EQ(R.first->second, 5); EXPECT_TRUE(R.second); EXPECT_EQ(MV.size(), 2u); EXPECT_EQ(MV[1], 2); EXPECT_EQ(MV[4], 5); }
TEST(MapVectorTest, erase) { MapVector<int, int> MV; MV.insert(std::make_pair(1, 2)); MV.insert(std::make_pair(3, 4)); MV.insert(std::make_pair(5, 6)); ASSERT_EQ(MV.size(), 3u); MV.erase(MV.find(1)); ASSERT_EQ(MV.size(), 2u); ASSERT_EQ(MV.find(1), MV.end()); ASSERT_EQ(MV[3], 4); ASSERT_EQ(MV[5], 6); }
static void addAllTypes(MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, MCSection *OutputTypes, const std::vector<StringRef> &TypesSections, const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { for (StringRef Types : TypesSections) { Out.SwitchSection(OutputTypes); uint32_t Offset = 0; DataExtractor Data(Types, true, 0); while (Data.isValidOffset(Offset)) { UnitIndexEntry Entry = CUEntry; // Zero out the debug_info contribution Entry.Contributions[0] = {}; auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; C.Offset = TypesOffset; auto PrevOffset = Offset; // Length of the unit, including the 4 byte length field. C.Length = Data.getU32(&Offset) + 4; Data.getU16(&Offset); // Version Data.getU32(&Offset); // Abbrev offset Data.getU8(&Offset); // Address size auto Signature = Data.getU64(&Offset); Offset = PrevOffset + C.Length; auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); if (!P.second) continue; Out.EmitBytes(Types.substr(PrevOffset, C.Length)); TypesOffset += C.Length; } } }
static void addAllTypesFromDWP( MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries, const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) { Out.SwitchSection(OutputTypes); for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { auto *I = E.getOffsets(); if (!I) continue; auto P = TypeIndexEntries.insert(std::make_pair(E.getSignature(), TUEntry)); if (!P.second) continue; auto &Entry = P.first->second; // Zero out the debug_info contribution Entry.Contributions[0] = {}; for (auto Kind : TUIndex.getColumnKinds()) { auto &C = Entry.Contributions[Kind - DW_SECT_INFO]; C.Offset += I->Offset; C.Length = I->Length; ++I; } auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; Out.EmitBytes(Types.substr( C.Offset - TUEntry.Contributions[DW_SECT_TYPES - DW_SECT_INFO].Offset, C.Length)); C.Offset = TypesOffset; TypesOffset += C.Length; } }
TEST(MapVectorTest, remove_if) { MapVector<int, int> MV; MV.insert(std::make_pair(1, 11)); MV.insert(std::make_pair(2, 12)); MV.insert(std::make_pair(3, 13)); MV.insert(std::make_pair(4, 14)); MV.insert(std::make_pair(5, 15)); MV.insert(std::make_pair(6, 16)); ASSERT_EQ(MV.size(), 6u); MV.remove_if([](const std::pair<int, int> &Val) { return Val.second % 2; }); ASSERT_EQ(MV.size(), 3u); ASSERT_EQ(MV.find(1), MV.end()); ASSERT_EQ(MV.find(3), MV.end()); ASSERT_EQ(MV.find(5), MV.end()); ASSERT_EQ(MV[2], 12); ASSERT_EQ(MV[4], 14); ASSERT_EQ(MV[6], 16); }
static std::error_code write(MCStreamer &Out, ArrayRef<std::string> Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = { {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}}, {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, {"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}}, {"debug_tu_index", {TUIndexSection, static_cast<DWARFSectionKind>(0)}}}; MapVector<uint64_t, UnitIndexEntry> IndexEntries; MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries; StringMap<uint32_t> Strings; uint32_t StringOffset = 0; uint32_t ContributionOffsets[8] = {}; for (const auto &Input : Inputs) { auto ErrOrObj = object::ObjectFile::createObjectFile(Input); if (!ErrOrObj) return errorToErrorCode(ErrOrObj.takeError()); UnitIndexEntry CurEntry = {}; StringRef CurStrSection; StringRef CurStrOffsetSection; std::vector<StringRef> CurTypesSection; StringRef InfoSection; StringRef AbbrevSection; StringRef CurCUIndexSection; StringRef CurTUIndexSection; SmallVector<SmallString<32>, 4> UncompressedSections; for (const auto &Section : ErrOrObj->getBinary()->sections()) { if (Section.isBSS()) continue; if (Section.isVirtual()) continue; StringRef Name; if (std::error_code Err = Section.getName(Name)) return Err; Name = Name.substr(Name.find_first_not_of("._")); StringRef Contents; if (auto Err = Section.getContents(Contents)) return Err; if (Name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(Contents, OriginalSize)) return make_error_code(std::errc::invalid_argument); UncompressedSections.resize(UncompressedSections.size() + 1); if (zlib::uncompress(Contents, UncompressedSections.back(), OriginalSize) != zlib::StatusOK) { UncompressedSections.pop_back(); continue; } Name = Name.substr(1); Contents = UncompressedSections.back(); } auto SectionPair = KnownSections.find(Name); if (SectionPair == KnownSections.end()) continue; if (DWARFSectionKind Kind = SectionPair->second.second) { auto Index = Kind - DW_SECT_INFO; if (Kind != DW_SECT_TYPES) { CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; ContributionOffsets[Index] += (CurEntry.Contributions[Index].Length = Contents.size()); } switch (Kind) { case DW_SECT_INFO: InfoSection = Contents; break; case DW_SECT_ABBREV: AbbrevSection = Contents; break; default: break; } } MCSection *OutSection = SectionPair->second.first; if (OutSection == StrOffsetSection) CurStrOffsetSection = Contents; else if (OutSection == StrSection) CurStrSection = Contents; else if (OutSection == TypesSection) CurTypesSection.push_back(Contents); else if (OutSection == CUIndexSection) CurCUIndexSection = Contents; else if (OutSection == TUIndexSection) CurTUIndexSection = Contents; else { Out.SwitchSection(OutSection); Out.EmitBytes(Contents); } } if (InfoSection.empty()) continue; if (!CurCUIndexSection.empty()) { DWARFUnitIndex CUIndex(DW_SECT_INFO); DataExtractor CUIndexData(CurCUIndexSection, ErrOrObj->getBinary()->isLittleEndian(), 0); if (!CUIndex.parse(CUIndexData)) return make_error_code(std::errc::invalid_argument); for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { auto *I = E.getOffsets(); if (!I) continue; auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); CompileUnitIdentifiers ID = getCUIdentifiers( getSubsection(AbbrevSection, E, DW_SECT_ABBREV), getSubsection(InfoSection, E, DW_SECT_INFO), getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), CurStrSection); if (!P.second) { printDuplicateError(*P.first, ID, Input); return make_error_code(std::errc::invalid_argument); } auto &NewEntry = P.first->second; NewEntry.Name = ID.Name; NewEntry.DWOName = ID.DWOName; NewEntry.DWPName = Input; for (auto Kind : CUIndex.getColumnKinds()) { auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; C.Offset += I->Offset; C.Length = I->Length; ++I; } } if (!CurTypesSection.empty()) { assert(CurTypesSection.size() == 1); if (CurTUIndexSection.empty()) return make_error_code(std::errc::invalid_argument); DWARFUnitIndex TUIndex(DW_SECT_TYPES); DataExtractor TUIndexData(CurTUIndexSection, ErrOrObj->getBinary()->isLittleEndian(), 0); if (!TUIndex.parse(TUIndexData)) return make_error_code(std::errc::invalid_argument); addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(), CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); } } else { CompileUnitIdentifiers ID = getCUIdentifiers( AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); if (!P.second) { printDuplicateError(*P.first, ID, ""); return make_error_code(std::errc::invalid_argument); } P.first->second.Name = ID.Name; P.first->second.DWOName = ID.DWOName; addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); } if (auto Err = writeStringsAndOffsets(Out, Strings, StringOffset, StrSection, StrOffsetSection, CurStrSection, CurStrOffsetSection)) return Err; } // Lie about there being no info contributions so the TU index only includes // the type unit contribution ContributionOffsets[0] = 0; writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, TypeIndexEntries); // Lie about the type contribution ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0; // Unlie about the info contribution ContributionOffsets[0] = 1; writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, IndexEntries); return std::error_code(); }
static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, const HeaderSearchOptions &HeaderOpts, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, const LangOptions &LOpts, std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile, BackendAction Action) { StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); setCommandLineOpts(CGOpts); // We can simply import the values mentioned in the combined index, since // we should only invoke this using the individual indexes written out // via a WriteIndexesThinBackend. FunctionImporter::ImportMapTy ImportList; for (auto &GlobalList : *CombinedIndex) { // Ignore entries for undefined references. if (GlobalList.second.SummaryList.empty()) continue; auto GUID = GlobalList.first; assert(GlobalList.second.SummaryList.size() == 1 && "Expected individual combined index to have one summary per GUID"); auto &Summary = GlobalList.second.SummaryList[0]; // Skip the summaries for the importing module. These are included to // e.g. record required linkage changes. if (Summary->modulePath() == M->getModuleIdentifier()) continue; // Doesn't matter what value we plug in to the map, just needs an entry // to provoke importing by thinBackend. ImportList[Summary->modulePath()][GUID] = 1; } std::vector<std::unique_ptr<llvm::MemoryBuffer>> OwnedImports; MapVector<llvm::StringRef, llvm::BitcodeModule> ModuleMap; for (auto &I : ImportList) { ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr = llvm::MemoryBuffer::getFile(I.first()); if (!MBOrErr) { errs() << "Error loading imported file '" << I.first() << "': " << MBOrErr.getError().message() << "\n"; return; } Expected<BitcodeModule> BMOrErr = FindThinLTOModule(**MBOrErr); if (!BMOrErr) { handleAllErrors(BMOrErr.takeError(), [&](ErrorInfoBase &EIB) { errs() << "Error loading imported file '" << I.first() << "': " << EIB.message() << '\n'; }); return; } ModuleMap.insert({I.first(), *BMOrErr}); OwnedImports.push_back(std::move(*MBOrErr)); } auto AddStream = [&](size_t Task) { return llvm::make_unique<lto::NativeObjectStream>(std::move(OS)); }; lto::Config Conf; Conf.CPU = TOpts.CPU; Conf.CodeModel = getCodeModel(CGOpts); Conf.MAttrs = TOpts.Features; Conf.RelocModel = getRelocModel(CGOpts); Conf.CGOptLevel = getCGOptLevel(CGOpts); initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts); Conf.SampleProfile = std::move(SampleProfile); Conf.UseNewPM = CGOpts.ExperimentalNewPassManager; switch (Action) { case Backend_EmitNothing: Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) { return false; }; break; case Backend_EmitLL: Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) { M->print(*OS, nullptr, CGOpts.EmitLLVMUseLists); return false; }; break; case Backend_EmitBC: Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) { WriteBitcodeToFile(M, *OS, CGOpts.EmitLLVMUseLists); return false; }; break; default: Conf.CGFileType = getCodeGenFileType(Action); break; } if (Error E = thinBackend( Conf, 0, AddStream, *M, *CombinedIndex, ImportList, ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { errs() << "Error running ThinLTO backend: " << EIB.message() << '\n'; }); } }
static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile) { StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); // We can simply import the values mentioned in the combined index, since // we should only invoke this using the individual indexes written out // via a WriteIndexesThinBackend. FunctionImporter::ImportMapTy ImportList; for (auto &GlobalList : *CombinedIndex) { auto GUID = GlobalList.first; assert(GlobalList.second.size() == 1 && "Expected individual combined index to have one summary per GUID"); auto &Summary = GlobalList.second[0]; // Skip the summaries for the importing module. These are included to // e.g. record required linkage changes. if (Summary->modulePath() == M->getModuleIdentifier()) continue; // Doesn't matter what value we plug in to the map, just needs an entry // to provoke importing by thinBackend. ImportList[Summary->modulePath()][GUID] = 1; } std::vector<std::unique_ptr<llvm::MemoryBuffer>> OwnedImports; MapVector<llvm::StringRef, llvm::BitcodeModule> ModuleMap; for (auto &I : ImportList) { ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr = llvm::MemoryBuffer::getFile(I.first()); if (!MBOrErr) { errs() << "Error loading imported file '" << I.first() << "': " << MBOrErr.getError().message() << "\n"; return; } Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(**MBOrErr); if (!BMsOrErr) { handleAllErrors(BMsOrErr.takeError(), [&](ErrorInfoBase &EIB) { errs() << "Error loading imported file '" << I.first() << "': " << EIB.message() << '\n'; }); return; } // The bitcode file may contain multiple modules, we want the one with a // summary. bool FoundModule = false; for (BitcodeModule &BM : *BMsOrErr) { Expected<bool> HasSummary = BM.hasSummary(); if (HasSummary && *HasSummary) { ModuleMap.insert({I.first(), BM}); FoundModule = true; break; } } if (!FoundModule) { errs() << "Error loading imported file '" << I.first() << "': Could not find module summary\n"; return; } OwnedImports.push_back(std::move(*MBOrErr)); } auto AddStream = [&](size_t Task) { return llvm::make_unique<lto::NativeObjectStream>(std::move(OS)); }; lto::Config Conf; Conf.SampleProfile = SampleProfile; if (Error E = thinBackend( Conf, 0, AddStream, *M, *CombinedIndex, ImportList, ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { errs() << "Error running ThinLTO backend: " << EIB.message() << '\n'; }); } }