【发布时间】:2017-04-20 12:13:09
【问题描述】:
TLTR
对于 arm 内在函数,如何将 uint8x16_t 类型的 128 位变量输入到期望 uint16x8_t 的函数中?
扩展版
上下文:我有一个灰度图像,每像素 1 个字节。我想将其缩小 2 倍。对于每个 2x2 输入框,我想取最小像素。在纯 C 中,代码如下所示:
for (int y = 0; y < rows; y += 2) {
uint8_t* p_out = outBuffer + (y / 2) * outStride;
uint8_t* p_in = inBuffer + y * inStride;
for (int x = 0; x < cols; x += 2) {
*p_out = min(min(p_in[0],p_in[1]),min(p_in[inStride],p_in[inStride + 1]) );
p_out++;
p_in+=2;
}
}
其中行和列都是 2 的倍数。我将“跨步”称为从图像中的一个像素到紧接下方的像素所需的字节步骤。
现在我想对它进行矢量化。这个想法是:
- 连续取 2 行像素
- 从顶行开始在
a中加载16 个字节,并在b中立即加载下面的16 个字节 - 逐字节计算
a和b之间的最小值。存储在a。 - 创建
a的副本,将其右移1 个字节(8 位)。将其存储在b。 - 逐字节计算
a和b之间的最小值。存储在a。 - 在输出图像中存储
a的每一秒字节(丢弃一半字节)
我想用 Neon 内部函数来写这个。好消息是,每一步都存在与之匹配的内在函数。
例如,在第 3 点可以使用(来自here):
uint8x16_t vminq_u8(uint8x16_t a, uint8x16_t b);
在第 4 点,可以使用 8 位移位(来自 here)使用以下之一:
uint16x8_t vrshrq_n_u16(uint16x8_t a, __constrange(1,16) int b);
uint32x4_t vrshrq_n_u32(uint32x4_t a, __constrange(1,32) int b);
uint64x2_t vrshrq_n_u64(uint64x2_t a, __constrange(1,64) int b);
那是因为我不关心字节 1,3,5,7,9,11,13,15 会发生什么,因为无论如何它们都会从最终结果中被丢弃。 (这里的正确性已经过验证,不是问题的重点。)
但是,vminq_u8 的输出是 uint8x16_t 类型,它与我想使用的 shift 内在函数不兼容。在 C++ 中,我用this templated data structure 解决了这个问题,而我被告知问题cannot be reliably addressed using union (编辑:虽然那个答案是指C++,实际上是in C type punning IS allowed),也不是@ 987654326@,因为这会破坏严格的别名规则。
在使用 ARM Neon 内部函数时组合不同数据类型的方法是什么?
【问题讨论】:
标签: c arm vectorization neon