Skip to content

Commit e06e8a1

Browse files
committed
optimization
1 parent 34cbef1 commit e06e8a1

1 file changed

Lines changed: 37 additions & 14 deletions

File tree

headers/fastpfor_neon.h

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,22 +193,45 @@ static inline __m128i _mm_shuffle_epi8(__m128i a, __m128i b) {
193193
return vreinterpretq_s64_u8(vqtbl1q_u8(tbl, idx));
194194
}
195195
static inline __m128i _mm_shuffle_epi32(__m128i a, const int imm) {
196-
uint32_t t[4];
197-
uint32_t r[4];
198-
vst1q_u32(t, vreinterpretq_u32_s64(a));
199-
r[0] = t[imm & 3];
200-
r[1] = t[(imm >> 2) & 3];
201-
r[2] = t[(imm >> 4) & 3];
202-
r[3] = t[(imm >> 6) & 3];
203-
return vreinterpretq_s64_u32(vld1q_u32(r));
196+
/* Permute the four 32-bit lanes. `imm` is a compile-time constant at every
197+
* call site, so the broadcast fast paths fold away and the general case
198+
* builds a constant byte index that compiles to a single TBL. */
199+
uint32x4_t v = vreinterpretq_u32_s64(a);
200+
if (imm == 0x00)
201+
return vreinterpretq_s64_u32(vdupq_laneq_u32(v, 0));
202+
if (imm == 0x55)
203+
return vreinterpretq_s64_u32(vdupq_laneq_u32(v, 1));
204+
if (imm == 0xAA)
205+
return vreinterpretq_s64_u32(vdupq_laneq_u32(v, 2));
206+
if (imm == 0xFF)
207+
return vreinterpretq_s64_u32(vdupq_laneq_u32(v, 3));
208+
{
209+
const uint8_t b0 = (uint8_t)((imm & 3) * 4);
210+
const uint8_t b1 = (uint8_t)(((imm >> 2) & 3) * 4);
211+
const uint8_t b2 = (uint8_t)(((imm >> 4) & 3) * 4);
212+
const uint8_t b3 = (uint8_t)(((imm >> 6) & 3) * 4);
213+
const uint8x16_t idx = {
214+
b0, (uint8_t)(b0 + 1), (uint8_t)(b0 + 2), (uint8_t)(b0 + 3),
215+
b1, (uint8_t)(b1 + 1), (uint8_t)(b1 + 2), (uint8_t)(b1 + 3),
216+
b2, (uint8_t)(b2 + 1), (uint8_t)(b2 + 2), (uint8_t)(b2 + 3),
217+
b3, (uint8_t)(b3 + 1), (uint8_t)(b3 + 2), (uint8_t)(b3 + 3)};
218+
return vreinterpretq_s64_u8(vqtbl1q_u8(vreinterpretq_u8_s64(a), idx));
219+
}
204220
}
205221
static inline __m128i _mm_blend_epi16(__m128i a, __m128i b, const int imm) {
206-
uint16_t m[8];
207-
int i;
208-
for (i = 0; i < 8; i++)
209-
m[i] = ((imm >> i) & 1) ? (uint16_t)0xFFFF : (uint16_t)0;
210-
return vreinterpretq_s64_u16(vbslq_u16(vld1q_u16(m),
211-
vreinterpretq_u16_s64(b),
222+
/* Per-16-bit-lane select from `a` (0) or `b` (1). `imm` is constant at every
223+
* call site, so this compound-literal mask folds to a constant vector load
224+
* feeding a single BSL, with no stack round-trip. */
225+
const uint16x8_t mask = {
226+
(imm & 0x01) ? (uint16_t)0xFFFF : (uint16_t)0,
227+
(imm & 0x02) ? (uint16_t)0xFFFF : (uint16_t)0,
228+
(imm & 0x04) ? (uint16_t)0xFFFF : (uint16_t)0,
229+
(imm & 0x08) ? (uint16_t)0xFFFF : (uint16_t)0,
230+
(imm & 0x10) ? (uint16_t)0xFFFF : (uint16_t)0,
231+
(imm & 0x20) ? (uint16_t)0xFFFF : (uint16_t)0,
232+
(imm & 0x40) ? (uint16_t)0xFFFF : (uint16_t)0,
233+
(imm & 0x80) ? (uint16_t)0xFFFF : (uint16_t)0};
234+
return vreinterpretq_s64_u16(vbslq_u16(mask, vreinterpretq_u16_s64(b),
212235
vreinterpretq_u16_s64(a)));
213236
}
214237

0 commit comments

Comments
 (0)