我有一个16 uint8_t块的传入字节流,我需要扩展到4倍的uint32x4_t霓虹灯寄存器以进行进一步的处理。这将在基于Cortex-A55的核心上运行。下面是一个例子字节流:{0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xF}.
到目前为止,我得到的是:
#include <stdint.h>
#if defined(__aarch64__)
#include <arm_neon.h>
#else
typedef unsigned int uint32x4_t __attribute__ ((vector_size (16)));
typedef unsigned char uint8x16_t __attribute__ ((vector_size (16)));
#endif
#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define select_u8x4_from_u8x16( a, b, c, d) {255,255,255,(a),255,255,255,(b),255,255,255,(c),255,255,255,(d)}
#else
#define select_u8x4_from_u8x16( a, b, c, d) {(a),255,255,255,(b),255,255,255,(c),255,255,255,(d),255,255,255}
#endif
//Wrapper around vqtbl1q_u8()
static inline uint8x16_t table_16u8(uint8x16_t mat, uint8x16_t indexes)
{
#if defined( __aarch64__ )
return vqtbl1q_u8(mat, indexes);
#else
uint8x16_t result;
for( unsigned i = 0; i < sizeof(mat); ++i )
{
result[i] = mat[indexes[i]];
}
return result;
#endif
}
uint32_t test_function(const uint8_t * samples, unsigned num_samples/*always divisible by 16*/)
{
static const uint8x16_t idx_a = select_u8x4_from_u8x16(0,1,2,3);
static const uint8x16_t idx_b = select_u8x4_from_u8x16(4,5,6,7);
static const uint8x16_t idx_c = select_u8x4_from_u8x16(8,9,10,11);
static const uint8x16_t idx_d = select_u8x4_from_u8x16(12,13,14,15);
uint32x4_t dummy_accumulator = {0,0,0,0};
for(unsigned x = 0; x < num_samples; x += 16)
{
/*Begin section I'd like help with*/
uint8x16_t pxvect = *((uint8x16_t*)(samples+x));
uint32x4_t temp_a = (uint32x4_t)table_16u8(pxvect, idx_a);/*holds {0x0,0x1,0x2,0x3}*/
uint32x4_t temp_b = (uint32x4_t)table_16u8(pxvect, idx_b);/*holds {0x4,0x5,0x6,0x7}*/
uint32x4_t temp_c = (uint32x4_t)table_16u8(pxvect, idx_c);/*holds {0x8,0x9,0xA,0xB}*/
uint32x4_t temp_d = (uint32x4_t)table_16u8(pxvect, idx_d);/*holds {0xC,0xD,0xE,0xF}*/
/*End section I'd like help with.*/
/*Sum the values to produce a return value*/
dummy_accumulator += temp_a;
dummy_accumulator += temp_b;
dummy_accumulator += temp_c;
dummy_accumulator += temp_d;
}
return dummy_accumulator[0]+dummy_accumulator[1]+dummy_accumulator[2]+dummy_accumulator[3];
}
uint32_t test_harness(void)
{
uint8_t test_vec[] = {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xF};
return test_function(test_vec, sizeof(test_vec));
}我见过VLD4,但这会带来结果,我不想那样。如果我计算转置(我宁愿不计算,其余的数学没有显示),我的第一关是:
uint32_t test_function(const uint8_t * samples, unsigned num_samples/*always divisible by 16*/)
{
#define splat_u32x4(a){(a),(a),(a),(a)}
static const uint32x4_t mask_a = splat_u32x4(0xffUL);
static const uint32x4_t mask_b = splat_u32x4(0xffUL<<8);
static const uint32x4_t mask_c = splat_u32x4(0xffUL<<16);
static const uint32x4_t mask_d = splat_u32x4(0xffUL<<24);
uint32x4_t dummy_accumulator = {0,0,0,0};
for(unsigned x = 0; x < num_samples; x += 16)
{
/*Begin section I'd like help with*/
uint8x16_t pxvect = *((uint8x16_t*)(samples+x));
uint32x4_t temp_a = ((uint32x4_t)pxvect & mask_a) >> 0; /*holds{0x0,0x4,0x8,0xC}*/
uint32x4_t temp_b = ((uint32x4_t)pxvect & mask_b) >> 8; /*holds{0x1,0x5,0x9,0xD}*/
uint32x4_t temp_c = ((uint32x4_t)pxvect & mask_c) >> 16;/*holds{0x2,0x6,0xA,0xE}*/
uint32x4_t temp_d = ((uint32x4_t)pxvect & mask_d) >> 24;/*holds{0x3,0x7,0xB,0xF}*/
/*End section I'd like help with.*/
/*Sum the values to produce a return value*/
dummy_accumulator += temp_a;
dummy_accumulator += temp_b;
dummy_accumulator += temp_c;
dummy_accumulator += temp_d;
}
return dummy_accumulator[0]+dummy_accumulator[1]+dummy_accumulator[2]+dummy_accumulator[3];
}我希望尽可能快地加载16个字节并将它们扩展到4x0扩展的uint32x4_t寄存器中,最好是以线性顺序,而不是4x4转置。有没有更好的方法来做到这一点?
发布于 2022-11-16 02:01:21
uint8x16_t in = vld1q_u8(pSrc);
uint16x8_t templ, temph;
uint32x4x4_t out;
templ = vmovl_u8(vget_low_u8(in));
temph = vmovl_u8(vget_high_u8(in));
out.val[0] = vmovl_u16(vget_low_u16(templ));
out.val[1] = vmovl_u16(vget_high_u16(templ));
out.val[2] = vmovl_u16(vget_low_u16(temph));
out.val[3] = vmovl_u16(vget_high_u16(temph));发布于 2022-11-15 22:18:08
另一种选择-使用加法加零:
// Widen 16x U8 to 2x 8x U16 values
vaddl_u8()
vaddl_high_u8()
// Widen 8x U16 to 2x 4x U32 values
vaddl_u16()
vaddl_high_u16()
// Widen 8x U16 to 2x 4x U32 values
vaddl_u16()
vaddl_high_u16()这仍然是6个操作,但是由于它们只有一个结果寄存器,所以它可能比vzip更快。
发布于 2022-11-15 22:02:30
我会用vzip来做这个:
q0 = 16 packed byte values
q1 = Zeros
q2 = Zeros
q3 = Zeros
vzip.u8 q0, q2 // Interleave u8 and zeros to get u16 values
vzip.u16 q0, q1 // Interleave u16 and zeros to get u32 values
vzip.u16 q2, q3 // Interleave u16 and zeros to get u32 values值在q0、q1、q2、q3中以线性顺序结束。vzip的缺点是,每次迭代都会破坏零寄存器,因此您最终需要为每次迭代重新加载q1/2/3和零。
https://stackoverflow.com/questions/74452212
复制相似问题