From 590d79530e14e4e9d458aa080dab6a54392e68fc Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:21:26 +0000 Subject: [PATCH] perf(sourcemap): shorten main loop encoding VLQ (#4586) Reduce number of operations in main loop in source map VLQ encoding. #4583 made pushing a byte to output only 2 instructions, so that makes it workable to repeat `push_byte_unchecked` inside and outside the loop. On a local benchmark of just VLQ encoding shows this increases performance by 16% (on top of the 11% from #4583). Probably main gain is it makes a fast path for encoding `0`, which is common. --- crates/oxc_sourcemap/src/encode.rs | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/crates/oxc_sourcemap/src/encode.rs b/crates/oxc_sourcemap/src/encode.rs index a974d1648..90ebfce78 100644 --- a/crates/oxc_sourcemap/src/encode.rs +++ b/crates/oxc_sourcemap/src/encode.rs @@ -217,25 +217,33 @@ static B64_CHARS: Aligned64 = Aligned64([ unsafe fn encode_vlq(out: &mut String, num: i64) { let mut num = if num < 0 { ((-num) << 1) + 1 } else { num << 1 }; + // Breaking out of loop early when have reached last char (rather than conditionally adding + // 32 for last char within the loop) removes 3 instructions from the loop. + // https://godbolt.org/z/Es4Pavh9j + // This translates to a 16% speed-up for VLQ encoding. + let mut digit; loop { - let mut digit = num & 0b11111; + digit = num & 0b11111; num >>= 5; - if num > 0 { - digit |= 1 << 5; - } - - let b = B64_CHARS.0[digit as usize]; - // SAFETY: - // * This loop can execute a maximum of 7 times, caller promises there are at least - // 7 bytes spare capacity in `out` at start, and we only push 1 byte on each turn, - // so guaranteed there is at least 1 byte capacity in `out` here. - // * All values in `B64_CHARS` lookup table are ASCII bytes. - push_byte_unchecked(out, b); - if num == 0 { break; } + + let b = B64_CHARS.0[digit as usize + 32]; + // SAFETY: + // * This loop can execute a maximum of 7 times, and on last turn will exit before getting here. + // Caller promises there are at least 7 bytes spare capacity in `out` at start. We only + // push 1 byte on each turn, so guaranteed there is at least 1 byte capacity in `out` here. + // * All values in `B64_CHARS` lookup table are ASCII bytes. + push_byte_unchecked(out, b); } + + let b = B64_CHARS.0[digit as usize]; + // SAFETY: + // * The loop above pushes max 6 bytes. Caller promises there are at least 7 bytes spare capacity + // in `out` at start. So guaranteed there is at least 1 byte capacity in `out` here. + // * All values in `B64_CHARS` lookup table are ASCII bytes. + push_byte_unchecked(out, b); } /// Push a byte to `out` without bounds checking.