英特尔提供了一个名为_mm256_madd_epi16的C风格函数,基本上就是这样
__m256i _mm256_madd_epi16(__ m256i a,__ m256i b)
在a和b中多次打包有符号的16位整数,产生中间带符号的32位整数.水平添加相邻的中间32位整数对,并将结果打包为dst.
现在我有两个__m256i变量,每个变量都有32个8位int.
我想实现_mm256_madd_epi16与之相同的功能,但结果__m256i中的每个int32_t元素是四个signed char产品的总和,而不是两对signed int16_t.
我可以在标量循环中做到这一点:
alignas(32) uint32_t res[8];
for (int i = 0; i < 32; ++i)
res[i / 4] += _mm256_extract_epi8(a, i) * _mm256_extract_epi8(b, i);
return _mm256_load_si256((__m256i*)res);
Run Code Online (Sandbox Code Playgroud)
请注意,乘法结果在添加之前是符号扩展的int,并且_mm256_extract_epi8辅助函数1 返回signed__int8.没关系总数uint32_t而不是int32_t; 无论如何它只能添加四个8x8 => 16位数字才能溢出.
它看起来非常难看,并且不能高效运行,除非编译器使用SIMD做一些魔术,而不是编写为标量提取.
脚注1: _mm256_extract_epi8不是内在的. vpextrb仅适用于256位向量的低通道,此辅助函数可能允许索引不是编译时常量.
我想计算y = ax + b,其中x和y是一个像素值[即,值范围为0~255的字节],a而且b是浮点数
由于我需要对图像中的每个像素应用此公式,此外,a和b对于不同的像素是不同的.在C++中直接计算很慢,所以我很有兴趣知道c ++中的sse2指令.
搜索之后,我发现浮点数与sse2的乘法和加法一样_mm_mul_ps和_mm_add_ps.但首先,我需要将字节中的x转换为float(4字节).
问题是,在我从字节数据源(_mm_load_si128)加载数据后,如何将数据从byte转换为float?
我想做的是:
请注意,大多数输入具有较小的绝对值范围,如[-6,6],因此固定因子可以将它们映射到[-127,127].
我只使用avx2指令集,所以内在函数就像_mm256_cvtepi32_epi8不能使用一样.我想使用,_mm256_packs_epi16但它将两个输入混合在一起.:(
我还编写了一些将32位浮点数转换为16位int的代码,它正如我想要的那样工作.
void Quantize(const float* input, __m256i* output, float quant_mult, int num_rows, int width) {
// input is a matrix actuaaly, num_rows and width represent the number of rows and columns of the matrix
assert(width % 16 == 0);
int num_input_chunks = width / 16;
__m256 avx2_quant_mult = _mm256_set_ps(quant_mult, quant_mult, quant_mult, quant_mult,
quant_mult, quant_mult, quant_mult, quant_mult);
for (int i = 0; i < num_rows; ++i) {
const float* input_row = input + …Run Code Online (Sandbox Code Playgroud)