SSE 半负载 (_mm_loadh_pi / _mm_loadl_pi) 发出警告
SSE half loads (_mm_loadh_pi / _mm_loadl_pi) issue warnings
我从英特尔网站上借用了矩阵反演算法:http://download.intel.com/design/PentiumIII/sml/24504301.pdf
它使用 _mm_loadh_pi 和 _mm_loadl_pi 加载 4x4 矩阵系数并同时进行部分洗牌。我的应用程序的性能改进是显着的,如果我使用 _mm_load_ps 对矩阵进行经典加载/随机排序,它会稍微慢一些。
但是这种加载方法发出编译警告:"tmp1 在此函数中使用未初始化"
__m128 tmp1;
tmp1 = _mm_loadh_pi(_mm_loadl_pi(tmp1, (__m64*)(src)), (__m64*)(src+ 4));
这在某种程度上是有道理的,因为 tmp1 是 _mm_loadl_pi 的输入参数,并且会影响结果。
但是,详细了解代码的功能表明 tmp1 不需要初始化。初始化会稍微减慢代码的速度(这是可测量的)。
您是否知道如何删除警告,如果可能的话,以便携式方式,而无需初始化 tmp1?
_mm_undefined_ps
的用途(但它实际上只有助于英特尔编译器的代码生成。 其他编译器通常将其处理方式与 _mm_setzero_ps
类似)。
除此之外,您还需要两个浮点数的movsd
加载,这些浮点数零扩展并打破了对寄存器旧值的错误依赖,而不是合并的movlps
。 (除非你正在构建一个粗糙的旧 32 位 CPU,它有 SSE1 但没有 SSE2,就像你的代码最初编写的 PIII 一样。
投射到double *
并使用_mm_load_sd
. 您不会自己取消引用它,只是通过 _mm_load_sd
,所以我认为这仍然是 100% 严格混叠安全的。 不过,它在实践中适用于当前的编译器! 如果事实证明不安全,_mm_loadl_epi64
(movq
)需要一个__m128i const*
参数(奇怪,因为它只加载低64位,但它是一种may_alias类型,你绝对可以安全地使用来读取任何其他类型,如char*
。
static inline
__m128 stride_gather(float *src) {
__m128 tmp1 = _mm_castpd_ps(_mm_load_sd((const double*)src)); // movsd
tmp1 = _mm_loadh_pi(tmp1, (const __m64*)(src+4)); // movhps
return tmp1;
}
gcc7 及更高版本使用 movq
而不是 movsd
,这很奇怪,但我认为这很好。 在最坏的情况下,旁路延迟延迟的额外周期作为某些旧 CPU 上movhps
的输入,但不会造成吞吐量损失。
其他 3 个主要编译器 (clang/ICC/MSVC) 都将其编译为预期的 movsd
/movhps
,而对旧值 xmm0 没有错误的依赖。 (Godbolt编译器资源管理器上的source+asm输出。
我尝试了3个编译器:MS Visual Studio 2012,gcc481和Intel icl 13.1。正如你所指出的,他们都会发出警告。我发现 gcc 和 MS 都会自动生成 tmp1 的初始化代码,即使它们警告缺少初始化。MS 编译器生成不需要的内存访问:movaps xmm0,xmmword ptr [rsp]
。GCC 生成更高效xorps xmm0,xmm0
.因此,在 gcc 的情况下,添加 tmp1=_mm_setzero_ps()
会消除警告并生成与没有完全相同的代码。在 MS 的情况下,添加 tmp1=_mm_setzero_ps()
会使代码更短,并且可能更快。只有英特尔编译器足够智能,可以避免不必要的初始化。以下是 MS 和 gcc 编译器的可能解决方法:
__m128 tmp1 = _mm_loadh_pi(_mm_load_ps (src), (__m64*)(src + 4));
代码生成为:
movaps xmm0,xmmword ptr [rcx]
movhps xmm0,qword ptr [rcx+10h]
它看起来更短,但应该进行基准测试以确保它更快。
09/12/2013: 不同警告抑制想法的测试代码:
#include <xmmintrin.h>
#include <stdint.h>
#include <stdio.h>
//---------------------------------------------------------------------------
// original code from http://download.intel.com/design/PentiumIII/sml/24504301.pdf
__m128 func1 (float *src)
{
__m128 tmp1;
tmp1 = _mm_loadh_pi(_mm_loadl_pi(tmp1, (__m64*)(src)), (__m64*)(src+ 4));
return tmp1;
}
//---------------------------------------------------------------------------
// original code plus tmp1 initialization
__m128 func2 (float *src)
{
__m128 tmp1 = _mm_loadh_pi(_mm_loadl_pi (_mm_setzero_ps (), (__m64*)(src)), (__m64*)(src + 4));
return tmp1;
}
//---------------------------------------------------------------------------
// use redundant load to eliminate warning
__m128 func3 (float *src)
{
__m128 tmp1 = _mm_loadh_pi(_mm_load_ps (src), (__m64*)(src + 4));
return tmp1;
}
//---------------------------------------------------------------------------
static void dump (void *data)
{
float *f16 = data;
int index;
for (index = 0; index < 4; index++)
printf ("%g ", f16 [index]);
printf ("n");
}
//---------------------------------------------------------------------------
int main (void)
{
float f [8] = {1, 2, 3, 4, 5, 6, 7, 8};
__m128 tmp;
tmp = func1 (f);
dump (&tmp);
tmp = func2 (f);
dump (&tmp);
tmp = func3 (f);
dump (&tmp);
return 0;
}
构建命令:
gcc -O3 -Wall -Wfatal-errors sample.c -osample.exe
objdump -Mintel --disassemble sample.exe > disasm.txt
cl -Ox -Zi -W4 sample.c
dumpbin -disasm -symbols sample.exe > disasm.txt
icl -Ox -Zi sample.c
dumpbin -disasm -symbols sample.exe > disasm.txt
- 基于树莓pi的tensorflow lite量化ssd目标检测
- 计算 PI 最多 42 位小数
- 如何在C++中将 chrono::秒转换为 HH:MM:SS 格式的字符串?
- 如何从远程 SFTP 服务器获取 HH-MM-SS 时间戳格式的文件列表
- 将 hh:mm:ss.zzz 时间 QString 转换为毫秒的单行函数?
- 使用莱布尼茨公式的 Pi 近似
- 为什么 std::round(sin(pi/6)) 不等于 1?
- 格式化时间 c++ dd/mm/yyyy hh:ss.
- Opencv GStreamer管道在Raspberry Pi 4上不起作用
- Raspberry Pi OpenVG C/C++
- 如何将鼠标坐标转换为"mm"
- C++数学问题和 5/4*pi 与 5*pi/4
- Raspberry Pi Zero W 上的 OpenCV - 浮点异常
- 如何在C++中将秒更改为 HH:MM:SS 格式?
- 从Raspberry Pi / Linux上的Python脚本运行和停止C++程序
- 使 C++ Pi 近似在 GPU Nvidia 970M CUDA 上的 Paralell 中运行
- 仅在 rasperry pi 要求时才在 Arduino 上运行C++
- 在 c++ 或 python 中生成一个体面的视差图以在 Raspberry Pi 上实现的最佳方法(算法或函数)是什么
- 与Qt交叉编译到Raspberry Pi 3B+通讯录(协议缓冲区)-错误符号查找错误
- 为什么OpenCV在Raspberry Pi 3B+上表现不佳