我正在寻找一种将元素从8位源数组(uint8_t*)加载到数据格式为uint16x8_t或更好的uint16x8x3_t的AArch64neon/ASIMD寄存器的方法.因此,基本上,源数组中的每个字节都必须作为短字节加载到寄存器中.

在for循环中,我必须在每次迭代中使用一批新的值进行加载.

我找不到任何ASIMD内部函数来做这件事,但也许我遗漏了一些东西.我目前的方法是首先将元素加载为uint8x8x3_t,执行扩大左移(使用vmovl_u8,使元素变为uint16x8_t),但这似乎非常低效:

uint8x8x3_t bgrChunk = vld3_u8(bgr);
uint16x8_t b = vmovl_u8(bgrChunk.val[0]);
uint16x8_t g = vmovl_u8(bgrChunk.val[1]);
uint16x8_t r = vmovl_u8(bgrChunk.val[2]);
bgr += 24; // Required for next iteration

我也try 了以下方法,但这个性能比上面的更差;

uint16_t bgrValues[] = { bgr++, bgr++, bgr++, ... repeat up to 24 elements ..., bgr++, bgr++ };
uint16x8x3_t bgrChunk = vld3q_u16(bgrValues);

有没有更有效的方法来做到这一点,或者我是不是错过了一些内在的东西,可以让我更容易做到这一点?

Edit; Extended example of what I want

假设我有一个数组uint8_t*,其值为{ 5,33,102,153. }

有没有一种方法可以将每个8位individual元素作为16位值直接加载到寄存器中,以便该寄存器将包含16-bit个值{5,33,102,153...}?

void foo(uint8_t* bgr, uint16_t width, uint16_t height) {
  for (uint16_t y = 0; y < height; y++) {
    for (uint16_t x = 0; x < width; x += 8) {
      // I want to load 8-bit values as 16-bit values here. Is there a more efficient way to do this than the code below?
      uint8x8x3_t bgrChunk = vld3_u8(bgr);
      uint16x8_t b = vmovl_u8(bgrChunk.val[0]);
      uint16x8_t g = vmovl_u8(bgrChunk.val[1]);
      uint16x8_t r = vmovl_u8(bgrChunk.val[2]);
      bgr += 24;
      // ... Some operations working on the loaded data
    }
  }
}

推荐答案

这是一个用于加载/存储的正交指令集,因此对于更宽的加载,您需要将8位值加载到寄存器中,然后作为第二次操作将其扩展到16位.

根据您下一步的操作,这第二个操作通常可能是一个有用的算术操作,而不仅仅是一次移动.例如,vmull_s8()vaddl_s8()vsubl_s8()都返回16位结果.如果你想走另一条路,也有类似的缩小范围.

C++相关问答推荐

为什么这个select()会阻止?

C中出现分段错误后关闭文件

无法用C++编译我的单元测试

如何知道我是否从非阻塞套接字读取所有内容

进程已完成,退出代码为138 Clion

初始变量重置后,char[]的赋值将消失

如何在STM8项目中导入STM8S/A标准外设库(ST VisualDeveloper)?

无法在OpenGL上绘制三角形

我的C函数起作用了,但我不确定为什么

处理EPOLL_WAIT中的接收数据和连接关闭信号

我在C中运行和调试时得到了不同的输出

C标准关于外部常量的说明

为什么GCC-O1优化破解了这个代码,为了一个GameBoy高级只读存储器而修改了VRAM的循环?

C-try 将整数和 struct 数组存储到二进制文件中

为什么会出现此错误?二进制表达式的操作数无效

&stdbool.h&q;在嵌入式系统中的使用

Malloc和对齐

无法理解 fgets 输出

为什么 int32_t 和 int16_t 在 printf 输出中具有相同的位数?

使用复合文字数组初始化的指针数组