xref: /aosp_15_r20/external/llvm/lib/MC/StringTableBuilder.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- StringTableBuilder.cpp - String table building utility ------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker 
10*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/StringTableBuilder.h"
11*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/STLExtras.h"
12*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/COFF.h"
13*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Endian.h"
14*9880d681SAndroid Build Coastguard Worker 
15*9880d681SAndroid Build Coastguard Worker #include <vector>
16*9880d681SAndroid Build Coastguard Worker 
17*9880d681SAndroid Build Coastguard Worker using namespace llvm;
18*9880d681SAndroid Build Coastguard Worker 
StringTableBuilder(Kind K,unsigned Alignment)19*9880d681SAndroid Build Coastguard Worker StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment)
20*9880d681SAndroid Build Coastguard Worker     : K(K), Alignment(Alignment) {
21*9880d681SAndroid Build Coastguard Worker   // Account for leading bytes in table so that offsets returned from add are
22*9880d681SAndroid Build Coastguard Worker   // correct.
23*9880d681SAndroid Build Coastguard Worker   switch (K) {
24*9880d681SAndroid Build Coastguard Worker   case RAW:
25*9880d681SAndroid Build Coastguard Worker     Size = 0;
26*9880d681SAndroid Build Coastguard Worker     break;
27*9880d681SAndroid Build Coastguard Worker   case MachO:
28*9880d681SAndroid Build Coastguard Worker   case ELF:
29*9880d681SAndroid Build Coastguard Worker     Size = 1;
30*9880d681SAndroid Build Coastguard Worker     break;
31*9880d681SAndroid Build Coastguard Worker   case WinCOFF:
32*9880d681SAndroid Build Coastguard Worker     Size = 4;
33*9880d681SAndroid Build Coastguard Worker     break;
34*9880d681SAndroid Build Coastguard Worker   }
35*9880d681SAndroid Build Coastguard Worker }
36*9880d681SAndroid Build Coastguard Worker 
37*9880d681SAndroid Build Coastguard Worker typedef std::pair<CachedHash<StringRef>, size_t> StringPair;
38*9880d681SAndroid Build Coastguard Worker 
39*9880d681SAndroid Build Coastguard Worker // Returns the character at Pos from end of a string.
charTailAt(StringPair * P,size_t Pos)40*9880d681SAndroid Build Coastguard Worker static int charTailAt(StringPair *P, size_t Pos) {
41*9880d681SAndroid Build Coastguard Worker   StringRef S = P->first.Val;
42*9880d681SAndroid Build Coastguard Worker   if (Pos >= S.size())
43*9880d681SAndroid Build Coastguard Worker     return -1;
44*9880d681SAndroid Build Coastguard Worker   return (unsigned char)S[S.size() - Pos - 1];
45*9880d681SAndroid Build Coastguard Worker }
46*9880d681SAndroid Build Coastguard Worker 
47*9880d681SAndroid Build Coastguard Worker // Three-way radix quicksort. This is much faster than std::sort with strcmp
48*9880d681SAndroid Build Coastguard Worker // because it does not compare characters that we already know the same.
multikey_qsort(StringPair ** Begin,StringPair ** End,int Pos)49*9880d681SAndroid Build Coastguard Worker static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) {
50*9880d681SAndroid Build Coastguard Worker tailcall:
51*9880d681SAndroid Build Coastguard Worker   if (End - Begin <= 1)
52*9880d681SAndroid Build Coastguard Worker     return;
53*9880d681SAndroid Build Coastguard Worker 
54*9880d681SAndroid Build Coastguard Worker   // Partition items. Items in [Begin, P) are greater than the pivot,
55*9880d681SAndroid Build Coastguard Worker   // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot.
56*9880d681SAndroid Build Coastguard Worker   int Pivot = charTailAt(*Begin, Pos);
57*9880d681SAndroid Build Coastguard Worker   StringPair **P = Begin;
58*9880d681SAndroid Build Coastguard Worker   StringPair **Q = End;
59*9880d681SAndroid Build Coastguard Worker   for (StringPair **R = Begin + 1; R < Q;) {
60*9880d681SAndroid Build Coastguard Worker     int C = charTailAt(*R, Pos);
61*9880d681SAndroid Build Coastguard Worker     if (C > Pivot)
62*9880d681SAndroid Build Coastguard Worker       std::swap(*P++, *R++);
63*9880d681SAndroid Build Coastguard Worker     else if (C < Pivot)
64*9880d681SAndroid Build Coastguard Worker       std::swap(*--Q, *R);
65*9880d681SAndroid Build Coastguard Worker     else
66*9880d681SAndroid Build Coastguard Worker       R++;
67*9880d681SAndroid Build Coastguard Worker   }
68*9880d681SAndroid Build Coastguard Worker 
69*9880d681SAndroid Build Coastguard Worker   multikey_qsort(Begin, P, Pos);
70*9880d681SAndroid Build Coastguard Worker   multikey_qsort(Q, End, Pos);
71*9880d681SAndroid Build Coastguard Worker   if (Pivot != -1) {
72*9880d681SAndroid Build Coastguard Worker     // qsort(P, Q, Pos + 1), but with tail call optimization.
73*9880d681SAndroid Build Coastguard Worker     Begin = P;
74*9880d681SAndroid Build Coastguard Worker     End = Q;
75*9880d681SAndroid Build Coastguard Worker     ++Pos;
76*9880d681SAndroid Build Coastguard Worker     goto tailcall;
77*9880d681SAndroid Build Coastguard Worker   }
78*9880d681SAndroid Build Coastguard Worker }
79*9880d681SAndroid Build Coastguard Worker 
finalize()80*9880d681SAndroid Build Coastguard Worker void StringTableBuilder::finalize() {
81*9880d681SAndroid Build Coastguard Worker   finalizeStringTable(/*Optimize=*/true);
82*9880d681SAndroid Build Coastguard Worker }
83*9880d681SAndroid Build Coastguard Worker 
finalizeInOrder()84*9880d681SAndroid Build Coastguard Worker void StringTableBuilder::finalizeInOrder() {
85*9880d681SAndroid Build Coastguard Worker   finalizeStringTable(/*Optimize=*/false);
86*9880d681SAndroid Build Coastguard Worker }
87*9880d681SAndroid Build Coastguard Worker 
finalizeStringTable(bool Optimize)88*9880d681SAndroid Build Coastguard Worker void StringTableBuilder::finalizeStringTable(bool Optimize) {
89*9880d681SAndroid Build Coastguard Worker   typedef std::pair<CachedHash<StringRef>, size_t> StringOffsetPair;
90*9880d681SAndroid Build Coastguard Worker   std::vector<StringOffsetPair *> Strings;
91*9880d681SAndroid Build Coastguard Worker   Strings.reserve(StringIndexMap.size());
92*9880d681SAndroid Build Coastguard Worker   for (StringOffsetPair &P : StringIndexMap)
93*9880d681SAndroid Build Coastguard Worker     Strings.push_back(&P);
94*9880d681SAndroid Build Coastguard Worker 
95*9880d681SAndroid Build Coastguard Worker   if (!Strings.empty()) {
96*9880d681SAndroid Build Coastguard Worker     // If we're optimizing, sort by name. If not, sort by previously assigned
97*9880d681SAndroid Build Coastguard Worker     // offset.
98*9880d681SAndroid Build Coastguard Worker     if (Optimize) {
99*9880d681SAndroid Build Coastguard Worker       multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
100*9880d681SAndroid Build Coastguard Worker     } else {
101*9880d681SAndroid Build Coastguard Worker       std::sort(Strings.begin(), Strings.end(),
102*9880d681SAndroid Build Coastguard Worker                 [](const StringOffsetPair *LHS, const StringOffsetPair *RHS) {
103*9880d681SAndroid Build Coastguard Worker                   return LHS->second < RHS->second;
104*9880d681SAndroid Build Coastguard Worker                 });
105*9880d681SAndroid Build Coastguard Worker     }
106*9880d681SAndroid Build Coastguard Worker   }
107*9880d681SAndroid Build Coastguard Worker 
108*9880d681SAndroid Build Coastguard Worker   switch (K) {
109*9880d681SAndroid Build Coastguard Worker   case RAW:
110*9880d681SAndroid Build Coastguard Worker     break;
111*9880d681SAndroid Build Coastguard Worker   case ELF:
112*9880d681SAndroid Build Coastguard Worker   case MachO:
113*9880d681SAndroid Build Coastguard Worker     // Start the table with a NUL byte.
114*9880d681SAndroid Build Coastguard Worker     StringTable += '\x00';
115*9880d681SAndroid Build Coastguard Worker     break;
116*9880d681SAndroid Build Coastguard Worker   case WinCOFF:
117*9880d681SAndroid Build Coastguard Worker     // Make room to write the table size later.
118*9880d681SAndroid Build Coastguard Worker     StringTable.append(4, '\x00');
119*9880d681SAndroid Build Coastguard Worker     break;
120*9880d681SAndroid Build Coastguard Worker   }
121*9880d681SAndroid Build Coastguard Worker 
122*9880d681SAndroid Build Coastguard Worker   StringRef Previous;
123*9880d681SAndroid Build Coastguard Worker   for (StringOffsetPair *P : Strings) {
124*9880d681SAndroid Build Coastguard Worker     StringRef S = P->first.Val;
125*9880d681SAndroid Build Coastguard Worker     if (K == WinCOFF)
126*9880d681SAndroid Build Coastguard Worker       assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
127*9880d681SAndroid Build Coastguard Worker 
128*9880d681SAndroid Build Coastguard Worker     if (Optimize && Previous.endswith(S)) {
129*9880d681SAndroid Build Coastguard Worker       size_t Pos = StringTable.size() - S.size() - (K != RAW);
130*9880d681SAndroid Build Coastguard Worker       if (!(Pos & (Alignment - 1))) {
131*9880d681SAndroid Build Coastguard Worker         P->second = Pos;
132*9880d681SAndroid Build Coastguard Worker         continue;
133*9880d681SAndroid Build Coastguard Worker       }
134*9880d681SAndroid Build Coastguard Worker     }
135*9880d681SAndroid Build Coastguard Worker 
136*9880d681SAndroid Build Coastguard Worker     if (Optimize) {
137*9880d681SAndroid Build Coastguard Worker       size_t Start = alignTo(StringTable.size(), Alignment);
138*9880d681SAndroid Build Coastguard Worker       P->second = Start;
139*9880d681SAndroid Build Coastguard Worker       StringTable.append(Start - StringTable.size(), '\0');
140*9880d681SAndroid Build Coastguard Worker     } else {
141*9880d681SAndroid Build Coastguard Worker       assert(P->second == StringTable.size() &&
142*9880d681SAndroid Build Coastguard Worker              "different strtab offset after finalization");
143*9880d681SAndroid Build Coastguard Worker     }
144*9880d681SAndroid Build Coastguard Worker 
145*9880d681SAndroid Build Coastguard Worker     StringTable += S;
146*9880d681SAndroid Build Coastguard Worker     if (K != RAW)
147*9880d681SAndroid Build Coastguard Worker       StringTable += '\x00';
148*9880d681SAndroid Build Coastguard Worker     Previous = S;
149*9880d681SAndroid Build Coastguard Worker   }
150*9880d681SAndroid Build Coastguard Worker 
151*9880d681SAndroid Build Coastguard Worker   switch (K) {
152*9880d681SAndroid Build Coastguard Worker   case RAW:
153*9880d681SAndroid Build Coastguard Worker   case ELF:
154*9880d681SAndroid Build Coastguard Worker     break;
155*9880d681SAndroid Build Coastguard Worker   case MachO:
156*9880d681SAndroid Build Coastguard Worker     // Pad to multiple of 4.
157*9880d681SAndroid Build Coastguard Worker     while (StringTable.size() % 4)
158*9880d681SAndroid Build Coastguard Worker       StringTable += '\x00';
159*9880d681SAndroid Build Coastguard Worker     break;
160*9880d681SAndroid Build Coastguard Worker   case WinCOFF:
161*9880d681SAndroid Build Coastguard Worker     // Write the table size in the first word.
162*9880d681SAndroid Build Coastguard Worker     assert(StringTable.size() <= std::numeric_limits<uint32_t>::max());
163*9880d681SAndroid Build Coastguard Worker     uint32_t Size = static_cast<uint32_t>(StringTable.size());
164*9880d681SAndroid Build Coastguard Worker     support::endian::write<uint32_t, support::little, support::unaligned>(
165*9880d681SAndroid Build Coastguard Worker         StringTable.data(), Size);
166*9880d681SAndroid Build Coastguard Worker     break;
167*9880d681SAndroid Build Coastguard Worker   }
168*9880d681SAndroid Build Coastguard Worker 
169*9880d681SAndroid Build Coastguard Worker   Size = StringTable.size();
170*9880d681SAndroid Build Coastguard Worker }
171*9880d681SAndroid Build Coastguard Worker 
clear()172*9880d681SAndroid Build Coastguard Worker void StringTableBuilder::clear() {
173*9880d681SAndroid Build Coastguard Worker   StringTable.clear();
174*9880d681SAndroid Build Coastguard Worker   StringIndexMap.clear();
175*9880d681SAndroid Build Coastguard Worker }
176*9880d681SAndroid Build Coastguard Worker 
getOffset(StringRef S) const177*9880d681SAndroid Build Coastguard Worker size_t StringTableBuilder::getOffset(StringRef S) const {
178*9880d681SAndroid Build Coastguard Worker   assert(isFinalized());
179*9880d681SAndroid Build Coastguard Worker   auto I = StringIndexMap.find(S);
180*9880d681SAndroid Build Coastguard Worker   assert(I != StringIndexMap.end() && "String is not in table!");
181*9880d681SAndroid Build Coastguard Worker   return I->second;
182*9880d681SAndroid Build Coastguard Worker }
183*9880d681SAndroid Build Coastguard Worker 
add(StringRef S)184*9880d681SAndroid Build Coastguard Worker size_t StringTableBuilder::add(StringRef S) {
185*9880d681SAndroid Build Coastguard Worker   assert(!isFinalized());
186*9880d681SAndroid Build Coastguard Worker   size_t Start = alignTo(Size, Alignment);
187*9880d681SAndroid Build Coastguard Worker   auto P = StringIndexMap.insert(std::make_pair(S, Start));
188*9880d681SAndroid Build Coastguard Worker   if (P.second)
189*9880d681SAndroid Build Coastguard Worker     Size = Start + S.size() + (K != RAW);
190*9880d681SAndroid Build Coastguard Worker   return P.first->second;
191*9880d681SAndroid Build Coastguard Worker }
192