c++ - “&”与“&&”表达式的C++编译标准?
问题描述
我有一个核心函数评估 4 个以上的简单算术比较以返回一个布尔值。这将在一个非常大的循环中被称为 O(N^2) 次,并且基于返回的单个条件分支。
如果函数写成:
return x < y && g < h && m < n && q < r;
与使用“&”的 0 相比,它会生成 3 个条件分支吗?此代码将公开发布,因此可以在具有许多不同编译器实现的许多不同平台上编译。
虽然单个实现可能足够聪明以优化短路,但是否将类似的内容写入标准(c++11、14、17 或 20)?只使用“&”对性能来说会“更安全”吗?
解决方案
我已经提供了 4 个代码示例,对Godbolt有一些警告。
- 无副作用
- 平凡的类型
#include <stdint.h>
#include <xmmintrin.h>
bool Test1(int x, int y, int g, int h, int m, int n, int q, int r) {
return x < y && g < h && m < n && q < r;
}
bool Test2(int x, int y, int g, int h, int m, int n, int q, int r) {
const bool a = x < y && g < h;
const bool b = m < n && q < r;
return a && b;
}
bool TestSIMD(__m128i v1, __m128i v2) {
__m128i vcmp = _mm_cmplt_epi32(v1, v2);
uint16_t mask = _mm_movemask_epi8(vcmp);
return (mask == 0xffff);
}
bool Test4(int x, int y, int g, int h, int m, int n, int q, int r) {
return x < y & g < h & m < n & q < r;
}
这编译为
Test1(int, int, int, int, int, int, int, int):
cmp edi, esi
setl al
cmp edx, ecx
setl dl
and al, dl
je .L1
cmp r8d, r9d
mov ecx, DWORD PTR [rsp+16]
setl al
cmp DWORD PTR [rsp+8], ecx
setl dl
and eax, edx
.L1:
ret
Test2(int, int, int, int, int, int, int, int):
cmp r8d, r9d
mov r10d, DWORD PTR [rsp+16]
setl al
cmp DWORD PTR [rsp+8], r10d
setl r8b
and eax, r8d
cmp edx, ecx
setl dl
and eax, edx
cmp edi, esi
setl dl
and eax, edx
ret
TestSIMD(long long __vector(2), long long __vector(2)):
vpcmpgtd xmm1, xmm1, xmm0
vpmovmskb eax, xmm1
cmp ax, -1
sete al
ret
Test4(int, int, int, int, int, int, int, int):
cmp r8d, r9d
mov r10d, DWORD PTR [rsp+16]
setl al
cmp DWORD PTR [rsp+8], r10d
setl r8b
and eax, r8d
cmp edx, ecx
setl dl
and eax, edx
cmp edi, esi
setl dl
and eax, edx
ret
循环时间是近似的,因为我没有费心分析每条指令。
- 第一种情况有一个条件分支,如果每次都没有正确预测分支,这可能会很糟糕。取 2(正确预测及早输出)、3、4 或 2+12(分支错误预测)。由于数据微不足道且没有副作用,因此编译器会随意使用短路。
- 第二种情况没有分支,但与第一种情况一样需要 3 或 4 个周期。但是每次的执行时间应该是一样的。
- 由于数据依赖性,SIMD 解决方案需要 4 个周期,没有分支。但是使用的流水线要少得多,因此可以与更多指令重叠。此外,数据必须可加载到寄存器中或已经存在于寄存器中,这至少需要一个额外的周期。
- & 解决方案也需要 4 个周期,但也使用 13 条指令。
因此,如果这接近您的问题,请使用 SIMD,如果您可以在您的平台上使用最快的 Test2 和 Test4。
推荐阅读
- c - 尽管 DLGC_WANTTAB 多行 EDIT 对话框控件不使用制表符
- python - Scikit-learn SequentialFeatureSelector 输入包含 NaN、无穷大或对于 dtype('float64') 来说太大的值。即使有管道
- tensorflow - 自定义 keras 真正的正数指标是否应该始终返回一个整数?
- python - seaborn 情节不在子情节上绘制
- c# - 如何在不知道 JSON 值的情况下动态解析一些 JSON?
- html - 内置 Bootstrap 'scrollTo' 功能?
- python - 使用 PySpark 数据框中的 2 列作为查找替换所有其他列
- wordpress - 使用 WordPress 网站插件或使用第 3 方的自动滴灌/工作流表单
- winforms - PowerShell Winform GUI 中的 WebView2
- r - R:从两列创建整数数组,然后绘制直方图