summaryrefslogtreecommitdiff
path: root/src/text_run.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-14 17:36:22 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-14 17:36:22 +0300
commit13bf7edad251df9943bd75665a3510535849b0ac (patch)
tree4597aae71940edac0b7d8b416c4803cd72ac5345 /src/text_run.c
parent513bf031a589d9e2a1a2730adf56f95e5e316a06 (diff)
Deduplicate scroll and SIMD paths while preserving performance
Diffstat (limited to 'src/text_run.c')
-rw-r--r--src/text_run.c102
1 files changed, 40 insertions, 62 deletions
diff --git a/src/text_run.c b/src/text_run.c
index bf0e8a9..028b160 100644
--- a/src/text_run.c
+++ b/src/text_run.c
@@ -53,17 +53,11 @@ static TERM_MAYBE_UNUSED int width_run_find(uint32_t cp)
static TERM_MAYBE_UNUSED uint16_t width_cache_covers(const struct width_cache *wc,
const uint32_t *cp)
{
- uint32_t lo0 = wc->lo[0], span0 = wc->span[0];
- uint32_t lo1 = wc->lo[1], span1 = wc->span[1];
- uint32_t lo2 = wc->lo[2], span2 = wc->span[2];
- uint32_t lo3 = wc->lo[3], span3 = wc->span[3];
uint16_t covered = 0;
for (int l = 0; l < 16; l++) {
- uint32_t c = cp[l];
- bool hit = ((c - lo0 <= span0) |
- (c - lo1 <= span1) |
- (c - lo2 <= span2) |
- (c - lo3 <= span3));
+ bool hit = false;
+ for (int k = 0; k < TERM_WIDTH_SLOTS; k++)
+ hit |= cp[l] - wc->lo[k] <= wc->span[k];
covered |= (uint16_t)(hit << l);
}
return covered;
@@ -146,24 +140,20 @@ TERM_TARGET_AVX512
static inline struct width_ranges width_ranges_load(const struct width_cache *wc)
{
struct width_ranges r;
- r.lo[0] = _mm512_set1_epi32((int)wc->lo[0]);
- r.span[0] = _mm512_set1_epi32((int)wc->span[0]);
- r.lo[1] = _mm512_set1_epi32((int)wc->lo[1]);
- r.span[1] = _mm512_set1_epi32((int)wc->span[1]);
- r.lo[2] = _mm512_set1_epi32((int)wc->lo[2]);
- r.span[2] = _mm512_set1_epi32((int)wc->span[2]);
- r.lo[3] = _mm512_set1_epi32((int)wc->lo[3]);
- r.span[3] = _mm512_set1_epi32((int)wc->span[3]);
+ for (int k = 0; k < TERM_WIDTH_SLOTS; k++) {
+ r.lo[k] = _mm512_set1_epi32((int)wc->lo[k]);
+ r.span[k] = _mm512_set1_epi32((int)wc->span[k]);
+ }
return r;
}
TERM_TARGET_AVX512
static inline __mmask16 width_ranges_cover(const struct width_ranges *r, __m512i cps)
{
- return _mm512_cmple_epu32_mask(_mm512_sub_epi32(cps, r->lo[0]), r->span[0])
- | _mm512_cmple_epu32_mask(_mm512_sub_epi32(cps, r->lo[1]), r->span[1])
- | _mm512_cmple_epu32_mask(_mm512_sub_epi32(cps, r->lo[2]), r->span[2])
- | _mm512_cmple_epu32_mask(_mm512_sub_epi32(cps, r->lo[3]), r->span[3]);
+ __mmask16 covered = 0;
+ for (int k = 0; k < TERM_WIDTH_SLOTS; k++)
+ covered |= _mm512_cmple_epu32_mask(_mm512_sub_epi32(cps, r->lo[k]), r->span[k]);
+ return covered;
}
TERM_TARGET_AVX512
@@ -189,6 +179,31 @@ static inline void store_narrow_cells(uint64_t * restrict dst, __m512i base, __m
#undef TERM_NARROW_QUAD
}
+/* Both cell and history writers validate and classify the same UTF-8 block. */
+TERM_TARGET_AVX512
+static inline bool classify_3byte_block(__m512i in, struct width_ranges *ranges,
+ struct width_cache *wc, __m512i *cps)
+{
+ if (TERM_EXPECT(_mm512_test_epi8_mask(
+ _mm512_xor_si512(in, _mm512_loadu_si512(utf8_3byte_want)),
+ _mm512_loadu_si512(utf8_3byte_bits)) & UTF8_3BYTE_SPAN, 0))
+ return false;
+ *cps = utf8_3byte_decode(_mm512_permutexvar_epi8(_mm512_loadu_si512(utf8_3byte_shuffle), in));
+ if (_mm512_cmplt_epu32_mask(*cps, _mm512_set1_epi32((int)UTF8_3BYTE_MIN)) ||
+ _mm512_cmple_epu32_mask(
+ _mm512_sub_epi32(*cps, _mm512_set1_epi32((int)UTF8_SURROGATE_LO)),
+ _mm512_set1_epi32((int)(UTF8_SURROGATE_HI - UTF8_SURROGATE_LO))))
+ return false;
+ __mmask16 covered = width_ranges_cover(ranges, *cps);
+ if (TERM_EXPECT(covered != 0xFFFF || wc->klass == 0, 0)) {
+ uint32_t cp[16];
+ _mm512_storeu_si512(cp, *cps);
+ if (!width_cache_extend(wc, cp, covered)) return false;
+ *ranges = width_ranges_load(wc);
+ }
+ return true;
+}
+
TERM_TARGET_AVX512
static TERM_NOINLINE int
decode_3byte_blocks(uint64_t * restrict dst, const char * restrict buf, int len, int cols_left,
@@ -197,33 +212,14 @@ decode_3byte_blocks(uint64_t * restrict dst, const char * restrict buf, int len,
int * restrict out_cols, uint32_t * restrict last_cp)
{
struct width_ranges ranges = width_ranges_load(wc);
- __m512i shuffle = _mm512_loadu_si512(utf8_3byte_shuffle);
- __m512i want = _mm512_loadu_si512(utf8_3byte_want);
- __m512i bits = _mm512_loadu_si512(utf8_3byte_bits);
uint32_t last = *last_cp;
int i = 0, cx = 0;
while (i + 48 <= len && cx + 32 <= cols_left &&
((unsigned char)buf[i + 45] & UTF8_LEAD3_MASK) == UTF8_LEAD3_TAG) {
__m512i in = _mm512_maskz_loadu_epi8(UTF8_3BYTE_SPAN, buf + i);
- if (TERM_EXPECT(_mm512_test_epi8_mask(_mm512_xor_si512(in, want), bits) &
- UTF8_3BYTE_SPAN, 0))
- break;
-
- __m512i cps = utf8_3byte_decode(_mm512_permutexvar_epi8(shuffle, in));
- if (_mm512_cmplt_epu32_mask(cps, _mm512_set1_epi32((int)UTF8_3BYTE_MIN)) ||
- _mm512_cmple_epu32_mask(
- _mm512_sub_epi32(cps, _mm512_set1_epi32((int)UTF8_SURROGATE_LO)),
- _mm512_set1_epi32((int)(UTF8_SURROGATE_HI - UTF8_SURROGATE_LO))))
- break;
- __mmask16 covered = width_ranges_cover(&ranges, cps);
- if (TERM_EXPECT(covered != 0xFFFF || wc->klass == 0, 0)) {
- uint32_t cp[16];
- _mm512_storeu_si512(cp, cps);
- if (!width_cache_extend(wc, cp, covered))
- break;
- ranges = width_ranges_load(wc);
- }
+ __m512i cps;
+ if (!classify_3byte_block(in, &ranges, wc, &cps)) break;
if (wc->klass == 2) {
store_wide_cells(dst, base_wide_pair, cps);
@@ -258,9 +254,6 @@ text_3byte_blocks(uint8_t * restrict dst, const char * restrict buf, int len, in
0, 36, 37, 38, 0, 39, 40, 41, 0, 42, 43, 44, 0, 45, 46, 47,
};
struct width_ranges ranges = width_ranges_load(wc);
- __m512i shuffle = _mm512_loadu_si512(utf8_3byte_shuffle);
- __m512i want = _mm512_loadu_si512(utf8_3byte_want);
- __m512i bits = _mm512_loadu_si512(utf8_3byte_bits);
__m512i idx = _mm512_loadu_si512(spread);
__m512i prefix = _mm512_set1_epi8((char)0xF5);
uint32_t last = *last_cp;
@@ -269,23 +262,8 @@ text_3byte_blocks(uint8_t * restrict dst, const char * restrict buf, int len, in
while (i + 48 <= len && cx + 32 <= cols_left &&
((unsigned char)buf[i + 45] & UTF8_LEAD3_MASK) == UTF8_LEAD3_TAG) {
__m512i in = _mm512_maskz_loadu_epi8(UTF8_3BYTE_SPAN, buf + i);
- if (TERM_EXPECT(_mm512_test_epi8_mask(_mm512_xor_si512(in, want), bits) &
- UTF8_3BYTE_SPAN, 0))
- break;
- __m512i cps = utf8_3byte_decode(_mm512_permutexvar_epi8(shuffle, in));
- if (_mm512_cmplt_epu32_mask(cps, _mm512_set1_epi32((int)UTF8_3BYTE_MIN)) ||
- _mm512_cmple_epu32_mask(
- _mm512_sub_epi32(cps, _mm512_set1_epi32((int)UTF8_SURROGATE_LO)),
- _mm512_set1_epi32((int)(UTF8_SURROGATE_HI - UTF8_SURROGATE_LO))))
- break;
- __mmask16 covered = width_ranges_cover(&ranges, cps);
- if (TERM_EXPECT(covered != 0xFFFF || wc->klass == 0, 0)) {
- uint32_t cp[16];
- _mm512_storeu_si512(cp, cps);
- if (!width_cache_extend(wc, cp, covered))
- break;
- ranges = width_ranges_load(wc);
- }
+ __m512i cps;
+ if (!classify_3byte_block(in, &ranges, wc, &cps)) break;
if (wc->klass == 2) {
__m512i out = _mm512_mask_mov_epi8(_mm512_permutexvar_epi8(idx, in),
0x1111111111111111ull, prefix);