@@ -1746,6 +1746,7 @@ void CStringSection::finalizeContents() {
17461746void DeduplicatedCStringSection::finalizeContents () {
17471747 // Find the largest alignment required for each string.
17481748 DenseMap<CachedHashStringRef, Align> strToAlignment;
1749+ // Used for tail merging only
17491750 std::vector<CachedHashStringRef> deduplicatedStrs;
17501751 for (const CStringInputSection *isec : inputs) {
17511752 for (const auto &[i, piece] : llvm::enumerate (isec->pieces )) {
@@ -1755,7 +1756,7 @@ void DeduplicatedCStringSection::finalizeContents() {
17551756 assert (isec->align != 0 );
17561757 auto align = getStringPieceAlignment (isec, piece);
17571758 auto [it, wasInserted] = strToAlignment.try_emplace (s, align);
1758- if (wasInserted)
1759+ if (config-> tailMergeStrings && wasInserted)
17591760 deduplicatedStrs.push_back (s);
17601761 if (!wasInserted && it->second < align)
17611762 it->second = align;
@@ -1784,17 +1785,17 @@ void DeduplicatedCStringSection::finalizeContents() {
17841785 mergeCandidate = s;
17851786 continue ;
17861787 }
1787- uint64_t tailOffset = mergeCandidate->size () - s.size ();
1788+ uint64_t tailMergeOffset = mergeCandidate->size () - s.size ();
17881789 // TODO: If the tail offset is incompatible with this string's alignment, we
17891790 // might be able to find another superstring with a compatible tail offset.
17901791 // The difficulty is how to do this efficiently
17911792 const auto &align = strToAlignment.at (s);
1792- if (!isAligned (align, tailOffset ))
1793+ if (!isAligned (align, tailMergeOffset ))
17931794 continue ;
17941795 auto &mergeCandidateAlign = strToAlignment[*mergeCandidate];
17951796 if (align > mergeCandidateAlign)
17961797 mergeCandidateAlign = align;
1797- tailMergeMap.try_emplace (s, *mergeCandidate, tailOffset );
1798+ tailMergeMap.try_emplace (s, *mergeCandidate, tailMergeOffset );
17981799 }
17991800
18001801 // Sort the strings for performance and compression size win, and then
@@ -1803,38 +1804,34 @@ void DeduplicatedCStringSection::finalizeContents() {
18031804 for (auto &[isec, i] : priorityBuilder.buildCStringPriorities (inputs)) {
18041805 auto &piece = isec->pieces [i];
18051806 auto s = isec->getCachedHashStringRef (i);
1806- // Skip tail merged strings until their superstring offsets are resolved
1807- if (tailMergeMap.count (s))
1808- continue ;
1807+ // Any string can be tail merged with itself with an offset of zero
1808+ uint64_t tailMergeOffset = 0 ;
1809+ auto mergeIt =
1810+ config->tailMergeStrings ? tailMergeMap.find (s) : tailMergeMap.end ();
1811+ if (mergeIt != tailMergeMap.end ()) {
1812+ auto &[superString, offset] = mergeIt->second ;
1813+ // s can be tail merged with superString. Do not layout s. Instead layout
1814+ // superString if we haven't already
1815+ assert (superString.val ().ends_with (s.val ()));
1816+ s = superString;
1817+ tailMergeOffset = offset;
1818+ }
18091819 auto [it, wasInserted] = stringOffsetMap.try_emplace (s, /* placeholder*/ 0 );
18101820 if (wasInserted) {
18111821 // Avoid computing the offset until we are sure we will need to
18121822 uint64_t offset = alignTo (size, strToAlignment.at (s));
18131823 it->second = offset;
18141824 size = offset + s.size () + 1 ; // account for null terminator
18151825 }
1816- // If the string was already in stringOffsetMap, it is a duplicate and we
1817- // only need to assign the offset.
1818- piece.outSecOff = it->second ;
1819- }
1820- for (CStringInputSection *isec : inputs) {
1821- for (const auto &[i, piece] : llvm::enumerate (isec->pieces )) {
1822- if (!piece.live )
1823- continue ;
1824- auto s = isec->getCachedHashStringRef (i);
1825- auto it = tailMergeMap.find (s);
1826- if (it == tailMergeMap.end ())
1827- continue ;
1828- const auto &[superString, tailOffset] = it->second ;
1829- assert (superString.val ().ends_with (s.val ()));
1830- assert (!tailMergeMap.count (superString));
1831- auto &outSecOff = stringOffsetMap[s];
1832- outSecOff = stringOffsetMap.at (superString) + tailOffset;
1833- piece.outSecOff = outSecOff;
1834- assert (isAligned (strToAlignment.at (s), piece.outSecOff ));
1826+ piece.outSecOff = it->second + tailMergeOffset;
1827+ if (mergeIt != tailMergeMap.end ()) {
1828+ auto &tailMergedString = mergeIt->first ;
1829+ stringOffsetMap[tailMergedString] = piece.outSecOff ;
1830+ assert (isAligned (strToAlignment.at (tailMergedString), piece.outSecOff ));
18351831 }
1836- isec->isFinal = true ;
18371832 }
1833+ for (CStringInputSection *isec : inputs)
1834+ isec->isFinal = true ;
18381835}
18391836
18401837void DeduplicatedCStringSection::writeTo (uint8_t *buf) const {
0 commit comments