ARM64 ASIMD 内在函数将 uint8_t* 加载到 uint16x8(x3) 中?

问题描述 投票:0回答:1

我正在寻找一种将 8 位源数组 (

uint8_t*
) 中的元素加载到 AArch64 NEON / ASIMD 寄存器的方法,数据格式为
uint16x8_t
甚至更好
uint16x8x3_t
。所以基本上,源数组中的每个字节都必须作为短字节加载到寄存器中。

在 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

我也尝试过以下方法,但这比上面的表现更差;

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

是否有更有效的方法来做到这一点,或者我是否缺少一些内在的东西,这将使我更容易做到这一点?

编辑;我想要的扩展示例

假设我有一个数组

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
    }
  }
}
c++ c simd arm64 neon
1个回答
0
投票

它是一个正交指令集,因此为了扩大负载,您需要将 8 位值加载到寄存器中,然后作为第二次操作扩大到 16 位。

根据您接下来要做什么,第二个操作通常可能是一个有用的算术运算,而不仅仅是一次移动。例如,

vmull_s8()
vaddl_s8()
vsubl_s8()
都返回 16 位结果。如果您想走另一条路,也有类似的缩小等价物。

© www.soinside.com 2019 - 2024. All rights reserved.