首页 > 解决方案 > ARM NEON:常规 C 代码在简单乘法中比 ARM Neon 代码更快?

问题描述

我正在使用 ARM NEON 内在函数为数组实现简单的乘法。输入是一个 uint8 数组,输出是一个 uint16 数组。但是,常规的本机代码比 NEON 优化的代码要快。谁能帮我弄清楚如何改进 NEON 代码?

我的常规代码是

    uint16_t scale_factor = 300;
    for(int i = 0; i < output_size; i++)
    {        
        out_16bit[i] = (uint16_t)(in_ptr[i] * scale_factor) ;
    }

我的霓虹灯代码是

    uint16_t* out_ptr = out_16bit;
    uint8_t* in_ptr = in_8bit;
    uint16_t scale_factor = 300;

    for(int i = 0; i < out_size/16; i++)
    {
        uint8x16_t in_v0 = vld1q_u8(in_ptr);
        in_ptr += 16;

        uint16x8_t in_16_v0 = vmovl_u8(vget_low_u8(in_v0));
        uint16x8_t in_16_v1 = vmovl_u8(vget_high_u8(in_v0));

        uint16x8_t res_0 = vmulq_n_u16(in_16_v0, scale_factor);
        uint16x8_t res_1 = vmulq_n_u16(in_16_v1, scale_factor);

        // code below takes long time
        vst1q_u16(out_ptr,res_0);  
        vst1q_u16(out_ptr+8,res_1);  
        out_ptr += 16;

    }

我还做了一些分析,发现如果我注释掉vst1q_u16s 或out_ptr += 16,速度很快。但如果我保持上述两个,它会很慢。所以我想这可能是因为指针的增量正在等待完成vst1q_u16?然后我更新了NEON代码以在和之间添加一些代码vst1q_u16out_ptr+=16如下所示,

    uint8x16_t in_v0 = vld1q_u8(in_ptr);
    uint16x8_t in_16_v0 = vmovl_u8(vget_low_u8(in_v0));
    uint16x8_t in_16_v1 = vmovl_u8(vget_high_u8(in_v0));

    uint16x8_t res_0 = vmulq_n_u16(in_16_v0, scale_factor);
    uint16x8_t res_1 = vmulq_n_u16(in_16_v1, scale_factor);
    vst1q_u16(out_ptr,res_0);  
    vst1q_u16(out_ptr+8,res_1);  
    for(int i = 1; i < out_size/16; i++)
    {

        in_v0 = vld1q_u8(in_ptr);
        in_16_v0 = vmovl_u8(vget_low_u8(in_v0));
        in_16_v1 = vmovl_u8(vget_high_u8(in_v0));
    
        out_ptr += 16;

        res_0 = vmulq_n_u16(in_16_v0, scale_factor);
        res_1 = vmulq_n_u16(in_16_v1, scale_factor);

        vst1q_u16(out_ptr,res_0);  
        vst1q_u16(out_ptr+8,res_1);  

    
    }

但是这个改变没有奏效......请帮助告诉我应该怎么做......谢谢。

标签: armsimdintrinsicsneon

解决方案


如评论中所述,简单的答案是自动矢量化。我不确定clang 6,但在以Neon平台为目标时,最近的clang肯定会默认自动矢量化为Neon,并且很难在像这种乘法这样简单的事情上击败自动矢量化。也许为您的特定处理器展开最佳循环。但它很容易比自动矢量化更糟糕。Godbolt 是一个非常好的比较方法,以及分析您的所有更改。

所有的评论也都很好。

有关 Neon 内在函数最佳实践的更多文档,Arm 的Neon 微型网站有非常有用的信息,尤其是关于Optimizing C with Neon intrinsics的文档。


推荐阅读