如何使用 NEON 在 ARM 程序集中实现 16 位>32 位查找表?



在iOS 6项目中,我有一个缓冲区,其中包含两个字节的单词(16位),需要通过查找表将其转换为四个字节的词(32位)。我将这些值硬编码到表中,然后使用两字节缓冲区的值来确定要检索的32位表值。这里有一个例子:

void map_values(uint32_t *dst,uint16_t *src,uint32_t *lut,int buf_length){
    int i=0;
    for(i=0;i<buf_length;i++){
        *dst = *(lut+(*src));
        dst++;
        src++;
    }
}

问题是,它太慢了。是否可以通过使用NEON一次处理4个输出字节来加快速度?问题是,我不确定如何从src缓冲区中获取值,并将其用作查找表的输入,以确定要检索的值。此外,表和输出缓冲区中的字长相同,但源的字长不同。因此,我只能读取两个16位的字作为输入,而我需要四个32位的字输出。有什么想法吗?也许有更好的方法来解决这个问题吗?

clang的电流asm输出(clang-O3-arch armv7 lut.c-S):

    .section    __TEXT,__text,regular,pure_instructions
    .section    __TEXT,__textcoal_nt,coalesced,pure_instructions
    .section    __TEXT,__const_coal,coalesced
    .section    __TEXT,__picsymbolstub4,symbol_stubs,none,16
    .section    __TEXT,__StaticInit,regular,pure_instructions
    .syntax unified
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _map_values
    .align  2
    .code   16                      @ @map_values
    .thumb_func _map_values
_map_values:
@ BB#0:
    cmp r3, #0
    it  eq
    bxeq    lr
LBB0_1:                                 @ %.lr.ph
                                        @ =>This Inner Loop Header: Depth=1
    ldrh    r9, [r1], #2
    subs    r3, #1
    ldr.w   r9, [r2, r9, lsl #2]
    str r9, [r0], #4
    bne LBB0_1
@ BB#2:                                 @ %._crit_edge
    bx  lr

.subsections_via_symbols

查找表(几乎)是不可分解的。使用vtbl指令可以处理非常小的查找表,但您的查找表太大了。

您使用查找表做什么?如果可以在不需要太多工作的情况下快速计算这些值,而不是查找它们,那么这实际上可能是你的一个重大胜利。

我的第一个想法是,您可能会从Accelerate框架的vecLib部分的vtablelookup中获得一些运气。签名为:

vUInt32 vtablelookup (
   vSInt32 Index_Vect,
   uint32_t *Table
);

其中CCD_ 3和CCD_。我相信这个功能是由ARM上的NEON支持的。最大的问题是将src数组转换为32位索引,这可能会大大降低速度,从而使矢量化查找带来的速度增益变得毫无意义。

相关内容

最新更新