Skip to content

Commit e1525ab

Browse files
committed
perf: small tweaks targeting cache prediction
1 parent 193bb38 commit e1525ab

File tree

6 files changed

+15
-53
lines changed

6 files changed

+15
-53
lines changed

assembly/deserialize/simd/string.ts

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,17 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
7171
const block = load<v128>(srcStart);
7272
store<v128>(bs.offset, block);
7373

74-
const eq5C = i16x8.eq(load<v128>(srcStart), SPLAT_5C);
75-
let mask = i16x8.bitmask(eq5C);
74+
const eq5C = i16x8.eq(block, SPLAT_5C);
75+
7676
// Early exit
77-
if (mask === 0) {
77+
if (!v128.any_true(eq5C)) {
7878
srcStart += 16;
7979
bs.offset += 16;
8080
continue;
8181
}
8282

83+
let mask = i16x8.bitmask(eq5C);
84+
8385
let srcChg: usize = 0;
8486
let lastLane: usize = 0;
8587
do {
@@ -157,40 +159,3 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
157159

158160
return bs.out<string>();
159161
}
160-
161-
/**
162-
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
163-
* is the ASCII backslash (`'\\'`, 0x5C).
164-
*
165-
* The mask is produced in two stages:
166-
* 1. Detects bytes equal to 0x5C using a SWAR equality test.
167-
* 2. Clears matches where 0x5C appears in the **high byte** of a UTF-16 code unit,
168-
* ensuring only valid low-byte backslashes are reported.
169-
*
170-
* Each matching lane sets itself to 0x80.
171-
*/
172-
// @ts-ignore: decorator
173-
@inline function backslash_mask(block: u64): u64 {
174-
const b = block ^ 0x005C_005C_005C_005C;
175-
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
176-
const high_byte_mask =
177-
~(((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000)
178-
^ 0x8000_8000_8000_8000) >> 8;
179-
return backslash_mask & high_byte_mask;
180-
}
181-
182-
/**
183-
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
184-
* is the ASCII backslash (`'\\'`, 0x5C).
185-
*
186-
* Each matching lane sets itself to 0x80.
187-
*
188-
* WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
189-
* This is useful for a hot path where it is possible to detect the false positive scalarly.
190-
*/
191-
// @ts-ignore: decorator
192-
@inline function backslash_mask_unsafe(block: u64): u64 {
193-
const b = block ^ 0x005C_005C_005C_005C;
194-
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
195-
return backslash_mask;
196-
}

assembly/deserialize/swar/string.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { hex4_to_u16_swar } from "../../util/swar";
3030
// -\n- 2 -*-_ - 2
3131
// --\n 4 --*_ - 2
3232
// ---\n 6 ---* - 0
33-
// Formula: overflow =
33+
// Formula: overflow =
3434

3535
/**
3636
* Deserializes strings back into into their original form using SIMD operations
@@ -48,7 +48,8 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
4848
while (srcStart < srcEnd8) {
4949
const block = load<u64>(srcStart);
5050
store<u64>(bs.offset, block);
51-
let mask = backslash_mask_unsafe(block);
51+
52+
let mask = inline.always(backslash_mask_unsafe(block));
5253

5354
// Early exit
5455
if (mask === 0) {
@@ -153,7 +154,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
153154
* is the ASCII backslash (`'\\'`, 0x5C).
154155
*
155156
* Each matching lane sets itself to 0x80.
156-
*
157+
*
157158
* WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
158159
* This is useful for a hot path where it is possible to detect the false positive scalarly.
159160
*/

assembly/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ export namespace JSON {
183183
// @ts-ignore: type
184184
return deserializeString_SIMD(dataPtr, dataPtr + dataSize);
185185
}
186-
// }
187186
} else if (isArray<T>()) {
188187
// @ts-ignore
189188
return inline.always(deserializeArray<nonnull<T>>(dataPtr, dataPtr + dataSize, changetype<usize>(instantiate<T>())));

assembly/serialize/simd/string.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,13 @@ export function serializeString_SIMD(src: string): void {
5757
const sieve = v128.or(eq22, v128.or(eq5C, v128.or(lt20, gteD8)));
5858
// console.log("sieve : " + mask_to_string_v128(sieve));
5959

60-
if (v128.any_true(sieve)) {
61-
62-
let mask = i8x16.bitmask(sieve);
63-
64-
if (mask === 0) {
60+
if (!v128.any_true(sieve)) {
6561
bs.offset += 16;
6662
srcStart += 16;
6763
continue;
68-
}
64+
}
65+
66+
let mask = i8x16.bitmask(sieve);
6967

7068
do {
7169
const laneIdx = ctz(mask);
@@ -125,7 +123,6 @@ export function serializeString_SIMD(src: string): void {
125123
store<v128>(dstIdx, load<v128>(srcIdx, 1), 12);
126124
bs.offset += 10;
127125
} while (mask !== 0);
128-
}
129126

130127
srcStart += 16;
131128
bs.offset += 16;
@@ -195,4 +192,4 @@ export function serializeString_SIMD(src: string): void {
195192
// @ts-ignore: inline
196193
@inline function hexNibble(n: u16): u16 {
197194
return n < 10 ? (48 + n) : (87 + n);
198-
}
195+
}

assembly/serialize/swar/number.ts

Whitespace-only changes.

assembly/serialize/swar/string.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,4 @@ export function serializeString_SWAR(src: string): void {
189189
);
190190
const hi = block & 0xFF00_FF00_FF00_FF00;
191191
return ascii_mask | hi;
192-
}
192+
}

0 commit comments

Comments
 (0)