在下面的代码片段中,两个函数执行完全相同的功能并且在逻辑上是等效的。
constexpr char a[] = {50, 100};
bool contains_loop(char num) {
for (int i = 0; i < 2; ++ i) {
if (a[i] == num) {
return true;
}
}
return false;
}
bool contains_expanded(char num) {
return num == a[0] || num == a[1];
}
Run Code Online (Sandbox Code Playgroud)
我在godbolt中的测试表明,在/O2打开的 x64 MSVC 19.30 中,contains_loop未针对展开进行优化。汇编代码中,仍然有计数器,而编译后的汇编代码中没有contains_expanded。
inc rax
cmp rax, 2
Run Code Online (Sandbox Code Playgroud)
在 gcc 中-O3,它们被编译为完全相同的汇编代码。
这种优化看起来非常简单,但我无法让 MSVC 对其进行优化(自动)。我在这里缺少什么?
我基本上是在重写这个答案,因为我错误地拨打了电话contains_expanded,而不是contains_loop您所询问的电话。
简短的回答是,即使使用 VS2022(真实的东西)和 /O2 和 /Oi,循环显然也没有展开。我什至尝试了支持大小而不是支持速度,结果是相同的。
我用了这个基本的主要
int main()
{
std::vector<char> vals { 50, 49};
std::cout << "Test" << std::endl;
for (auto v : vals)
{
const auto val = contains_expanded(v);
std::cout << "Contains = " << v << std::boolalpha << val;
}
}
Run Code Online (Sandbox Code Playgroud)
我的编译优化开关使用/O2 和/Oi。这是输出命令 tlog 文件中的编译行
^C:\USERS\JMOLE\SOURCE\REPOS\TESTCPP\TESTCPP\TESTCPP.CPP
/c /Zi /nologo /W3 /WX- /diagnostics:column /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /permissive- /Fo"X64\RELEASE\\" /Fd"X64\RELEASE\VC143.PDB" /external:W3 /Gd /TP /FC C:\USERS\JMOLE\SOURCE\REPOS\TESTCPP\TESTCPP\TESTCPP.CPP
Run Code Online (Sandbox Code Playgroud)
这是我的版本中的调用列表contains_loop。
const auto val = contains_loop(v);
00007FF7234D1224 xor eax,eax
00007FF7234D1226 cmp byte ptr [rax+r15],bl
00007FF7234D122A je main+0AAh (07FF7234D123Ah)
00007FF7234D122C inc rax
00007FF7234D122F cmp rax,2
00007FF7234D1233 jl main+96h (07FF7234D1226h)
00007FF7234D1235 xor sil,sil
00007FF7234D1238 jmp main+0ADh (07FF7234D123Dh)
00007FF7234D123A mov sil,1
Run Code Online (Sandbox Code Playgroud)
因此,无论您选择什么优化,循环都不会在 MSVC 中展开。如果你错过了什么,我不知道它是什么