编辑:更改了MWE以避免进行大量优化,从而将手写版本减少为1
。
所以在阅读完这里的讨论之后:Implementing comparison operators via 'tuple' and 'tie', a good idea?,我想检查一下评论中的一个陈述(JohannesD):
看到编译器内联并优化了与元组和引用有关的所有内容,发出的汇编几乎与手写代码完全相同,我们感到非常惊讶。
问题1:如何正确检查此声明?
所以这就是我尝试过的:因为我从未接触过或看过汇编,所以我想让最简单的代码示例成为可能。但是,我还想比较编译器优化的汇编版本,以免混淆非内联函数等。结果是编译器基本上优化了我的整个MWE。因此,我添加了cout
。但这当然会给组件带来一些不必要的混乱。
问题2:在不引入太多新代码的情况下,有什么方法可以避免代码被完全优化?
所以我的MWE目前是你在下面找到的那个。在发布模式下使用Visual Studio,我编译了代码并使用它来查看程序集:How to view the assembly behind the code using Visual C++?。首先,我确保C ++ 14建议(auto tied()...
行)产生与没有这个额外函数的汇编代码完全相同的汇编代码。然后我想将它与手写代码进行比较,但得到完全不同的汇编输出,或者看起来似乎因为我对组装不太了解。
问题3:我在两个版本之间看到类似的行,但在使用元组的行中有很多其他行。这些额外的行做了什么?
问题4:汇编的长度不等于代码的缓慢。好的,但实际上可以从这个程序集中读出两个版本的性能有多少?
MWE - 编辑:现在没有希望得到优化
#include <tuple>
#include <iostream>
struct item_new {
item_new(int lx = 0, int ly = 0, int lz = 0, int ld = 0) :x(lx), y(ly), z(lz), d(ld) {}
int x, y, z, d;
auto tied() const { return std::tie(z, y, x, d); }
bool operator<(const item_new &rhs) const {
return tied() < rhs.tied();
}
};
struct item {
item(int lx = 0, int ly = 0, int lz = 0, int ld = 0) :x(lx), y(ly), z(lz), d(ld) {}
int x, y, z, d;
bool operator<(const item &rhs) const {
if (z < rhs.z)
return true;
if (z == rhs.z) {
if (y < rhs.y)
return true;
if (y == rhs.y) {
if (x < rhs.x)
return true;
if (x == rhs.x && d < rhs.d)
return true;
}
}
return false;
}
};
int main()
{
int x,y,z,d;
std::cin >> x;
std::cin >> y;
std::cin >> z;
std::cin >> d;
item a(x, y, z, d), b(7, 8, 9, 0);
//item_new a(x,y,z,d), b(7,8,9,0);
bool result = a<b;
std::cout << result;
return 0;
}
手写版本的汇编
int main()
{
012B1002 in al,dx
012B1003 and esp,0FFFFFFF8h
012B1006 sub esp,18h
012B1009 mov eax,dword ptr ds:[012B3004h]
012B100E xor eax,esp
012B1010 mov dword ptr [esp+14h],eax
int x,y,z,d;
std::cin >> x;
012B1014 mov ecx,dword ptr ds:[12B2038h]
012B101A lea eax,[esp+0Ch]
012B101E push eax
012B101F call dword ptr ds:[12B2034h]
std::cin >> y;
012B1025 mov ecx,dword ptr ds:[12B2038h]
012B102B lea eax,[esp+8]
012B102F push eax
012B1030 call dword ptr ds:[12B2034h]
std::cin >> z;
012B1036 mov ecx,dword ptr ds:[12B2038h]
012B103C lea eax,[esp+4]
012B1040 push eax
012B1041 call dword ptr ds:[12B2034h]
std::cin >> d;
012B1047 mov ecx,dword ptr ds:[12B2038h]
std::cin >> d;
012B104D lea eax,[esp+10h]
012B1051 push eax
012B1052 call dword ptr ds:[12B2034h]
item a(x, y, z, d), b(7, 8, 9, 0);
//item_new a(x,y,z,d), b(7,8,9,0);
bool result = a<b;
012B1058 mov eax,dword ptr [esp+4]
012B105C cmp eax,9
012B105F jge main+67h (012B1067h)
012B1061 mov byte ptr [esp],1
012B1065 jmp main+8Eh (012B108Eh)
012B1067 jne main+8Ah (012B108Ah)
012B1069 mov eax,dword ptr [esp+8]
012B106D cmp eax,8
012B1070 jl main+61h (012B1061h)
012B1072 jne main+8Ah (012B108Ah)
012B1074 mov eax,dword ptr [esp+0Ch]
012B1078 cmp eax,7
012B107B jl main+61h (012B1061h)
012B107D jne main+8Ah (012B108Ah)
012B107F cmp dword ptr [esp+10h],0
012B1084 mov byte ptr [esp],1
012B1088 jl main+8Eh (012B108Eh)
012B108A mov byte ptr [esp],0
std::cout << result;
012B108E push dword ptr [esp]
012B1091 mov ecx,dword ptr ds:[12B2040h]
012B1097 call dword ptr ds:[12B203Ch]
return 0;
}
012B109D mov ecx,dword ptr [esp+14h]
012B10A1 xor eax,eax
012B10A3 xor ecx,esp
012B10A5 call __security_check_cookie (012B10AEh)
012B10AA mov esp,ebp
012B10AC pop ebp
012B10AD ret
使用std :: tie
组装版本 int main()
{
00F41002 in al,dx
00F41003 and esp,0FFFFFFF8h
00F41006 sub esp,3Ch
00F41009 mov eax,dword ptr ds:[00F43004h]
00F4100E xor eax,esp
00F41010 mov dword ptr [esp+38h],eax
int x,y,z,d;
std::cin >> x;
00F41014 mov ecx,dword ptr ds:[0F42038h]
00F4101A lea eax,[esp+8]
00F4101E push esi
00F4101F push eax
00F41020 call dword ptr ds:[0F42034h]
std::cin >> y;
00F41026 mov ecx,dword ptr ds:[0F42038h]
00F4102C lea eax,[esp+10h]
00F41030 push eax
00F41031 call dword ptr ds:[0F42034h]
std::cin >> z;
00F41037 mov ecx,dword ptr ds:[0F42038h]
00F4103D lea eax,[esp+14h]
00F41041 push eax
00F41042 call dword ptr ds:[0F42034h]
std::cin >> d;
00F41048 mov ecx,dword ptr ds:[0F42038h]
00F4104E lea eax,[esp+18h]
00F41052 push eax
00F41053 call dword ptr ds:[0F42034h]
//item a(x, y, z, d), b(7, 8, 9, 0);
item_new a(x,y,z,d), b(7,8,9,0);
00F41059 mov edx,dword ptr [esp+14h]
00F4105D movaps xmm0,xmmword ptr ds:[0F42110h]
00F41064 mov eax,dword ptr [esp+0Ch]
00F41068 mov ecx,dword ptr [esp+10h]
00F4106C mov esi,dword ptr [esp+18h]
00F41070 mov dword ptr [esp+1Ch],eax
00F41074 mov dword ptr [esp+20h],ecx
00F41078 mov dword ptr [esp+24h],edx
00F4107C mov dword ptr [esp+28h],esi
00F41080 movups xmmword ptr [esp+2Ch],xmm0
bool result = a<b;
00F41085 cmp edx,9
00F41088 jl main+0A5h (0F410A5h)
00F4108A jg main+9Eh (0F4109Eh)
00F4108C cmp ecx,8
00F4108F jl main+0A5h (0F410A5h)
00F41091 jg main+9Eh (0F4109Eh)
00F41093 cmp eax,7
00F41096 jl main+0A5h (0F410A5h)
00F41098 jg main+9Eh (0F4109Eh)
00F4109A test esi,esi
00F4109C js main+0A5h (0F410A5h)
00F4109E mov byte ptr [esp+8],0
00F410A3 jmp main+0AAh (0F410AAh)
00F410A5 mov byte ptr [esp+8],1
std::cout << result;
00F410AA push dword ptr [esp+8]
00F410AE mov ecx,dword ptr ds:[0F42040h]
00F410B4 call dword ptr ds:[0F4203Ch]
return 0;
}
00F410BA mov ecx,dword ptr [esp+3Ch]
00F410BE xor eax,eax
00F410C0 pop esi
00F410C1 xor ecx,esp
00F410C3 call __security_check_cookie (0F410CCh)
00F410C8 mov esp,ebp
00F410CA pop ebp
00F410CB ret