与 ARM Neon vtbx 的字节顺序混淆

Posted

技术标签:

【中文标题】与 ARM Neon vtbx 的字节顺序混淆【英文标题】:Endianness confusion with ARM Neon vtbx 【发布时间】:2017-02-23 14:10:49 【问题描述】:

我有一个 16 字节排列掩码 uint8_t[16] 和一个 16 字节数据数组 uint32_t[4]。我想像这样使用vtbl“洗牌”这个数据数组:

          0   1   2   3   4   5   6   7    8   9    A    B    C    D    E    F
  Data ||0x0,0x0,0x1,0x2|0x0,0x3,0x0,0x4||0x5,0x6, 0x7, 0x8| 0x0, 0x0, 0x0, 0x9||

 SMask ||0x2,0x3,0x5,0x6|0x7,0x8,0x9,0xA||0xB,0xF,0x10,0x10|0x10,0x10,0x10,0x10||

Result ||0x1,0x2,0x3,0x0|0x4,0x5,0x6,0x7||0x8,0x9, 0x0, 0x0| 0x0, 0x0, 0x0, 0x0||

这是我目前的代码:

#include <iostream>
#include <arm_neon.h>

inline uint8x16_t Shuffle(const uint8x16_t & src, const uint8x16_t & shuffle) 
  return vcombine_u8(
          vtbl2_u8(
            (const uint8x8x2_t &)src, 
            vget_low_u8(shuffle)
          ),
          vtbl2_u8(
            (const uint8x8x2_t &)src, 
          vget_high_u8(shuffle)
          )
        );


int main() 
   uint32_t* data32 = new uint32_t[4];
   data32[0] = 258;             // [0x00 0x00 0x01 0x02]
   data32[1] = 196612;          // [0x00 0x03 0x00 0x04]
   data32[2] = 84281096;        // [0x05 0x06 0x07 0x08]
   data32[3] = 9;               // [0x00 0x00 0x00 0x09]    
   /*load structure*/
   uint32x4_t data32Vec = vld1q_u32(data32);

   uint8_t* sMask = new uint8_t[16];
   sMask[0] = 2;
   sMask[1] = 3;
   sMask[2] = 5;
   sMask[3] = 6;
   sMask[4] = 7;
   sMask[5] = 8;
   sMask[6] = 9;
   sMask[7] = 10;
   sMask[8] = 11;
   sMask[9] = 15;
   sMask[10] = 16;
   sMask[11] = 16;
   sMask[12] = 16;
   sMask[13] = 16;
   sMask[14] = 16;
   sMask[15] = 16;
   /*load permutationmask into vector register*/
   uint8x16_t shuffleMask = vld1q_u8(sMask);

   uint8_t* comprData = new uint8_t[16];
   /*shuffle the data with the mask and store it into an uint8_t[16]*/
   vst1q_u8(comprData, Shuffle(vreinterpretq_u8_u32(data32Vec),shuffleMask));
   for(int i = 0; i < 16; ++i) 
      std::cout << (unsigned)comprData[i] << "   " ;
   
   std::cout << std::endl;
   delete[] comprData;
   delete[] sMask;
   delete[] data32;
   return 0;

输出如下所示:

0   0   0   3   0   8   7   6   5   0   0   0   0   0   0   0

应该是这样的:

1   2   3   0   4   5   6   7   8   9   0   0   0   0   0   0

我认为这与字节序有关,但只是看不到问题所在。有人有提示吗?

我更新了有关 ErmIg 答案的代码。主要问题是,我混淆了 vtbx 和 vtbl。

真诚的

【问题讨论】:

【参考方案1】:

可能对你有帮助(我使用这些函数来洗牌向量内的字节用于 Arm NEON):

    inline uint8x16_t Shuffle(const uint8x16_t & src, const uint8x16_t & shuffle)
    
        return vcombine_u8(
            vtbl2_u8((const uint8x8x2_t &)src, vget_low_u8(shuffle)),
            vtbl2_u8((const uint8x8x2_t &)src, vget_high_u8(shuffle)));
    

    inline uint8x16_t Shuffle(const uint8x16x2_t & src, const uint8x16_t & shuffle)
    
        return vcombine_u8(
            vtbl4_u8((const uint8x8x4_t &)src, vget_low_u8(shuffle)), 
            vtbl4_u8((const uint8x8x4_t &)src, vget_high_u8(shuffle)));
    

【讨论】:

我认为 vtbl2 的第一个参数需要一个目标寄存器?但这看起来不错。事实上,我认为我混淆了 vtbl 和 vtbx 的行为。 Vtbl 是我需要的,因此如果索引超出范围,它会插入零。我最初认为 vtbx 会有这种行为 :(

以上是关于与 ARM Neon vtbx 的字节顺序混淆的主要内容,如果未能解决你的问题,请参考以下文章

有效计算 arm neon 中 16 字节缓冲区中不同值的数量

将 Java 位图打包到 ByteBuffer 中 - 字节顺序与像素格式和字节序不匹配(ARM)

使用NEON优化ARM的卷积运算

如何使用 neon 访问超过 256 字节的查找表?

是否可以在 ARM(Android/Linux)上更改字节顺序?

Aarch64 NEON 中的 UADDL 与 UADDL2