gpt4 book ai didi

c++ - SIMD -> uint16_t array to float array 在 float 上工作然后返回 uint16_t

转载 作者:太空宇宙 更新时间:2023-11-04 10:16:29 25 4
gpt4 key购买 nike

我目前正在从事一个处理图像的项目。为了加快这个过程(并增加我的知识),我决定使用 SIMD 指令编写一些基本函数。

使用for循环的代码是

int idx;
uint16_t* A, B, C;
float gAlpha = 0.8;
float alpha = 0.2;
for (size_t rw = 0; rw < height; rw++) {
for (size_t cl = 0; cl < width; cl++) {
idx = rw * width + height;
C[idx] = static_cast<uint16_t>(gAlpha * static_cast<float>(A[idx]) + alpha * static_cast<float>(B[idx]));
}
}
}

这个循环可能并不完美,但它完美地完成了工作,我的单元测试给了我预期的结果。

正如我所说,我正在尝试使用 SIMD 内在函数转换这些循环。这是我的工作代码,正如您将看到的,它不是很漂亮......我们确实可以访问 AVX2 的内在代码。

size_t n_pixels = height * width;
for (size_t px = 0; px < n_pixels; px += 8) {
__m128i xlo = _mm_unpacklo_epi16(_mm_load_si128((__m128i*)&A[px]), _mm_set1_epi16(0));
__m128i xhi = _mm_unpackhi_epi16(_mm_load_si128((__m128i*)&A[px]), _mm_set1_epi16(0));
__m128 ylo = _mm_cvtepi32_ps(xlo);
__m128 yhi = _mm_cvtepi32_ps(xhi);
__m256 pxMinFl = _mm256_castps128_ps256(ylo);
pxMinFl = _mm256_insertf128_ps(pxMinFl, yhi, 1);

xlo = _mm_unpacklo_epi16(_mm_load_si128((__m128i*)&B[px]), _mm_set1_epi16(0));
xhi = _mm_unpackhi_epi16(_mm_load_si128((__m128i*)&B[px]), _mm_set1_epi16(0));
ylo = _mm_cvtepi32_ps(xlo);
yhi = _mm_cvtepi32_ps(xhi);
__m256 pxMaxFl = _mm256_castps128_ps256(ylo);
pxMaxFl = _mm256_insertf128_ps(pxMaxFl, yhi, 1);

__m256 avGain1 = _mm256_set1_ps(gAlpha);
__m256 avGain2 = _mm256_set1_ps(alpha);

__m256 prodUp = _mm256_mul_ps(prodUp, avGain1);
__m256 prodBt = _mm256_mul_ps(prodBt, avGain2);
__m256 pxOutFl = _mm256_add_ps(prodUp, prodBt);

__m128 ylo_ps = _mm256_castps256_ps128(pxOutFl);
__m128 yhi_ps = _mm256_extractf128_ps(pxOutFl, 1);
__m128i xlo_ep = _mm_cvtps_epi32(ylo_ps);
__m128i xhi_ep = _mm_cvtps_epi32(yhi_ps); <- POINT 1

int* xl = reinterpret_cast<int*>(&xlo_ep); <- POINT 2
for (int i=0; i < 8; i++) { <- POINT 2
C[px + i] = static_cast<uint16_t>(xl[i]); <- POINT 2
}
}

这段代码可能有大量优化可以完成,但我已经检查过 pxOutFl 的输出是否符合预期值。当我查看如何将数据保存回输出数组 C 时,对我来说开始看起来像黑魔法的地方开始出现。首先,如果我在 POINT 1 处注释该行,则 代码不起作用 即使如您所见,我不使用该变量。其次,我猜想有比我用来将数据存储回 uint16_t 数组(要点 2)的技巧更好的解决方案,但我找不到有效的解决方案。

有人能指出我正确的方向吗?我错过了什么?我该如何改进这段代码?

提前致谢!

PS:我们在 Linux (Fedora 25) 上使用 Intel 编译器 2017 作为并行工作室专业版 2117。

最佳答案

您可以将第 2 点的所有内容重写为:

_mm_storeu_si128((__m128i *)&C[px], xlo_ep);

另请注意,_mm_load_si128 的所有实例都可能是 _mm_loadu_si128,因为您似乎无法保证任何地方的对齐。

关于c++ - SIMD -> uint16_t array to float array 在 float 上工作然后返回 uint16_t,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46002375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com