@@ -1746,6 +1746,7 @@ void CStringSection::finalizeContents() {
1746
1746
void DeduplicatedCStringSection::finalizeContents () {
1747
1747
// Find the largest alignment required for each string.
1748
1748
DenseMap<CachedHashStringRef, Align> strToAlignment;
1749
+ // Used for tail merging only
1749
1750
std::vector<CachedHashStringRef> deduplicatedStrs;
1750
1751
for (const CStringInputSection *isec : inputs) {
1751
1752
for (const auto &[i, piece] : llvm::enumerate (isec->pieces )) {
@@ -1755,7 +1756,7 @@ void DeduplicatedCStringSection::finalizeContents() {
1755
1756
assert (isec->align != 0 );
1756
1757
auto align = getStringPieceAlignment (isec, piece);
1757
1758
auto [it, wasInserted] = strToAlignment.try_emplace (s, align);
1758
- if (wasInserted)
1759
+ if (config-> tailMergeStrings && wasInserted)
1759
1760
deduplicatedStrs.push_back (s);
1760
1761
if (!wasInserted && it->second < align)
1761
1762
it->second = align;
@@ -1784,17 +1785,17 @@ void DeduplicatedCStringSection::finalizeContents() {
1784
1785
mergeCandidate = s;
1785
1786
continue ;
1786
1787
}
1787
- uint64_t tailOffset = mergeCandidate->size () - s.size ();
1788
+ uint64_t tailMergeOffset = mergeCandidate->size () - s.size ();
1788
1789
// TODO: If the tail offset is incompatible with this string's alignment, we
1789
1790
// might be able to find another superstring with a compatible tail offset.
1790
1791
// The difficulty is how to do this efficiently
1791
1792
const auto &align = strToAlignment.at (s);
1792
- if (!isAligned (align, tailOffset ))
1793
+ if (!isAligned (align, tailMergeOffset ))
1793
1794
continue ;
1794
1795
auto &mergeCandidateAlign = strToAlignment[*mergeCandidate];
1795
1796
if (align > mergeCandidateAlign)
1796
1797
mergeCandidateAlign = align;
1797
- tailMergeMap.try_emplace (s, *mergeCandidate, tailOffset );
1798
+ tailMergeMap.try_emplace (s, *mergeCandidate, tailMergeOffset );
1798
1799
}
1799
1800
1800
1801
// Sort the strings for performance and compression size win, and then
@@ -1803,38 +1804,34 @@ void DeduplicatedCStringSection::finalizeContents() {
1803
1804
for (auto &[isec, i] : priorityBuilder.buildCStringPriorities (inputs)) {
1804
1805
auto &piece = isec->pieces [i];
1805
1806
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
+ }
1809
1819
auto [it, wasInserted] = stringOffsetMap.try_emplace (s, /* placeholder*/ 0 );
1810
1820
if (wasInserted) {
1811
1821
// Avoid computing the offset until we are sure we will need to
1812
1822
uint64_t offset = alignTo (size, strToAlignment.at (s));
1813
1823
it->second = offset;
1814
1824
size = offset + s.size () + 1 ; // account for null terminator
1815
1825
}
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 ));
1835
1831
}
1836
- isec->isFinal = true ;
1837
1832
}
1833
+ for (CStringInputSection *isec : inputs)
1834
+ isec->isFinal = true ;
1838
1835
}
1839
1836
1840
1837
void DeduplicatedCStringSection::writeTo (uint8_t *buf) const {
0 commit comments