std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) { OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator; // Populate the hash table generator. for (const auto &I : FunctionData) Generator.insert(I.getKey(), &I.getValue()); using namespace llvm::support; endian::Writer<little> LE(OS); // Write the header. IndexedInstrProf::Header Header; Header.Magic = IndexedInstrProf::Magic; Header.Version = IndexedInstrProf::Version; Header.MaxFunctionCount = MaxFunctionCount; Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType); Header.HashOffset = 0; int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t); // Only write out all the fields execpt 'HashOffset'. We need // to remember the offset of that field to allow back patching // later. for (int I = 0; I < N - 1; I++) LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]); // Save a space to write the hash table start location. uint64_t HashTableStartLoc = OS.tell(); // Reserve the space for HashOffset field. LE.write<uint64_t>(0); // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS); return std::make_pair(HashTableStartLoc, HashTableStart); }
/// EmitIdentifierTable - Emits two tables to the PTH file. The first is /// a hashtable mapping from identifier strings to persistent IDs. The second /// is a straight table mapping from persistent IDs to string data (the /// keys of the first table). /// std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() { // Build two maps: // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset) // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs // Note that we use 'calloc', so all the bytes are 0. PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey)); // Create the hashtable. OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap; // Generate mapping from persistent IDs -> IdentifierInfo*. for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) { // Decrement by 1 because we are using a vector for the lookup and // 0 is reserved for NULL. assert(I->second > 0); assert(I->second-1 < idcount); unsigned idx = I->second-1; // Store the mapping from persistent ID to IdentifierInfo* IIDMap[idx].II = I->first; // Store the reverse mapping in a hashtable. IIOffMap.insert(&IIDMap[idx], I->second); } // Write out the inverse map first. This causes the PCIDKey entries to // record PTH file offsets for the string data. This is used to write // the second table. Offset StringTableOffset = IIOffMap.Emit(Out); // Now emit the table mapping from persistent IDs to PTH file offsets. Offset IDOff = Out.tell(); Emit32(idcount); // Emit the number of identifiers. for (unsigned i = 0 ; i < idcount; ++i) Emit32(IIDMap[i].FileOffset); // Finally, release the inverse map. free(IIDMap); return std::make_pair(IDOff, StringTableOffset); }
std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) { OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator; // Populate the hash table generator. for (const auto &I : FunctionData) Generator.insert(I.getKey(), &I.getValue()); using namespace llvm::support; endian::Writer<little> LE(OS); // Write the header. LE.write<uint64_t>(IndexedInstrProf::Magic); LE.write<uint64_t>(IndexedInstrProf::Version); LE.write<uint64_t>(MaxFunctionCount); LE.write<uint64_t>(static_cast<uint64_t>(IndexedInstrProf::HashType)); // Save a space to write the hash table start location. uint64_t HashTableStartLoc = OS.tell(); LE.write<uint64_t>(0); // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS); return std::make_pair(HashTableStartLoc, HashTableStart); }
void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { using namespace llvm; // Emit the file header. Stream.Emit((unsigned)'B', 8); Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'G', 8); Stream.Emit((unsigned)'I', 8); // Write the block-info block, which describes the records in this bitcode // file. emitBlockInfoBlock(Stream); Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3); // Write the metadata. SmallVector<uint64_t, 2> Record; Record.push_back(CurrentVersion); Stream.EmitRecord(INDEX_METADATA, Record); // Write the set of known module files. for (ModuleFilesMap::iterator M = ModuleFiles.begin(), MEnd = ModuleFiles.end(); M != MEnd; ++M) { Record.clear(); Record.push_back(M->second.ID); Record.push_back(M->first->getSize()); Record.push_back(M->first->getModificationTime()); // File name StringRef Name(M->first->getName()); Record.push_back(Name.size()); Record.append(Name.begin(), Name.end()); // Dependencies Record.push_back(M->second.Dependencies.size()); Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end()); Stream.EmitRecord(MODULE, Record); } // Write the identifier -> module file mapping. { OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator; IdentifierIndexWriterTrait Trait; // Populate the hash table. for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(), IEnd = InterestingIdentifiers.end(); I != IEnd; ++I) { Generator.insert(I->first(), I->second, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> IdentifierTable; uint32_t BucketOffset; { llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } // Create a blob abbreviation BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the identifier table Record.clear(); Record.push_back(IDENTIFIER_INDEX); Record.push_back(BucketOffset); Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str()); } // FIXME: Selectors. Stream.ExitBlock(); }
void InstrProfWriter::writeImpl(ProfOStream &OS) { using namespace IndexedInstrProf; OnDiskChainedHashTableGenerator<InstrProfRecordWriterTrait> Generator; InstrProfSummaryBuilder ISB(ProfileSummaryBuilder::DefaultCutoffs); InfoObj->SummaryBuilder = &ISB; InstrProfSummaryBuilder CSISB(ProfileSummaryBuilder::DefaultCutoffs); InfoObj->CSSummaryBuilder = &CSISB; // Populate the hash table generator. for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) Generator.insert(I.getKey(), &I.getValue()); // Write the header. IndexedInstrProf::Header Header; Header.Magic = IndexedInstrProf::Magic; Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion; if (ProfileKind == PF_IRLevel) Header.Version |= VARIANT_MASK_IR_PROF; if (ProfileKind == PF_IRLevelWithCS) { Header.Version |= VARIANT_MASK_IR_PROF; Header.Version |= VARIANT_MASK_CSIR_PROF; } Header.Unused = 0; Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType); Header.HashOffset = 0; int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t); // Only write out all the fields except 'HashOffset'. We need // to remember the offset of that field to allow back patching // later. for (int I = 0; I < N - 1; I++) OS.write(reinterpret_cast<uint64_t *>(&Header)[I]); // Save the location of Header.HashOffset field in \c OS. uint64_t HashTableStartFieldOffset = OS.tell(); // Reserve the space for HashOffset field. OS.write(0); // Reserve space to write profile summary data. uint32_t NumEntries = ProfileSummaryBuilder::DefaultCutoffs.size(); uint32_t SummarySize = Summary::getSize(Summary::NumKinds, NumEntries); // Remember the summary offset. uint64_t SummaryOffset = OS.tell(); for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) OS.write(0); uint64_t CSSummaryOffset = 0; uint64_t CSSummarySize = 0; if (ProfileKind == PF_IRLevelWithCS) { CSSummaryOffset = OS.tell(); CSSummarySize = SummarySize / sizeof(uint64_t); for (unsigned I = 0; I < CSSummarySize; I++) OS.write(0); } // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj); // Allocate space for data to be serialized out. std::unique_ptr<IndexedInstrProf::Summary> TheSummary = IndexedInstrProf::allocSummary(SummarySize); // Compute the Summary and copy the data to the data // structure to be serialized out (to disk or buffer). std::unique_ptr<ProfileSummary> PS = ISB.getSummary(); setSummary(TheSummary.get(), *PS); InfoObj->SummaryBuilder = nullptr; // For Context Sensitive summary. std::unique_ptr<IndexedInstrProf::Summary> TheCSSummary = nullptr; if (ProfileKind == PF_IRLevelWithCS) { TheCSSummary = IndexedInstrProf::allocSummary(SummarySize); std::unique_ptr<ProfileSummary> CSPS = CSISB.getSummary(); setSummary(TheCSSummary.get(), *CSPS); } InfoObj->CSSummaryBuilder = nullptr; // Now do the final patch: PatchItem PatchItems[] = { // Patch the Header.HashOffset field. {HashTableStartFieldOffset, &HashTableStart, 1}, // Patch the summary data. {SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()), (int)(SummarySize / sizeof(uint64_t))}, {CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()), (int)CSSummarySize}}; OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems)); }
void InstrProfWriter::writeImpl(ProfOStream &OS) { OnDiskChainedHashTableGenerator<InstrProfRecordWriterTrait> Generator; using namespace IndexedInstrProf; std::vector<uint32_t> Cutoffs(&SummaryCutoffs[0], &SummaryCutoffs[NumSummaryCutoffs]); ProfileSummary PS(Cutoffs); InfoObj->TheProfileSummary = &PS; // Populate the hash table generator. for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) Generator.insert(I.getKey(), &I.getValue()); // Write the header. IndexedInstrProf::Header Header; Header.Magic = IndexedInstrProf::Magic; Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion; Header.Unused = 0; Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType); Header.HashOffset = 0; int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t); // Only write out all the fields except 'HashOffset'. We need // to remember the offset of that field to allow back patching // later. for (int I = 0; I < N - 1; I++) OS.write(reinterpret_cast<uint64_t *>(&Header)[I]); // Save the location of Header.HashOffset field in \c OS. uint64_t HashTableStartFieldOffset = OS.tell(); // Reserve the space for HashOffset field. OS.write(0); // Reserve space to write profile summary data. uint32_t NumEntries = Cutoffs.size(); uint32_t SummarySize = Summary::getSize(Summary::NumKinds, NumEntries); // Remember the summary offset. uint64_t SummaryOffset = OS.tell(); for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) OS.write(0); // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj); // Allocate space for data to be serialized out. std::unique_ptr<IndexedInstrProf::Summary> TheSummary = IndexedInstrProf::allocSummary(SummarySize); // Compute the Summary and copy the data to the data // structure to be serialized out (to disk or buffer). setSummary(TheSummary.get(), PS); InfoObj->TheProfileSummary = 0; // Now do the final patch: PatchItem PatchItems[] = { // Patch the Header.HashOffset field. {HashTableStartFieldOffset, &HashTableStart, 1}, // Patch the summary data. {SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()), (int)(SummarySize / sizeof(uint64_t))}}; OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems)); }