Skip to content

Commit 171f7d5

Browse files
committed
[Compression] Increase the number of chars used on non APInt words.
This commit accelerates the performance of DecodeStringFromNumber by increasing the number of characters that fit into a 64-bit word from 8 (conservative estimate that we have 8bit ascii chars) to 10 (6-bit encoding). We now compute the number of characters that fit into a 64 bit word based on the length of the character set at compile time.
1 parent 3aaac0f commit 171f7d5

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

lib/ABI/Compression.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,31 @@ std::string swift::Compress::EncodeCBCString(StringRef In) {
147147
/// insert them into the string builder \p SB.
148148
static void DecodeFixedWidth(APInt &Num, std::string &SB) {
149149
uint64_t CL = Huffman::CharsetLength;
150+
151+
// NL is the number of characters that we can hold in a 64bit number.
152+
// Each letter takes Log2(CL) bits. Doing this computation in floating-
153+
// point arithmetic could give a slightly better (more optimistic) result,
154+
// but the computation may not be constant at compile time.
155+
uint64_t NumLetters = 64 / Log2_64_Ceil(CL);
156+
150157
assert(Num.getBitWidth() > 8 &&
151158
"Not enough bits for arithmetic on this alphabet");
152159

153160
// Try to decode eight numbers at once. It is much faster to work with
154161
// local 64bit numbers than working with APInt. In this loop we try to
155-
// extract 8 characters at one and process them using a local 64bit number.
156-
// In this code we assume a worse case scenario where our alphabet is a full
157-
// 8-bit ascii. It is possible to improve this code by packing one or two
158-
// more characters into the 64bit local variable.
159-
uint64_t CL8 = CL * CL * CL * CL * CL * CL * CL * CL;
160-
while (Num.ugt(CL8)) {
162+
// extract NL characters at once and process them using a local 64-bit
163+
// number.
164+
165+
// Calculate CharsetLength**NumLetters (CL to the power of NL), which is the
166+
// highest numeric value that can hold NumLetters characters in a 64bit
167+
// number. Notice: this loop is optimized away and CLX is computed to a
168+
// constant integer at compile time.
169+
uint64_t CLX = 1;
170+
for (unsigned i = 0; i < NumLetters; i++) { CLX *= CL; }
171+
172+
while (Num.ugt(CLX)) {
161173
unsigned BW = Num.getBitWidth();
162-
APInt C = APInt(BW, CL8);
174+
APInt C = APInt(BW, CLX);
163175
APInt Quotient(1, 0), Remainder(1, 0);
164176
APInt::udivrem(Num, C, Quotient, Remainder);
165177

@@ -170,7 +182,7 @@ static void DecodeFixedWidth(APInt &Num, std::string &SB) {
170182
// need to be able to perform the "mod charset_length" operation.
171183
Num = Quotient.zextOrTrunc(std::max(Quotient.getActiveBits(), 64u));
172184
uint64_t Tail = Remainder.getZExtValue();
173-
for (int i=0; i < 8; i++) {
185+
for (unsigned i = 0; i < NumLetters; i++) {
174186
SB += Huffman::Charset[Tail % CL];
175187
Tail = Tail / CL;
176188
}

0 commit comments

Comments
 (0)